Commit f058d51c authored by Linus Torvalds's avatar Linus Torvalds

Merge http://linux-scsi.bkbits.net/scsi-for-linus-2.5

into penguin.transmeta.com:/home/penguin/torvalds/repositories/kernel/linux
parents 8c777fd8 1b4c4bcb
...@@ -40,6 +40,11 @@ const unsigned char scsi_command_size[8] = ...@@ -40,6 +40,11 @@ const unsigned char scsi_command_size[8] =
#define BLK_DEFAULT_TIMEOUT (60 * HZ) #define BLK_DEFAULT_TIMEOUT (60 * HZ)
/* defined in ../scsi/scsi.h ... should it be included? */
#ifndef SCSI_SENSE_BUFFERSIZE
#define SCSI_SENSE_BUFFERSIZE 64
#endif
int blk_do_rq(request_queue_t *q, struct block_device *bdev, struct request *rq) int blk_do_rq(request_queue_t *q, struct block_device *bdev, struct request *rq)
{ {
DECLARE_COMPLETION(wait); DECLARE_COMPLETION(wait);
...@@ -126,11 +131,11 @@ static int sg_io(request_queue_t *q, struct block_device *bdev, ...@@ -126,11 +131,11 @@ static int sg_io(request_queue_t *q, struct block_device *bdev,
struct sg_io_hdr *uptr) struct sg_io_hdr *uptr)
{ {
unsigned long uaddr, start_time; unsigned long uaddr, start_time;
int err, reading, writing, nr_sectors; int reading, writing, nr_sectors;
struct sg_io_hdr hdr; struct sg_io_hdr hdr;
struct request *rq; struct request *rq;
struct bio *bio; struct bio *bio;
char sense[24]; char sense[SCSI_SENSE_BUFFERSIZE];
void *buffer; void *buffer;
if (!access_ok(VERIFY_WRITE, uptr, sizeof(*uptr))) if (!access_ok(VERIFY_WRITE, uptr, sizeof(*uptr)))
...@@ -265,26 +270,36 @@ static int sg_io(request_queue_t *q, struct block_device *bdev, ...@@ -265,26 +270,36 @@ static int sg_io(request_queue_t *q, struct block_device *bdev,
start_time = jiffies; start_time = jiffies;
/* /* ignore return value. All information is passed back to caller
* return -EIO if we didn't transfer all data, caller can look at * (if he doesn't check that is his problem).
* residual count to find out how much did succeed * N.B. a non-zero SCSI status is _not_ necessarily an error.
*/ */
err = blk_do_rq(q, bdev, rq); blk_do_rq(q, bdev, rq);
if (rq->data_len > 0)
err = -EIO;
if (bio) { if (bio) {
bio_unmap_user(bio, reading); bio_unmap_user(bio, reading);
bio_put(bio); bio_put(bio);
} }
/* write to all output members */
hdr.status = rq->errors; hdr.status = rq->errors;
hdr.masked_status = (hdr.status >> 1) & 0x1f;
hdr.msg_status = 0;
hdr.host_status = 0;
hdr.driver_status = 0;
hdr.info = 0;
if (hdr.masked_status || hdr.host_status || hdr.driver_status)
hdr.info |= SG_INFO_CHECK;
hdr.resid = rq->data_len; hdr.resid = rq->data_len;
hdr.duration = (jiffies - start_time) * (1000 / HZ); hdr.duration = (jiffies - start_time) * (1000 / HZ);
hdr.sb_len_wr = 0;
if (rq->sense_len && hdr.sbp) { if (rq->sense_len && hdr.sbp) {
if (!copy_to_user(hdr.sbp,rq->sense, rq->sense_len)) int len = (hdr.mx_sb_len < rq->sense_len) ?
hdr.sb_len_wr = rq->sense_len; hdr.mx_sb_len : rq->sense_len;
if (!copy_to_user(hdr.sbp, rq->sense, len))
hdr.sb_len_wr = len;
} }
blk_put_request(rq); blk_put_request(rq);
...@@ -297,8 +312,9 @@ static int sg_io(request_queue_t *q, struct block_device *bdev, ...@@ -297,8 +312,9 @@ static int sg_io(request_queue_t *q, struct block_device *bdev,
kfree(buffer); kfree(buffer);
} }
/* may not have succeeded, but output values written to control
return err; * structure (struct sg_io_hdr). */
return 0;
} }
#define FORMAT_UNIT_TIMEOUT (2 * 60 * 60 * HZ) #define FORMAT_UNIT_TIMEOUT (2 * 60 * 60 * HZ)
......
...@@ -36,6 +36,7 @@ ...@@ -36,6 +36,7 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/list.h> #include <linux/list.h>
#include <linux/completion.h>
#define __KERNEL_SYSCALLS__ #define __KERNEL_SYSCALLS__
...@@ -314,9 +315,10 @@ int __scsi_add_host(struct Scsi_Host *shost) ...@@ -314,9 +315,10 @@ int __scsi_add_host(struct Scsi_Host *shost)
**/ **/
int scsi_add_host(struct Scsi_Host *shost, struct device *dev) int scsi_add_host(struct Scsi_Host *shost, struct device *dev)
{ {
if (dev) {
dev->class_data = shost; dev->class_data = shost;
shost->host_gendev = dev; shost->host_gendev = dev;
}
return __scsi_add_host(shost); return __scsi_add_host(shost);
} }
...@@ -335,10 +337,11 @@ void scsi_unregister(struct Scsi_Host *shost) ...@@ -335,10 +337,11 @@ void scsi_unregister(struct Scsi_Host *shost)
* Next, kill the kernel error recovery thread for this host. * Next, kill the kernel error recovery thread for this host.
*/ */
if (shost->ehandler) { if (shost->ehandler) {
DECLARE_MUTEX_LOCKED(sem); DECLARE_COMPLETION(sem);
shost->eh_notify = &sem; shost->eh_notify = &sem;
send_sig(SIGHUP, shost->ehandler, 1); shost->eh_kill = 1;
down(&sem); up(shost->eh_wait);
wait_for_completion(&sem);
shost->eh_notify = NULL; shost->eh_notify = NULL;
} }
...@@ -368,7 +371,7 @@ struct Scsi_Host * scsi_register(Scsi_Host_Template *shost_tp, int xtr_bytes) ...@@ -368,7 +371,7 @@ struct Scsi_Host * scsi_register(Scsi_Host_Template *shost_tp, int xtr_bytes)
{ {
struct Scsi_Host *shost, *shost_scr; struct Scsi_Host *shost, *shost_scr;
int gfp_mask; int gfp_mask;
DECLARE_MUTEX_LOCKED(sem); DECLARE_COMPLETION(sem);
/* Check to see if this host has any error handling facilities */ /* Check to see if this host has any error handling facilities */
if(shost_tp->eh_strategy_handler == NULL && if(shost_tp->eh_strategy_handler == NULL &&
...@@ -464,7 +467,7 @@ struct Scsi_Host * scsi_register(Scsi_Host_Template *shost_tp, int xtr_bytes) ...@@ -464,7 +467,7 @@ struct Scsi_Host * scsi_register(Scsi_Host_Template *shost_tp, int xtr_bytes)
* Now wait for the kernel error thread to initialize itself * Now wait for the kernel error thread to initialize itself
* as it might be needed when we scan the bus. * as it might be needed when we scan the bus.
*/ */
down(&sem); wait_for_completion(&sem);
shost->eh_notify = NULL; shost->eh_notify = NULL;
shost->hostt->present++; shost->hostt->present++;
......
...@@ -381,11 +381,12 @@ struct Scsi_Host ...@@ -381,11 +381,12 @@ struct Scsi_Host
struct task_struct * ehandler; /* Error recovery thread. */ struct task_struct * ehandler; /* Error recovery thread. */
struct semaphore * eh_wait; /* The error recovery thread waits on struct semaphore * eh_wait; /* The error recovery thread waits on
this. */ this. */
struct semaphore * eh_notify; /* wait for eh to begin */ struct completion * eh_notify; /* wait for eh to begin or end */
struct semaphore * eh_action; /* Wait for specific actions on the struct semaphore * eh_action; /* Wait for specific actions on the
host. */ host. */
unsigned int eh_active:1; /* Indicates the eh thread is awake and active if unsigned int eh_active:1; /* Indicates the eh thread is awake and active if
this is true. */ this is true. */
unsigned int eh_kill:1; /* set when killing the eh thread */
wait_queue_head_t host_wait; wait_queue_head_t host_wait;
Scsi_Host_Template * hostt; Scsi_Host_Template * hostt;
atomic_t host_active; /* commands checked out */ atomic_t host_active; /* commands checked out */
......
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/smp_lock.h> #include <linux/smp_lock.h>
#include <linux/completion.h>
#define __KERNEL_SYSCALLS__ #define __KERNEL_SYSCALLS__
...@@ -41,20 +42,6 @@ ...@@ -41,20 +42,6 @@
#include <scsi/scsi_ioctl.h> /* grr */ #include <scsi/scsi_ioctl.h> /* grr */
/*
* We must always allow SHUTDOWN_SIGS. Even if we are not a module,
* the host drivers that we are using may be loaded as modules, and
* when we unload these, we need to ensure that the error handler thread
* can be shut down.
*
* Note - when we unload a module, we send a SIGHUP. We mustn't
* enable SIGTERM, as this is how the init shuts things down when you
* go to single-user mode. For that matter, init also sends SIGKILL,
* so we mustn't enable that one either. We use SIGHUP instead. Other
* options would be SIGPWR, I suppose.
*/
#define SHUTDOWN_SIGS (sigmask(SIGHUP))
#ifdef DEBUG #ifdef DEBUG
#define SENSE_TIMEOUT SCSI_TIMEOUT #define SENSE_TIMEOUT SCSI_TIMEOUT
#else #else
...@@ -1589,12 +1576,10 @@ void scsi_error_handler(void *data) ...@@ -1589,12 +1576,10 @@ void scsi_error_handler(void *data)
int rtn; int rtn;
DECLARE_MUTEX_LOCKED(sem); DECLARE_MUTEX_LOCKED(sem);
/* spin_lock_irq(&current->sig->siglock);
* We only listen to signals if the HA was loaded as a module. sigfillset(&current->blocked);
* If the HA was compiled into the kernel, then we don't listen recalc_sigpending();
* to any signals. spin_unlock_irq(&current->sig->siglock);
*/
siginitsetinv(&current->blocked, SHUTDOWN_SIGS);
lock_kernel(); lock_kernel();
...@@ -1618,9 +1603,9 @@ void scsi_error_handler(void *data) ...@@ -1618,9 +1603,9 @@ void scsi_error_handler(void *data)
/* /*
* Wake up the thread that created us. * Wake up the thread that created us.
*/ */
SCSI_LOG_ERROR_RECOVERY(3, printk("Wake up parent \n")); SCSI_LOG_ERROR_RECOVERY(3, printk("Wake up parent of scsi_eh_%d\n",shost->host_no));
up(shost->eh_notify); complete(shost->eh_notify);
while (1) { while (1) {
/* /*
...@@ -1628,7 +1613,7 @@ void scsi_error_handler(void *data) ...@@ -1628,7 +1613,7 @@ void scsi_error_handler(void *data)
* away and die. This typically happens if the user is * away and die. This typically happens if the user is
* trying to unload a module. * trying to unload a module.
*/ */
SCSI_LOG_ERROR_RECOVERY(1, printk("Error handler sleeping\n")); SCSI_LOG_ERROR_RECOVERY(1, printk("Error handler scsi_eh_%d sleeping\n",shost->host_no));
/* /*
* Note - we always use down_interruptible with the semaphore * Note - we always use down_interruptible with the semaphore
...@@ -1640,10 +1625,10 @@ void scsi_error_handler(void *data) ...@@ -1640,10 +1625,10 @@ void scsi_error_handler(void *data)
* semaphores isn't unreasonable. * semaphores isn't unreasonable.
*/ */
down_interruptible(&sem); down_interruptible(&sem);
if (signal_pending(current)) if (shost->eh_kill)
break; break;
SCSI_LOG_ERROR_RECOVERY(1, printk("Error handler waking up\n")); SCSI_LOG_ERROR_RECOVERY(1, printk("Error handler scsi_eh_%d waking up\n",shost->host_no));
shost->eh_active = 1; shost->eh_active = 1;
...@@ -1671,7 +1656,7 @@ void scsi_error_handler(void *data) ...@@ -1671,7 +1656,7 @@ void scsi_error_handler(void *data)
} }
SCSI_LOG_ERROR_RECOVERY(1, printk("Error handler exiting\n")); SCSI_LOG_ERROR_RECOVERY(1, printk("Error handler scsi_eh_%d exiting\n",shost->host_no));
/* /*
* Make sure that nobody tries to wake us up again. * Make sure that nobody tries to wake us up again.
...@@ -1691,13 +1676,9 @@ void scsi_error_handler(void *data) ...@@ -1691,13 +1676,9 @@ void scsi_error_handler(void *data)
/* /*
* If anyone is waiting for us to exit (i.e. someone trying to unload * If anyone is waiting for us to exit (i.e. someone trying to unload
* a driver), then wake up that process to let them know we are on * a driver), then wake up that process to let them know we are on
* the way out the door. This may be overkill - I *think* that we * the way out the door.
* could probably just unload the driver and send the signal, and when
* the error handling thread wakes up that it would just exit without
* needing to touch any memory associated with the driver itself.
*/ */
if (shost->eh_notify != NULL) complete_and_exit(shost->eh_notify, 0);
up(shost->eh_notify);
} }
/** /**
......
...@@ -495,6 +495,7 @@ void scsi_io_completion(Scsi_Cmnd * SCpnt, int good_sectors, ...@@ -495,6 +495,7 @@ void scsi_io_completion(Scsi_Cmnd * SCpnt, int good_sectors,
int this_count = SCpnt->bufflen >> 9; int this_count = SCpnt->bufflen >> 9;
request_queue_t *q = SCpnt->device->request_queue; request_queue_t *q = SCpnt->device->request_queue;
struct request *req = SCpnt->request; struct request *req = SCpnt->request;
int clear_errors = 1;
/* /*
* We must do one of several things here: * We must do one of several things here:
...@@ -528,10 +529,22 @@ void scsi_io_completion(Scsi_Cmnd * SCpnt, int good_sectors, ...@@ -528,10 +529,22 @@ void scsi_io_completion(Scsi_Cmnd * SCpnt, int good_sectors,
kfree(SCpnt->buffer); kfree(SCpnt->buffer);
} }
if (blk_pc_request(req)) { if (blk_pc_request(req)) { /* SG_IO ioctl from block level */
req->errors = result & 0xff; req->errors = (driver_byte(result) & DRIVER_SENSE) ?
(CHECK_CONDITION << 1) : (result & 0xff);
if (!result) if (!result)
req->data_len -= SCpnt->bufflen; req->data_len -= SCpnt->bufflen;
else {
clear_errors = 0;
if (SCpnt->sense_buffer[0] & 0x70) {
int len = 8 + SCpnt->sense_buffer[7];
if (len > SCSI_SENSE_BUFFERSIZE)
len = SCSI_SENSE_BUFFERSIZE;
memcpy(req->sense, SCpnt->sense_buffer, len);
req->sense_len = len;
}
}
} }
/* /*
...@@ -552,6 +565,7 @@ void scsi_io_completion(Scsi_Cmnd * SCpnt, int good_sectors, ...@@ -552,6 +565,7 @@ void scsi_io_completion(Scsi_Cmnd * SCpnt, int good_sectors,
req->nr_sectors, good_sectors)); req->nr_sectors, good_sectors));
SCSI_LOG_HLCOMPLETE(1, printk("use_sg is %d\n ", SCpnt->use_sg)); SCSI_LOG_HLCOMPLETE(1, printk("use_sg is %d\n ", SCpnt->use_sg));
if (clear_errors)
req->errors = 0; req->errors = 0;
/* /*
* If multiple sectors are requested in one buffer, then * If multiple sectors are requested in one buffer, then
......
...@@ -213,6 +213,7 @@ sdev_rd_attr (device_blocked, "%d\n"); ...@@ -213,6 +213,7 @@ sdev_rd_attr (device_blocked, "%d\n");
sdev_rd_attr (current_queue_depth, "%d\n"); sdev_rd_attr (current_queue_depth, "%d\n");
sdev_rd_attr (new_queue_depth, "%d\n"); sdev_rd_attr (new_queue_depth, "%d\n");
sdev_rd_attr (type, "%d\n"); sdev_rd_attr (type, "%d\n");
sdev_rd_attr (scsi_level, "%d\n");
sdev_rd_attr (access_count, "%d\n"); sdev_rd_attr (access_count, "%d\n");
sdev_rd_attr (vendor, "%.8s\n"); sdev_rd_attr (vendor, "%.8s\n");
sdev_rd_attr (model, "%.16s\n"); sdev_rd_attr (model, "%.16s\n");
...@@ -224,6 +225,7 @@ static struct device_attribute * const sdev_attrs[] = { ...@@ -224,6 +225,7 @@ static struct device_attribute * const sdev_attrs[] = {
&dev_attr_current_queue_depth, &dev_attr_current_queue_depth,
&dev_attr_new_queue_depth, &dev_attr_new_queue_depth,
&dev_attr_type, &dev_attr_type,
&dev_attr_scsi_level,
&dev_attr_access_count, &dev_attr_access_count,
&dev_attr_vendor, &dev_attr_vendor,
&dev_attr_model, &dev_attr_model,
......
...@@ -79,7 +79,7 @@ struct scsi_disk { ...@@ -79,7 +79,7 @@ struct scsi_disk {
u8 media_present; u8 media_present;
u8 write_prot; u8 write_prot;
unsigned WCE : 1; /* state of disk WCE bit */ unsigned WCE : 1; /* state of disk WCE bit */
unsigned RCD : 1; /* state of disk RCD bit */ unsigned RCD : 1; /* state of disk RCD bit, unused */
}; };
static LIST_HEAD(sd_devlist); static LIST_HEAD(sd_devlist);
...@@ -217,7 +217,7 @@ static int sd_init_command(struct scsi_cmnd * SCpnt) ...@@ -217,7 +217,7 @@ static int sd_init_command(struct scsi_cmnd * SCpnt)
block = SCpnt->request->sector; block = SCpnt->request->sector;
this_count = SCpnt->request_bufflen >> 9; this_count = SCpnt->request_bufflen >> 9;
SCSI_LOG_HLQUEUE(1, printk("sd_command_init: disk=%s, block=%llu, " 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 || !sdp->online || if (!sdp || !sdp->online ||
...@@ -809,9 +809,22 @@ sd_spinup_disk(struct scsi_disk *sdkp, char *diskname, ...@@ -809,9 +809,22 @@ sd_spinup_disk(struct scsi_disk *sdkp, char *diskname,
if (media_not_present(sdkp, SRpnt)) if (media_not_present(sdkp, SRpnt))
return; return;
/* Look for devices that return NOT_READY. if (the_result == 0)
* Issue command to spin up drive for these cases. */ break; /* all is well now */
if (the_result && SRpnt->sr_sense_buffer[2] == NOT_READY) {
/*
* 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)
break; /* manual intervention required */
/*
* Issue command to spin up drive when not ready
*/
if (SRpnt->sr_sense_buffer[2] == NOT_READY) {
unsigned long time1; unsigned long time1;
if (!spintime) { if (!spintime) {
printk(KERN_NOTICE "%s: Spinning up disk...", printk(KERN_NOTICE "%s: Spinning up disk...",
...@@ -839,7 +852,7 @@ sd_spinup_disk(struct scsi_disk *sdkp, char *diskname, ...@@ -839,7 +852,7 @@ sd_spinup_disk(struct scsi_disk *sdkp, char *diskname,
} while(time1); } while(time1);
printk("."); printk(".");
} }
} while (the_result && spintime && } while (spintime &&
time_after(spintime_value + 100 * HZ, jiffies)); time_after(spintime_value + 100 * HZ, jiffies));
if (spintime) { if (spintime) {
...@@ -850,80 +863,6 @@ sd_spinup_disk(struct scsi_disk *sdkp, char *diskname, ...@@ -850,80 +863,6 @@ sd_spinup_disk(struct scsi_disk *sdkp, char *diskname,
} }
} }
/*
* sd_read_cache_type - called only from sd_init_onedisk()
*/
static void
sd_read_cache_type(struct scsi_disk *sdkp, char *diskname,
struct scsi_request *SRpnt, unsigned char *buffer) {
unsigned char cmd[10];
int the_result, retries;
retries = 3;
do {
memset((void *) &cmd[0], 0, 10);
cmd[0] = MODE_SENSE;
cmd[1] = 0x08; /* DBD */
cmd[2] = 0x08; /* current values, cache page */
cmd[4] = 128; /* allocation length */
memset((void *) buffer, 0, 24);
SRpnt->sr_cmd_len = 0;
SRpnt->sr_sense_buffer[0] = 0;
SRpnt->sr_sense_buffer[2] = 0;
SRpnt->sr_data_direction = SCSI_DATA_READ;
scsi_wait_req(SRpnt, (void *) cmd, (void *) buffer,
128, SD_TIMEOUT, SD_MAX_RETRIES);
the_result = SRpnt->sr_result;
retries--;
} while (the_result && retries);
if (the_result) {
if(status_byte(the_result) == CHECK_CONDITION
&& (SRpnt->sr_sense_buffer[0] & 0x70) == 0x70
&& (SRpnt->sr_sense_buffer[2] & 0x0f) == ILLEGAL_REQUEST
/* The next are ASC 0x24 ASCQ 0x00: Invalid field in CDB */
&& SRpnt->sr_sense_buffer[12] == 0x24
&& SRpnt->sr_sense_buffer[13] == 0x00) {
printk(KERN_NOTICE "SCSI device %s: cache data unavailable\n", diskname);
} else {
printk(KERN_ERR "%s : MODE SENSE failed.\n"
"%s : status = %x, message = %02x, host = %d, driver = %02x \n",
diskname, diskname,
status_byte(the_result),
msg_byte(the_result),
host_byte(the_result),
driver_byte(the_result)
);
if (driver_byte(the_result) & DRIVER_SENSE)
print_req_sense("sd", SRpnt);
else
printk(KERN_ERR "%s : sense not available. \n", diskname);
printk(KERN_ERR "%s : assuming drive cache: write through\n", diskname);
}
sdkp->WCE = 0;
sdkp->RCD = 0;
} else {
const char *types[] = { "write through", "none", "write back", "write back, no read (daft)" };
int ct = 0;
int offset = buffer[3] + 4; /* offset to start of mode page */
sdkp->WCE = (buffer[offset + 2] & 0x04) == 0x04;
sdkp->RCD = (buffer[offset + 2] & 0x01) == 0x01;
ct = sdkp->RCD + 2*sdkp->WCE;
printk(KERN_NOTICE "SCSI device %s: drive cache: %s\n", diskname, types[ct]);
}
}
/* /*
* read disk capacity - called only in sd_init_onedisk() * read disk capacity - called only in sd_init_onedisk()
*/ */
...@@ -1102,11 +1041,12 @@ sd_read_capacity(struct scsi_disk *sdkp, char *diskname, ...@@ -1102,11 +1041,12 @@ sd_read_capacity(struct scsi_disk *sdkp, char *diskname,
static int static int
sd_do_mode_sense6(struct scsi_device *sdp, struct scsi_request *SRpnt, sd_do_mode_sense6(struct scsi_device *sdp, struct scsi_request *SRpnt,
int modepage, unsigned char *buffer, int len) { int dbd, int modepage, unsigned char *buffer, int len) {
unsigned char cmd[8]; unsigned char cmd[8];
memset((void *) &cmd[0], 0, 8); memset((void *) &cmd[0], 0, 8);
cmd[0] = MODE_SENSE; cmd[0] = MODE_SENSE;
cmd[1] = dbd;
cmd[2] = modepage; cmd[2] = modepage;
cmd[4] = len; cmd[4] = len;
...@@ -1115,6 +1055,8 @@ sd_do_mode_sense6(struct scsi_device *sdp, struct scsi_request *SRpnt, ...@@ -1115,6 +1055,8 @@ sd_do_mode_sense6(struct scsi_device *sdp, struct scsi_request *SRpnt,
SRpnt->sr_sense_buffer[2] = 0; SRpnt->sr_sense_buffer[2] = 0;
SRpnt->sr_data_direction = SCSI_DATA_READ; SRpnt->sr_data_direction = SCSI_DATA_READ;
memset((void *) buffer, 0, len);
scsi_wait_req(SRpnt, (void *) cmd, (void *) buffer, scsi_wait_req(SRpnt, (void *) cmd, (void *) buffer,
len, SD_TIMEOUT, SD_MAX_RETRIES); len, SD_TIMEOUT, SD_MAX_RETRIES);
...@@ -1135,7 +1077,7 @@ sd_read_write_protect_flag(struct scsi_disk *sdkp, char *diskname, ...@@ -1135,7 +1077,7 @@ sd_read_write_protect_flag(struct scsi_disk *sdkp, char *diskname,
* We have to start carefully: some devices hang if we ask * We have to start carefully: some devices hang if we ask
* for more than is available. * for more than is available.
*/ */
res = sd_do_mode_sense6(sdp, SRpnt, 0x3F, buffer, 4); res = sd_do_mode_sense6(sdp, SRpnt, 0, 0x3F, buffer, 4);
/* /*
* Second attempt: ask for page 0 * Second attempt: ask for page 0
...@@ -1143,13 +1085,13 @@ sd_read_write_protect_flag(struct scsi_disk *sdkp, char *diskname, ...@@ -1143,13 +1085,13 @@ sd_read_write_protect_flag(struct scsi_disk *sdkp, char *diskname,
* Sense Key 5: Illegal Request, Sense Code 24: Invalid field in CDB. * Sense Key 5: Illegal Request, Sense Code 24: Invalid field in CDB.
*/ */
if (res) if (res)
res = sd_do_mode_sense6(sdp, SRpnt, 0, buffer, 4); res = sd_do_mode_sense6(sdp, SRpnt, 0, 0, buffer, 4);
/* /*
* Third attempt: ask 255 bytes, as we did earlier. * Third attempt: ask 255 bytes, as we did earlier.
*/ */
if (res) if (res)
res = sd_do_mode_sense6(sdp, SRpnt, 0x3F, buffer, 255); res = sd_do_mode_sense6(sdp, SRpnt, 0, 0x3F, buffer, 255);
if (res) { if (res) {
printk(KERN_WARNING printk(KERN_WARNING
...@@ -1163,6 +1105,65 @@ sd_read_write_protect_flag(struct scsi_disk *sdkp, char *diskname, ...@@ -1163,6 +1105,65 @@ sd_read_write_protect_flag(struct scsi_disk *sdkp, char *diskname,
} }
} }
/*
* sd_read_cache_type - called only from sd_init_onedisk()
*/
static void
sd_read_cache_type(struct scsi_disk *sdkp, char *diskname,
struct scsi_request *SRpnt, unsigned char *buffer) {
struct scsi_device *sdp = sdkp->device;
int len = 0, res;
const int dbd = 0x08; /* DBD */
const int modepage = 0x08; /* current values, cache page */
/* cautiously ask */
res = sd_do_mode_sense6(sdp, SRpnt, dbd, modepage, buffer, 4);
if (res == 0) {
/* that went OK, now ask for the proper length */
len = buffer[0] + 1;
if (len > 128)
len = 128;
res = sd_do_mode_sense6(sdp, SRpnt, dbd, modepage, buffer, len);
}
if (res == 0 && buffer[3] + 6 < len) {
const char *types[] = {
"write through", "none", "write back",
"write back, no read (daft)"
};
int ct = 0;
int offset = buffer[3] + 4; /* start of mode page */
sdkp->WCE = ((buffer[offset + 2] & 0x04) != 0);
sdkp->RCD = ((buffer[offset + 2] & 0x01) != 0);
ct = sdkp->RCD + 2*sdkp->WCE;
printk(KERN_NOTICE "SCSI device %s: drive cache: %s\n",
diskname, types[ct]);
} else {
if (res == 0 ||
(status_byte(res) == CHECK_CONDITION
&& (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)) {
printk(KERN_NOTICE "%s: cache data unavailable\n",
diskname);
} else {
printk(KERN_ERR "%s: asking for cache data failed\n",
diskname);
}
printk(KERN_ERR "%s: assuming drive cache: write through\n",
diskname);
sdkp->WCE = 0;
sdkp->RCD = 0;
}
}
/** /**
* sd_init_onedisk - called the first time a new disk is seen, * sd_init_onedisk - called the first time a new disk is seen,
* performs disk spin up, read_capacity, etc. * performs disk spin up, read_capacity, etc.
...@@ -1208,15 +1209,20 @@ sd_init_onedisk(struct scsi_disk * sdkp, struct gendisk *disk) ...@@ -1208,15 +1209,20 @@ sd_init_onedisk(struct scsi_disk * sdkp, struct gendisk *disk)
sdkp->device->sector_size = 512; sdkp->device->sector_size = 512;
sdkp->media_present = 1; sdkp->media_present = 1;
sdkp->write_prot = 0; sdkp->write_prot = 0;
sdkp->WCE = 0;
sdkp->RCD = 0;
sd_spinup_disk(sdkp, disk->disk_name, SRpnt, buffer); sd_spinup_disk(sdkp, disk->disk_name, SRpnt, buffer);
sd_read_cache_type(sdkp, disk->disk_name, SRpnt, buffer);
if (sdkp->media_present) if (sdkp->media_present)
sd_read_capacity(sdkp, disk->disk_name, SRpnt, buffer); sd_read_capacity(sdkp, disk->disk_name, SRpnt, buffer);
if (sdp->removable && sdkp->media_present) if (sdp->removable && sdkp->media_present)
sd_read_write_protect_flag(sdkp, disk->disk_name, SRpnt, buffer); sd_read_write_protect_flag(sdkp, disk->disk_name, SRpnt, buffer);
/* without media there is no reason to ask;
moreover, some devices react badly if we do */
if (sdkp->media_present)
sd_read_cache_type(sdkp, disk->disk_name, SRpnt, buffer);
SRpnt->sr_device->ten = 1; SRpnt->sr_device->ten = 1;
SRpnt->sr_device->remap = 1; SRpnt->sr_device->remap = 1;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment