diff options
author | Martin K. Petersen <martin.petersen@oracle.com> | 2008-07-17 17:08:48 -0400 |
---|---|---|
committer | James Bottomley <James.Bottomley@HansenPartnership.com> | 2008-07-26 15:14:55 -0400 |
commit | 7027ad72a689797475973c6feb5f0b673382f779 (patch) | |
tree | 4f6daa1d509708fb340d09608d79557a9af57f00 /drivers/scsi | |
parent | db007fc5e20c00b356e9ffe2d0e007398c65c837 (diff) |
[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>
Diffstat (limited to 'drivers/scsi')
-rw-r--r-- | drivers/scsi/scsi.c | 36 | ||||
-rw-r--r-- | drivers/scsi/scsi_lib.c | 25 | ||||
-rw-r--r-- | drivers/scsi/scsi_priv.h | 1 |
3 files changed, 59 insertions, 3 deletions
diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index 5276e73c58fc..ee6be596503d 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c | |||
@@ -197,11 +197,43 @@ static void | |||
197 | scsi_pool_free_command(struct scsi_host_cmd_pool *pool, | 197 | scsi_pool_free_command(struct scsi_host_cmd_pool *pool, |
198 | struct scsi_cmnd *cmd) | 198 | struct scsi_cmnd *cmd) |
199 | { | 199 | { |
200 | if (cmd->prot_sdb) | ||
201 | kmem_cache_free(scsi_sdb_cache, cmd->prot_sdb); | ||
202 | |||
200 | kmem_cache_free(pool->sense_slab, cmd->sense_buffer); | 203 | kmem_cache_free(pool->sense_slab, cmd->sense_buffer); |
201 | kmem_cache_free(pool->cmd_slab, cmd); | 204 | kmem_cache_free(pool->cmd_slab, cmd); |
202 | } | 205 | } |
203 | 206 | ||
204 | /** | 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; | ||
234 | } | ||
235 | |||
236 | /** | ||
205 | * __scsi_get_command - Allocate a struct scsi_cmnd | 237 | * __scsi_get_command - Allocate a struct scsi_cmnd |
206 | * @shost: host to transmit command | 238 | * @shost: host to transmit command |
207 | * @gfp_mask: allocation mask | 239 | * @gfp_mask: allocation mask |
@@ -214,7 +246,7 @@ struct scsi_cmnd *__scsi_get_command(struct Scsi_Host *shost, gfp_t gfp_mask) | |||
214 | struct scsi_cmnd *cmd; | 246 | struct scsi_cmnd *cmd; |
215 | unsigned char *buf; | 247 | unsigned char *buf; |
216 | 248 | ||
217 | cmd = scsi_pool_alloc_command(shost->cmd_pool, gfp_mask); | 249 | cmd = scsi_host_alloc_command(shost, gfp_mask); |
218 | 250 | ||
219 | if (unlikely(!cmd)) { | 251 | if (unlikely(!cmd)) { |
220 | unsigned long flags; | 252 | unsigned long flags; |
@@ -457,7 +489,7 @@ int scsi_setup_command_freelist(struct Scsi_Host *shost) | |||
457 | /* | 489 | /* |
458 | * Get one backup command for this host. | 490 | * Get one backup command for this host. |
459 | */ | 491 | */ |
460 | cmd = scsi_pool_alloc_command(shost->cmd_pool, gfp_mask); | 492 | cmd = scsi_host_alloc_command(shost, gfp_mask); |
461 | if (!cmd) { | 493 | if (!cmd) { |
462 | scsi_put_host_cmd_pool(gfp_mask); | 494 | scsi_put_host_cmd_pool(gfp_mask); |
463 | shost->cmd_pool = NULL; | 495 | shost->cmd_pool = NULL; |
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index fe77ccacf319..a47c05d7829a 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c | |||
@@ -65,7 +65,7 @@ static struct scsi_host_sg_pool scsi_sg_pools[] = { | |||
65 | }; | 65 | }; |
66 | #undef SP | 66 | #undef SP |
67 | 67 | ||
68 | static struct kmem_cache *scsi_sdb_cache; | 68 | struct kmem_cache *scsi_sdb_cache; |
69 | 69 | ||
70 | static void scsi_run_queue(struct request_queue *q); | 70 | static void scsi_run_queue(struct request_queue *q); |
71 | 71 | ||
@@ -787,6 +787,9 @@ void scsi_release_buffers(struct scsi_cmnd *cmd) | |||
787 | kmem_cache_free(scsi_sdb_cache, bidi_sdb); | 787 | kmem_cache_free(scsi_sdb_cache, bidi_sdb); |
788 | cmd->request->next_rq->special = NULL; | 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 | EXPORT_SYMBOL(scsi_release_buffers); | 794 | EXPORT_SYMBOL(scsi_release_buffers); |
792 | 795 | ||
@@ -1072,6 +1075,26 @@ int scsi_init_io(struct scsi_cmnd *cmd, gfp_t gfp_mask) | |||
1072 | goto err_exit; | 1075 | goto err_exit; |
1073 | } | 1076 | } |
1074 | 1077 | ||
1078 | if (blk_integrity_rq(cmd->request)) { | ||
1079 | struct scsi_data_buffer *prot_sdb = cmd->prot_sdb; | ||
1080 | int ivecs, count; | ||
1081 | |||
1082 | BUG_ON(prot_sdb == NULL); | ||
1083 | ivecs = blk_rq_count_integrity_sg(cmd->request); | ||
1084 | |||
1085 | if (scsi_alloc_sgtable(prot_sdb, ivecs, gfp_mask)) { | ||
1086 | error = BLKPREP_DEFER; | ||
1087 | goto err_exit; | ||
1088 | } | ||
1089 | |||
1090 | count = blk_rq_map_integrity_sg(cmd->request, | ||
1091 | prot_sdb->table.sgl); | ||
1092 | BUG_ON(unlikely(count > ivecs)); | ||
1093 | |||
1094 | cmd->prot_sdb = prot_sdb; | ||
1095 | cmd->prot_sdb->table.nents = count; | ||
1096 | } | ||
1097 | |||
1075 | return BLKPREP_OK ; | 1098 | return BLKPREP_OK ; |
1076 | 1099 | ||
1077 | err_exit: | 1100 | err_exit: |
diff --git a/drivers/scsi/scsi_priv.h b/drivers/scsi/scsi_priv.h index b33e72516ef8..79f0f7511204 100644 --- a/drivers/scsi/scsi_priv.h +++ b/drivers/scsi/scsi_priv.h | |||
@@ -77,6 +77,7 @@ extern void scsi_exit_queue(void); | |||
77 | struct request_queue; | 77 | struct request_queue; |
78 | struct request; | 78 | struct request; |
79 | extern int scsi_prep_fn(struct request_queue *, struct request *); | 79 | extern int scsi_prep_fn(struct request_queue *, struct request *); |
80 | extern struct kmem_cache *scsi_sdb_cache; | ||
80 | 81 | ||
81 | /* scsi_proc.c */ | 82 | /* scsi_proc.c */ |
82 | #ifdef CONFIG_SCSI_PROC_FS | 83 | #ifdef CONFIG_SCSI_PROC_FS |