[PATCH] start stop libata attached SATA disks

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Jeff,
Here is half a patch.

Adds minimal START STOP UNIT SCSI command functionality
to libata (follows sat-r04 apart from the IMMED bit).
Tries to implement the TEST UNIT READY SCSI command.

Patch against lk 2.6.13-rc4 . There are comments in the
code where I was on thin ice.

Tested on my ST380013AS Seagate SATA disk on a Sil 3112
HBA. Stop (spin down) seems to work. Starting a disk
works (well the disk spins up) but the command is aborted
after 3.8 seconds. There doesn't seem to be a mechanism to pass
through timeouts from SG_IO (or the SCSI ULDs) into libata.
Probably the READ VERIFY is not set up properly.
TEST UNIT READY code just doesn't work at all ... the
corresponding ATA command (CHECK POWER MODE) sends a return
value back in the nsector register of the response. I
tried ata_tf_read() but that just made the device inoperable.

The TEST UNIT READY implementation needs to be solid since
the sd driver issues it when it first sees a disk. If sd
receives a NOT READY sense key then it will try to send
a START STOP UNIT command to spin up the disk.

I notice that when the SATA disk is in standby mode, sending
it a normal read command works (i.e. the disk spins up, the
read command waits patiently and then does the read). This
is different to a SCSI disk that would reject a media access
command when in standby mode.

Signed-off-by: Douglas Gilbert <dougg@xxxxxxxxxx>
but not ready for production.

Doug Gilbert

--- linux/include/linux/ata.h	2005-07-30 10:22:09.000000000 +1000
+++ linux/include/linux/ata.h2613rc4standby	2005-07-31 12:21:55.000000000 +1000
@@ -108,6 +108,8 @@
 
 	/* ATA device commands */
 	ATA_CMD_CHK_POWER	= 0xE5, /* check power mode */
+	ATA_CMD_STANDBY		= 0xE2, /* place in standby power mode */
+	ATA_CMD_IDLE		= 0xE3, /* place in idle power mode */
 	ATA_CMD_EDD		= 0x90,	/* execute device diagnostic */
 	ATA_CMD_FLUSH		= 0xE7,
 	ATA_CMD_FLUSH_EXT	= 0xEA,
