I have an old Maxtor 7Y250M0 SATA drive that didn't quite work when
attached to an Intel AHCI controller. The drive was properly
detected, but any attempt to read from the drive failed. It worked
fine if I switched the SATA controller into IDE mode in the BIOS, so
the drive was fine. Turns out our atascsi layer didn't set the
transfer mode like our old wdc/pciide code does. Fixing this
omission makes the drive work.
It doesn't really make all that much sense doing this for a SATA drive
since they don't really support different DMA modes. But there is a
PATA variant of the same drive, so I suppose somebody left an obselete
check in the firmware code.
The diff below only checks for Ultra DMA modes. All SATA drives
should support those. If we ever want to support ancient PATA drives
over atascsi, some additional code will be needed.
ok?
Index: atascsi.c
===================================================================
RCS file: /cvs/src/sys/dev/ata/atascsi.c,v
retrieving revision 1.125
diff -u -p -r1.125 atascsi.c
--- atascsi.c 28 Aug 2015 00:03:53 -0000 1.125
+++ atascsi.c 28 Dec 2015 23:23:14 -0000
@@ -266,6 +266,8 @@ atascsi_probe(struct scsi_link *link)
int port, type, qdepth;
int rv;
u_int16_t cmdset;
+ u_int16_t validinfo, ultradma;
+ int i, xfermode = -1;
port = link->target;
if (port >= as->as_link.adapter_buswidth)
@@ -363,6 +365,24 @@ atascsi_probe(struct scsi_link *link)
if (type != ATA_PORT_T_DISK)
return (0);
+
+ /*
+ * Early SATA drivers (as well as PATA drives) need to have
+ * their transfer mode set properly, otherwise commands that
+ * use DMA will time out.
+ */
+ validinfo = letoh16(ap->ap_identify.validinfo);
+ if (ISSET(validinfo, ATA_ID_VALIDINFO_ULTRADMA)) {
+ ultradma = letoh16(ap->ap_identify.ultradma);
+ for (i = 7; i >= 0; i--) {
+ if (ultradma & (1 << i)) {
+ xfermode = ATA_SF_XFERMODE_UDMA | i;
+ break;
+ }
+ }
+ }
+ if (xfermode != -1)
+ (void)atascsi_port_set_features(ap, ATA_SF_XFERMODE, xfermode);
if (as->as_capability & ASAA_CAP_NCQ &&
ISSET(letoh16(ap->ap_identify.satacap), ATA_SATACAP_NCQ) &&
Index: atascsi.h
===================================================================
RCS file: /cvs/src/sys/dev/ata/atascsi.h,v
retrieving revision 1.49
diff -u -p -r1.49 atascsi.h
--- atascsi.h 15 May 2015 10:54:26 -0000 1.49
+++ atascsi.h 28 Dec 2015 23:23:14 -0000
@@ -53,6 +53,8 @@ struct scsi_link;
* ATA SET FEATURES subcommands
*/
#define ATA_SF_WRITECACHE_EN 0x02
+#define ATA_SF_XFERMODE 0x03
+#define ATA_SF_XFERMODE_UDMA 0x40
#define ATA_SF_LOOKAHEAD_EN 0xaa
struct ata_identify {
@@ -77,6 +79,7 @@ struct ata_identify {
u_int16_t piomode; /* 51 */
u_int16_t dmamode; /* 52 */
u_int16_t validinfo; /* 53 */
+#define ATA_ID_VALIDINFO_ULTRADMA 0x0004
u_int16_t curcyls; /* 54 */
u_int16_t curheads; /* 55 */
u_int16_t cursectrk; /* 56 */