On Tue, Dec 29, 2015 at 12:43:43AM +0100, Mark Kettenis wrote:
> 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
Catching up on holiday email, not sure if this already went in, but there
is a typo (drives not drivers) in the previous line.
-ml
> + * 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 */
>