diff options
| -rw-r--r-- | drivers/scsi/scsi.c | 96 | ||||
| -rw-r--r-- | include/scsi/scsi_host.h | 7 |
2 files changed, 84 insertions, 19 deletions
diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index 586c241c941e..c4d632c27a3e 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c | |||
| @@ -331,46 +331,103 @@ void scsi_put_command(struct scsi_cmnd *cmd) | |||
| 331 | } | 331 | } |
| 332 | EXPORT_SYMBOL(scsi_put_command); | 332 | EXPORT_SYMBOL(scsi_put_command); |
| 333 | 333 | ||
| 334 | static struct scsi_host_cmd_pool *scsi_get_host_cmd_pool(gfp_t gfp_mask) | 334 | static struct scsi_host_cmd_pool * |
| 335 | scsi_find_host_cmd_pool(struct Scsi_Host *shost) | ||
| 335 | { | 336 | { |
| 337 | if (shost->hostt->cmd_size) | ||
| 338 | return shost->hostt->cmd_pool; | ||
| 339 | if (shost->unchecked_isa_dma) | ||
| 340 | return &scsi_cmd_dma_pool; | ||
| 341 | return &scsi_cmd_pool; | ||
| 342 | } | ||
| 343 | |||
| 344 | static void | ||
| 345 | scsi_free_host_cmd_pool(struct scsi_host_cmd_pool *pool) | ||
| 346 | { | ||
| 347 | kfree(pool->sense_name); | ||
| 348 | kfree(pool->cmd_name); | ||
| 349 | kfree(pool); | ||
| 350 | } | ||
| 351 | |||
| 352 | static struct scsi_host_cmd_pool * | ||
| 353 | scsi_alloc_host_cmd_pool(struct Scsi_Host *shost) | ||
| 354 | { | ||
| 355 | struct scsi_host_template *hostt = shost->hostt; | ||
| 356 | struct scsi_host_cmd_pool *pool; | ||
| 357 | |||
| 358 | pool = kzalloc(sizeof(*pool), GFP_KERNEL); | ||
| 359 | if (!pool) | ||
| 360 | return NULL; | ||
| 361 | |||
| 362 | pool->cmd_name = kasprintf(GFP_KERNEL, "%s_cmd", hostt->name); | ||
| 363 | pool->sense_name = kasprintf(GFP_KERNEL, "%s_sense", hostt->name); | ||
| 364 | if (!pool->cmd_name || !pool->sense_name) { | ||
| 365 | scsi_free_host_cmd_pool(pool); | ||
| 366 | return NULL; | ||
| 367 | } | ||
| 368 | |||
| 369 | pool->slab_flags = SLAB_HWCACHE_ALIGN; | ||
| 370 | if (shost->unchecked_isa_dma) { | ||
| 371 | pool->slab_flags |= SLAB_CACHE_DMA; | ||
| 372 | pool->gfp_mask = __GFP_DMA; | ||
| 373 | } | ||
| 374 | return pool; | ||
| 375 | } | ||
| 376 | |||
| 377 | static struct scsi_host_cmd_pool * | ||
| 378 | scsi_get_host_cmd_pool(struct Scsi_Host *shost) | ||
| 379 | { | ||
| 380 | struct scsi_host_template *hostt = shost->hostt; | ||
| 336 | struct scsi_host_cmd_pool *retval = NULL, *pool; | 381 | struct scsi_host_cmd_pool *retval = NULL, *pool; |
| 382 | size_t cmd_size = sizeof(struct scsi_cmnd) + hostt->cmd_size; | ||
| 383 | |||
| 337 | /* | 384 | /* |
| 338 | * Select a command slab for this host and create it if not | 385 | * Select a command slab for this host and create it if not |
| 339 | * yet existent. | 386 | * yet existent. |
| 340 | */ | 387 | */ |
| 341 | mutex_lock(&host_cmd_pool_mutex); | 388 | mutex_lock(&host_cmd_pool_mutex); |
| 342 | pool = (gfp_mask & __GFP_DMA) ? &scsi_cmd_dma_pool : | 389 | pool = scsi_find_host_cmd_pool(shost); |
| 343 | &scsi_cmd_pool; | 390 | if (!pool) { |
| 391 | pool = scsi_alloc_host_cmd_pool(shost); | ||
| 392 | if (!pool) | ||
| 393 | goto out; | ||
| 394 | } | ||
| 395 | |||
| 344 | if (!pool->users) { | 396 | if (!pool->users) { |
| 345 | pool->cmd_slab = kmem_cache_create(pool->cmd_name, | 397 | pool->cmd_slab = kmem_cache_create(pool->cmd_name, cmd_size, 0, |
| 346 | sizeof(struct scsi_cmnd), 0, | ||
| 347 | pool->slab_flags, NULL); | 398 | pool->slab_flags, NULL); |
| 348 | if (!pool->cmd_slab) | 399 | if (!pool->cmd_slab) |
| 349 | goto fail; | 400 | goto out_free_pool; |
| 350 | 401 | ||
| 351 | pool->sense_slab = kmem_cache_create(pool->sense_name, | 402 | pool->sense_slab = kmem_cache_create(pool->sense_name, |
| 352 | SCSI_SENSE_BUFFERSIZE, 0, | 403 | SCSI_SENSE_BUFFERSIZE, 0, |
| 353 | pool->slab_flags, NULL); | 404 | pool->slab_flags, NULL); |
| 354 | if (!pool->sense_slab) { | 405 | if (!pool->sense_slab) |
| 355 | kmem_cache_destroy(pool->cmd_slab); | 406 | goto out_free_slab; |
| 356 | goto fail; | ||
| 357 | } | ||
| 358 | } | 407 | } |
| 359 | 408 | ||
| 360 | pool->users++; | 409 | pool->users++; |
| 361 | retval = pool; | 410 | retval = pool; |
| 362 | fail: | 411 | out: |
| 363 | mutex_unlock(&host_cmd_pool_mutex); | 412 | mutex_unlock(&host_cmd_pool_mutex); |
| 364 | return retval; | 413 | return retval; |
| 414 | |||
| 415 | out_free_slab: | ||
| 416 | kmem_cache_destroy(pool->cmd_slab); | ||
| 417 | out_free_pool: | ||
| 418 | if (hostt->cmd_size) | ||
| 419 | scsi_free_host_cmd_pool(pool); | ||
| 420 | goto out; | ||
| 365 | } | 421 | } |
| 366 | 422 | ||
| 367 | static void scsi_put_host_cmd_pool(gfp_t gfp_mask) | 423 | static void scsi_put_host_cmd_pool(struct Scsi_Host *shost) |
| 368 | { | 424 | { |
| 425 | struct scsi_host_template *hostt = shost->hostt; | ||
| 369 | struct scsi_host_cmd_pool *pool; | 426 | struct scsi_host_cmd_pool *pool; |
| 370 | 427 | ||
| 371 | mutex_lock(&host_cmd_pool_mutex); | 428 | mutex_lock(&host_cmd_pool_mutex); |
| 372 | pool = (gfp_mask & __GFP_DMA) ? &scsi_cmd_dma_pool : | 429 | pool = scsi_find_host_cmd_pool(shost); |
| 373 | &scsi_cmd_pool; | 430 | |
| 374 | /* | 431 | /* |
| 375 | * This may happen if a driver has a mismatched get and put | 432 | * This may happen if a driver has a mismatched get and put |
| 376 | * of the command pool; the driver should be implicated in | 433 | * of the command pool; the driver should be implicated in |
| @@ -381,6 +438,8 @@ static void scsi_put_host_cmd_pool(gfp_t gfp_mask) | |||
| 381 | if (!--pool->users) { | 438 | if (!--pool->users) { |
| 382 | kmem_cache_destroy(pool->cmd_slab); | 439 | kmem_cache_destroy(pool->cmd_slab); |
| 383 | kmem_cache_destroy(pool->sense_slab); | 440 | kmem_cache_destroy(pool->sense_slab); |
| 441 | if (hostt->cmd_size) | ||
| 442 | scsi_free_host_cmd_pool(pool); | ||
| 384 | } | 443 | } |
| 385 | mutex_unlock(&host_cmd_pool_mutex); | 444 | mutex_unlock(&host_cmd_pool_mutex); |
| 386 | } | 445 | } |
| @@ -397,14 +456,13 @@ static void scsi_put_host_cmd_pool(gfp_t gfp_mask) | |||
| 397 | */ | 456 | */ |
| 398 | int scsi_setup_command_freelist(struct Scsi_Host *shost) | 457 | int scsi_setup_command_freelist(struct Scsi_Host *shost) |
| 399 | { | 458 | { |
| 400 | struct scsi_cmnd *cmd; | ||
| 401 | const gfp_t gfp_mask = shost->unchecked_isa_dma ? GFP_DMA : GFP_KERNEL; | 459 | const gfp_t gfp_mask = shost->unchecked_isa_dma ? GFP_DMA : GFP_KERNEL; |
| 460 | struct scsi_cmnd *cmd; | ||
| 402 | 461 | ||
| 403 | spin_lock_init(&shost->free_list_lock); | 462 | spin_lock_init(&shost->free_list_lock); |
| 404 | INIT_LIST_HEAD(&shost->free_list); | 463 | INIT_LIST_HEAD(&shost->free_list); |
| 405 | 464 | ||
| 406 | shost->cmd_pool = scsi_get_host_cmd_pool(gfp_mask); | 465 | shost->cmd_pool = scsi_get_host_cmd_pool(shost); |
| 407 | |||
| 408 | if (!shost->cmd_pool) | 466 | if (!shost->cmd_pool) |
| 409 | return -ENOMEM; | 467 | return -ENOMEM; |
| 410 | 468 | ||
| @@ -413,7 +471,7 @@ int scsi_setup_command_freelist(struct Scsi_Host *shost) | |||
| 413 | */ | 471 | */ |
| 414 | cmd = scsi_host_alloc_command(shost, gfp_mask); | 472 | cmd = scsi_host_alloc_command(shost, gfp_mask); |
| 415 | if (!cmd) { | 473 | if (!cmd) { |
| 416 | scsi_put_host_cmd_pool(gfp_mask); | 474 | scsi_put_host_cmd_pool(shost); |
| 417 | shost->cmd_pool = NULL; | 475 | shost->cmd_pool = NULL; |
| 418 | return -ENOMEM; | 476 | return -ENOMEM; |
| 419 | } | 477 | } |
| @@ -442,7 +500,7 @@ void scsi_destroy_command_freelist(struct Scsi_Host *shost) | |||
| 442 | scsi_host_free_command(shost, cmd); | 500 | scsi_host_free_command(shost, cmd); |
| 443 | } | 501 | } |
| 444 | shost->cmd_pool = NULL; | 502 | shost->cmd_pool = NULL; |
| 445 | scsi_put_host_cmd_pool(shost->unchecked_isa_dma ? GFP_DMA : GFP_KERNEL); | 503 | scsi_put_host_cmd_pool(shost); |
| 446 | } | 504 | } |
| 447 | 505 | ||
| 448 | #ifdef CONFIG_SCSI_LOGGING | 506 | #ifdef CONFIG_SCSI_LOGGING |
diff --git a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h index 53075e5039e6..94844fc77b97 100644 --- a/include/scsi/scsi_host.h +++ b/include/scsi/scsi_host.h | |||
| @@ -15,6 +15,7 @@ struct completion; | |||
| 15 | struct module; | 15 | struct module; |
| 16 | struct scsi_cmnd; | 16 | struct scsi_cmnd; |
| 17 | struct scsi_device; | 17 | struct scsi_device; |
| 18 | struct scsi_host_cmd_pool; | ||
| 18 | struct scsi_target; | 19 | struct scsi_target; |
| 19 | struct Scsi_Host; | 20 | struct Scsi_Host; |
| 20 | struct scsi_host_cmd_pool; | 21 | struct scsi_host_cmd_pool; |
| @@ -524,6 +525,12 @@ struct scsi_host_template { | |||
| 524 | * scsi_netlink.h | 525 | * scsi_netlink.h |
| 525 | */ | 526 | */ |
| 526 | u64 vendor_id; | 527 | u64 vendor_id; |
| 528 | |||
| 529 | /* | ||
| 530 | * Additional per-command data allocated for the driver. | ||
| 531 | */ | ||
| 532 | unsigned int cmd_size; | ||
| 533 | struct scsi_host_cmd_pool *cmd_pool; | ||
| 527 | }; | 534 | }; |
| 528 | 535 | ||
| 529 | /* | 536 | /* |
