#include <linux/blkdev.h>
#include <linux/blkpg.h>
#include <linux/kref.h>
+#include <linux/delay.h>
#include <asm/uaccess.h>
#include <scsi/scsi.h>
* Number of allowed retries
*/
#define SD_MAX_RETRIES 5
+#define SD_PASSTHROUGH_RETRIES 1
static void scsi_disk_release(struct kref *kref);
};
static DEFINE_IDR(sd_index_idr);
-static spinlock_t sd_index_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(sd_index_lock);
/* This semaphore is used to mediate the 0->1 reference get in the
* face of object destruction (i.e. we can't allow a get on an
static void scsi_disk_put(struct scsi_disk *sdkp)
{
+ struct scsi_device *sdev = sdkp->device;
+
down(&sd_ref_sem);
- scsi_device_put(sdkp->device);
kref_put(&sdkp->kref, scsi_disk_release);
+ scsi_device_put(sdev);
up(&sd_ref_sem);
}
struct gendisk *disk;
sector_t block;
struct scsi_device *sdp = SCpnt->device;
+ struct request *rq = SCpnt->request;
timeout = sdp->timeout;
/*
- * these are already setup, just copy cdb basically
+ * SG_IO from block layer already setup, just copy cdb basically
*/
- if (SCpnt->request->flags & REQ_BLOCK_PC) {
- struct request *rq = SCpnt->request;
-
+ if (blk_pc_request(rq)) {
if (sizeof(rq->cmd) > sizeof(SCpnt->cmnd))
return 0;
timeout = rq->timeout;
SCpnt->transfersize = rq->data_len;
+ SCpnt->allowed = SD_PASSTHROUGH_RETRIES;
goto queue;
}
/*
* we only do REQ_CMD and REQ_BLOCK_PC
*/
- if (!(SCpnt->request->flags & REQ_CMD))
+ if (!blk_fs_request(rq))
return 0;
- disk = SCpnt->request->rq_disk;
- block = SCpnt->request->sector;
+ disk = rq->rq_disk;
+ block = rq->sector;
this_count = SCpnt->request_bufflen >> 9;
SCSI_LOG_HLQUEUE(1, printk("sd_init_command: disk=%s, block=%llu, "
- "count=%d\n", disk->disk_name, (unsigned long long)block, this_count));
+ "count=%d\n", disk->disk_name,
+ (unsigned long long)block, this_count));
if (!sdp || !scsi_device_online(sdp) ||
- block + SCpnt->request->nr_sectors > get_capacity(disk)) {
+ block + rq->nr_sectors > get_capacity(disk)) {
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;
}
* for this.
*/
if (sdp->sector_size == 1024) {
- if ((block & 1) || (SCpnt->request->nr_sectors & 1)) {
+ if ((block & 1) || (rq->nr_sectors & 1)) {
printk(KERN_ERR "sd: Bad block number requested");
return 0;
} else {
}
}
if (sdp->sector_size == 2048) {
- if ((block & 3) || (SCpnt->request->nr_sectors & 3)) {
+ if ((block & 3) || (rq->nr_sectors & 3)) {
printk(KERN_ERR "sd: Bad block number requested");
return 0;
} else {
}
}
if (sdp->sector_size == 4096) {
- if ((block & 7) || (SCpnt->request->nr_sectors & 7)) {
+ if ((block & 7) || (rq->nr_sectors & 7)) {
printk(KERN_ERR "sd: Bad block number requested");
return 0;
} else {
this_count = this_count >> 3;
}
}
- if (rq_data_dir(SCpnt->request) == WRITE) {
+ if (rq_data_dir(rq) == WRITE) {
if (!sdp->writeable) {
return 0;
}
SCpnt->cmnd[0] = WRITE_6;
SCpnt->sc_data_direction = DMA_TO_DEVICE;
- } else if (rq_data_dir(SCpnt->request) == READ) {
+ } else if (rq_data_dir(rq) == READ) {
SCpnt->cmnd[0] = READ_6;
SCpnt->sc_data_direction = DMA_FROM_DEVICE;
} else {
- printk(KERN_ERR "sd: Unknown command %lx\n",
- SCpnt->request->flags);
-/* overkill panic("Unknown sd command %lx\n", SCpnt->request->flags); */
+ printk(KERN_ERR "sd: Unknown command %lx\n", rq->flags);
+/* overkill panic("Unknown sd command %lx\n", rq->flags); */
return 0;
}
SCSI_LOG_HLQUEUE(2, printk("%s : %s %d/%ld 512 byte blocks.\n",
- disk->disk_name, (rq_data_dir(SCpnt->request) == WRITE) ?
- "writing" : "reading", this_count, SCpnt->request->nr_sectors));
+ disk->disk_name, (rq_data_dir(rq) == WRITE) ?
+ "writing" : "reading", this_count, rq->nr_sectors));
SCpnt->cmnd[1] = 0;
*/
SCpnt->transfersize = sdp->sector_size;
SCpnt->underflow = this_count << 9;
+ SCpnt->allowed = SD_MAX_RETRIES;
queue:
- SCpnt->allowed = SD_MAX_RETRIES;
SCpnt->timeout_per_command = timeout;
/*
* may try and take the device offline, in which case all further
* access to the device is prohibited.
*/
- if (!scsi_block_when_processing_errors(sdp))
- return -ENODEV;
+ error = scsi_nonblockable_ioctl(sdp, cmd, p, filp);
+ if (!scsi_block_when_processing_errors(sdp) || !error)
+ return error;
if (cmd == HDIO_GETGEO) {
if (!arg)
int this_count = SCpnt->bufflen;
int good_bytes = (result == 0 ? this_count : 0);
sector_t block_sectors = 1;
+ u64 first_err_block;
sector_t error_sector;
+ struct scsi_sense_hdr sshdr;
+ int sense_valid = 0;
+ int sense_deferred = 0;
+ int info_valid;
+
+ if (result) {
+ sense_valid = scsi_command_normalize_sense(SCpnt, &sshdr);
+ if (sense_valid)
+ sense_deferred = scsi_sense_is_deferred(&sshdr);
+ }
+
#ifdef CONFIG_SCSI_LOGGING
SCSI_LOG_HLCOMPLETE(1, printk("sd_rw_intr: %s: res=0x%x\n",
SCpnt->request->rq_disk->disk_name, result));
- if (0 != result) {
- SCSI_LOG_HLCOMPLETE(1, printk("sd_rw_intr: sb[0,2,asc,ascq]"
- "=%x,%x,%x,%x\n", SCpnt->sense_buffer[0],
- SCpnt->sense_buffer[2], SCpnt->sense_buffer[12],
- SCpnt->sense_buffer[13]));
+ if (sense_valid) {
+ SCSI_LOG_HLCOMPLETE(1, printk("sd_rw_intr: sb[respc,sk,asc,"
+ "ascq]=%x,%x,%x,%x\n", sshdr.response_code,
+ sshdr.sense_key, sshdr.asc, sshdr.ascq));
}
#endif
/*
unnecessary additional work such as memcpy's that could be avoided.
*/
- /* An error occurred */
- if (driver_byte(result) != 0 && /* An error occurred */
- (SCpnt->sense_buffer[0] & 0x7f) == 0x70) { /* Sense current */
- switch (SCpnt->sense_buffer[2]) {
+ /*
+ * If SG_IO from block layer then set good_bytes to stop retries;
+ * else if errors, check them, and if necessary prepare for
+ * (partial) retries.
+ */
+ if (blk_pc_request(SCpnt->request))
+ good_bytes = this_count;
+ else if (driver_byte(result) != 0 &&
+ sense_valid && !sense_deferred) {
+ switch (sshdr.sense_key) {
case MEDIUM_ERROR:
- if (!(SCpnt->sense_buffer[0] & 0x80))
- break;
if (!blk_fs_request(SCpnt->request))
break;
- error_sector = (SCpnt->sense_buffer[3] << 24) |
- (SCpnt->sense_buffer[4] << 16) |
- (SCpnt->sense_buffer[5] << 8) |
- SCpnt->sense_buffer[6];
+ info_valid = scsi_get_sense_info_fld(
+ SCpnt->sense_buffer, SCSI_SENSE_BUFFERSIZE,
+ &first_err_block);
+ /*
+ * May want to warn and skip if following cast results
+ * in actual truncation (if sector_t < 64 bits)
+ */
+ error_sector = (sector_t)first_err_block;
if (SCpnt->request->bio != NULL)
block_sectors = bio_sectors(SCpnt->request->bio);
switch (SCpnt->device->sector_size) {
*/
scsi_print_sense("sd", SCpnt);
SCpnt->result = 0;
- SCpnt->sense_buffer[0] = 0x0;
+ memset(SCpnt->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
good_bytes = this_count;
break;
static int media_not_present(struct scsi_disk *sdkp, struct scsi_request *srp)
{
+ struct scsi_sense_hdr sshdr;
+
if (!srp->sr_result)
return 0;
if (!(driver_byte(srp->sr_result) & DRIVER_SENSE))
return 0;
- if (srp->sr_sense_buffer[2] != NOT_READY &&
- srp->sr_sense_buffer[2] != UNIT_ATTENTION)
- return 0;
- if (srp->sr_sense_buffer[12] != 0x3A) /* medium not present */
- return 0;
-
+ /* not invoked for commands that could return deferred errors */
+ if (scsi_request_normalize_sense(srp, &sshdr)) {
+ if (sshdr.sense_key != NOT_READY &&
+ sshdr.sense_key != UNIT_ATTENTION)
+ return 0;
+ if (sshdr.asc != 0x3A) /* medium not present */
+ return 0;
+ }
set_media_not_present(sdkp);
return 1;
}
unsigned long spintime_value = 0;
int retries, spintime;
unsigned int the_result;
+ struct scsi_sense_hdr sshdr;
+ int sense_valid = 0;
spintime = 0;
memset((void *) &cmd[1], 0, 9);
SRpnt->sr_cmd_len = 0;
- SRpnt->sr_sense_buffer[0] = 0;
- SRpnt->sr_sense_buffer[2] = 0;
+ memset(SRpnt->sr_sense_buffer, 0,
+ SCSI_SENSE_BUFFERSIZE);
SRpnt->sr_data_direction = DMA_NONE;
scsi_wait_req (SRpnt, (void *) cmd, (void *) buffer,
0/*512*/, SD_TIMEOUT, SD_MAX_RETRIES);
the_result = SRpnt->sr_result;
+ if (the_result)
+ sense_valid = scsi_request_normalize_sense(
+ SRpnt, &sshdr);
retries++;
} while (retries < 3 &&
(!scsi_status_is_good(the_result) ||
((driver_byte(the_result) & DRIVER_SENSE) &&
- SRpnt->sr_sense_buffer[2] == UNIT_ATTENTION)));
+ sense_valid && sshdr.sense_key == UNIT_ATTENTION)));
/*
* If the drive has indicated to us that it doesn't have
/* no sense, TUR either succeeded or failed
* with a status error */
if(!spintime && !scsi_status_is_good(the_result))
- printk(KERN_NOTICE "%s: Unit Not Ready, error = 0x%x\n", diskname, the_result);
+ printk(KERN_NOTICE "%s: Unit Not Ready, "
+ "error = 0x%x\n", diskname, the_result);
break;
}
* If manual intervention is required, or this is an
* absent USB storage device, a spinup is meaningless.
*/
- if (SRpnt->sr_sense_buffer[2] == NOT_READY &&
- SRpnt->sr_sense_buffer[12] == 4 /* not ready */ &&
- SRpnt->sr_sense_buffer[13] == 3) {
+ if (sense_valid &&
+ sshdr.sense_key == NOT_READY &&
+ sshdr.asc == 4 && sshdr.ascq == 3) {
break; /* manual intervention required */
/*
* Issue command to spin up drive when not ready
*/
- } else if (SRpnt->sr_sense_buffer[2] == NOT_READY) {
- unsigned long time1;
+ } else if (sense_valid && sshdr.sense_key == NOT_READY) {
if (!spintime) {
printk(KERN_NOTICE "%s: Spinning up disk...",
diskname);
memset((void *) &cmd[2], 0, 8);
cmd[4] = 1; /* Start spin cycle */
SRpnt->sr_cmd_len = 0;
- SRpnt->sr_sense_buffer[0] = 0;
- SRpnt->sr_sense_buffer[2] = 0;
+ memset(SRpnt->sr_sense_buffer, 0,
+ SCSI_SENSE_BUFFERSIZE);
SRpnt->sr_data_direction = DMA_NONE;
scsi_wait_req(SRpnt, (void *)cmd,
spintime_value = jiffies;
}
spintime = 1;
- time1 = HZ;
/* Wait 1 second for next try */
- do {
- current->state = TASK_UNINTERRUPTIBLE;
- time1 = schedule_timeout(time1);
- } while(time1);
+ msleep(1000);
printk(".");
} else {
/* we don't understand the sense code, so it's
* probably pointless to loop */
if(!spintime) {
- printk(KERN_NOTICE "%s: Unit Not Ready, sense:\n", diskname);
+ printk(KERN_NOTICE "%s: Unit Not Ready, "
+ "sense:\n", diskname);
scsi_print_req_sense("", SRpnt);
}
break;
int the_result, retries;
int sector_size = 0;
int longrc = 0;
+ struct scsi_sense_hdr sshdr;
+ int sense_valid = 0;
repeat:
retries = 3;
}
SRpnt->sr_cmd_len = 0;
- SRpnt->sr_sense_buffer[0] = 0;
- SRpnt->sr_sense_buffer[2] = 0;
+ memset(SRpnt->sr_sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
SRpnt->sr_data_direction = DMA_FROM_DEVICE;
scsi_wait_req(SRpnt, (void *) cmd, (void *) buffer,
return;
the_result = SRpnt->sr_result;
+ if (the_result)
+ sense_valid = scsi_request_normalize_sense(SRpnt,
+ &sshdr);
retries--;
} while (the_result && retries);
/* Set dirty bit for removable devices if not ready -
* sometimes drives will not report this properly. */
if (sdp->removable &&
- SRpnt->sr_sense_buffer[2] == NOT_READY)
+ sense_valid && sshdr.sense_key == NOT_READY)
sdp->changed = 1;
/* Either no media are present but the drive didn't tell us,
" READ CAPACITY(16).\n", diskname);
longrc = 1;
goto repeat;
- } else {
- printk(KERN_ERR "%s: too big for kernel. Assuming maximum 2Tb\n", diskname);
}
+ printk(KERN_ERR "%s: too big for this kernel. Use a "
+ "kernel compiled with support for large block "
+ "devices.\n", diskname);
+ sdkp->capacity = 0;
+ goto got_data;
}
sdkp->capacity = 1 + (((sector_t)buffer[0] << 24) |
(buffer[1] << 16) |
(buffer[9] << 16) | (buffer[10] << 8) | buffer[11];
}
+ /* Some devices return the total number of sectors, not the
+ * highest sector number. Make the necessary adjustment. */
+ if (sdp->fix_capacity)
+ --sdkp->capacity;
+
got_data:
if (sector_size == 0) {
sector_size = 512;
* For this reason, we leave the thing in the table.
*/
sdkp->capacity = 0;
+ /*
+ * set a bogus sector size so the normal read/write
+ * logic in the block layer will eventually refuse any
+ * request on this device without tripping over power
+ * of two sector size assumptions
+ */
+ sector_size = 512;
}
{
/*
const int dbd = 0; /* DBD */
const int modepage = 0x08; /* current values, cache page */
struct scsi_mode_data data;
+ struct scsi_sense_hdr sshdr;
if (sdkp->device->skip_ms_page_8)
goto defaults;
}
bad_sense:
- if ((SRpnt->sr_sense_buffer[0] & 0x70) == 0x70
- && (SRpnt->sr_sense_buffer[2] & 0x0f) == ILLEGAL_REQUEST
- /* ASC 0x24 ASCQ 0x00: Invalid field in CDB */
- && SRpnt->sr_sense_buffer[12] == 0x24
- && SRpnt->sr_sense_buffer[13] == 0x00) {
+ if (scsi_request_normalize_sense(SRpnt, &sshdr) &&
+ sshdr.sense_key == ILLEGAL_REQUEST &&
+ sshdr.asc == 0x24 && sshdr.ascq == 0x0)
printk(KERN_NOTICE "%s: cache data unavailable\n",
- diskname);
- } else {
+ diskname); /* Invalid field in CDB */
+ else
printk(KERN_ERR "%s: asking for cache data failed\n",
diskname);
- }
defaults:
printk(KERN_ERR "%s: assuming drive cache: write through\n",