diff -ur linuxorig/drivers/scsi/sd.c linux-2.4.23/drivers/scsi/sd.c --- linuxorig/drivers/scsi/sd.c 2003-12-15 18:32:06.000000000 -0500 +++ linux-2.4.23/drivers/scsi/sd.c 2003-12-15 18:35:18.000000000 -0500 @@ -108,6 +108,8 @@ static int sd_detect(Scsi_Device *); static void sd_detach(Scsi_Device *); static int sd_init_command(Scsi_Cmnd *); +static void sd_start (Scsi_Cmnd * SCpnt); +static void sd_devname(unsigned int disknum, char *buffer); static struct Scsi_Device_Template sd_template = { name:"disk", @@ -154,6 +156,7 @@ struct Scsi_Host * host; Scsi_Device * SDev; int diskinfo[4]; + char nbuf[6]; SDev = rscsi_disks[DEVICE_NR(dev)].device; if (!SDev) @@ -238,6 +241,8 @@ return -EFAULT; return 0; } + case SD_IOCTL_IDLE: + return (jiffies - rscsi_disks[DEVICE_NR(dev)].idle) / HZ + 1; case BLKGETSIZE: case BLKGETSIZE64: case BLKROSET: @@ -259,6 +264,16 @@ return revalidate_scsidisk(dev, 1); default: + if (cmd == SCSI_IOCTL_STOP_UNIT) { + rscsi_disks[DEVICE_NR(dev)].spindown = 1; + sd_devname(DEVICE_NR(dev), nbuf); +/* printk(KERN_INFO "%s: Spinning down disk.\n",nbuf); */ + } + if (cmd == SCSI_IOCTL_START_UNIT) { + rscsi_disks[DEVICE_NR(dev)].spindown = 0; + sd_devname(DEVICE_NR(dev), nbuf); + printk(KERN_INFO "%s: Spinning up disk.\n",nbuf); + } return scsi_ioctl(rscsi_disks[DEVICE_NR(dev)].device , cmd, (void *) arg); } } @@ -311,6 +326,14 @@ SCpnt->request.rq_dev, block)); dpnt = &rscsi_disks[dev]; + + /* Update idle-since time */ + rscsi_disks[dev].idle = jiffies; + + /* Spin up */ + if (dpnt->spindown) { + sd_start(SCpnt); + } if (dev >= sd_template.dev_max || !dpnt->device || !dpnt->device->online || @@ -700,6 +723,20 @@ * them to SCSI commands. */ +/* + * handle spinup of idle disks + */ + +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; + sd_init_onedisk(DEVICE_NR(SCpnt->request.rq_dev)); + rscsi_disks[DEVICE_NR(SCpnt->request.rq_dev)].spindown = 0; + SCpnt->use_sg = old_use_sg; + SCpnt->bufflen = oldbufflen; +} static int check_scsidisk_media_change(kdev_t full_dev) { diff -ur linuxorig/drivers/scsi/sd.h linux-2.4.23/drivers/scsi/sd.h --- linuxorig/drivers/scsi/sd.h 2003-12-15 18:32:15.000000000 -0500 +++ linux-2.4.23/drivers/scsi/sd.h 2003-12-15 18:35:18.000000000 -0500 @@ -26,6 +26,8 @@ typedef struct scsi_disk { unsigned capacity; /* size in blocks */ Scsi_Device *device; + unsigned long idle; /* idle time in jiffies */ + unsigned char spindown; /* is down */ unsigned char ready; /* flag ready for FLOPTICAL */ unsigned char write_prot; /* flag write_protect for rmvable dev */ unsigned char sector_bit_size; /* sector_size = 2 to the bit size power */ diff -ur linuxorig/include/scsi/scsi_ioctl.h linux-2.4.23/include/scsi/scsi_ioctl.h --- linuxorig/include/scsi/scsi_ioctl.h 2003-12-15 18:33:30.000000000 -0500 +++ linux-2.4.23/include/scsi/scsi_ioctl.h 2003-12-15 18:35:18.000000000 -0500 @@ -14,6 +14,7 @@ #define SCSI_REMOVAL_PREVENT 1 #define SCSI_REMOVAL_ALLOW 0 +#define SD_IOCTL_IDLE 4746 #ifdef __KERNEL__