From bd441deaf341c524b28fd72831ebf6fef88f1c41 Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Tue, 13 Mar 2007 12:52:29 -0500 Subject: [SCSI] fix write buffer length in scsi_req_map_sg() sg's may have setup a the buffer with a different length than the transfer length so we should be using the bufflen passed in as the request's data len. Signed-off-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/scsi_lib.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) (limited to 'drivers/scsi/scsi_lib.c') diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index a417a6ff9f9..277f1b64e9a 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -301,7 +301,7 @@ static int scsi_req_map_sg(struct request *rq, struct scatterlist *sgl, { struct request_queue *q = rq->q; int nr_pages = (bufflen + sgl[0].offset + PAGE_SIZE - 1) >> PAGE_SHIFT; - unsigned int data_len = 0, len, bytes, off; + unsigned int data_len = bufflen, len, bytes, off; struct page *page; struct bio *bio = NULL; int i, err, nr_vecs = 0; @@ -310,10 +310,15 @@ static int scsi_req_map_sg(struct request *rq, struct scatterlist *sgl, page = sgl[i].page; off = sgl[i].offset; len = sgl[i].length; - data_len += len; - while (len > 0) { + while (len > 0 && data_len > 0) { + /* + * sg sends a scatterlist that is larger than + * the data_len it wants transferred for certain + * IO sizes + */ bytes = min_t(unsigned int, len, PAGE_SIZE - off); + bytes = min(bytes, data_len); if (!bio) { nr_vecs = min_t(int, BIO_MAX_PAGES, nr_pages); @@ -345,12 +350,13 @@ static int scsi_req_map_sg(struct request *rq, struct scatterlist *sgl, page++; len -= bytes; + data_len -=bytes; off = 0; } } rq->buffer = rq->data = NULL; - rq->data_len = data_len; + rq->data_len = bufflen; return 0; free_bios: -- cgit v1.2.3-70-g09d2 From 52aeeca9001d1b4037a8e5d0c001ebb5fdc61b37 Mon Sep 17 00:00:00 2001 From: Michael Reed Date: Mon, 17 Sep 2007 15:11:39 -0700 Subject: [SCSI] stale residual returned on write following BUSY retry A BUSY status returned on a write request results in a stale residual being returned when the write ultimately successfully completes. This can be reproduced as follows: 1) issue immediate mode rewind to scsi tape drive 2) issue write request The tape drive returns busy. The low level driver detects underrun and sets the residual into the scsi command. The low level driver responds with (DID_OK << 16) | scsi_status. scsi_status is 8, hence status_byte(result) == 4, i.e., BUSY. scsi_softirq_done() calls scsi_decide_disposition() which returns ADD_TO_MLQUEUE. scsi_softirq_done() then calls scsi_queue_insert() which, on the way to resubmitting the request to the driver, calls scsi_init_cmd_errh(). The attached patch modifies scsi_init_cmd_errh() to clear the resid field. This prevents a "stale" residual from being returned when the scsi command finally completes without a BUSY status. Signed-off-by: Michael Reed Signed-off-by: James Bottomley --- drivers/scsi/scsi_lib.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/scsi/scsi_lib.c') diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 277f1b64e9a..47d3cdd6ddf 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -449,6 +449,7 @@ EXPORT_SYMBOL_GPL(scsi_execute_async); static void scsi_init_cmd_errh(struct scsi_cmnd *cmd) { cmd->serial_number = 0; + cmd->resid = 0; memset(cmd->sense_buffer, 0, sizeof cmd->sense_buffer); if (cmd->cmd_len == 0) cmd->cmd_len = COMMAND_SIZE(cmd->cmnd[0]); -- cgit v1.2.3-70-g09d2 From 7f9a6bc4e9d59e7fcf03ed23f60cd81ca5d80b65 Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Sat, 4 Aug 2007 10:06:25 -0500 Subject: [SCSI] move ULD attachment into the prep function 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). Acked-by: Jens Axboe Signed-off-by: James Bottomley --- drivers/scsi/scsi_lib.c | 84 ++++++++++++++++++++-------------------------- drivers/scsi/sd.c | 48 ++++++++++++++++++-------- drivers/scsi/sr.c | 59 +++++++++++++++++++++----------- include/scsi/scsi_driver.h | 9 ++++- include/scsi/sd.h | 1 - 5 files changed, 119 insertions(+), 82 deletions(-) (limited to 'drivers/scsi/scsi_lib.c') diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 47d3cdd6ddf..94d82cb9662 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -1039,9 +1039,6 @@ static int scsi_init_io(struct scsi_cmnd *cmd) printk(KERN_ERR "req nr_sec %lu, cur_nr_sec %u\n", req->nr_sectors, req->current_nr_sectors); - /* release the command and kill it */ - scsi_release_buffers(cmd); - scsi_put_command(cmd); return BLKPREP_KILL; } @@ -1078,9 +1075,13 @@ static void scsi_blk_pc_done(struct scsi_cmnd *cmd) scsi_io_completion(cmd, cmd->request_bufflen); } -static int scsi_setup_blk_pc_cmnd(struct scsi_device *sdev, struct request *req) +int scsi_setup_blk_pc_cmnd(struct scsi_device *sdev, struct request *req) { struct scsi_cmnd *cmd; + int ret = scsi_prep_state_check(sdev, req); + + if (ret != BLKPREP_OK) + return ret; cmd = scsi_get_cmd_from_req(sdev, req); if (unlikely(!cmd)) @@ -1126,18 +1127,20 @@ static int scsi_setup_blk_pc_cmnd(struct scsi_device *sdev, struct request *req) cmd->done = scsi_blk_pc_done; return BLKPREP_OK; } +EXPORT_SYMBOL(scsi_setup_blk_pc_cmnd); /* * Setup a REQ_TYPE_FS command. These are simple read/write request * from filesystems that still need to be translated to SCSI CDBs from * the ULD. */ -static int scsi_setup_fs_cmnd(struct scsi_device *sdev, struct request *req) +int scsi_setup_fs_cmnd(struct scsi_device *sdev, struct request *req) { struct scsi_cmnd *cmd; - struct scsi_driver *drv; - int ret; + int ret = scsi_prep_state_check(sdev, req); + if (ret != BLKPREP_OK) + return ret; /* * Filesystem requests must transfer data. */ @@ -1147,26 +1150,12 @@ 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); } +EXPORT_SYMBOL(scsi_setup_fs_cmnd); -static int scsi_prep_fn(struct request_queue *q, struct request *req) +int scsi_prep_state_check(struct scsi_device *sdev, struct request *req) { - struct scsi_device *sdev = q->queuedata; int ret = BLKPREP_OK; /* @@ -1212,35 +1201,25 @@ static int scsi_prep_fn(struct request_queue *q, struct request *req) ret = BLKPREP_KILL; break; } - - if (ret != BLKPREP_OK) - goto out; } + return ret; +} +EXPORT_SYMBOL(scsi_prep_state_check); - switch (req->cmd_type) { - case REQ_TYPE_BLOCK_PC: - ret = scsi_setup_blk_pc_cmnd(sdev, req); - break; - case REQ_TYPE_FS: - ret = scsi_setup_fs_cmnd(sdev, req); - break; - default: - /* - * All other command types are not supported. - * - * Note that these days the SCSI subsystem does not use - * REQ_TYPE_SPECIAL requests anymore. These are only used - * (directly or via blk_insert_request) by non-SCSI drivers. - */ - blk_dump_rq_flags(req, "SCSI bad req"); - ret = BLKPREP_KILL; - break; - } +int scsi_prep_return(struct request_queue *q, struct request *req, int ret) +{ + struct scsi_device *sdev = q->queuedata; - out: switch (ret) { case BLKPREP_KILL: req->errors = DID_NO_CONNECT << 16; + /* release the command and kill it */ + if (req->special) { + struct scsi_cmnd *cmd = req->special; + scsi_release_buffers(cmd); + scsi_put_command(cmd); + req->special = NULL; + } break; case BLKPREP_DEFER: /* @@ -1257,6 +1236,17 @@ static int scsi_prep_fn(struct request_queue *q, struct request *req) return ret; } +EXPORT_SYMBOL(scsi_prep_return); + +static int scsi_prep_fn(struct request_queue *q, struct request *req) +{ + struct scsi_device *sdev = q->queuedata; + int ret = BLKPREP_KILL; + + if (req->cmd_type == REQ_TYPE_BLOCK_PC) + ret = scsi_setup_blk_pc_cmnd(sdev, req); + return scsi_prep_return(q, req, ret); +} /* * 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 2c6116fd457..38a41415004 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,31 @@ 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; + + if (rq->cmd_type == REQ_TYPE_BLOCK_PC) { + ret = scsi_setup_blk_pc_cmnd(sdp, rq); + goto out; + } else if (rq->cmd_type != REQ_TYPE_FS) { + ret = BLKPREP_KILL; + goto out; + } + ret = scsi_setup_fs_cmnd(sdp, rq); + if (ret != BLKPREP_OK) + goto out; + SCpnt = rq->special; + + /* from here on until we're complete, any goto out + * is used for a killable error condition */ + ret = BLKPREP_KILL; SCSI_LOG_HLQUEUE(1, scmd_printk(KERN_INFO, SCpnt, "sd_init_command: block=%llu, " @@ -353,7 +369,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 out; } if (sdp->changed) { @@ -362,8 +378,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 out; } + SCSI_LOG_HLQUEUE(2, scmd_printk(KERN_INFO, SCpnt, "block=%llu\n", (unsigned long long)block)); @@ -382,7 +399,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 out; } else { block = block >> 1; this_count = this_count >> 1; @@ -392,7 +409,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 out; } else { block = block >> 2; this_count = this_count >> 2; @@ -402,7 +419,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 out; } else { block = block >> 3; this_count = this_count >> 3; @@ -410,7 +427,7 @@ static int sd_init_command(struct scsi_cmnd * SCpnt) } if (rq_data_dir(rq) == WRITE) { if (!sdp->writeable) { - return 0; + goto out; } SCpnt->cmnd[0] = WRITE_6; SCpnt->sc_data_direction = DMA_TO_DEVICE; @@ -419,7 +436,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 out; } SCSI_LOG_HLQUEUE(2, scmd_printk(KERN_INFO, SCpnt, @@ -470,7 +487,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 out; } SCpnt->cmnd[1] |= (unsigned char) ((block >> 16) & 0x1f); @@ -501,7 +518,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; + ret = BLKPREP_OK; + out: + return scsi_prep_return(q, rq, ret); } /** @@ -1669,6 +1688,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 902eb11ffe8..a0c4e13d4da 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,39 @@ 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; + struct scsi_device *sdp = q->queuedata; + int ret; + + if (rq->cmd_type == REQ_TYPE_BLOCK_PC) { + ret = scsi_setup_blk_pc_cmnd(sdp, rq); + goto out; + } else if (rq->cmd_type != REQ_TYPE_FS) { + ret = BLKPREP_KILL; + goto out; + } + ret = scsi_setup_fs_cmnd(sdp, rq); + if (ret != BLKPREP_OK) + goto out; + SCpnt = rq->special; + cd = scsi_cd(rq->rq_disk); + + /* from here on until we're complete, any goto out + * is used for a killable error condition */ + ret = BLKPREP_KILL; 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 out; } if (cd->device->changed) { @@ -316,7 +334,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 out; } /* @@ -333,21 +351,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 out; } - if (rq_data_dir(SCpnt->request) == WRITE) { + if (rq_data_dir(rq) == WRITE) { if (!cd->device->writeable) - return 0; + goto out; 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 out; } { @@ -368,10 +386,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 out; } this_count = (SCpnt->request_bufflen >> 9) / (s_size >> 9); @@ -379,12 +397,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 +437,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; + ret = BLKPREP_OK; + out: + return scsi_prep_return(q, rq, ret); } static int sr_block_open(struct inode *inode, struct file *file) @@ -590,6 +610,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 3465f31a21c..56a304709fd 100644 --- a/include/scsi/scsi_driver.h +++ b/include/scsi/scsi_driver.h @@ -5,13 +5,15 @@ struct module; struct scsi_cmnd; +struct scsi_device; +struct request; +struct request_queue; 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 +27,9 @@ extern int scsi_register_interface(struct class_interface *); #define scsi_unregister_interface(intf) \ class_interface_unregister(intf) +int scsi_setup_blk_pc_cmnd(struct scsi_device *sdev, struct request *req); +int scsi_setup_fs_cmnd(struct scsi_device *sdev, struct request *req); +int scsi_prep_state_check(struct scsi_device *sdev, struct request *req); +int scsi_prep_return(struct request_queue *q, struct request *req, int ret); + #endif /* _SCSI_SCSI_DRIVER_H */ diff --git a/include/scsi/sd.h b/include/scsi/sd.h index ce02ad1f518..aa1e7161301 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 *); -- cgit v1.2.3-70-g09d2 From 311b581e1d87be87f78e6e17fc50f468f2dec561 Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Sun, 23 Sep 2007 09:08:46 -0500 Subject: [SCSI] Fix device not ready printk Because scsi_print_sense_hdr prefixes with KERN_INFO, the output from scsi_io_completion looks like: sd 0:0:0:0: [sdb] Device not ready: <6>: Sense Key : 0x2 [current] : ASC=0x4 ASCQ=0x3 By using scsi_show_sense_hdr, we can get the much more appealing output: sd 0:0:0:0: [sdb] Device not ready: Sense Key : 0x2 [current] sd 0:0:0:0: [sdb] Device not ready: ASC=0x4 ASCQ=0x3 Acked-by: Matthew Wilcox Signed-off-by: James Bottomley --- drivers/scsi/constants.c | 14 ++++++++++++++ drivers/scsi/scsi_lib.c | 10 +++++----- include/scsi/scsi_dbg.h | 2 ++ 3 files changed, 21 insertions(+), 5 deletions(-) (limited to 'drivers/scsi/scsi_lib.c') diff --git a/drivers/scsi/constants.c b/drivers/scsi/constants.c index 7bdeed1c5a5..024553f9c24 100644 --- a/drivers/scsi/constants.c +++ b/drivers/scsi/constants.c @@ -1235,6 +1235,20 @@ scsi_print_sense_hdr(const char *name, struct scsi_sense_hdr *sshdr) } EXPORT_SYMBOL(scsi_print_sense_hdr); +/* + * Print normalized SCSI sense header with device information and a prefix. + */ +void +scsi_cmd_print_sense_hdr(struct scsi_cmnd *scmd, const char *desc, + struct scsi_sense_hdr *sshdr) +{ + scmd_printk(KERN_INFO, scmd, "%s: ", desc); + scsi_show_sense_hdr(sshdr); + scmd_printk(KERN_INFO, scmd, "%s: ", desc); + scsi_show_extd_sense(sshdr->asc, sshdr->ascq); +} +EXPORT_SYMBOL(scsi_cmd_print_sense_hdr); + static void scsi_decode_sense_buffer(const unsigned char *sense_buffer, int sense_len, struct scsi_sense_hdr *sshdr) diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 94d82cb9662..86fd3abe731 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -944,11 +944,11 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes) break; } } - if (!(req->cmd_flags & REQ_QUIET)) { - scmd_printk(KERN_INFO, cmd, - "Device not ready: "); - scsi_print_sense_hdr("", &sshdr); - } + if (!(req->cmd_flags & REQ_QUIET)) + scsi_cmd_print_sense_hdr(cmd, + "Device not ready", + &sshdr); + scsi_end_request(cmd, 0, this_count, 1); return; case VOLUME_OVERFLOW: diff --git a/include/scsi/scsi_dbg.h b/include/scsi/scsi_dbg.h index 5a43a4cd96c..e89844cc2cd 100644 --- a/include/scsi/scsi_dbg.h +++ b/include/scsi/scsi_dbg.h @@ -9,6 +9,8 @@ extern void __scsi_print_command(unsigned char *); extern void scsi_show_extd_sense(unsigned char, unsigned char); extern void scsi_show_sense_hdr(struct scsi_sense_hdr *); extern void scsi_print_sense_hdr(const char *, struct scsi_sense_hdr *); +extern void scsi_cmd_print_sense_hdr(struct scsi_cmnd *, const char *, + struct scsi_sense_hdr *); extern void scsi_print_sense(char *, struct scsi_cmnd *); extern void __scsi_print_sense(const char *name, const unsigned char *sense_buffer, -- cgit v1.2.3-70-g09d2 From 6f5391c283d7fdcf24bf40786ea79061919d1e1d Mon Sep 17 00:00:00 2001 From: Matthew Wilcox Date: Tue, 25 Sep 2007 12:42:04 -0400 Subject: [SCSI] Get rid of scsi_cmnd->done The ULD ->done callback moves into the scsi_driver. By moving the call to scsi_io_completion() from scsi_blk_pc_done() to scsi_finish_command(), we can eliminate the latter entirely. By returning 'good_bytes' from the ->done callback (rather than invoking scsi_io_completion()), we can stop exporting scsi_io_completion(). Also move the prototypes from sd.h to sd.c as they're all internal anyway. Rename sd_rw_intr to sd_done and rw_intr to sr_done. Inspired-by: Christoph Hellwig Signed-off-by: Matthew Wilcox Signed-off-by: James Bottomley --- drivers/scsi/scsi.c | 20 +++++++++++++++++--- drivers/scsi/scsi_error.c | 1 - drivers/scsi/scsi_lib.c | 14 -------------- drivers/scsi/scsi_priv.h | 1 + drivers/scsi/sd.c | 28 ++++++++++++++++++---------- drivers/scsi/sr.c | 21 ++++++--------------- include/scsi/scsi_cmnd.h | 2 -- include/scsi/scsi_driver.h | 1 + include/scsi/sd.h | 13 ------------- 9 files changed, 43 insertions(+), 58 deletions(-) (limited to 'drivers/scsi/scsi_lib.c') diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index 07a7c2a70a3..19294882245 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -59,6 +59,7 @@ #include #include #include +#include #include #include #include @@ -367,9 +368,8 @@ void scsi_log_send(struct scsi_cmnd *cmd) scsi_print_command(cmd); if (level > 3) { printk(KERN_INFO "buffer = 0x%p, bufflen = %d," - " done = 0x%p, queuecommand 0x%p\n", + " queuecommand 0x%p\n", scsi_sglist(cmd), scsi_bufflen(cmd), - cmd->done, cmd->device->host->hostt->queuecommand); } @@ -654,6 +654,12 @@ void __scsi_done(struct scsi_cmnd *cmd) blk_complete_request(rq); } +/* Move this to a header if it becomes more generally useful */ +static struct scsi_driver *scsi_cmd_to_driver(struct scsi_cmnd *cmd) +{ + return *(struct scsi_driver **)cmd->request->rq_disk->private_data; +} + /* * Function: scsi_finish_command * @@ -665,6 +671,8 @@ void scsi_finish_command(struct scsi_cmnd *cmd) { struct scsi_device *sdev = cmd->device; struct Scsi_Host *shost = sdev->host; + struct scsi_driver *drv; + unsigned int good_bytes; scsi_device_unbusy(sdev); @@ -690,7 +698,13 @@ void scsi_finish_command(struct scsi_cmnd *cmd) "Notifying upper driver of completion " "(result %x)\n", cmd->result)); - cmd->done(cmd); + good_bytes = cmd->request_bufflen; + if (cmd->request->cmd_type != REQ_TYPE_BLOCK_PC) { + drv = scsi_cmd_to_driver(cmd); + if (drv->done) + good_bytes = drv->done(cmd); + } + scsi_io_completion(cmd, good_bytes); } EXPORT_SYMBOL(scsi_finish_command); diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index 44e6721ddea..f49feb9351d 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -1671,7 +1671,6 @@ scsi_reset_provider(struct scsi_device *dev, int flag) memset(&scmd->cmnd, '\0', sizeof(scmd->cmnd)); scmd->scsi_done = scsi_reset_provider_done_command; - scmd->done = NULL; scmd->request_buffer = NULL; scmd->request_bufflen = 0; diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 86fd3abe731..fac34293bef 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -982,7 +982,6 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes) } scsi_end_request(cmd, 0, this_count, !result); } -EXPORT_SYMBOL(scsi_io_completion); /* * Function: scsi_init_io() @@ -1063,18 +1062,6 @@ static struct scsi_cmnd *scsi_get_cmd_from_req(struct scsi_device *sdev, return cmd; } -static void scsi_blk_pc_done(struct scsi_cmnd *cmd) -{ - BUG_ON(!blk_pc_request(cmd->request)); - /* - * This will complete the whole command with uptodate=1 so - * as far as the block layer is concerned the command completed - * successfully. Since this is a REQ_BLOCK_PC command the - * caller should check the request's errors value - */ - scsi_io_completion(cmd, cmd->request_bufflen); -} - int scsi_setup_blk_pc_cmnd(struct scsi_device *sdev, struct request *req) { struct scsi_cmnd *cmd; @@ -1124,7 +1111,6 @@ int scsi_setup_blk_pc_cmnd(struct scsi_device *sdev, struct request *req) cmd->transfersize = req->data_len; cmd->allowed = req->retries; cmd->timeout_per_command = req->timeout; - cmd->done = scsi_blk_pc_done; return BLKPREP_OK; } EXPORT_SYMBOL(scsi_setup_blk_pc_cmnd); diff --git a/drivers/scsi/scsi_priv.h b/drivers/scsi/scsi_priv.h index ee8efe849bf..eff00595189 100644 --- a/drivers/scsi/scsi_priv.h +++ b/drivers/scsi/scsi_priv.h @@ -68,6 +68,7 @@ extern int scsi_maybe_unblock_host(struct scsi_device *sdev); extern void scsi_device_unbusy(struct scsi_device *sdev); extern int scsi_queue_insert(struct scsi_cmnd *cmd, int reason); extern void scsi_next_command(struct scsi_cmnd *cmd); +extern void scsi_io_completion(struct scsi_cmnd *, unsigned int); extern void scsi_run_host_queues(struct Scsi_Host *shost); extern struct request_queue *scsi_alloc_queue(struct scsi_device *sdev); extern void scsi_free_queue(struct request_queue *q); diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 38a41415004..0a3a528212c 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -86,6 +86,19 @@ MODULE_ALIAS_SCSI_DEVICE(TYPE_DISK); MODULE_ALIAS_SCSI_DEVICE(TYPE_MOD); MODULE_ALIAS_SCSI_DEVICE(TYPE_RBC); +static int sd_revalidate_disk(struct gendisk *); +static int sd_probe(struct device *); +static int sd_remove(struct device *); +static void sd_shutdown(struct device *); +static int sd_suspend(struct device *, pm_message_t state); +static int sd_resume(struct device *); +static void sd_rescan(struct device *); +static int sd_done(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 *); +static void sd_print_result(struct scsi_disk *, int); + static DEFINE_IDR(sd_index_idr); static DEFINE_SPINLOCK(sd_index_lock); @@ -240,6 +253,7 @@ static struct scsi_driver sd_template = { .shutdown = sd_shutdown, }, .rescan = sd_rescan, + .done = sd_done, }; /* @@ -508,12 +522,6 @@ static int sd_prep_fn(struct request_queue *q, struct request *rq) SCpnt->allowed = SD_MAX_RETRIES; SCpnt->timeout_per_command = timeout; - /* - * This is the completion routine we use. This is matched in terms - * of capability to this function. - */ - SCpnt->done = sd_rw_intr; - /* * This indicates that the command is ready from our end to be * queued. @@ -908,13 +916,13 @@ static struct block_device_operations sd_fops = { }; /** - * sd_rw_intr - bottom half handler: called when the lower level + * sd_done - bottom half handler: called when the lower level * driver has completed (successfully or otherwise) a scsi command. * @SCpnt: mid-level's per command structure. * * Note: potentially run from within an ISR. Must not block. **/ -static void sd_rw_intr(struct scsi_cmnd * SCpnt) +static int sd_done(struct scsi_cmnd *SCpnt) { int result = SCpnt->result; unsigned int xfer_size = SCpnt->request_bufflen; @@ -935,7 +943,7 @@ static void sd_rw_intr(struct scsi_cmnd * SCpnt) SCSI_LOG_HLCOMPLETE(1, scsi_print_result(SCpnt)); if (sense_valid) { SCSI_LOG_HLCOMPLETE(1, scmd_printk(KERN_INFO, SCpnt, - "sd_rw_intr: sb[respc,sk,asc," + "sd_done: sb[respc,sk,asc," "ascq]=%x,%x,%x,%x\n", sshdr.response_code, sshdr.sense_key, sshdr.asc, @@ -1007,7 +1015,7 @@ static void sd_rw_intr(struct scsi_cmnd * SCpnt) break; } out: - scsi_io_completion(SCpnt, good_bytes); + return good_bytes; } static int media_not_present(struct scsi_disk *sdkp, diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c index a0c4e13d4da..c6199903114 100644 --- a/drivers/scsi/sr.c +++ b/drivers/scsi/sr.c @@ -78,6 +78,7 @@ MODULE_ALIAS_SCSI_DEVICE(TYPE_WORM); static int sr_probe(struct device *); static int sr_remove(struct device *); +static int sr_done(struct scsi_cmnd *); static struct scsi_driver sr_template = { .owner = THIS_MODULE, @@ -86,6 +87,7 @@ static struct scsi_driver sr_template = { .probe = sr_probe, .remove = sr_remove, }, + .done = sr_done, }; static unsigned long sr_index_bits[SR_DISKS / BITS_PER_LONG]; @@ -208,12 +210,12 @@ static int sr_media_change(struct cdrom_device_info *cdi, int slot) } /* - * rw_intr is the interrupt routine for the device driver. + * sr_done is the interrupt routine for the device driver. * - * It will be notified on the end of a SCSI read / write, and will take on + * It will be notified on the end of a SCSI read / write, and will take one * of several actions based on success or failure. */ -static void rw_intr(struct scsi_cmnd * SCpnt) +static int sr_done(struct scsi_cmnd *SCpnt) { int result = SCpnt->result; int this_count = SCpnt->request_bufflen; @@ -286,12 +288,7 @@ static void rw_intr(struct scsi_cmnd * SCpnt) } } - /* - * This calls the generic completion function, now that we know - * how many actual sectors finished, and how many sectors we need - * to say have failed. - */ - scsi_io_completion(SCpnt, good_bytes); + return good_bytes; } static int sr_prep_fn(struct request_queue *q, struct request *rq) @@ -427,12 +424,6 @@ static int sr_prep_fn(struct request_queue *q, struct request *rq) SCpnt->allowed = MAX_RETRIES; SCpnt->timeout_per_command = timeout; - /* - * This is the completion routine we use. This is matched in terms - * of capability to this function. - */ - SCpnt->done = rw_intr; - /* * This indicates that the command is ready from our end to be * queued. diff --git a/include/scsi/scsi_cmnd.h b/include/scsi/scsi_cmnd.h index 4fddef72746..65ab5145a09 100644 --- a/include/scsi/scsi_cmnd.h +++ b/include/scsi/scsi_cmnd.h @@ -33,7 +33,6 @@ struct scsi_cmnd { struct list_head list; /* scsi_cmnd participates in queue lists */ struct list_head eh_entry; /* entry for the host eh_cmd_q */ int eh_eflags; /* Used by error handlr */ - void (*done) (struct scsi_cmnd *); /* Mid-level done function */ /* * A SCSI Command is assigned a nonzero serial_number before passed @@ -121,7 +120,6 @@ extern struct scsi_cmnd *__scsi_get_command(struct Scsi_Host *, gfp_t); extern void scsi_put_command(struct scsi_cmnd *); extern void __scsi_put_command(struct Scsi_Host *, struct scsi_cmnd *, struct device *); -extern void scsi_io_completion(struct scsi_cmnd *, unsigned int); extern void scsi_finish_command(struct scsi_cmnd *cmd); extern void scsi_req_abort_cmd(struct scsi_cmnd *cmd); diff --git a/include/scsi/scsi_driver.h b/include/scsi/scsi_driver.h index 56a304709fd..1f5ca7f6211 100644 --- a/include/scsi/scsi_driver.h +++ b/include/scsi/scsi_driver.h @@ -15,6 +15,7 @@ struct scsi_driver { struct device_driver gendrv; void (*rescan)(struct device *); + int (*done)(struct scsi_cmnd *); }; #define to_scsi_driver(drv) \ container_of((drv), struct scsi_driver, gendrv) diff --git a/include/scsi/sd.h b/include/scsi/sd.h index aa1e7161301..f7513313ef0 100644 --- a/include/scsi/sd.h +++ b/include/scsi/sd.h @@ -47,19 +47,6 @@ struct scsi_disk { }; #define to_scsi_disk(obj) container_of(obj,struct scsi_disk,cdev) -static int sd_revalidate_disk(struct gendisk *disk); -static void sd_rw_intr(struct scsi_cmnd * SCpnt); -static int sd_probe(struct device *); -static int sd_remove(struct device *); -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 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 *); -static void sd_print_result(struct scsi_disk *, int); - #define sd_printk(prefix, sdsk, fmt, a...) \ (sdsk)->disk ? \ sdev_printk(prefix, (sdsk)->device, "[%s] " fmt, \ -- cgit v1.2.3-70-g09d2