/*
 * 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;
}
Exemple #2
0
/*
 * 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
}