diff -u -ur linux-2.3.3/drivers/scsi/sd.c linux/drivers/scsi/sd.c --- linux-2.3.3/drivers/scsi/sd.c Thu May 20 22:12:07 1999 +++ linux/drivers/scsi/sd.c Fri May 21 19:47:08 1999 @@ -102,6 +102,47 @@ static int sd_detect(Scsi_Device *); static void sd_detach(Scsi_Device *); +/* + * handle spinup of idle disks + */ + +static void sd_start_done (Scsi_Cmnd * SCpnt) +{ + int result = SCpnt->result; + Scsi_Device * dev = rscsi_disks[DEVICE_NR(SCpnt->request.rq_dev)].device; + + if (result) { + printk("sd error : host %d channel %d id %d lun %d return code = %x\n", + dev->host->host_no, dev->channel, dev->id, dev->lun, result); + + if (driver_byte(result) & DRIVER_SENSE) + print_sense("sd", SCpnt); + SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.current_nr_sectors); + } + + /* Retry the operation */ + requeue_sd_request(SCpnt); +} + +static void sd_start (Scsi_Cmnd * SCpnt) +{ + unsigned char cmd[12]; + int old_use_sg = SCpnt->use_sg, oldbufflen = SCpnt->bufflen; + Scsi_Device * dev = rscsi_disks[DEVICE_NR(SCpnt->request.rq_dev)].device; + + cmd[0] = START_STOP; + cmd[1] = dev->lun << 5; + cmd[2] = cmd[3] = cmd[5] = 0; + cmd[4] = 1; + + SCpnt->use_sg = 0; /* No scatter/gather for START_STOP */ + SCpnt->bufflen = 0; /* No response for START_STOP */ + scsi_do_cmd(SCpnt, cmd, NULL, 0, sd_start_done, 60 * HZ, MAX_RETRIES); + SCpnt->use_sg = old_use_sg; + SCpnt->bufflen = oldbufflen; +} + + static void sd_devname(unsigned int disknum, char * buffer) { if( disknum < 26 ) @@ -505,6 +546,13 @@ requeue_sd_request(SCpnt); return; } + + /* Try to restart the drive if it's idle */ + if ((SCpnt->sense_buffer[2] & 0x0f) == 0x02) + { + sd_start(SCpnt); + return; + } } /* driver byte != 0 */ if (result) { printk("SCSI disk error : host %d channel %d id %d lun %d return code = %x\n", @@ -678,6 +726,9 @@ goto repeat; } + /* Update idle-since time */ + rscsi_disks[dev].idle = jiffies; + block += sd[devm].start_sect; if (rscsi_disks[dev].device->changed) @@ -1760,6 +1811,7 @@ sd_template.dev_noticed--; sd_template.nr_dev--; SD_GENDISK(start).nr_real--; + dpnt->idle = 0; /* has been idle forever */ return; } return; diff -u -ur linux-2.3.3/drivers/scsi/sd.h linux/drivers/scsi/sd.h --- linux-2.3.3/drivers/scsi/sd.h Thu May 20 22:29:04 1999 +++ linux/drivers/scsi/sd.h Fri May 21 19:21:59 1999 @@ -36,6 +36,7 @@ unsigned ten:1; /* support ten byte read / write */ unsigned remap:1; /* support remapping */ unsigned has_part_table:1; /* has partition table */ + unsigned long idle; /* has been idle since */ } Scsi_Disk; extern Scsi_Disk * rscsi_disks; diff -u -ur linux-2.3.3/drivers/scsi/sd_ioctl.c linux/drivers/scsi/sd_ioctl.c --- linux-2.3.3/drivers/scsi/sd_ioctl.c Thu May 20 22:12:15 1999 +++ linux/drivers/scsi/sd_ioctl.c Fri May 21 19:20:01 1999 @@ -94,6 +94,15 @@ return -EACCES; return revalidate_scsidisk(dev, 1); +#define SD_IOCTL_IDLE 4746 + case SD_IOCTL_IDLE: /* get idle time */ + if (!arg || !inode->i_rdev) + return -EINVAL; + if (rscsi_disks[MINOR(dev) >> 4].idle) + return (jiffies - rscsi_disks[MINOR(dev) >> 4].idle) / HZ + 1; + else + return 0; + default: return scsi_ioctl(rscsi_disks[DEVICE_NR(dev)].device , cmd, (void *) arg); }