diff options
| -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) */ |
