diff options
author | FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp> | 2008-01-15 23:32:17 -0500 |
---|---|---|
committer | James Bottomley <James.Bottomley@HansenPartnership.com> | 2008-01-23 12:37:37 -0500 |
commit | de25deb18016f66dcdede165d07654559bb332bc (patch) | |
tree | b566c2a369d3dce85507ab28ea20ffee020e0c06 | |
parent | b30c2fc1113edfb2371427c10503ff942b0a0370 (diff) |
[SCSI] use dynamically allocated sense buffer
This removes static array sense_buffer in scsi_cmnd and uses
dynamically allocated sense_buffer (with GFP_DMA).
The reason for doing this is that some architectures need cacheline
aligned buffer for DMA:
http://lkml.org/lkml/2007/11/19/2
The problems are that scsi_eh_prep_cmnd puts scsi_cmnd::sense_buffer
to sglist and some LLDs directly DMA to scsi_cmnd::sense_buffer. It's
necessary to DMA to scsi_cmnd::sense_buffer safely. This patch solves
these issues.
__scsi_get_command allocates sense_buffer via kmem_cache_alloc and
attaches it to a scsi_cmnd so everything just work as before.
Signed-off-by: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
-rw-r--r-- | drivers/scsi/hosts.c | 9 | ||||
-rw-r--r-- | drivers/scsi/scsi.c | 61 | ||||
-rw-r--r-- | drivers/scsi/scsi_priv.h | 2 | ||||
-rw-r--r-- | include/scsi/scsi_cmnd.h | 2 |
4 files changed, 70 insertions, 4 deletions
diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c index 9a10b4335e76..f5d3fbb55717 100644 --- a/drivers/scsi/hosts.c +++ b/drivers/scsi/hosts.c | |||
@@ -268,6 +268,7 @@ static void scsi_host_dev_release(struct device *dev) | |||
268 | } | 268 | } |
269 | 269 | ||
270 | scsi_destroy_command_freelist(shost); | 270 | scsi_destroy_command_freelist(shost); |
271 | scsi_destroy_command_sense_buffer(shost); | ||
271 | if (shost->bqt) | 272 | if (shost->bqt) |
272 | blk_free_tags(shost->bqt); | 273 | blk_free_tags(shost->bqt); |
273 | 274 | ||
@@ -372,10 +373,14 @@ struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize) | |||
372 | else | 373 | else |
373 | shost->dma_boundary = 0xffffffff; | 374 | shost->dma_boundary = 0xffffffff; |
374 | 375 | ||
375 | rval = scsi_setup_command_freelist(shost); | 376 | rval = scsi_setup_command_sense_buffer(shost); |
376 | if (rval) | 377 | if (rval) |
377 | goto fail_kfree; | 378 | goto fail_kfree; |
378 | 379 | ||
380 | rval = scsi_setup_command_freelist(shost); | ||
381 | if (rval) | ||
382 | goto fail_destroy_sense; | ||
383 | |||
379 | device_initialize(&shost->shost_gendev); | 384 | device_initialize(&shost->shost_gendev); |
380 | snprintf(shost->shost_gendev.bus_id, BUS_ID_SIZE, "host%d", | 385 | snprintf(shost->shost_gendev.bus_id, BUS_ID_SIZE, "host%d", |
381 | shost->host_no); | 386 | shost->host_no); |
@@ -399,6 +404,8 @@ struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize) | |||
399 | 404 | ||
400 | fail_destroy_freelist: | 405 | fail_destroy_freelist: |
401 | scsi_destroy_command_freelist(shost); | 406 | scsi_destroy_command_freelist(shost); |
407 | fail_destroy_sense: | ||
408 | scsi_destroy_command_sense_buffer(shost); | ||
402 | fail_kfree: | 409 | fail_kfree: |
403 | kfree(shost); | 410 | kfree(shost); |
404 | return NULL; | 411 | return NULL; |
diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index 54ff611b8677..0a4a5b8b87c6 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c | |||
@@ -161,6 +161,9 @@ static struct scsi_host_cmd_pool scsi_cmd_dma_pool = { | |||
161 | 161 | ||
162 | static DEFINE_MUTEX(host_cmd_pool_mutex); | 162 | static DEFINE_MUTEX(host_cmd_pool_mutex); |
163 | 163 | ||
164 | static struct kmem_cache *sense_buffer_slab; | ||
165 | static int sense_buffer_slab_users; | ||
166 | |||
164 | /** | 167 | /** |
165 | * __scsi_get_command - Allocate a struct scsi_cmnd | 168 | * __scsi_get_command - Allocate a struct scsi_cmnd |
166 | * @shost: host to transmit command | 169 | * @shost: host to transmit command |
@@ -172,6 +175,7 @@ static DEFINE_MUTEX(host_cmd_pool_mutex); | |||
172 | struct scsi_cmnd *__scsi_get_command(struct Scsi_Host *shost, gfp_t gfp_mask) | 175 | struct scsi_cmnd *__scsi_get_command(struct Scsi_Host *shost, gfp_t gfp_mask) |
173 | { | 176 | { |
174 | struct scsi_cmnd *cmd; | 177 | struct scsi_cmnd *cmd; |
178 | unsigned char *buf; | ||
175 | 179 | ||
176 | cmd = kmem_cache_alloc(shost->cmd_pool->slab, | 180 | cmd = kmem_cache_alloc(shost->cmd_pool->slab, |
177 | gfp_mask | shost->cmd_pool->gfp_mask); | 181 | gfp_mask | shost->cmd_pool->gfp_mask); |
@@ -186,6 +190,21 @@ struct scsi_cmnd *__scsi_get_command(struct Scsi_Host *shost, gfp_t gfp_mask) | |||
186 | list_del_init(&cmd->list); | 190 | list_del_init(&cmd->list); |
187 | } | 191 | } |
188 | spin_unlock_irqrestore(&shost->free_list_lock, flags); | 192 | spin_unlock_irqrestore(&shost->free_list_lock, flags); |
193 | |||
194 | if (cmd) { | ||
195 | buf = cmd->sense_buffer; | ||
196 | memset(cmd, 0, sizeof(*cmd)); | ||
197 | cmd->sense_buffer = buf; | ||
198 | } | ||
199 | } else { | ||
200 | buf = kmem_cache_alloc(sense_buffer_slab, __GFP_DMA|gfp_mask); | ||
201 | if (likely(buf)) { | ||
202 | memset(cmd, 0, sizeof(*cmd)); | ||
203 | cmd->sense_buffer = buf; | ||
204 | } else { | ||
205 | kmem_cache_free(shost->cmd_pool->slab, cmd); | ||
206 | cmd = NULL; | ||
207 | } | ||
189 | } | 208 | } |
190 | 209 | ||
191 | return cmd; | 210 | return cmd; |
@@ -212,7 +231,6 @@ struct scsi_cmnd *scsi_get_command(struct scsi_device *dev, gfp_t gfp_mask) | |||
212 | if (likely(cmd != NULL)) { | 231 | if (likely(cmd != NULL)) { |
213 | unsigned long flags; | 232 | unsigned long flags; |
214 | 233 | ||
215 | memset(cmd, 0, sizeof(*cmd)); | ||
216 | cmd->device = dev; | 234 | cmd->device = dev; |
217 | init_timer(&cmd->eh_timeout); | 235 | init_timer(&cmd->eh_timeout); |
218 | INIT_LIST_HEAD(&cmd->list); | 236 | INIT_LIST_HEAD(&cmd->list); |
@@ -246,8 +264,10 @@ void __scsi_put_command(struct Scsi_Host *shost, struct scsi_cmnd *cmd, | |||
246 | } | 264 | } |
247 | spin_unlock_irqrestore(&shost->free_list_lock, flags); | 265 | spin_unlock_irqrestore(&shost->free_list_lock, flags); |
248 | 266 | ||
249 | if (likely(cmd != NULL)) | 267 | if (likely(cmd != NULL)) { |
268 | kmem_cache_free(sense_buffer_slab, cmd->sense_buffer); | ||
250 | kmem_cache_free(shost->cmd_pool->slab, cmd); | 269 | kmem_cache_free(shost->cmd_pool->slab, cmd); |
270 | } | ||
251 | 271 | ||
252 | put_device(dev); | 272 | put_device(dev); |
253 | } | 273 | } |
@@ -290,6 +310,7 @@ int scsi_setup_command_freelist(struct Scsi_Host *shost) | |||
290 | { | 310 | { |
291 | struct scsi_host_cmd_pool *pool; | 311 | struct scsi_host_cmd_pool *pool; |
292 | struct scsi_cmnd *cmd; | 312 | struct scsi_cmnd *cmd; |
313 | unsigned char *sense_buffer; | ||
293 | 314 | ||
294 | spin_lock_init(&shost->free_list_lock); | 315 | spin_lock_init(&shost->free_list_lock); |
295 | INIT_LIST_HEAD(&shost->free_list); | 316 | INIT_LIST_HEAD(&shost->free_list); |
@@ -319,9 +340,18 @@ int scsi_setup_command_freelist(struct Scsi_Host *shost) | |||
319 | GFP_KERNEL | shost->cmd_pool->gfp_mask); | 340 | GFP_KERNEL | shost->cmd_pool->gfp_mask); |
320 | if (!cmd) | 341 | if (!cmd) |
321 | goto fail2; | 342 | goto fail2; |
343 | |||
344 | sense_buffer = kmem_cache_alloc(sense_buffer_slab, | ||
345 | GFP_KERNEL | __GFP_DMA); | ||
346 | if (!sense_buffer) | ||
347 | goto destroy_backup; | ||
348 | |||
349 | cmd->sense_buffer = sense_buffer; | ||
322 | list_add(&cmd->list, &shost->free_list); | 350 | list_add(&cmd->list, &shost->free_list); |
323 | return 0; | 351 | return 0; |
324 | 352 | ||
353 | destroy_backup: | ||
354 | kmem_cache_free(shost->cmd_pool->slab, cmd); | ||
325 | fail2: | 355 | fail2: |
326 | mutex_lock(&host_cmd_pool_mutex); | 356 | mutex_lock(&host_cmd_pool_mutex); |
327 | if (!--pool->users) | 357 | if (!--pool->users) |
@@ -342,6 +372,7 @@ void scsi_destroy_command_freelist(struct Scsi_Host *shost) | |||
342 | 372 | ||
343 | cmd = list_entry(shost->free_list.next, struct scsi_cmnd, list); | 373 | cmd = list_entry(shost->free_list.next, struct scsi_cmnd, list); |
344 | list_del_init(&cmd->list); | 374 | list_del_init(&cmd->list); |
375 | kmem_cache_free(sense_buffer_slab, cmd->sense_buffer); | ||
345 | kmem_cache_free(shost->cmd_pool->slab, cmd); | 376 | kmem_cache_free(shost->cmd_pool->slab, cmd); |
346 | } | 377 | } |
347 | 378 | ||
@@ -351,6 +382,32 @@ void scsi_destroy_command_freelist(struct Scsi_Host *shost) | |||
351 | mutex_unlock(&host_cmd_pool_mutex); | 382 | mutex_unlock(&host_cmd_pool_mutex); |
352 | } | 383 | } |
353 | 384 | ||
385 | int scsi_setup_command_sense_buffer(struct Scsi_Host *shost) | ||
386 | { | ||
387 | mutex_lock(&host_cmd_pool_mutex); | ||
388 | if (!sense_buffer_slab_users) { | ||
389 | sense_buffer_slab = kmem_cache_create("scsi_sense_buffer", | ||
390 | SCSI_SENSE_BUFFERSIZE, | ||
391 | 0, SLAB_CACHE_DMA, NULL); | ||
392 | if (!sense_buffer_slab) { | ||
393 | mutex_unlock(&host_cmd_pool_mutex); | ||
394 | return -ENOMEM; | ||
395 | } | ||
396 | } | ||
397 | sense_buffer_slab_users++; | ||
398 | mutex_unlock(&host_cmd_pool_mutex); | ||
399 | |||
400 | return 0; | ||
401 | } | ||
402 | |||
403 | void scsi_destroy_command_sense_buffer(struct Scsi_Host *shost) | ||
404 | { | ||
405 | mutex_lock(&host_cmd_pool_mutex); | ||
406 | if (!--sense_buffer_slab_users) | ||
407 | kmem_cache_destroy(sense_buffer_slab); | ||
408 | mutex_unlock(&host_cmd_pool_mutex); | ||
409 | } | ||
410 | |||
354 | #ifdef CONFIG_SCSI_LOGGING | 411 | #ifdef CONFIG_SCSI_LOGGING |
355 | void scsi_log_send(struct scsi_cmnd *cmd) | 412 | void scsi_log_send(struct scsi_cmnd *cmd) |
356 | { | 413 | { |
diff --git a/drivers/scsi/scsi_priv.h b/drivers/scsi/scsi_priv.h index 3f34e9376b0a..55c6f71a9aee 100644 --- a/drivers/scsi/scsi_priv.h +++ b/drivers/scsi/scsi_priv.h | |||
@@ -27,6 +27,8 @@ extern void scsi_exit_hosts(void); | |||
27 | extern int scsi_dispatch_cmd(struct scsi_cmnd *cmd); | 27 | extern int scsi_dispatch_cmd(struct scsi_cmnd *cmd); |
28 | extern int scsi_setup_command_freelist(struct Scsi_Host *shost); | 28 | extern int scsi_setup_command_freelist(struct Scsi_Host *shost); |
29 | extern void scsi_destroy_command_freelist(struct Scsi_Host *shost); | 29 | extern void scsi_destroy_command_freelist(struct Scsi_Host *shost); |
30 | extern int scsi_setup_command_sense_buffer(struct Scsi_Host *shost); | ||
31 | extern void scsi_destroy_command_sense_buffer(struct Scsi_Host *shost); | ||
30 | extern void __scsi_done(struct scsi_cmnd *cmd); | 32 | extern void __scsi_done(struct scsi_cmnd *cmd); |
31 | #ifdef CONFIG_SCSI_LOGGING | 33 | #ifdef CONFIG_SCSI_LOGGING |
32 | void scsi_log_send(struct scsi_cmnd *cmd); | 34 | void scsi_log_send(struct scsi_cmnd *cmd); |
diff --git a/include/scsi/scsi_cmnd.h b/include/scsi/scsi_cmnd.h index 3f47e522a1ec..abd7479ff452 100644 --- a/include/scsi/scsi_cmnd.h +++ b/include/scsi/scsi_cmnd.h | |||
@@ -88,7 +88,7 @@ struct scsi_cmnd { | |||
88 | working on */ | 88 | working on */ |
89 | 89 | ||
90 | #define SCSI_SENSE_BUFFERSIZE 96 | 90 | #define SCSI_SENSE_BUFFERSIZE 96 |
91 | unsigned char sense_buffer[SCSI_SENSE_BUFFERSIZE]; | 91 | unsigned char *sense_buffer; |
92 | /* obtained by REQUEST SENSE when | 92 | /* obtained by REQUEST SENSE when |
93 | * CHECK CONDITION is received on original | 93 | * CHECK CONDITION is received on original |
94 | * command (auto-sense) */ | 94 | * command (auto-sense) */ |