diff -u -ur linux-vanille/drivers/scsi/sd.c linux/drivers/scsi/sd.c --- linux-vanille/drivers/scsi/sd.c Sat Oct 31 21:38:18 1998 +++ linux/drivers/scsi/sd.c Sat Oct 31 21:29:35 1998 @@ -102,6 +102,54 @@ 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; + + if (result) { + printk("SCSI disk error : host %d channel %d id %d lun %d return code = %x\n", + rscsi_disks[DEVICE_NR(SCpnt->request.rq_dev)].device->host->host_no, + rscsi_disks[DEVICE_NR(SCpnt->request.rq_dev)].device->channel, + rscsi_disks[DEVICE_NR(SCpnt->request.rq_dev)].device->id, + rscsi_disks[DEVICE_NR(SCpnt->request.rq_dev)].device->lun, result); + + if (driver_byte(result) & DRIVER_SENSE) + print_sense("sd", SCpnt); + SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.current_nr_sectors); + requeue_sd_request(SCpnt); + return; + } + + /* Retry the operation */ + requeue_sd_request(SCpnt); + return; +} + +static void sd_start (Scsi_Cmnd * SCpnt) +{ + unsigned char cmd[12]; + int dev, old_use_sg = SCpnt->use_sg, oldbufflen = SCpnt->bufflen; + + dev = DEVICE_NR(SCpnt->request.rq_dev); + + cmd[0] = START_STOP; + cmd[1] = (rscsi_disks[dev].device->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 +553,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 +733,9 @@ goto repeat; } + /* Update idle-since time */ + rscsi_disks[dev].idle = jiffies; + block += sd[devm].start_sect; if (rscsi_disks[dev].device->changed) @@ -1744,6 +1802,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-vanille/drivers/scsi/sd.h linux/drivers/scsi/sd.h --- linux-vanille/drivers/scsi/sd.h Sat Oct 31 21:36:01 1998 +++ linux/drivers/scsi/sd.h Sat Oct 31 21:20:44 1998 @@ -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-vanille/drivers/scsi/sd_ioctl.c linux/drivers/scsi/sd_ioctl.c --- linux-vanille/drivers/scsi/sd_ioctl.c Sat Oct 31 21:36:01 1998 +++ linux/drivers/scsi/sd_ioctl.c Sat Oct 31 21:20:44 1998 @@ -103,6 +103,15 @@ invalidate_buffers(inode->i_rdev); return 0; +#define SD_IOCTL_IDLE 4746 /* get idle time */ + case SD_IOCTL_IDLE: + if (!arg) return -EINVAL; + if (!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; + case BLKRRPART: /* Re-read partition tables */ if (!capable(CAP_SYS_ADMIN)) return -EACCES;