See https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=202712 See https://github.com/westerndigitalcorporation/RISC-V-Linux/blob/master/linux/drivers/ata/libata-core.c#L3556 Index: sys/cam/ata/ata_xpt.c =================================================================== --- sys/cam/ata/ata_xpt.c (revision 345870) +++ sys/cam/ata/ata_xpt.c (working copy) @@ -146,6 +146,8 @@ typedef struct { int restart; int spinup; int faults; + int setmode_failed; + int wantmode; u_int caps; struct cam_periph *periph; } probe_softc; @@ -464,6 +466,7 @@ negotiate: else path->device->inq_flags |= SID_DMA; xpt_async(AC_GETDEV_CHANGED, path, NULL); + softc->wantmode = mode; cam_fill_ataio(ataio, 1, probedone, @@ -782,13 +785,24 @@ out: else softc->restart = 0; - /* Old PIO2 devices may not support mode setting. */ + /* Handle SETMODE quirks. */ } else if (softc->action == PROBE_SETMODE && - status == CAM_ATA_STATUS_ERROR && - ata_max_pmode(ident_buf) <= ATA_PIO2 && - (ident_buf->capabilities1 & ATA_SUPPORT_IORDY) == 0) { - goto noerror; + status == CAM_ATA_STATUS_ERROR) { + /* Old PIO2 devices may not support mode setting. */ + if (ata_max_pmode(ident_buf) <= ATA_PIO2 && + (ident_buf->capabilities1 & ATA_SUPPORT_IORDY) == 0) + goto noerror; + /* + * If SETMODE failed, do IDENTIFY again and see if + * the disk has the mode we wanted to set. + */ + softc->setmode_failed = 1; + PROBE_SET_ACTION(softc, PROBE_IDENTIFY); + xpt_release_ccb(done_ccb); + xpt_schedule(periph, priority); + goto out; + /* * Some old WD SATA disks report supported and enabled * device-initiated interface power management, but return @@ -1019,10 +1033,24 @@ noerror: ata_device_transport(path); if (changed) proberequestdefaultnegotiation(periph); - PROBE_SET_ACTION(softc, PROBE_SETMODE); - xpt_release_ccb(done_ccb); - xpt_schedule(periph, priority); - goto out; + if (!softc->setmode_failed) { + /* Normal IDENTIFY, proceed to SETMODE. */ + PROBE_SET_ACTION(softc, PROBE_SETMODE); + xpt_release_ccb(done_ccb); + xpt_schedule(periph, priority); + goto out; + } else if (ata_max_mode(ident_buf, 0) == softc->wantmode) { + /* + * IDENTIFY after a failed SETMODE and the actual mode + * is what we requested. So, pretend that SETMODE + * succeeded. + */ + softc->action = PROBE_SETMODE; + goto noerror; + } else { + /* The mode is wrong, the probe failed. */ + goto device_fail; + } } case PROBE_SPINUP: if (bootverbose)