- Add support for an extra scatter-gather list containing protection information. - Remember devices with protection information turned on in INQUIRY. Signed-off-by: Martin K. Petersen <martin.petersen@xxxxxxxxxx> --- 4 files changed, 62 insertions(+) drivers/scsi/scsi_lib.c | 38 ++++++++++++++++++++++++++++++++++++++ drivers/scsi/scsi_scan.c | 3 +++ include/scsi/scsi_cmnd.h | 20 ++++++++++++++++++++ include/scsi/scsi_device.h | 1 + diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -778,6 +778,11 @@ void scsi_release_buffers(struct scsi_cm kmem_cache_free(scsi_sdb_cache, bidi_sdb); cmd->request->next_rq->special = NULL; } + + if (scsi_prot_sg_count(cmd)) { + scsi_free_sgtable(cmd->prot_sdb); + kmem_cache_free(scsi_sdb_cache, cmd->prot_sdb); + } } EXPORT_SYMBOL(scsi_release_buffers); @@ -1031,6 +1036,32 @@ static int scsi_init_sgtable(struct requ return BLKPREP_OK; } +static int scsi_protect_io(struct scsi_cmnd *cmd, gfp_t gfp_mask) +{ + struct request *req; + struct scsi_data_buffer *pdb; + int ivecs, count; + + req = cmd->request; + + pdb = kmem_cache_zalloc(scsi_sdb_cache, gfp_mask); + if (unlikely(pdb == NULL)) + return BLKPREP_DEFER; + + ivecs = blk_rq_count_integrity_sg(req); + + if (unlikely(scsi_alloc_sgtable(pdb, ivecs, gfp_mask))) + return BLKPREP_DEFER; + + count = blk_rq_map_integrity_sg(req, pdb->table.sgl); + BUG_ON(unlikely(count > ivecs)); + + cmd->prot_sdb = pdb; + cmd->prot_sdb->table.nents = count; + + return BLKPREP_OK; +} + /* * Function: scsi_init_io() * @@ -1060,6 +1091,13 @@ int scsi_init_io(struct scsi_cmnd *cmd, error = scsi_init_sgtable(cmd->request->next_rq, bidi_sdb, GFP_ATOMIC); if (error) + goto err_exit; + } + + if (blk_integrity_rq(cmd->request)) { + error = scsi_protect_io(cmd, gfp_mask); + + if (error != BLKPREP_OK) goto err_exit; } diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c @@ -882,6 +882,9 @@ static int scsi_add_lun(struct scsi_devi if (*bflags & BLIST_USE_10_BYTE_MS) sdev->use_10_for_ms = 1; + + if (inq_result[5] & 0x1) + sdev->protection = 1; /* set the device running here so that slave configure * may do I/O */ diff --git a/include/scsi/scsi_cmnd.h b/include/scsi/scsi_cmnd.h --- a/include/scsi/scsi_cmnd.h +++ b/include/scsi/scsi_cmnd.h @@ -88,6 +88,8 @@ struct scsi_cmnd { /* These elements define the operation we ultimately want to perform */ struct scsi_data_buffer sdb; + struct scsi_data_buffer *prot_sdb; + unsigned underflow; /* Return error if less than this amount is transferred */ @@ -209,4 +211,22 @@ static inline int scsi_sg_copy_to_buffer buf, buflen); } +static inline unsigned scsi_prot_sg_count(struct scsi_cmnd *cmd) +{ + return cmd->prot_sdb ? cmd->prot_sdb->table.nents : 0; +} + +static inline struct scatterlist *scsi_prot_sglist(struct scsi_cmnd *cmd) +{ + return cmd->prot_sdb ? cmd->prot_sdb->table.sgl : NULL; +} + +static inline struct scsi_data_buffer *scsi_prot(struct scsi_cmnd *cmd) +{ + return cmd->prot_sdb; +} + +#define scsi_for_each_prot_sg(cmd, sg, nseg, __i) \ + for_each_sg(scsi_prot_sglist(cmd), sg, nseg, __i) + #endif /* _SCSI_SCSI_CMND_H */ diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h --- a/include/scsi/scsi_device.h +++ b/include/scsi/scsi_device.h @@ -140,6 +140,7 @@ struct scsi_device { unsigned guess_capacity:1; /* READ_CAPACITY might be too high by 1 */ unsigned retry_hwerror:1; /* Retry HARDWARE_ERROR */ unsigned last_sector_bug:1; /* Always read last sector in a 1 sector read */ + unsigned protection:1; /* Data Integrity Field */ DECLARE_BITMAP(supported_events, SDEV_EVT_MAXBITS); /* supported events */ struct list_head event_list; /* asserted events */ -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html