/* * Per-port thread helper. This helper thread is responsible for * atomically retrieving and clearing the signal mask and calling * the machine-independant driver core. * * MPSAFE */ static void sili_port_thread(void *arg) { struct sili_port *ap = arg; int mask; /* * The helper thread is responsible for the initial port init, * so all the ports can be inited in parallel. * * We also run the state machine which should do all probes. * Since CAM is not attached yet we will not get out-of-order * SCSI attachments. */ sili_os_lock_port(ap); sili_port_init(ap); sili_port_state_machine(ap, 1); sili_os_unlock_port(ap); atomic_clear_int(&ap->ap_signal, AP_SIGF_INIT); wakeup(&ap->ap_signal); /* * Then loop on the helper core. */ mask = ap->ap_signal; while ((mask & AP_SIGF_STOP) == 0) { atomic_clear_int(&ap->ap_signal, mask); sili_port_thread_core(ap, mask); lockmgr(&ap->ap_sig_lock, LK_EXCLUSIVE); if (ap->ap_signal == 0) { lksleep(&ap->ap_thread, &ap->ap_sig_lock, 0, "siport", 0); } lockmgr(&ap->ap_sig_lock, LK_RELEASE); mask = ap->ap_signal; } ap->ap_thread = NULL; }
/* * This is called from the port hardreset code. */ int sili_pm_port_probe(struct sili_port *ap, int orig_error) { struct ata_port *at; int error; int i; /* * Clean up the port state machine */ sili_pwrite(ap, SILI_PREG_CTL_SET, SILI_PREG_CTL_PMA); sili_pwrite(ap, SILI_PREG_CTL_SET, SILI_PREG_CTL_INIT); if (sili_pwait_clr_to(ap, 5000, SILI_PREG_STATUS, SILI_PREG_CTL_INIT)) { kprintf("%s: PM probe: unable to init port\n", PORTNAME(ap)); return (EBUSY); } if (sili_pwait_set(ap, SILI_PREG_STATUS, SILI_PREG_STATUS_READY)) { kprintf("%s: PM probe: port will not come ready\n", PORTNAME(ap)); return (EBUSY); } /* * Issue a soft-reset of target 15 */ ap->ap_state = AP_S_NORMAL; sili_pwrite(ap, SILI_PREG_SERR, -1); error = sili_pm_softreset(ap, 15); if (error == 0) error = sili_pm_identify(ap); /* * Finalize. If the softreset failed. Re-init the port * state machine again so the normal non-PM softreset does * not bog down. */ if (error == 0) { for (i = 0; i < SILI_MAX_PMPORTS; ++i) { at = &ap->ap_ata[i]; at->at_probe = ATA_PROBE_NEED_INIT; at->at_features |= ATA_PORT_F_RESCAN; at->at_features &= ~ATA_PORT_F_READLOG; } ap->ap_type = ATA_PORT_T_PM; return (0); } sili_pwrite(ap, SILI_PREG_CTL_CLR, SILI_PREG_CTL_PMA); sili_port_init(ap); if (orig_error == 0) { if (sili_pwait_set_to(ap, 5000, SILI_PREG_STATUS, SILI_PREG_STATUS_READY)) { kprintf("%s: PM probe: port will not come ready\n", PORTNAME(ap)); orig_error = EBUSY; } } return (orig_error); #if 0 sili_pwrite(ap, SILI_PREG_CTL_CLR, SILI_PREG_CTL_RESUME); sili_pwrite(ap, SILI_PREG_CTL_CLR, SILI_PREG_CTL_PMA); sili_pwrite(ap, SILI_PREG_CTL_SET, SILI_PREG_CTL_INIT); if (sili_pwait_clr_to(ap, 5000, SILI_PREG_STATUS, SILI_PREG_CTL_INIT)) { kprintf("%s: PM probe: unable to init port\n", PORTNAME(ap)); orig_error = EBUSY; } if (sili_pwait_set(ap, SILI_PREG_STATUS, SILI_PREG_STATUS_READY)) { kprintf("%s: PM probe: port will not come ready\n", PORTNAME(ap)); orig_error = EBUSY; } kprintf("ORIG ERROR %d\n", orig_error); if (orig_error) return (orig_error); /* * If we originally detected a device redo the device reset to * try to clear the mess. */ sili_pwrite(ap, SILI_PREG_CTL_SET, SILI_PREG_CTL_DEVRESET); if (sili_pwait_clr(ap, SILI_PREG_CTL_SET, SILI_PREG_CTL_DEVRESET)) { kprintf("%s: PM probe: unable to reset\n", PORTNAME(ap)); orig_error = EBUSY; } if (sili_pwait_set(ap, SILI_PREG_STATUS, SILI_PREG_STATUS_READY)) { kprintf("%s: PM probe: port will not come ready\n", PORTNAME(ap)); orig_error = EBUSY; } return (orig_error); #endif }