James Bottomley wrote:
> One of the intents of the block prep function was to allow ULDs to use
> it for preprocessing. The original SCSI model was to have a single prep
> function and add a pointer indirect filter to build the necessary
> commands. This patch reverses that, does away with the init_command
> field of the scsi_driver structure and makes ULDs attach directly to the
> prep function instead. The value is really that it allows us to begin
> to separate the ULDs from the SCSI mid layer (as long as they don't use
> any core functions---which is hard at the moment---a ULD doesn't even
> need SCSI to bind).
>
> James
>
> Index: BUILD-2.6/drivers/scsi/scsi_lib.c
It turns out this patch is dependent on previous
sd: disentangle barriers in SCSI (02)
and that one is dependent on the previous-previous one:
block: add protocol discriminators to requests and queues. (01)
but the middle one (02) does not apply it looks like there is a missing
hunk for scsi_lib.c in the first (01)
<sd: disentangle barriers in SCSI (02)>
@@ -1596,7 +1580,6 @@ struct request_queue *scsi_alloc_queue(s
return NULL;
blk_queue_prep_rq(q, scsi_prep_fn);
- blk_queue_issue_flush_fn(q, scsi_issue_flush_fn);
blk_queue_softirq_done(q, scsi_softirq_done);
blk_queue_protocol(q, BLK_PROTOCOL_SCSI);
return q;
</sd: disentangle barriers in SCSI (02)>
The before last sync line:
blk_queue_protocol(q, BLK_PROTOCOL_SCSI);
is missing from (01). Any thing else I need?
So I guess my first complain is that these should have been
a series to denote dependency. Also I think an email with
deeper explanation of where you are going with these, and
what is the motivation could be nice.
Apart from that:
Ouch! ;) That patch hurts.
What is the time frame for these changes are they for immediate
inclusion into scsi-misc and into 2.6.24 merge window? Before
scsi_data_buff, sglist, bidi, Mike's execute_async_cleanup ... ?
I do not like this patch. I think that if your motivation was
to make sd/sr and other ULD's more independent of scsi-ml than
you achieved the opposite. 5 exported functions and intimate
knowledge of scsi_lib internals. Lots of same cut and past code
in ULD's. Interdependence of scsi_lib.c with it's ULD's. Will
make it hard for scsi_lib to change without touching ULD's.
(And there are lots of scheduled changes :-))
What about below approach?
What I tried to do is keep scsi_lib private, export a more
simple API for ULD's. And keep common code common.
The code was compiled and booted but I did not do any error
injection and/or low memory condition testing.
[PATCH 3/3] move ULD attachment into the prep function
- scsi_lib.c prep_fn will only support blk_pc_commands.
- Let ULD's that support blk_fs_request() overload prep_fn.
sd.c and sr.c will do so.
- scsi_lib exports a scsi_prep_cmnd() helper that will take
a request and allocate and return a struct scsi_cmnd.
- If ULD decides it wants to fail the command allocated above
It must call a new export scsi_prep_return() to cancel the
request and return the command to free store.
git-diff
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index 60cbe37..c8ed932 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -1128,8 +1128,6 @@ static int scsi_setup_blk_pc_cmnd(struct scsi_device
*sdev, struct request *req)
static int scsi_setup_fs_cmnd(struct scsi_device *sdev, struct request *req)
{
struct scsi_cmnd *cmd;
- struct scsi_driver *drv;
- int ret;
/*
* Filesystem requests must transfer data.
@@ -1140,24 +1138,11 @@ static int scsi_setup_fs_cmnd(struct scsi_device *sdev,
struct request *req)
if (unlikely(!cmd))
return BLKPREP_DEFER;
- ret = scsi_init_io(cmd);
- if (unlikely(ret))
- return ret;
-
- /*
- * Initialize the actual SCSI command for this request.
- */
- drv = *(struct scsi_driver **)req->rq_disk->private_data;
- if (unlikely(!drv->init_command(cmd))) {
- scsi_release_buffers(cmd);
- scsi_put_command(cmd);
- return BLKPREP_KILL;
- }
-
- return BLKPREP_OK;
+ return scsi_init_io(cmd);
}
-static int scsi_prep_fn(struct request_queue *q, struct request *req)
+struct scsi_cmnd *scsi_prep_cmnd(struct request_queue *q, struct request *req,
+ int *pRet)
{
struct scsi_device *sdev = q->queuedata;
int ret = BLKPREP_OK;
@@ -1231,6 +1216,16 @@ static int scsi_prep_fn(struct request_queue *q, struct
request *req)
}
out:
+ *pRet = ret;
+ return req->special;
+}
+EXPORT_SYMBOL(scsi_prep_cmnd);
+
+int scsi_prep_return(struct request_queue *q, struct request *req,
+ struct scsi_cmnd *cmd, int ret)
+{
+ struct scsi_device *sdev = q->queuedata;
+
switch (ret) {
case BLKPREP_KILL:
req->errors = DID_NO_CONNECT << 16;
@@ -1248,8 +1243,25 @@ static int scsi_prep_fn(struct request_queue *q, struct
request *req)
req->cmd_flags |= REQ_DONTPREP;
}
+ if (cmd) {
+ scsi_release_buffers(cmd);
+ scsi_put_command(cmd);
+ }
return ret;
}
+EXPORT_SYMBOL(scsi_prep_return);
+
+static int scsi_prep_fn(struct request_queue *q, struct request *req)
+{
+ int ret = BLKPREP_KILL;
+ struct scsi_cmnd *cmd = NULL;
+ if (blk_pc_request(req))
+ cmd = scsi_prep_cmnd(q, req, &ret);
+ if (!cmd || ret) {
+ return scsi_prep_return(q, req, cmd, ret);
+ }
+ return BLKPREP_OK;
+}
/*
* scsi_dev_queue_ready: if we can send requests to sdev, return 1 else
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index 2c6116f..a2381c8 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -240,7 +240,6 @@ static struct scsi_driver sd_template = {
.shutdown = sd_shutdown,
},
.rescan = sd_rescan,
- .init_command = sd_init_command,
};
/*
@@ -331,14 +330,22 @@ static void scsi_disk_put(struct scsi_disk *sdkp)
*
* Returns 1 if successful and 0 if error (or cannot be done now).
**/
-static int sd_init_command(struct scsi_cmnd * SCpnt)
+static int sd_prep_fn(struct request_queue *q, struct request *rq)
{
- struct scsi_device *sdp = SCpnt->device;
- struct request *rq = SCpnt->request;
+ struct scsi_cmnd *SCpnt;
+ struct scsi_device *sdp = q->queuedata;
struct gendisk *disk = rq->rq_disk;
sector_t block = rq->sector;
- unsigned int this_count = SCpnt->request_bufflen >> 9;
+ unsigned int this_count = rq->nr_sectors;
unsigned int timeout = sdp->timeout;
+ int ret = BLKPREP_KILL;
+
+ SCpnt = scsi_prep_cmnd(q, rq, &ret);
+ if (!SCpnt || ret) {
+ goto error;
+ }
+ if (blk_pc_request(rq))
+ return BLKPREP_OK;
SCSI_LOG_HLQUEUE(1, scmd_printk(KERN_INFO, SCpnt,
"sd_init_command: block=%llu, "
@@ -353,7 +360,7 @@ static int sd_init_command(struct scsi_cmnd * SCpnt)
rq->nr_sectors));
SCSI_LOG_HLQUEUE(2, scmd_printk(KERN_INFO, SCpnt,
"Retry with 0x%p\n", SCpnt));
- return 0;
+ goto error;
}
if (sdp->changed) {
@@ -362,8 +369,9 @@ static int sd_init_command(struct scsi_cmnd * SCpnt)
* the changed bit has been reset
*/
/* printk("SCSI disk has been changed. Prohibiting further
I/O.\n"); */
- return 0;
+ goto error;
}
+
SCSI_LOG_HLQUEUE(2, scmd_printk(KERN_INFO, SCpnt, "block=%llu\n",
(unsigned long long)block));
@@ -382,7 +390,7 @@ static int sd_init_command(struct scsi_cmnd * SCpnt)
if ((block & 1) || (rq->nr_sectors & 1)) {
scmd_printk(KERN_ERR, SCpnt,
"Bad block number requested\n");
- return 0;
+ goto error;
} else {
block = block >> 1;
this_count = this_count >> 1;
@@ -392,7 +400,7 @@ static int sd_init_command(struct scsi_cmnd * SCpnt)
if ((block & 3) || (rq->nr_sectors & 3)) {
scmd_printk(KERN_ERR, SCpnt,
"Bad block number requested\n");
- return 0;
+ goto error;
} else {
block = block >> 2;
this_count = this_count >> 2;
@@ -402,7 +410,7 @@ static int sd_init_command(struct scsi_cmnd * SCpnt)
if ((block & 7) || (rq->nr_sectors & 7)) {
scmd_printk(KERN_ERR, SCpnt,
"Bad block number requested\n");
- return 0;
+ goto error;
} else {
block = block >> 3;
this_count = this_count >> 3;
@@ -410,7 +418,7 @@ static int sd_init_command(struct scsi_cmnd * SCpnt)
}
if (rq_data_dir(rq) == WRITE) {
if (!sdp->writeable) {
- return 0;
+ goto error;
}
SCpnt->cmnd[0] = WRITE_6;
SCpnt->sc_data_direction = DMA_TO_DEVICE;
@@ -419,7 +427,7 @@ static int sd_init_command(struct scsi_cmnd * SCpnt)
SCpnt->sc_data_direction = DMA_FROM_DEVICE;
} else {
scmd_printk(KERN_ERR, SCpnt, "Unknown command %x\n",
rq->cmd_flags);
- return 0;
+ goto error;
}
SCSI_LOG_HLQUEUE(2, scmd_printk(KERN_INFO, SCpnt,
@@ -470,7 +478,7 @@ static int sd_init_command(struct scsi_cmnd * SCpnt)
*/
scmd_printk(KERN_ERR, SCpnt,
"FUA write on READ/WRITE(6) drive\n");
- return 0;
+ goto error;
}
SCpnt->cmnd[1] |= (unsigned char) ((block >> 16) & 0x1f);
@@ -501,7 +509,9 @@ static int sd_init_command(struct scsi_cmnd * SCpnt)
* This indicates that the command is ready from our end to be
* queued.
*/
- return 1;
+ return BLKPREP_OK;
+ error:
+ return scsi_prep_return(q, rq, SCpnt, ret);
}
/**
@@ -1669,6 +1679,7 @@ static int sd_probe(struct device *dev)
sd_revalidate_disk(gd);
+ blk_queue_prep_rq(sdp->request_queue, sd_prep_fn);
blk_queue_issue_flush_fn(sdp->request_queue, sd_issue_flush);
gd->driverfs_dev = &sdp->sdev_gendev;
diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c
index 902eb11..2b727d6 100644
--- a/drivers/scsi/sr.c
+++ b/drivers/scsi/sr.c
@@ -78,7 +78,6 @@ MODULE_ALIAS_SCSI_DEVICE(TYPE_WORM);
static int sr_probe(struct device *);
static int sr_remove(struct device *);
-static int sr_init_command(struct scsi_cmnd *);
static struct scsi_driver sr_template = {
.owner = THIS_MODULE,
@@ -87,7 +86,6 @@ static struct scsi_driver sr_template = {
.probe = sr_probe,
.remove = sr_remove,
},
- .init_command = sr_init_command,
};
static unsigned long sr_index_bits[SR_DISKS / BITS_PER_LONG];
@@ -296,19 +294,30 @@ static void rw_intr(struct scsi_cmnd * SCpnt)
scsi_io_completion(SCpnt, good_bytes);
}
-static int sr_init_command(struct scsi_cmnd * SCpnt)
+static int sr_prep_fn(struct request_queue *q, struct request *rq)
{
int block=0, this_count, s_size, timeout = SR_TIMEOUT;
- struct scsi_cd *cd = scsi_cd(SCpnt->request->rq_disk);
+ struct scsi_cd *cd;
+ struct scsi_cmnd *SCpnt;
+ int ret = BLKPREP_KILL;
+
+ SCpnt = scsi_prep_cmnd(q, rq, &ret);
+ if (!SCpnt || ret) {
+ goto error;
+ }
+ if (blk_pc_request(rq))
+ return BLKPREP_OK;
+
+ cd = scsi_cd(rq->rq_disk);
SCSI_LOG_HLQUEUE(1, printk("Doing sr request, dev = %s, block = %d\n",
cd->disk->disk_name, block));
if (!cd->device || !scsi_device_online(cd->device)) {
SCSI_LOG_HLQUEUE(2, printk("Finishing %ld sectors\n",
- SCpnt->request->nr_sectors));
+ rq->nr_sectors));
SCSI_LOG_HLQUEUE(2, printk("Retry with 0x%p\n", SCpnt));
- return 0;
+ goto error;
}
if (cd->device->changed) {
@@ -316,7 +325,7 @@ static int sr_init_command(struct scsi_cmnd * SCpnt)
* quietly refuse to do anything to a changed disc until the
* changed bit has been reset
*/
- return 0;
+ goto error;
}
/*
@@ -333,21 +342,21 @@ static int sr_init_command(struct scsi_cmnd * SCpnt)
if (s_size != 512 && s_size != 1024 && s_size != 2048) {
scmd_printk(KERN_ERR, SCpnt, "bad sector size %d\n", s_size);
- return 0;
+ goto error;
}
- if (rq_data_dir(SCpnt->request) == WRITE) {
+ if (rq_data_dir(rq) == WRITE) {
if (!cd->device->writeable)
- return 0;
+ goto error;
SCpnt->cmnd[0] = WRITE_10;
SCpnt->sc_data_direction = DMA_TO_DEVICE;
cd->cdi.media_written = 1;
- } else if (rq_data_dir(SCpnt->request) == READ) {
+ } else if (rq_data_dir(rq) == READ) {
SCpnt->cmnd[0] = READ_10;
SCpnt->sc_data_direction = DMA_FROM_DEVICE;
} else {
- blk_dump_rq_flags(SCpnt->request, "Unknown sr command");
- return 0;
+ blk_dump_rq_flags(rq, "Unknown sr command");
+ goto error;
}
{
@@ -368,10 +377,10 @@ static int sr_init_command(struct scsi_cmnd * SCpnt)
/*
* request doesn't start on hw block boundary, add scatter pads
*/
- if (((unsigned int)SCpnt->request->sector % (s_size >> 9)) ||
+ if (((unsigned int)rq->sector % (s_size >> 9)) ||
(SCpnt->request_bufflen % s_size)) {
scmd_printk(KERN_NOTICE, SCpnt, "unaligned transfer\n");
- return 0;
+ goto error;
}
this_count = (SCpnt->request_bufflen >> 9) / (s_size >> 9);
@@ -379,12 +388,12 @@ static int sr_init_command(struct scsi_cmnd * SCpnt)
SCSI_LOG_HLQUEUE(2, printk("%s : %s %d/%ld 512 byte blocks.\n",
cd->cdi.name,
- (rq_data_dir(SCpnt->request) == WRITE) ?
+ (rq_data_dir(rq) == WRITE) ?
"writing" : "reading",
- this_count, SCpnt->request->nr_sectors));
+ this_count, rq->nr_sectors));
SCpnt->cmnd[1] = 0;
- block = (unsigned int)SCpnt->request->sector / (s_size >> 9);
+ block = (unsigned int)rq->sector / (s_size >> 9);
if (this_count > 0xffff) {
this_count = 0xffff;
@@ -419,7 +428,9 @@ static int sr_init_command(struct scsi_cmnd * SCpnt)
* This indicates that the command is ready from our end to be
* queued.
*/
- return 1;
+ return BLKPREP_OK;
+ error:
+ return scsi_prep_return(q, rq, SCpnt, ret);
}
static int sr_block_open(struct inode *inode, struct file *file)
@@ -590,6 +601,7 @@ static int sr_probe(struct device *dev)
/* FIXME: need to handle a get_capabilities failure properly ?? */
get_capabilities(cd);
+ blk_queue_prep_rq(sdev->request_queue, sr_prep_fn);
sr_vendor_init(cd);
disk->driverfs_dev = &sdev->sdev_gendev;
diff --git a/include/scsi/scsi_driver.h b/include/scsi/scsi_driver.h
index 3465f31..56df2ed 100644
--- a/include/scsi/scsi_driver.h
+++ b/include/scsi/scsi_driver.h
@@ -11,7 +11,6 @@ struct scsi_driver {
struct module *owner;
struct device_driver gendrv;
- int (*init_command)(struct scsi_cmnd *);
void (*rescan)(struct device *);
};
#define to_scsi_driver(drv) \
@@ -25,4 +24,9 @@ extern int scsi_register_interface(struct class_interface *);
#define scsi_unregister_interface(intf) \
class_interface_unregister(intf)
+extern struct scsi_cmnd *scsi_prep_cmnd(struct request_queue *,
+ struct request *req, int *pRet);
+extern int scsi_prep_return(struct request_queue *, struct request *req,
+ struct scsi_cmnd *cmd, int ret);
+
#endif /* _SCSI_SCSI_DRIVER_H */
diff --git a/include/scsi/sd.h b/include/scsi/sd.h
index ce02ad1..aa1e716 100644
--- a/include/scsi/sd.h
+++ b/include/scsi/sd.h
@@ -55,7 +55,6 @@ static void sd_shutdown(struct device *dev);
static int sd_suspend(struct device *dev, pm_message_t state);
static int sd_resume(struct device *dev);
static void sd_rescan(struct device *);
-static int sd_init_command(struct scsi_cmnd *);
static void sd_read_capacity(struct scsi_disk *sdkp, unsigned char *buffer);
static void scsi_disk_release(struct class_device *cdev);
static void sd_print_sense_hdr(struct scsi_disk *, struct scsi_sense_hdr *);
-
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at http://vger.kernel.org/majordomo-info.html