diff options
Diffstat (limited to 'drivers/scsi/scsi_lib.c')
-rw-r--r-- | drivers/scsi/scsi_lib.c | 44 |
1 files changed, 36 insertions, 8 deletions
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 8f010a314a3..faee4757c03 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -367,7 +367,7 @@ static int scsi_req_map_sg(struct request *rq, struct scatterlist *sgl, int nsegs, unsigned bufflen, gfp_t gfp) { struct request_queue *q = rq->q; - int nr_pages = (bufflen + PAGE_SIZE - 1) >> PAGE_SHIFT; + int nr_pages = (bufflen + sgl[0].offset + PAGE_SIZE - 1) >> PAGE_SHIFT; unsigned int data_len = 0, len, bytes, off; struct page *page; struct bio *bio = NULL; @@ -1067,16 +1067,29 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes, break; case NOT_READY: /* - * If the device is in the process of becoming ready, - * retry. + * If the device is in the process of becoming + * ready, or has a temporary blockage, retry. */ - if (sshdr.asc == 0x04 && sshdr.ascq == 0x01) { - scsi_requeue_command(q, cmd); - return; + if (sshdr.asc == 0x04) { + switch (sshdr.ascq) { + case 0x01: /* becoming ready */ + case 0x04: /* format in progress */ + case 0x05: /* rebuild in progress */ + case 0x06: /* recalculation in progress */ + case 0x07: /* operation in progress */ + case 0x08: /* Long write in progress */ + case 0x09: /* self test in progress */ + scsi_requeue_command(q, cmd); + return; + default: + break; + } } - if (!(req->flags & REQ_QUIET)) + if (!(req->flags & REQ_QUIET)) { scmd_printk(KERN_INFO, cmd, - "Device not ready.\n"); + "Device not ready: "); + scsi_print_sense_hdr("", &sshdr); + } scsi_end_request(cmd, 0, this_count, 1); return; case VOLUME_OVERFLOW: @@ -1479,6 +1492,8 @@ static inline int scsi_host_queue_ready(struct request_queue *q, static void scsi_kill_request(struct request *req, request_queue_t *q) { struct scsi_cmnd *cmd = req->special; + struct scsi_device *sdev = cmd->device; + struct Scsi_Host *shost = sdev->host; blkdev_dequeue_request(req); @@ -1491,6 +1506,19 @@ static void scsi_kill_request(struct request *req, request_queue_t *q) scsi_init_cmd_errh(cmd); cmd->result = DID_NO_CONNECT << 16; atomic_inc(&cmd->device->iorequest_cnt); + + /* + * SCSI request completion path will do scsi_device_unbusy(), + * bump busy counts. To bump the counters, we need to dance + * with the locks as normal issue path does. + */ + sdev->device_busy++; + spin_unlock(sdev->request_queue->queue_lock); + spin_lock(shost->host_lock); + shost->host_busy++; + spin_unlock(shost->host_lock); + spin_lock(sdev->request_queue->queue_lock); + __scsi_done(cmd); } |