Disable sending Early R_OK on SiI3726/SiI3826 port multipliers.
With "cached read" HDD testing and multiple ports busy on a SATA host controller, 3726/3826 PMP will very rarely drop a deferred R_OK that was intended for the host. Symptom will be all 5 drives under test will timeout, get reset, and recover. Submitted by: Rich Futyma <rich.futyma@sanmina.com> MFC after: 2 weeks
This commit is contained in:
parent
dfd7a7f46d
commit
84dac288fb
@ -64,6 +64,9 @@ __FBSDID("$FreeBSD$");
|
||||
typedef enum {
|
||||
PMP_STATE_NORMAL,
|
||||
PMP_STATE_PORTS,
|
||||
PMP_STATE_PM_QUIRKS_1,
|
||||
PMP_STATE_PM_QUIRKS_2,
|
||||
PMP_STATE_PM_QUIRKS_3,
|
||||
PMP_STATE_PRECONFIG,
|
||||
PMP_STATE_RESET,
|
||||
PMP_STATE_CONNECT,
|
||||
@ -317,7 +320,11 @@ pmpasync(void *callback_arg, u_int32_t code,
|
||||
if (code == AC_SENT_BDR || code == AC_BUS_RESET)
|
||||
softc->found = 0; /* We have to reset everything. */
|
||||
if (softc->state == PMP_STATE_NORMAL) {
|
||||
softc->state = PMP_STATE_PRECONFIG;
|
||||
if (softc->pm_pid == 0x37261095 ||
|
||||
softc->pm_pid == 0x38261095)
|
||||
softc->state = PMP_STATE_PM_QUIRKS_1;
|
||||
else
|
||||
softc->state = PMP_STATE_PRECONFIG;
|
||||
cam_periph_acquire(periph);
|
||||
xpt_schedule(periph, CAM_PRIORITY_DEV);
|
||||
} else
|
||||
@ -427,7 +434,10 @@ pmpstart(struct cam_periph *periph, union ccb *start_ccb)
|
||||
|
||||
if (softc->restart) {
|
||||
softc->restart = 0;
|
||||
softc->state = min(softc->state, PMP_STATE_PRECONFIG);
|
||||
if (softc->pm_pid == 0x37261095 || softc->pm_pid == 0x38261095)
|
||||
softc->state = min(softc->state, PMP_STATE_PM_QUIRKS_1);
|
||||
else
|
||||
softc->state = min(softc->state, PMP_STATE_PRECONFIG);
|
||||
}
|
||||
/* Fetch user wanted device speed. */
|
||||
if (softc->state == PMP_STATE_RESET ||
|
||||
@ -457,6 +467,32 @@ pmpstart(struct cam_periph *periph, union ccb *start_ccb)
|
||||
pmp_default_timeout * 1000);
|
||||
ata_pm_read_cmd(ataio, 2, 15);
|
||||
break;
|
||||
|
||||
case PMP_STATE_PM_QUIRKS_1:
|
||||
case PMP_STATE_PM_QUIRKS_3:
|
||||
cam_fill_ataio(ataio,
|
||||
pmp_retry_count,
|
||||
pmpdone,
|
||||
/*flags*/CAM_DIR_NONE,
|
||||
0,
|
||||
/*data_ptr*/NULL,
|
||||
/*dxfer_len*/0,
|
||||
pmp_default_timeout * 1000);
|
||||
ata_pm_read_cmd(ataio, 129, 15);
|
||||
break;
|
||||
|
||||
case PMP_STATE_PM_QUIRKS_2:
|
||||
cam_fill_ataio(ataio,
|
||||
pmp_retry_count,
|
||||
pmpdone,
|
||||
/*flags*/CAM_DIR_NONE,
|
||||
0,
|
||||
/*data_ptr*/NULL,
|
||||
/*dxfer_len*/0,
|
||||
pmp_default_timeout * 1000);
|
||||
ata_pm_write_cmd(ataio, 129, 15, softc->caps & ~0x1);
|
||||
break;
|
||||
|
||||
case PMP_STATE_PRECONFIG:
|
||||
/* Get/update host SATA capabilities. */
|
||||
bzero(&cts, sizeof(cts));
|
||||
@ -466,6 +502,8 @@ pmpstart(struct cam_periph *periph, union ccb *start_ccb)
|
||||
xpt_action((union ccb *)&cts);
|
||||
if (cts.xport_specific.sata.valid & CTS_SATA_VALID_CAPS)
|
||||
softc->caps = cts.xport_specific.sata.caps;
|
||||
else
|
||||
softc->caps = 0;
|
||||
cam_fill_ataio(ataio,
|
||||
pmp_retry_count,
|
||||
pmpdone,
|
||||
@ -575,7 +613,10 @@ pmpdone(struct cam_periph *periph, union ccb *done_ccb)
|
||||
if (softc->restart) {
|
||||
softc->restart = 0;
|
||||
xpt_release_ccb(done_ccb);
|
||||
softc->state = min(softc->state, PMP_STATE_PRECONFIG);
|
||||
if (softc->pm_pid == 0x37261095 || softc->pm_pid == 0x38261095)
|
||||
softc->state = min(softc->state, PMP_STATE_PM_QUIRKS_1);
|
||||
else
|
||||
softc->state = min(softc->state, PMP_STATE_PRECONFIG);
|
||||
xpt_schedule(periph, priority);
|
||||
return;
|
||||
}
|
||||
@ -618,10 +659,48 @@ pmpdone(struct cam_periph *periph, union ccb *done_ccb)
|
||||
printf("%s%d: %d fan-out ports\n",
|
||||
periph->periph_name, periph->unit_number,
|
||||
softc->pm_ports);
|
||||
if (softc->pm_pid == 0x37261095 || softc->pm_pid == 0x38261095)
|
||||
softc->state = PMP_STATE_PM_QUIRKS_1;
|
||||
else
|
||||
softc->state = PMP_STATE_PRECONFIG;
|
||||
xpt_release_ccb(done_ccb);
|
||||
xpt_schedule(periph, priority);
|
||||
return;
|
||||
|
||||
case PMP_STATE_PM_QUIRKS_1:
|
||||
softc->caps = (ataio->res.lba_high << 24) +
|
||||
(ataio->res.lba_mid << 16) +
|
||||
(ataio->res.lba_low << 8) +
|
||||
ataio->res.sector_count;
|
||||
if (softc->caps & 0x1)
|
||||
softc->state = PMP_STATE_PM_QUIRKS_2;
|
||||
else
|
||||
softc->state = PMP_STATE_PRECONFIG;
|
||||
xpt_release_ccb(done_ccb);
|
||||
xpt_schedule(periph, priority);
|
||||
return;
|
||||
|
||||
case PMP_STATE_PM_QUIRKS_2:
|
||||
if (bootverbose)
|
||||
softc->state = PMP_STATE_PM_QUIRKS_3;
|
||||
else
|
||||
softc->state = PMP_STATE_PRECONFIG;
|
||||
xpt_release_ccb(done_ccb);
|
||||
xpt_schedule(periph, priority);
|
||||
return;
|
||||
|
||||
case PMP_STATE_PM_QUIRKS_3:
|
||||
res = (ataio->res.lba_high << 24) +
|
||||
(ataio->res.lba_mid << 16) +
|
||||
(ataio->res.lba_low << 8) +
|
||||
ataio->res.sector_count;
|
||||
printf("%s%d: Disabling SiI3x26 R_OK in GSCR_POLL: %x->%x\n",
|
||||
periph->periph_name, periph->unit_number, softc->caps, res);
|
||||
softc->state = PMP_STATE_PRECONFIG;
|
||||
xpt_release_ccb(done_ccb);
|
||||
xpt_schedule(periph, priority);
|
||||
return;
|
||||
|
||||
case PMP_STATE_PRECONFIG:
|
||||
softc->pm_step = 0;
|
||||
softc->state = PMP_STATE_RESET;
|
||||
|
Loading…
Reference in New Issue
Block a user