--- linux/drivers/scsi/libata-scsi.c	2005-07-30 10:22:03.000000000 +1000
+++ linux/drivers/scsi/libata-scsi.c2613rc4stop	2005-07-31 17:52:34.000000000 +1000
@@ -391,6 +391,88 @@
 }
 
 /**
+ *	ata_scsi_tur_xlat - Translate SCSI TEST UNIT READY command
+ *	@qc: Storage for translated ATA taskfile
+ *	@scsicmd: SCSI command to translate (ignored)
+ *
+ *	Sets up an ATA taskfile to issue CHECK POWER MODE.
+ *
+ *	LOCKING:
+ *	spin_lock_irqsave(host_set lock)
+ *
+ *	RETURNS:
+ *	Zero on success, non-zero on error.
+ */
+
+static unsigned int ata_scsi_tur_xlat(struct ata_queued_cmd *qc, u8 *scsicmd)
+{
+	struct ata_taskfile *tf = &qc->tf;
+
+	tf->flags |= ATA_TFLAG_DEVICE;
+	tf->protocol = ATA_PROT_NODATA;
+	tf->command = ATA_CMD_CHK_POWER;
+
+	return 0;
+}
+
+/**
+ *	ata_scsi_start_stop_xlat - Translate SCSI START STOP UNIT command
+ *	@qc: Storage for translated ATA taskfile
+ *	@scsicmd: SCSI command to translate
+ *
+ *	Sets up an ATA taskfile to issue STANDBY (to stop) or READ VERIFY
+ *	(to start). Perhaps these commands should be preceded by
+ *	CHECK POWER MODE to see what power mode the device is already in.
+ *
+ *	LOCKING:
+ *	spin_lock_irqsave(host_set lock)
+ *
+ *	RETURNS:
+ *	Zero on success, non-zero on error.
+ */
+
+static unsigned int ata_scsi_start_stop_xlat(struct ata_queued_cmd *qc,
+					     u8 *scsicmd)
+{
+	struct ata_taskfile *tf = &qc->tf;
+
+	/*
+	 * Should probably precede any commands to change power mode with
+	 * CHECK POWER MODE to see what the current state of the device is.
+	 * The patch author does not know how to do this.
+	 * D. Gilbert 20050731
+	 */
+	tf->flags |= ATA_TFLAG_DEVICE | ATA_TFLAG_ISADDR;
+	tf->protocol = ATA_PROT_NODATA;
+	if (scsicmd[1] & 0x1) {
+		;	/* ignore IMMED bit, violates sat-r04 */
+	}
+	if (scsicmd[4] & 0x2)
+		return 1;	/* LOEJ bit set not supported */
+	if (((scsicmd[4] >> 4) & 0xf) != 0)
+		return 1;	/* power conditions not supported */
+	if (scsicmd[4] & 0x1) {
+		tf->nsect = 1;	/* 1 sector, lba=0 */
+		tf->lbah = 0x0;
+		tf->lbam = 0x0;
+		tf->lbal = 0x0;
+		tf->command = ATA_CMD_VERIFY;	/* READ VERIFY */
+	} else {
+		tf->nsect = 0;	/* time period value (0 implies now) */
+		tf->command = ATA_CMD_STANDBY;
+	}
+	/*
+	 * Standby and Idle condition timers could be implemented but that
+	 * would require libata to implement the Power condition mode page
+	 * and allow the user to change it. Changing mode pages requires
+	 * MODE SELECT to be implemented.
+	 */
+
+	return 0;
+}
+
+
+/**
  *	ata_scsi_flush_xlat - Translate SCSI SYNCHRONIZE CACHE command
  *	@qc: Storage for translated ATA taskfile
  *	@scsicmd: SCSI command to translate (ignored)
@@ -635,6 +717,34 @@
 	else
 		cmd->result = SAM_STAT_GOOD;
 
+#if 0
+// >>>>>> Couldn't get this code working: need to fetch nsector field
+//        from CHECK POWER MODE response. The following code,
+//        especially the ata_tf_read() made the device inoperable.
+	if (cmd->result == SAM_STAT_GOOD &&
+	    cmd->cmnd[0] == TEST_UNIT_READY) {
+
+		unsigned char *sb = cmd->sense_buffer;
+		struct ata_taskfile resp_tf;
+
+		ata_tf_read(qc->ap, &resp_tf);
+		/* result value in sector count field */
+		if (resp_tf.nsect == 0) {
+			/* standby mode */
+			sb[0] = 0x70;
+			sb[2] = NOT_READY;
+			sb[7] = 0x0a;
+			sb[12] = 0x4;	/* Logical unit not ready .. */
+			sb[13] = 0x2;	/* .. initializing command required */
+			cmd->result = SAM_STAT_CHECK_CONDITION;
+		} else if (resp_tf.nsect == 0x80) {
+			/* idle mode */
+			DPRINTK("CHECK POWER MODE reports idle\n");
+		}
+		/* else nsect should be 0xff implying active or idle */
+	}
+#endif
+
 	qc->scsidone(cmd);
 
 	return 0;
@@ -1434,6 +1544,10 @@
 	case VERIFY:
 	case VERIFY_16:
 		return ata_scsi_verify_xlat;
+	case TEST_UNIT_READY:
+		return ata_scsi_tur_xlat;
+	case START_STOP:
+		return ata_scsi_start_stop_xlat;
 	}
 
 	return NULL;
@@ -1544,7 +1658,6 @@
 		case REZERO_UNIT:
 		case SEEK_6:
 		case SEEK_10:
-		case TEST_UNIT_READY:
 		case FORMAT_UNIT:		/* FIXME: correct? */
 		case SEND_DIAGNOSTIC:		/* FIXME: correct? */
 			ata_scsi_rbuf_fill(&args, ata_scsiop_noop);

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [SCSI Target Devel]     [Linux SCSI Target Infrastructure]     [Kernel Newbies]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Linux IIO]     [Samba]     [Device Mapper]
  Powered by Linux