@@ -350,6 +350,7 @@ static void scsi_host_dev_release(struct device *dev)
if (parent)
put_device(parent);
+ kfree(shost->cmd_ext_buf);
kfree(shost);
}
@@ -131,9 +131,6 @@ static DEFINE_IDA(sd_index_ida);
* object after last put) */
static DEFINE_MUTEX(sd_ref_mutex);
-static struct kmem_cache *sd_cdb_cache;
-static mempool_t *sd_cdb_pool;
-
static const char *sd_cache_types[] = {
"write through", "none", "write back",
"write back, no read (daft)"
@@ -1026,6 +1023,13 @@ static int sd_setup_flush_cmnd(struct scsi_cmnd *cmd)
return BLKPREP_OK;
}
+static char *sd_get_ext_buf(struct scsi_device *sdp, struct scsi_cmnd *SCpnt)
+{
+ struct request *rq = SCpnt->request;
+
+ return &sdp->host->cmd_ext_buf[rq->tag * SD_EXT_CDB_SIZE];
+}
+
static int sd_setup_read_write_cmnd(struct scsi_cmnd *SCpnt)
{
struct request *rq = SCpnt->request;
@@ -1168,12 +1172,7 @@ static int sd_setup_read_write_cmnd(struct scsi_cmnd *SCpnt)
protect = 0;
if (protect && sdkp->protection_type == T10_PI_TYPE2_PROTECTION) {
- SCpnt->cmnd = mempool_alloc(sd_cdb_pool, GFP_ATOMIC);
-
- if (unlikely(SCpnt->cmnd == NULL)) {
- ret = BLKPREP_DEFER;
- goto out;
- }
+ SCpnt->cmnd = sd_get_ext_buf(sdp, SCpnt);
SCpnt->cmd_len = SD_EXT_CDB_SIZE;
memset(SCpnt->cmnd, 0, SCpnt->cmd_len);
@@ -1318,12 +1317,6 @@ static void sd_uninit_command(struct scsi_cmnd *SCpnt)
if (rq->rq_flags & RQF_SPECIAL_PAYLOAD)
__free_page(rq->special_vec.bv_page);
-
- if (SCpnt->cmnd != scsi_req(rq)->cmd) {
- mempool_free(SCpnt->cmnd, sd_cdb_pool);
- SCpnt->cmnd = NULL;
- SCpnt->cmd_len = 0;
- }
}
/**
@@ -3288,6 +3281,11 @@ static void sd_probe_async(void *data, async_cookie_t cookie)
sd_revalidate_disk(gd);
+ if (sdkp->capacity) {
+ if (sd_dif_config_host(sdkp))
+ return;
+ }
+
gd->flags = GENHD_FL_EXT_DEVT;
if (sdp->removable) {
gd->flags |= GENHD_FL_REMOVABLE;
@@ -3296,8 +3294,6 @@ static void sd_probe_async(void *data, async_cookie_t cookie)
blk_pm_runtime_init(sdp->request_queue, dev);
device_add_disk(dev, gd);
- if (sdkp->capacity)
- sd_dif_config_host(sdkp);
sd_revalidate_disk(gd);
@@ -3652,33 +3648,12 @@ static int __init init_sd(void)
if (err)
goto err_out;
- sd_cdb_cache = kmem_cache_create("sd_ext_cdb", SD_EXT_CDB_SIZE,
- 0, 0, NULL);
- if (!sd_cdb_cache) {
- printk(KERN_ERR "sd: can't init extended cdb cache\n");
- err = -ENOMEM;
- goto err_out_class;
- }
-
- sd_cdb_pool = mempool_create_slab_pool(SD_MEMPOOL_SIZE, sd_cdb_cache);
- if (!sd_cdb_pool) {
- printk(KERN_ERR "sd: can't init extended cdb pool\n");
- err = -ENOMEM;
- goto err_out_cache;
- }
-
err = scsi_register_driver(&sd_template.gendrv);
if (err)
- goto err_out_driver;
+ goto err_out_class;
return 0;
-err_out_driver:
- mempool_destroy(sd_cdb_pool);
-
-err_out_cache:
- kmem_cache_destroy(sd_cdb_cache);
-
err_out_class:
class_unregister(&sd_disk_class);
err_out:
@@ -3699,8 +3674,6 @@ static void __exit exit_sd(void)
SCSI_LOG_HLQUEUE(3, printk("exit_sd: exiting sd driver\n"));
scsi_unregister_driver(&sd_template.gendrv);
- mempool_destroy(sd_cdb_pool);
- kmem_cache_destroy(sd_cdb_cache);
class_unregister(&sd_disk_class);
@@ -254,13 +254,13 @@ static inline unsigned int sd_prot_flag_mask(unsigned int prot_op)
#ifdef CONFIG_BLK_DEV_INTEGRITY
-extern void sd_dif_config_host(struct scsi_disk *);
+extern int sd_dif_config_host(struct scsi_disk *);
extern void sd_dif_prepare(struct scsi_cmnd *scmd);
extern void sd_dif_complete(struct scsi_cmnd *, unsigned int);
#else /* CONFIG_BLK_DEV_INTEGRITY */
-static inline void sd_dif_config_host(struct scsi_disk *disk)
+static inline int sd_dif_config_host(struct scsi_disk *disk)
{
}
static inline int sd_dif_prepare(struct scsi_cmnd *scmd)
@@ -35,10 +35,33 @@
#include "sd.h"
+static int sd_dif_alloc_ext_buf(struct Scsi_Host *host)
+{
+ char *ext_buf;
+
+ spin_lock_irq(host->host_lock);
+ ext_buf = host->cmd_ext_buf;
+ spin_unlock_irq(host->host_lock);
+
+ if (ext_buf)
+ return 0;
+
+ ext_buf = kmalloc(host->can_queue * SD_EXT_CDB_SIZE, GFP_KERNEL);
+ spin_lock_irq(host->host_lock);
+ if (host->cmd_ext_buf)
+ kfree(ext_buf);
+ else
+ host->cmd_ext_buf = ext_buf;
+ ext_buf = host->cmd_ext_buf;
+ spin_unlock_irq(host->host_lock);
+
+ return ext_buf ? 0: -ENOMEM;
+}
+
/*
* Configure exchange of protection information between OS and HBA.
*/
-void sd_dif_config_host(struct scsi_disk *sdkp)
+int sd_dif_config_host(struct scsi_disk *sdkp)
{
struct scsi_device *sdp = sdkp->device;
struct gendisk *disk = sdkp->disk;
@@ -54,7 +77,7 @@ void sd_dif_config_host(struct scsi_disk *sdkp)
}
if (!dix)
- return;
+ return 0;
memset(&bi, 0, sizeof(bi));
@@ -91,8 +114,13 @@ void sd_dif_config_host(struct scsi_disk *sdkp)
bi.tag_size);
}
+ if (type == T10_PI_TYPE2_PROTECTION &&
+ sd_dif_alloc_ext_buf(sdkp->device->host))
+ return -ENOMEM;
+
out:
blk_integrity_register(disk, &bi);
+ return 0;
}
/*
@@ -726,6 +726,8 @@ struct Scsi_Host {
*/
struct device *dma_dev;
+ char *cmd_ext_buf;
+
/*
* We should ensure that this is aligned, both for better performance
* and also because some compilers (m68k) don't automatically force