[SCSI] Support devices with protection information

Implement support for DMA of protection information for devices that
are data integrity capable.

- Add support for mapping an extra scatter-gather list containing
the protection information.

- Allocate protection scsi_data_buffer if host is DIX (integrity DMA)
capable.

- Accessor function for checking whether a device has protection
enabled.

Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>

authored by

Martin K. Petersen and committed by
James Bottomley
7027ad72 db007fc5

+84 -3
+34 -2
drivers/scsi/scsi.c
··· 197 197 scsi_pool_free_command(struct scsi_host_cmd_pool *pool, 198 198 struct scsi_cmnd *cmd) 199 199 { 200 + if (cmd->prot_sdb) 201 + kmem_cache_free(scsi_sdb_cache, cmd->prot_sdb); 202 + 200 203 kmem_cache_free(pool->sense_slab, cmd->sense_buffer); 201 204 kmem_cache_free(pool->cmd_slab, cmd); 205 + } 206 + 207 + /** 208 + * scsi_host_alloc_command - internal function to allocate command 209 + * @shost: SCSI host whose pool to allocate from 210 + * @gfp_mask: mask for the allocation 211 + * 212 + * Returns a fully allocated command with sense buffer and protection 213 + * data buffer (where applicable) or NULL on failure 214 + */ 215 + static struct scsi_cmnd * 216 + scsi_host_alloc_command(struct Scsi_Host *shost, gfp_t gfp_mask) 217 + { 218 + struct scsi_cmnd *cmd; 219 + 220 + cmd = scsi_pool_alloc_command(shost->cmd_pool, gfp_mask); 221 + if (!cmd) 222 + return NULL; 223 + 224 + if (scsi_host_get_prot(shost) >= SHOST_DIX_TYPE0_PROTECTION) { 225 + cmd->prot_sdb = kmem_cache_zalloc(scsi_sdb_cache, gfp_mask); 226 + 227 + if (!cmd->prot_sdb) { 228 + scsi_pool_free_command(shost->cmd_pool, cmd); 229 + return NULL; 230 + } 231 + } 232 + 233 + return cmd; 202 234 } 203 235 204 236 /** ··· 246 214 struct scsi_cmnd *cmd; 247 215 unsigned char *buf; 248 216 249 - cmd = scsi_pool_alloc_command(shost->cmd_pool, gfp_mask); 217 + cmd = scsi_host_alloc_command(shost, gfp_mask); 250 218 251 219 if (unlikely(!cmd)) { 252 220 unsigned long flags; ··· 489 457 /* 490 458 * Get one backup command for this host. 491 459 */ 492 - cmd = scsi_pool_alloc_command(shost->cmd_pool, gfp_mask); 460 + cmd = scsi_host_alloc_command(shost, gfp_mask); 493 461 if (!cmd) { 494 462 scsi_put_host_cmd_pool(gfp_mask); 495 463 shost->cmd_pool = NULL;
+24 -1
drivers/scsi/scsi_lib.c
··· 65 65 }; 66 66 #undef SP 67 67 68 - static struct kmem_cache *scsi_sdb_cache; 68 + struct kmem_cache *scsi_sdb_cache; 69 69 70 70 static void scsi_run_queue(struct request_queue *q); 71 71 ··· 787 787 kmem_cache_free(scsi_sdb_cache, bidi_sdb); 788 788 cmd->request->next_rq->special = NULL; 789 789 } 790 + 791 + if (scsi_prot_sg_count(cmd)) 792 + scsi_free_sgtable(cmd->prot_sdb); 790 793 } 791 794 EXPORT_SYMBOL(scsi_release_buffers); 792 795 ··· 1073 1070 GFP_ATOMIC); 1074 1071 if (error) 1075 1072 goto err_exit; 1073 + } 1074 + 1075 + if (blk_integrity_rq(cmd->request)) { 1076 + struct scsi_data_buffer *prot_sdb = cmd->prot_sdb; 1077 + int ivecs, count; 1078 + 1079 + BUG_ON(prot_sdb == NULL); 1080 + ivecs = blk_rq_count_integrity_sg(cmd->request); 1081 + 1082 + if (scsi_alloc_sgtable(prot_sdb, ivecs, gfp_mask)) { 1083 + error = BLKPREP_DEFER; 1084 + goto err_exit; 1085 + } 1086 + 1087 + count = blk_rq_map_integrity_sg(cmd->request, 1088 + prot_sdb->table.sgl); 1089 + BUG_ON(unlikely(count > ivecs)); 1090 + 1091 + cmd->prot_sdb = prot_sdb; 1092 + cmd->prot_sdb->table.nents = count; 1076 1093 } 1077 1094 1078 1095 return BLKPREP_OK ;
+1
drivers/scsi/scsi_priv.h
··· 77 77 struct request_queue; 78 78 struct request; 79 79 extern int scsi_prep_fn(struct request_queue *, struct request *); 80 + extern struct kmem_cache *scsi_sdb_cache; 80 81 81 82 /* scsi_proc.c */ 82 83 #ifdef CONFIG_SCSI_PROC_FS
+20
include/scsi/scsi_cmnd.h
··· 90 90 91 91 /* These elements define the operation we ultimately want to perform */ 92 92 struct scsi_data_buffer sdb; 93 + struct scsi_data_buffer *prot_sdb; 94 + 93 95 unsigned underflow; /* Return error if less than 94 96 this amount is transferred */ 95 97 ··· 275 273 { 276 274 return scmd->request->sector; 277 275 } 276 + 277 + static inline unsigned scsi_prot_sg_count(struct scsi_cmnd *cmd) 278 + { 279 + return cmd->prot_sdb ? cmd->prot_sdb->table.nents : 0; 280 + } 281 + 282 + static inline struct scatterlist *scsi_prot_sglist(struct scsi_cmnd *cmd) 283 + { 284 + return cmd->prot_sdb ? cmd->prot_sdb->table.sgl : NULL; 285 + } 286 + 287 + static inline struct scsi_data_buffer *scsi_prot(struct scsi_cmnd *cmd) 288 + { 289 + return cmd->prot_sdb; 290 + } 291 + 292 + #define scsi_for_each_prot_sg(cmd, sg, nseg, __i) \ 293 + for_each_sg(scsi_prot_sglist(cmd), sg, nseg, __i) 278 294 279 295 #endif /* _SCSI_SCSI_CMND_H */
+5
include/scsi/scsi_device.h
··· 423 423 return sdev->inquiry[6] & (1<<6); 424 424 } 425 425 426 + static inline int scsi_device_protection(struct scsi_device *sdev) 427 + { 428 + return sdev->inquiry[5] & (1<<0); 429 + } 430 + 426 431 #define MODULE_ALIAS_SCSI_DEVICE(type) \ 427 432 MODULE_ALIAS("scsi:t-" __stringify(type) "*") 428 433 #define SCSI_DEVICE_MODALIAS_FMT "scsi:t-0x%02x"