111090SDavid.Hollister@Sun.COM /*
211090SDavid.Hollister@Sun.COM * CDDL HEADER START
311090SDavid.Hollister@Sun.COM *
411090SDavid.Hollister@Sun.COM * The contents of this file are subject to the terms of the
511090SDavid.Hollister@Sun.COM * Common Development and Distribution License (the "License").
611090SDavid.Hollister@Sun.COM * You may not use this file except in compliance with the License.
711090SDavid.Hollister@Sun.COM *
811090SDavid.Hollister@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
911090SDavid.Hollister@Sun.COM * or http://www.opensolaris.org/os/licensing.
1011090SDavid.Hollister@Sun.COM * See the License for the specific language governing permissions
1111090SDavid.Hollister@Sun.COM * and limitations under the License.
1211090SDavid.Hollister@Sun.COM *
1311090SDavid.Hollister@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each
1411090SDavid.Hollister@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1511090SDavid.Hollister@Sun.COM * If applicable, add the following below this CDDL HEADER, with the
1611090SDavid.Hollister@Sun.COM * fields enclosed by brackets "[]" replaced with your own identifying
1711090SDavid.Hollister@Sun.COM * information: Portions Copyright [yyyy] [name of copyright owner]
1811090SDavid.Hollister@Sun.COM *
1911090SDavid.Hollister@Sun.COM * CDDL HEADER END
2012060SDavid.Hollister@Sun.COM */
2112060SDavid.Hollister@Sun.COM /*
2212060SDavid.Hollister@Sun.COM * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
2311090SDavid.Hollister@Sun.COM */
2411090SDavid.Hollister@Sun.COM
2511090SDavid.Hollister@Sun.COM /*
2611090SDavid.Hollister@Sun.COM * PM8001 device state recovery routines
2711090SDavid.Hollister@Sun.COM */
2811090SDavid.Hollister@Sun.COM
2911090SDavid.Hollister@Sun.COM #include <sys/scsi/adapters/pmcs/pmcs.h>
3011090SDavid.Hollister@Sun.COM
3111090SDavid.Hollister@Sun.COM /*
3211090SDavid.Hollister@Sun.COM * SAS Topology Configuration
3311090SDavid.Hollister@Sun.COM */
3411267SJesse.Butler@Sun.COM static void pmcs_ds_operational(pmcs_phy_t *pptr, pmcs_xscsi_t *tgt);
3511090SDavid.Hollister@Sun.COM static void pmcs_handle_ds_recovery_error(pmcs_phy_t *phyp,
3611347SRamana.Srikanth@Sun.COM pmcs_xscsi_t *tgt, pmcs_hw_t *pwp, const char *func_name,
3711090SDavid.Hollister@Sun.COM char *reason_string);
3811090SDavid.Hollister@Sun.COM
3911090SDavid.Hollister@Sun.COM /*
4011090SDavid.Hollister@Sun.COM * Get device state. Called with statlock and PHY lock held.
4111090SDavid.Hollister@Sun.COM */
4211090SDavid.Hollister@Sun.COM static int
pmcs_get_dev_state(pmcs_hw_t * pwp,pmcs_phy_t * phyp,pmcs_xscsi_t * xp,uint8_t * ds)4311090SDavid.Hollister@Sun.COM pmcs_get_dev_state(pmcs_hw_t *pwp, pmcs_phy_t *phyp, pmcs_xscsi_t *xp,
4411090SDavid.Hollister@Sun.COM uint8_t *ds)
4511090SDavid.Hollister@Sun.COM {
4611090SDavid.Hollister@Sun.COM uint32_t htag, *ptr, msg[PMCS_MSG_SIZE];
4711090SDavid.Hollister@Sun.COM int result;
4811090SDavid.Hollister@Sun.COM struct pmcwork *pwrk;
4911090SDavid.Hollister@Sun.COM
5011090SDavid.Hollister@Sun.COM pmcs_prt(pwp, PMCS_PRT_DEBUG3, phyp, xp, "%s: tgt(0x%p)", __func__,
5111090SDavid.Hollister@Sun.COM (void *)xp);
5211090SDavid.Hollister@Sun.COM
5311090SDavid.Hollister@Sun.COM if (xp != NULL) {
5411090SDavid.Hollister@Sun.COM ASSERT(mutex_owned(&xp->statlock));
5511090SDavid.Hollister@Sun.COM }
5611256SRamana.Srikanth@Sun.COM
5711256SRamana.Srikanth@Sun.COM if (phyp == NULL) {
5811256SRamana.Srikanth@Sun.COM pmcs_prt(pwp, PMCS_PRT_DEBUG_DEV_STATE, NULL, xp,
5911256SRamana.Srikanth@Sun.COM "%s: PHY is NULL", __func__);
6011256SRamana.Srikanth@Sun.COM return (-1);
6111256SRamana.Srikanth@Sun.COM }
6211090SDavid.Hollister@Sun.COM ASSERT(mutex_owned(&phyp->phy_lock));
6311090SDavid.Hollister@Sun.COM
6411090SDavid.Hollister@Sun.COM pwrk = pmcs_gwork(pwp, PMCS_TAG_TYPE_WAIT, phyp);
6511090SDavid.Hollister@Sun.COM if (pwrk == NULL) {
6611090SDavid.Hollister@Sun.COM pmcs_prt(pwp, PMCS_PRT_ERR, phyp, xp, pmcs_nowrk, __func__);
6711090SDavid.Hollister@Sun.COM return (-1);
6811090SDavid.Hollister@Sun.COM }
6911090SDavid.Hollister@Sun.COM pwrk->arg = msg;
7011090SDavid.Hollister@Sun.COM pwrk->dtype = phyp->dtype;
7111090SDavid.Hollister@Sun.COM
7211090SDavid.Hollister@Sun.COM if (phyp->valid_device_id == 0) {
7311090SDavid.Hollister@Sun.COM pmcs_pwork(pwp, pwrk);
7411090SDavid.Hollister@Sun.COM pmcs_prt(pwp, PMCS_PRT_DEBUG, phyp, xp,
7511090SDavid.Hollister@Sun.COM "%s: Invalid DeviceID", __func__);
7611090SDavid.Hollister@Sun.COM return (-1);
7711090SDavid.Hollister@Sun.COM }
7811090SDavid.Hollister@Sun.COM htag = pwrk->htag;
7911090SDavid.Hollister@Sun.COM msg[0] = LE_32(PMCS_HIPRI(pwp, PMCS_OQ_GENERAL,
8011090SDavid.Hollister@Sun.COM PMCIN_GET_DEVICE_STATE));
8111090SDavid.Hollister@Sun.COM msg[1] = LE_32(pwrk->htag);
8211090SDavid.Hollister@Sun.COM msg[2] = LE_32(phyp->device_id);
8311347SRamana.Srikanth@Sun.COM CLEAN_MESSAGE(msg, 3);
8411090SDavid.Hollister@Sun.COM
8511090SDavid.Hollister@Sun.COM mutex_enter(&pwp->iqp_lock[PMCS_IQ_OTHER]);
8611090SDavid.Hollister@Sun.COM ptr = GET_IQ_ENTRY(pwp, PMCS_IQ_OTHER);
8711090SDavid.Hollister@Sun.COM if (ptr == NULL) {
8811090SDavid.Hollister@Sun.COM mutex_exit(&pwp->iqp_lock[PMCS_IQ_OTHER]);
8911090SDavid.Hollister@Sun.COM pmcs_pwork(pwp, pwrk);
9011090SDavid.Hollister@Sun.COM pmcs_prt(pwp, PMCS_PRT_ERR, phyp, xp, pmcs_nomsg, __func__);
9111090SDavid.Hollister@Sun.COM return (-1);
9211090SDavid.Hollister@Sun.COM }
9311090SDavid.Hollister@Sun.COM COPY_MESSAGE(ptr, msg, PMCS_MSG_SIZE);
9411090SDavid.Hollister@Sun.COM pwrk->state = PMCS_WORK_STATE_ONCHIP;
9511090SDavid.Hollister@Sun.COM INC_IQ_ENTRY(pwp, PMCS_IQ_OTHER);
9611090SDavid.Hollister@Sun.COM
9711090SDavid.Hollister@Sun.COM if (xp != NULL) {
9811090SDavid.Hollister@Sun.COM mutex_exit(&xp->statlock);
9911090SDavid.Hollister@Sun.COM }
10011090SDavid.Hollister@Sun.COM pmcs_unlock_phy(phyp);
10111090SDavid.Hollister@Sun.COM WAIT_FOR(pwrk, 1000, result);
10212462Sjesse.butler@oracle.com pmcs_pwork(pwp, pwrk);
10311090SDavid.Hollister@Sun.COM pmcs_lock_phy(phyp);
10411090SDavid.Hollister@Sun.COM
10511090SDavid.Hollister@Sun.COM if (xp != NULL) {
10611090SDavid.Hollister@Sun.COM mutex_enter(&xp->statlock);
10711090SDavid.Hollister@Sun.COM }
10811090SDavid.Hollister@Sun.COM
10911090SDavid.Hollister@Sun.COM if (result) {
11011090SDavid.Hollister@Sun.COM pmcs_timed_out(pwp, htag, __func__);
11111090SDavid.Hollister@Sun.COM pmcs_prt(pwp, PMCS_PRT_DEBUG, phyp, xp,
11211090SDavid.Hollister@Sun.COM "%s: cmd timed out, returning", __func__);
11311090SDavid.Hollister@Sun.COM return (-1);
11411090SDavid.Hollister@Sun.COM }
11511090SDavid.Hollister@Sun.COM if (LE_32(msg[2]) == 0) {
11611090SDavid.Hollister@Sun.COM *ds = (uint8_t)(LE_32(msg[4]));
11711090SDavid.Hollister@Sun.COM if (xp == NULL) {
11811090SDavid.Hollister@Sun.COM pmcs_prt(pwp, PMCS_PRT_DEBUG_DEV_STATE, phyp, xp,
11911090SDavid.Hollister@Sun.COM "%s: retrieved_ds=0x%x", __func__, *ds);
12011090SDavid.Hollister@Sun.COM } else if (*ds != xp->dev_state) {
12111090SDavid.Hollister@Sun.COM pmcs_prt(pwp, PMCS_PRT_DEBUG_DEV_STATE, phyp, xp,
12211090SDavid.Hollister@Sun.COM "%s: retrieved_ds=0x%x, target_ds=0x%x", __func__,
12311090SDavid.Hollister@Sun.COM *ds, xp->dev_state);
12411090SDavid.Hollister@Sun.COM }
12511090SDavid.Hollister@Sun.COM return (0);
12611090SDavid.Hollister@Sun.COM } else {
12711090SDavid.Hollister@Sun.COM pmcs_prt(pwp, PMCS_PRT_DEBUG_DEV_STATE, phyp, xp,
12811090SDavid.Hollister@Sun.COM "%s: cmd failed Status(0x%x), returning ", __func__,
12911090SDavid.Hollister@Sun.COM LE_32(msg[2]));
13011090SDavid.Hollister@Sun.COM return (-1);
13111090SDavid.Hollister@Sun.COM }
13211090SDavid.Hollister@Sun.COM }
13311090SDavid.Hollister@Sun.COM
13411090SDavid.Hollister@Sun.COM /*
13511090SDavid.Hollister@Sun.COM * Set device state. Called with target's statlock and PHY lock held.
13611090SDavid.Hollister@Sun.COM */
13711090SDavid.Hollister@Sun.COM static int
pmcs_set_dev_state(pmcs_hw_t * pwp,pmcs_phy_t * phyp,pmcs_xscsi_t * xp,uint8_t ds)13811090SDavid.Hollister@Sun.COM pmcs_set_dev_state(pmcs_hw_t *pwp, pmcs_phy_t *phyp, pmcs_xscsi_t *xp,
13911090SDavid.Hollister@Sun.COM uint8_t ds)
14011090SDavid.Hollister@Sun.COM {
14111090SDavid.Hollister@Sun.COM uint32_t htag, *ptr, msg[PMCS_MSG_SIZE];
14211090SDavid.Hollister@Sun.COM int result;
14311090SDavid.Hollister@Sun.COM uint8_t pds, nds;
14411090SDavid.Hollister@Sun.COM struct pmcwork *pwrk;
14511090SDavid.Hollister@Sun.COM
14611090SDavid.Hollister@Sun.COM pmcs_prt(pwp, PMCS_PRT_DEBUG_DEV_STATE, phyp, xp,
14711090SDavid.Hollister@Sun.COM "%s: ds: 0x%x tgt: 0x%p phy: 0x%p", __func__, ds, (void *)xp,
14811090SDavid.Hollister@Sun.COM (void *)phyp);
14911090SDavid.Hollister@Sun.COM
15011090SDavid.Hollister@Sun.COM if (phyp == NULL) {
15111090SDavid.Hollister@Sun.COM pmcs_prt(pwp, PMCS_PRT_DEBUG_DEV_STATE, NULL, xp,
15211090SDavid.Hollister@Sun.COM "%s: PHY is NULL", __func__);
15311090SDavid.Hollister@Sun.COM return (-1);
15411090SDavid.Hollister@Sun.COM }
15511090SDavid.Hollister@Sun.COM
15611090SDavid.Hollister@Sun.COM pwrk = pmcs_gwork(pwp, PMCS_TAG_TYPE_WAIT, phyp);
15711090SDavid.Hollister@Sun.COM if (pwrk == NULL) {
15811090SDavid.Hollister@Sun.COM pmcs_prt(pwp, PMCS_PRT_ERR, phyp, xp, pmcs_nowrk, __func__);
15911090SDavid.Hollister@Sun.COM return (-1);
16011090SDavid.Hollister@Sun.COM }
16111090SDavid.Hollister@Sun.COM if (phyp->valid_device_id == 0) {
16211090SDavid.Hollister@Sun.COM pmcs_pwork(pwp, pwrk);
16311090SDavid.Hollister@Sun.COM pmcs_prt(pwp, PMCS_PRT_DEBUG_DEV_STATE, phyp, xp,
16411090SDavid.Hollister@Sun.COM "%s: Invalid DeviceID", __func__);
16511090SDavid.Hollister@Sun.COM return (-1);
16611090SDavid.Hollister@Sun.COM }
16711090SDavid.Hollister@Sun.COM pwrk->arg = msg;
16811090SDavid.Hollister@Sun.COM pwrk->dtype = phyp->dtype;
16911090SDavid.Hollister@Sun.COM htag = pwrk->htag;
17011090SDavid.Hollister@Sun.COM msg[0] = LE_32(PMCS_HIPRI(pwp, PMCS_OQ_GENERAL,
17111090SDavid.Hollister@Sun.COM PMCIN_SET_DEVICE_STATE));
17211090SDavid.Hollister@Sun.COM msg[1] = LE_32(pwrk->htag);
17311090SDavid.Hollister@Sun.COM msg[2] = LE_32(phyp->device_id);
17411090SDavid.Hollister@Sun.COM msg[3] = LE_32(ds);
17511347SRamana.Srikanth@Sun.COM CLEAN_MESSAGE(msg, 4);
17611090SDavid.Hollister@Sun.COM
17711090SDavid.Hollister@Sun.COM mutex_enter(&pwp->iqp_lock[PMCS_IQ_OTHER]);
17811090SDavid.Hollister@Sun.COM ptr = GET_IQ_ENTRY(pwp, PMCS_IQ_OTHER);
17911090SDavid.Hollister@Sun.COM if (ptr == NULL) {
18011090SDavid.Hollister@Sun.COM mutex_exit(&pwp->iqp_lock[PMCS_IQ_OTHER]);
18111090SDavid.Hollister@Sun.COM pmcs_pwork(pwp, pwrk);
18211090SDavid.Hollister@Sun.COM pmcs_prt(pwp, PMCS_PRT_ERR, phyp, xp, pmcs_nomsg, __func__);
18311090SDavid.Hollister@Sun.COM return (-1);
18411090SDavid.Hollister@Sun.COM }
18511090SDavid.Hollister@Sun.COM COPY_MESSAGE(ptr, msg, PMCS_MSG_SIZE);
18611090SDavid.Hollister@Sun.COM pwrk->state = PMCS_WORK_STATE_ONCHIP;
18711090SDavid.Hollister@Sun.COM INC_IQ_ENTRY(pwp, PMCS_IQ_OTHER);
18811090SDavid.Hollister@Sun.COM
18911090SDavid.Hollister@Sun.COM if (xp != NULL) {
19011090SDavid.Hollister@Sun.COM mutex_exit(&xp->statlock);
19111090SDavid.Hollister@Sun.COM }
19211090SDavid.Hollister@Sun.COM pmcs_unlock_phy(phyp);
19311090SDavid.Hollister@Sun.COM WAIT_FOR(pwrk, 1000, result);
19412462Sjesse.butler@oracle.com pmcs_pwork(pwp, pwrk);
19511090SDavid.Hollister@Sun.COM pmcs_lock_phy(phyp);
19611090SDavid.Hollister@Sun.COM if (xp != NULL) {
19711090SDavid.Hollister@Sun.COM mutex_enter(&xp->statlock);
19811090SDavid.Hollister@Sun.COM }
19911090SDavid.Hollister@Sun.COM
20011090SDavid.Hollister@Sun.COM if (result) {
20111090SDavid.Hollister@Sun.COM pmcs_timed_out(pwp, htag, __func__);
20211090SDavid.Hollister@Sun.COM pmcs_prt(pwp, PMCS_PRT_DEBUG_DEV_STATE, phyp, xp,
20311090SDavid.Hollister@Sun.COM "%s: cmd timed out, returning", __func__);
20411090SDavid.Hollister@Sun.COM return (-1);
20511090SDavid.Hollister@Sun.COM }
20611090SDavid.Hollister@Sun.COM if (LE_32(msg[2]) == 0) {
20711090SDavid.Hollister@Sun.COM pds = (uint8_t)(LE_32(msg[4]) >> 4);
20811090SDavid.Hollister@Sun.COM nds = (uint8_t)(LE_32(msg[4]) & 0x0000000f);
20911090SDavid.Hollister@Sun.COM pmcs_prt(pwp, PMCS_PRT_DEBUG_DEV_STATE, phyp, xp,
21011090SDavid.Hollister@Sun.COM "%s: previous_ds=0x%x, new_ds=0x%x", __func__, pds, nds);
21111090SDavid.Hollister@Sun.COM if (xp != NULL) {
21211090SDavid.Hollister@Sun.COM xp->dev_state = nds;
21311090SDavid.Hollister@Sun.COM }
21411090SDavid.Hollister@Sun.COM return (0);
21511090SDavid.Hollister@Sun.COM } else {
21611090SDavid.Hollister@Sun.COM pmcs_prt(pwp, PMCS_PRT_DEBUG_DEV_STATE, phyp, xp,
21711090SDavid.Hollister@Sun.COM "%s: cmd failed Status(0x%x), returning ", __func__,
21811090SDavid.Hollister@Sun.COM LE_32(msg[2]));
21911090SDavid.Hollister@Sun.COM return (-1);
22011090SDavid.Hollister@Sun.COM }
22111090SDavid.Hollister@Sun.COM }
22211090SDavid.Hollister@Sun.COM
22311267SJesse.Butler@Sun.COM static void
pmcs_ds_operational(pmcs_phy_t * pptr,pmcs_xscsi_t * tgt)22411267SJesse.Butler@Sun.COM pmcs_ds_operational(pmcs_phy_t *pptr, pmcs_xscsi_t *tgt)
22511267SJesse.Butler@Sun.COM {
22611267SJesse.Butler@Sun.COM pmcs_hw_t *pwp;
22711267SJesse.Butler@Sun.COM
22811267SJesse.Butler@Sun.COM ASSERT(pptr);
22911267SJesse.Butler@Sun.COM pwp = pptr->pwp;
23011267SJesse.Butler@Sun.COM
23111267SJesse.Butler@Sun.COM if (tgt != NULL) {
23211267SJesse.Butler@Sun.COM tgt->recover_wait = 0;
23311267SJesse.Butler@Sun.COM }
23411267SJesse.Butler@Sun.COM pptr->ds_recovery_retries = 0;
23511267SJesse.Butler@Sun.COM
23611267SJesse.Butler@Sun.COM if ((pptr->ds_prev_good_recoveries == 0) ||
23711267SJesse.Butler@Sun.COM (ddi_get_lbolt() - pptr->last_good_recovery >
23811267SJesse.Butler@Sun.COM drv_usectohz(PMCS_MAX_DS_RECOVERY_TIME))) {
23911267SJesse.Butler@Sun.COM pptr->last_good_recovery = ddi_get_lbolt();
24011267SJesse.Butler@Sun.COM pptr->ds_prev_good_recoveries = 1;
24111267SJesse.Butler@Sun.COM } else if (ddi_get_lbolt() < pptr->last_good_recovery +
24211267SJesse.Butler@Sun.COM drv_usectohz(PMCS_MAX_DS_RECOVERY_TIME)) {
24311267SJesse.Butler@Sun.COM pptr->ds_prev_good_recoveries++;
24411267SJesse.Butler@Sun.COM } else {
24511347SRamana.Srikanth@Sun.COM pmcs_handle_ds_recovery_error(pptr, tgt, pwp, __func__,
24611347SRamana.Srikanth@Sun.COM "Max recovery attempts reached. Declaring PHY dead");
24711267SJesse.Butler@Sun.COM }
24811267SJesse.Butler@Sun.COM
24911267SJesse.Butler@Sun.COM /* Don't bother to run the work queues if the PHY is dead */
25011267SJesse.Butler@Sun.COM if (!pptr->dead) {
25111267SJesse.Butler@Sun.COM SCHEDULE_WORK(pwp, PMCS_WORK_RUN_QUEUES);
25211267SJesse.Butler@Sun.COM (void) ddi_taskq_dispatch(pwp->tq, pmcs_worker,
25311267SJesse.Butler@Sun.COM pwp, DDI_NOSLEEP);
25411267SJesse.Butler@Sun.COM }
25511267SJesse.Butler@Sun.COM }
25611267SJesse.Butler@Sun.COM
25711090SDavid.Hollister@Sun.COM void
pmcs_dev_state_recovery(pmcs_hw_t * pwp,pmcs_phy_t * phyp)25811090SDavid.Hollister@Sun.COM pmcs_dev_state_recovery(pmcs_hw_t *pwp, pmcs_phy_t *phyp)
25911090SDavid.Hollister@Sun.COM {
26011167SRamana.Srikanth@Sun.COM boolean_t reschedule = B_FALSE;
26111090SDavid.Hollister@Sun.COM uint8_t ds, tgt_dev_state;
26211090SDavid.Hollister@Sun.COM int rc;
26311090SDavid.Hollister@Sun.COM pmcs_xscsi_t *tgt;
26411090SDavid.Hollister@Sun.COM pmcs_phy_t *pptr, *pnext, *pchild;
26511090SDavid.Hollister@Sun.COM
26611090SDavid.Hollister@Sun.COM /*
26711090SDavid.Hollister@Sun.COM * First time, check to see if we're already performing recovery
26811090SDavid.Hollister@Sun.COM */
26911090SDavid.Hollister@Sun.COM if (phyp == NULL) {
27011090SDavid.Hollister@Sun.COM mutex_enter(&pwp->lock);
27111090SDavid.Hollister@Sun.COM if (pwp->ds_err_recovering) {
27211090SDavid.Hollister@Sun.COM mutex_exit(&pwp->lock);
27311090SDavid.Hollister@Sun.COM SCHEDULE_WORK(pwp, PMCS_WORK_DS_ERR_RECOVERY);
27411090SDavid.Hollister@Sun.COM return;
27511090SDavid.Hollister@Sun.COM }
27611090SDavid.Hollister@Sun.COM
27711090SDavid.Hollister@Sun.COM pwp->ds_err_recovering = 1;
27811090SDavid.Hollister@Sun.COM pptr = pwp->root_phys;
27911090SDavid.Hollister@Sun.COM mutex_exit(&pwp->lock);
28011090SDavid.Hollister@Sun.COM } else {
28111090SDavid.Hollister@Sun.COM pptr = phyp;
28211090SDavid.Hollister@Sun.COM }
28311090SDavid.Hollister@Sun.COM
28411090SDavid.Hollister@Sun.COM while (pptr) {
28511090SDavid.Hollister@Sun.COM /*
28611090SDavid.Hollister@Sun.COM * Since ds_err_recovering is set, we can be assured these
28711090SDavid.Hollister@Sun.COM * PHYs won't disappear on us while we do this.
28811090SDavid.Hollister@Sun.COM */
28911090SDavid.Hollister@Sun.COM pmcs_lock_phy(pptr);
29011090SDavid.Hollister@Sun.COM pchild = pptr->children;
29111090SDavid.Hollister@Sun.COM pnext = pptr->sibling;
29211090SDavid.Hollister@Sun.COM pmcs_unlock_phy(pptr);
29311090SDavid.Hollister@Sun.COM
29411090SDavid.Hollister@Sun.COM if (pchild) {
29511090SDavid.Hollister@Sun.COM pmcs_dev_state_recovery(pwp, pchild);
29611090SDavid.Hollister@Sun.COM }
29711090SDavid.Hollister@Sun.COM
29811090SDavid.Hollister@Sun.COM tgt = NULL;
29911090SDavid.Hollister@Sun.COM pmcs_lock_phy(pptr);
30011090SDavid.Hollister@Sun.COM
30111347SRamana.Srikanth@Sun.COM if (pptr->dead || !pptr->valid_device_id) {
30211347SRamana.Srikanth@Sun.COM goto next_phy;
30311347SRamana.Srikanth@Sun.COM }
30411347SRamana.Srikanth@Sun.COM
30511347SRamana.Srikanth@Sun.COM if (pptr->iport && (pptr->iport->ua_state != UA_ACTIVE)) {
30611347SRamana.Srikanth@Sun.COM pmcs_prt(pwp, PMCS_PRT_DEBUG, pptr, pptr->target,
30711347SRamana.Srikanth@Sun.COM "%s: No DS recovery on PHY %s, iport not active",
30811347SRamana.Srikanth@Sun.COM __func__, pptr->path);
30911090SDavid.Hollister@Sun.COM goto next_phy;
31011090SDavid.Hollister@Sun.COM }
31111090SDavid.Hollister@Sun.COM
31211090SDavid.Hollister@Sun.COM tgt = pptr->target;
31311090SDavid.Hollister@Sun.COM
31411090SDavid.Hollister@Sun.COM if (tgt != NULL) {
31511090SDavid.Hollister@Sun.COM mutex_enter(&tgt->statlock);
31611090SDavid.Hollister@Sun.COM if (tgt->recover_wait == 0) {
31711090SDavid.Hollister@Sun.COM goto next_phy;
31811090SDavid.Hollister@Sun.COM }
31911090SDavid.Hollister@Sun.COM tgt_dev_state = tgt->dev_state;
32011090SDavid.Hollister@Sun.COM } else {
32111090SDavid.Hollister@Sun.COM tgt_dev_state = PMCS_DEVICE_STATE_NOT_AVAILABLE;
32211090SDavid.Hollister@Sun.COM }
32311090SDavid.Hollister@Sun.COM
32411090SDavid.Hollister@Sun.COM if (pptr->prev_recovery) {
32511090SDavid.Hollister@Sun.COM if (ddi_get_lbolt() - pptr->prev_recovery <
32611090SDavid.Hollister@Sun.COM drv_usectohz(PMCS_DS_RECOVERY_INTERVAL)) {
32711090SDavid.Hollister@Sun.COM pmcs_prt(pwp, PMCS_PRT_DEBUG2, pptr, tgt,
32811090SDavid.Hollister@Sun.COM "%s: DS recovery on PHY %s "
32911090SDavid.Hollister@Sun.COM "re-invoked too soon. Skipping...",
33011090SDavid.Hollister@Sun.COM __func__, pptr->path);
33111167SRamana.Srikanth@Sun.COM if ((tgt) && (tgt->recover_wait)) {
33211167SRamana.Srikanth@Sun.COM reschedule = B_TRUE;
33311167SRamana.Srikanth@Sun.COM }
33411090SDavid.Hollister@Sun.COM goto next_phy;
33511090SDavid.Hollister@Sun.COM }
33611090SDavid.Hollister@Sun.COM }
33711090SDavid.Hollister@Sun.COM pptr->prev_recovery = ddi_get_lbolt();
33811090SDavid.Hollister@Sun.COM
33911090SDavid.Hollister@Sun.COM /*
34011090SDavid.Hollister@Sun.COM * Step 1: Put the device into the IN_RECOVERY state
34111090SDavid.Hollister@Sun.COM */
34211090SDavid.Hollister@Sun.COM rc = pmcs_get_dev_state(pwp, pptr, tgt, &ds);
34311090SDavid.Hollister@Sun.COM if (rc != 0) {
34411090SDavid.Hollister@Sun.COM pmcs_prt(pwp, PMCS_PRT_DEBUG, pptr, tgt,
34511090SDavid.Hollister@Sun.COM "%s: pmcs_get_dev_state on PHY %s "
34611090SDavid.Hollister@Sun.COM "failed (rc=%d)",
34711090SDavid.Hollister@Sun.COM __func__, pptr->path, rc);
34811090SDavid.Hollister@Sun.COM
34911090SDavid.Hollister@Sun.COM pmcs_handle_ds_recovery_error(pptr, tgt, pwp,
35011347SRamana.Srikanth@Sun.COM __func__, "pmcs_get_dev_state");
35111090SDavid.Hollister@Sun.COM
35211090SDavid.Hollister@Sun.COM goto next_phy;
35311090SDavid.Hollister@Sun.COM }
35411090SDavid.Hollister@Sun.COM
35511267SJesse.Butler@Sun.COM /* If the chip says it's operational, we're done */
35611267SJesse.Butler@Sun.COM if (ds == PMCS_DEVICE_STATE_OPERATIONAL) {
35711267SJesse.Butler@Sun.COM pmcs_ds_operational(pptr, tgt);
35811267SJesse.Butler@Sun.COM goto next_phy;
35911267SJesse.Butler@Sun.COM }
36011267SJesse.Butler@Sun.COM
36111090SDavid.Hollister@Sun.COM if ((tgt_dev_state == ds) &&
36211090SDavid.Hollister@Sun.COM (ds == PMCS_DEVICE_STATE_IN_RECOVERY)) {
36311090SDavid.Hollister@Sun.COM pmcs_prt(pwp, PMCS_PRT_DEBUG_DEV_STATE, pptr, tgt,
36411090SDavid.Hollister@Sun.COM "%s: Target 0x%p already IN_RECOVERY", __func__,
36511090SDavid.Hollister@Sun.COM (void *)tgt);
36611090SDavid.Hollister@Sun.COM } else {
36711090SDavid.Hollister@Sun.COM if (tgt != NULL) {
36811090SDavid.Hollister@Sun.COM tgt->dev_state = ds;
36911090SDavid.Hollister@Sun.COM }
37011090SDavid.Hollister@Sun.COM tgt_dev_state = ds;
37111090SDavid.Hollister@Sun.COM ds = PMCS_DEVICE_STATE_IN_RECOVERY;
37211090SDavid.Hollister@Sun.COM rc = pmcs_send_err_recovery_cmd(pwp, ds, pptr, tgt);
37311090SDavid.Hollister@Sun.COM pmcs_prt(pwp, PMCS_PRT_DEBUG_DEV_STATE, pptr, tgt,
37411090SDavid.Hollister@Sun.COM "%s: pmcs_send_err_recovery_cmd "
37511090SDavid.Hollister@Sun.COM "result(%d) tgt(0x%p) ds(0x%x) tgt->ds(0x%x)",
37611090SDavid.Hollister@Sun.COM __func__, rc, (void *)tgt, ds, tgt_dev_state);
37711090SDavid.Hollister@Sun.COM
37811090SDavid.Hollister@Sun.COM if (rc) {
37911090SDavid.Hollister@Sun.COM pmcs_prt(pwp, PMCS_PRT_DEBUG, pptr, tgt,
38011090SDavid.Hollister@Sun.COM "%s: pmcs_send_err_recovery_cmd to PHY %s "
38111090SDavid.Hollister@Sun.COM "failed (rc=%d)",
38211090SDavid.Hollister@Sun.COM __func__, pptr->path, rc);
38311090SDavid.Hollister@Sun.COM
38411090SDavid.Hollister@Sun.COM pmcs_handle_ds_recovery_error(pptr, tgt, pwp,
38511347SRamana.Srikanth@Sun.COM __func__, "pmcs_send_err_recovery_cmd");
38611090SDavid.Hollister@Sun.COM
38711090SDavid.Hollister@Sun.COM goto next_phy;
38811090SDavid.Hollister@Sun.COM }
38911090SDavid.Hollister@Sun.COM }
39011090SDavid.Hollister@Sun.COM
39111090SDavid.Hollister@Sun.COM /*
39211267SJesse.Butler@Sun.COM * Step 2: Perform a hard reset on the PHY.
39311347SRamana.Srikanth@Sun.COM */
39411347SRamana.Srikanth@Sun.COM pmcs_prt(pwp, PMCS_PRT_DEBUG_DEV_STATE, pptr, tgt,
39511347SRamana.Srikanth@Sun.COM "%s: Issue HARD_RESET to PHY %s", __func__,
39611347SRamana.Srikanth@Sun.COM pptr->path);
39711347SRamana.Srikanth@Sun.COM /*
39811347SRamana.Srikanth@Sun.COM * Must release statlock here because pmcs_reset_phy
39911347SRamana.Srikanth@Sun.COM * will drop and reacquire the PHY lock.
40011090SDavid.Hollister@Sun.COM */
40111347SRamana.Srikanth@Sun.COM if (tgt != NULL) {
40211347SRamana.Srikanth@Sun.COM mutex_exit(&tgt->statlock);
40311347SRamana.Srikanth@Sun.COM }
40411347SRamana.Srikanth@Sun.COM rc = pmcs_reset_phy(pwp, pptr, PMCS_PHYOP_HARD_RESET);
40511347SRamana.Srikanth@Sun.COM if (tgt != NULL) {
40611347SRamana.Srikanth@Sun.COM mutex_enter(&tgt->statlock);
40711347SRamana.Srikanth@Sun.COM }
40811347SRamana.Srikanth@Sun.COM if (rc) {
40911347SRamana.Srikanth@Sun.COM pmcs_prt(pwp, PMCS_PRT_DEBUG, pptr, tgt,
41011347SRamana.Srikanth@Sun.COM "%s: HARD_RESET to PHY %s failed (rc=%d)",
41111347SRamana.Srikanth@Sun.COM __func__, pptr->path, rc);
41211090SDavid.Hollister@Sun.COM
41311347SRamana.Srikanth@Sun.COM pmcs_handle_ds_recovery_error(pptr, tgt, pwp,
41411347SRamana.Srikanth@Sun.COM __func__, "HARD_RESET");
41511090SDavid.Hollister@Sun.COM
41611347SRamana.Srikanth@Sun.COM goto next_phy;
41711090SDavid.Hollister@Sun.COM }
41811090SDavid.Hollister@Sun.COM
41911090SDavid.Hollister@Sun.COM /*
42011090SDavid.Hollister@Sun.COM * Step 3: Abort all I/Os to the device
42111090SDavid.Hollister@Sun.COM */
42211090SDavid.Hollister@Sun.COM if (pptr->abort_all_start) {
42311090SDavid.Hollister@Sun.COM while (pptr->abort_all_start) {
42411090SDavid.Hollister@Sun.COM pmcs_prt(pwp, PMCS_PRT_DEBUG, pptr, tgt,
42511090SDavid.Hollister@Sun.COM "%s: Waiting for outstanding ABORT_ALL on "
42611090SDavid.Hollister@Sun.COM "PHY 0x%p", __func__, (void *)pptr);
42711090SDavid.Hollister@Sun.COM cv_wait(&pptr->abort_all_cv, &pptr->phy_lock);
42811090SDavid.Hollister@Sun.COM }
42911090SDavid.Hollister@Sun.COM } else {
43011090SDavid.Hollister@Sun.COM if (tgt != NULL) {
43111090SDavid.Hollister@Sun.COM mutex_exit(&tgt->statlock);
43211090SDavid.Hollister@Sun.COM }
43311090SDavid.Hollister@Sun.COM rc = pmcs_abort(pwp, pptr, pptr->device_id, 1, 1);
43411090SDavid.Hollister@Sun.COM if (tgt != NULL) {
43511090SDavid.Hollister@Sun.COM mutex_enter(&tgt->statlock);
43611090SDavid.Hollister@Sun.COM }
43711090SDavid.Hollister@Sun.COM if (rc != 0) {
43811090SDavid.Hollister@Sun.COM pptr->abort_pending = 1;
43911090SDavid.Hollister@Sun.COM pmcs_prt(pwp, PMCS_PRT_DEBUG, pptr, tgt,
44011090SDavid.Hollister@Sun.COM "%s: pmcs_abort to PHY %s failed (rc=%d)",
44111090SDavid.Hollister@Sun.COM __func__, pptr->path, rc);
44211090SDavid.Hollister@Sun.COM
44311090SDavid.Hollister@Sun.COM pmcs_handle_ds_recovery_error(pptr, tgt,
44411347SRamana.Srikanth@Sun.COM pwp, __func__, "pmcs_abort");
44511090SDavid.Hollister@Sun.COM
44611090SDavid.Hollister@Sun.COM goto next_phy;
44711090SDavid.Hollister@Sun.COM }
44811090SDavid.Hollister@Sun.COM }
44911090SDavid.Hollister@Sun.COM
45011090SDavid.Hollister@Sun.COM /*
45111090SDavid.Hollister@Sun.COM * Step 4: Set the device back to OPERATIONAL state
45211090SDavid.Hollister@Sun.COM */
45311090SDavid.Hollister@Sun.COM pmcs_prt(pwp, PMCS_PRT_DEBUG_DEV_STATE, pptr, tgt,
45411090SDavid.Hollister@Sun.COM "%s: Set PHY/tgt 0x%p/0x%p to OPERATIONAL state",
45511090SDavid.Hollister@Sun.COM __func__, (void *)pptr, (void *)tgt);
45611090SDavid.Hollister@Sun.COM rc = pmcs_set_dev_state(pwp, pptr, tgt,
45711090SDavid.Hollister@Sun.COM PMCS_DEVICE_STATE_OPERATIONAL);
45811090SDavid.Hollister@Sun.COM if (rc == 0) {
45911267SJesse.Butler@Sun.COM pmcs_ds_operational(pptr, tgt);
46011090SDavid.Hollister@Sun.COM } else {
46111090SDavid.Hollister@Sun.COM pmcs_prt(pwp, PMCS_PRT_DEBUG_DEV_STATE, pptr, tgt,
46211090SDavid.Hollister@Sun.COM "%s: Failed to SET tgt 0x%p to OPERATIONAL state",
46311090SDavid.Hollister@Sun.COM __func__, (void *)tgt);
46411090SDavid.Hollister@Sun.COM
46511090SDavid.Hollister@Sun.COM pmcs_handle_ds_recovery_error(pptr, tgt, pwp,
46611347SRamana.Srikanth@Sun.COM __func__, "SET tgt to OPERATIONAL state");
46711090SDavid.Hollister@Sun.COM
46811090SDavid.Hollister@Sun.COM goto next_phy;
46911090SDavid.Hollister@Sun.COM }
47011090SDavid.Hollister@Sun.COM
47111090SDavid.Hollister@Sun.COM next_phy:
47211090SDavid.Hollister@Sun.COM if (tgt) {
47311090SDavid.Hollister@Sun.COM mutex_exit(&tgt->statlock);
47411090SDavid.Hollister@Sun.COM }
47511090SDavid.Hollister@Sun.COM pmcs_unlock_phy(pptr);
47611090SDavid.Hollister@Sun.COM pptr = pnext;
47711090SDavid.Hollister@Sun.COM }
47811090SDavid.Hollister@Sun.COM
47911090SDavid.Hollister@Sun.COM /*
48011090SDavid.Hollister@Sun.COM * Only clear ds_err_recovering if we're exiting for good and not
48111090SDavid.Hollister@Sun.COM * just unwinding from recursion
48211090SDavid.Hollister@Sun.COM */
48311090SDavid.Hollister@Sun.COM if (phyp == NULL) {
48411090SDavid.Hollister@Sun.COM mutex_enter(&pwp->lock);
48511090SDavid.Hollister@Sun.COM pwp->ds_err_recovering = 0;
48611090SDavid.Hollister@Sun.COM mutex_exit(&pwp->lock);
48711090SDavid.Hollister@Sun.COM }
48811167SRamana.Srikanth@Sun.COM
48911167SRamana.Srikanth@Sun.COM if (reschedule) {
49011167SRamana.Srikanth@Sun.COM SCHEDULE_WORK(pwp, PMCS_WORK_DS_ERR_RECOVERY);
49111167SRamana.Srikanth@Sun.COM }
49211090SDavid.Hollister@Sun.COM }
49311090SDavid.Hollister@Sun.COM
49411090SDavid.Hollister@Sun.COM /*
49511090SDavid.Hollister@Sun.COM * Called with target's statlock held (if target is non-NULL) and PHY lock held.
49611090SDavid.Hollister@Sun.COM */
49711090SDavid.Hollister@Sun.COM int
pmcs_send_err_recovery_cmd(pmcs_hw_t * pwp,uint8_t dev_state,pmcs_phy_t * phyp,pmcs_xscsi_t * tgt)49811090SDavid.Hollister@Sun.COM pmcs_send_err_recovery_cmd(pmcs_hw_t *pwp, uint8_t dev_state, pmcs_phy_t *phyp,
49911090SDavid.Hollister@Sun.COM pmcs_xscsi_t *tgt)
50011090SDavid.Hollister@Sun.COM {
50111090SDavid.Hollister@Sun.COM int rc = -1;
50211090SDavid.Hollister@Sun.COM uint8_t tgt_dev_state = PMCS_DEVICE_STATE_NOT_AVAILABLE;
50311090SDavid.Hollister@Sun.COM
50411090SDavid.Hollister@Sun.COM if (tgt != NULL) {
50511090SDavid.Hollister@Sun.COM ASSERT(mutex_owned(&tgt->statlock));
50611090SDavid.Hollister@Sun.COM if (tgt->recovering) {
50711090SDavid.Hollister@Sun.COM return (0);
50811090SDavid.Hollister@Sun.COM }
50911090SDavid.Hollister@Sun.COM
51011090SDavid.Hollister@Sun.COM tgt->recovering = 1;
51111090SDavid.Hollister@Sun.COM tgt_dev_state = tgt->dev_state;
51211090SDavid.Hollister@Sun.COM }
51311090SDavid.Hollister@Sun.COM
51411090SDavid.Hollister@Sun.COM if (phyp == NULL) {
51511090SDavid.Hollister@Sun.COM pmcs_prt(pwp, PMCS_PRT_DEBUG_DEV_STATE, NULL, tgt,
51611090SDavid.Hollister@Sun.COM "%s: PHY is NULL", __func__);
51711090SDavid.Hollister@Sun.COM return (-1);
51811090SDavid.Hollister@Sun.COM }
51911090SDavid.Hollister@Sun.COM
52011090SDavid.Hollister@Sun.COM ASSERT(mutex_owned(&phyp->phy_lock));
52111090SDavid.Hollister@Sun.COM
52211090SDavid.Hollister@Sun.COM pmcs_prt(pwp, PMCS_PRT_DEBUG_DEV_STATE, phyp, tgt,
52311090SDavid.Hollister@Sun.COM "%s: ds: 0x%x, tgt ds(0x%x)", __func__, dev_state, tgt_dev_state);
52411090SDavid.Hollister@Sun.COM
52511090SDavid.Hollister@Sun.COM switch (dev_state) {
52611090SDavid.Hollister@Sun.COM case PMCS_DEVICE_STATE_IN_RECOVERY:
52711090SDavid.Hollister@Sun.COM if (tgt_dev_state == PMCS_DEVICE_STATE_IN_RECOVERY) {
52811090SDavid.Hollister@Sun.COM pmcs_prt(pwp, PMCS_PRT_DEBUG_DEV_STATE, phyp, tgt,
52911090SDavid.Hollister@Sun.COM "%s: Target 0x%p already IN_RECOVERY", __func__,
53011090SDavid.Hollister@Sun.COM (void *)tgt);
53111090SDavid.Hollister@Sun.COM rc = 0; /* This is not an error */
53211090SDavid.Hollister@Sun.COM goto no_action;
53311090SDavid.Hollister@Sun.COM }
53411090SDavid.Hollister@Sun.COM
53511090SDavid.Hollister@Sun.COM rc = pmcs_set_dev_state(pwp, phyp, tgt,
53611090SDavid.Hollister@Sun.COM PMCS_DEVICE_STATE_IN_RECOVERY);
53711090SDavid.Hollister@Sun.COM if (rc != 0) {
53811090SDavid.Hollister@Sun.COM pmcs_prt(pwp, PMCS_PRT_DEBUG_DEV_STATE, phyp, tgt,
53911090SDavid.Hollister@Sun.COM "%s(1): Failed to set tgt(0x%p) to IN_RECOVERY",
54011090SDavid.Hollister@Sun.COM __func__, (void *)tgt);
54111090SDavid.Hollister@Sun.COM }
54211090SDavid.Hollister@Sun.COM
54311090SDavid.Hollister@Sun.COM break;
54411090SDavid.Hollister@Sun.COM
54511090SDavid.Hollister@Sun.COM case PMCS_DEVICE_STATE_OPERATIONAL:
54611090SDavid.Hollister@Sun.COM if (tgt_dev_state != PMCS_DEVICE_STATE_IN_RECOVERY) {
54711090SDavid.Hollister@Sun.COM pmcs_prt(pwp, PMCS_PRT_DEBUG_DEV_STATE, phyp, tgt,
54811090SDavid.Hollister@Sun.COM "%s: Target 0x%p not ready to go OPERATIONAL",
54911090SDavid.Hollister@Sun.COM __func__, (void *)tgt);
55011090SDavid.Hollister@Sun.COM goto no_action;
55111090SDavid.Hollister@Sun.COM }
55211090SDavid.Hollister@Sun.COM
55311090SDavid.Hollister@Sun.COM rc = pmcs_set_dev_state(pwp, phyp, tgt,
55411090SDavid.Hollister@Sun.COM PMCS_DEVICE_STATE_OPERATIONAL);
55511090SDavid.Hollister@Sun.COM if (tgt != NULL) {
55611090SDavid.Hollister@Sun.COM tgt->reset_success = 1;
55711090SDavid.Hollister@Sun.COM }
55811090SDavid.Hollister@Sun.COM if (rc != 0) {
55911090SDavid.Hollister@Sun.COM pmcs_prt(pwp, PMCS_PRT_DEBUG_DEV_STATE, phyp, tgt,
56011090SDavid.Hollister@Sun.COM "%s(2): Failed to SET tgt(0x%p) to OPERATIONAL",
56111090SDavid.Hollister@Sun.COM __func__, (void *)tgt);
56211090SDavid.Hollister@Sun.COM if (tgt != NULL) {
56311090SDavid.Hollister@Sun.COM tgt->reset_success = 0;
56411090SDavid.Hollister@Sun.COM }
56511090SDavid.Hollister@Sun.COM }
56611090SDavid.Hollister@Sun.COM
56711090SDavid.Hollister@Sun.COM break;
56811090SDavid.Hollister@Sun.COM
56911090SDavid.Hollister@Sun.COM case PMCS_DEVICE_STATE_NON_OPERATIONAL:
57011090SDavid.Hollister@Sun.COM PHY_CHANGED(pwp, phyp);
57111090SDavid.Hollister@Sun.COM RESTART_DISCOVERY(pwp);
57211090SDavid.Hollister@Sun.COM pmcs_prt(pwp, PMCS_PRT_DEBUG_DEV_STATE, phyp, tgt,
57311090SDavid.Hollister@Sun.COM "%s: Device at %s is non-operational",
57411090SDavid.Hollister@Sun.COM __func__, phyp->path);
57511090SDavid.Hollister@Sun.COM if (tgt != NULL) {
57611090SDavid.Hollister@Sun.COM tgt->dev_state = PMCS_DEVICE_STATE_NON_OPERATIONAL;
57711090SDavid.Hollister@Sun.COM }
57811090SDavid.Hollister@Sun.COM rc = 0;
57911090SDavid.Hollister@Sun.COM
58011090SDavid.Hollister@Sun.COM break;
58111090SDavid.Hollister@Sun.COM
58211090SDavid.Hollister@Sun.COM default:
58311090SDavid.Hollister@Sun.COM pmcs_prt(pwp, PMCS_PRT_DEBUG_DEV_STATE, phyp, tgt,
58411090SDavid.Hollister@Sun.COM "%s: Invalid state requested (%d)", __func__,
58511090SDavid.Hollister@Sun.COM dev_state);
58611090SDavid.Hollister@Sun.COM break;
58711090SDavid.Hollister@Sun.COM
58811090SDavid.Hollister@Sun.COM }
58911090SDavid.Hollister@Sun.COM
59011090SDavid.Hollister@Sun.COM no_action:
59111090SDavid.Hollister@Sun.COM if (tgt != NULL) {
59211090SDavid.Hollister@Sun.COM tgt->recovering = 0;
59311090SDavid.Hollister@Sun.COM }
59411090SDavid.Hollister@Sun.COM return (rc);
59511090SDavid.Hollister@Sun.COM }
59611090SDavid.Hollister@Sun.COM
59711090SDavid.Hollister@Sun.COM /*
59811090SDavid.Hollister@Sun.COM * Start ssp event recovery. We have to schedule recovery operation because
59911090SDavid.Hollister@Sun.COM * it involves sending multiple commands to device and we should not do it
60011090SDavid.Hollister@Sun.COM * in the interrupt context.
60111090SDavid.Hollister@Sun.COM * If it is failure of a recovery command, let the recovery thread deal with it.
60212862Sjesse.butler@oracle.com * Called with the work lock held.
60311090SDavid.Hollister@Sun.COM */
60411090SDavid.Hollister@Sun.COM void
pmcs_start_ssp_event_recovery(pmcs_hw_t * pwp,pmcwork_t * pwrk,uint32_t * iomb,size_t amt)60511090SDavid.Hollister@Sun.COM pmcs_start_ssp_event_recovery(pmcs_hw_t *pwp, pmcwork_t *pwrk, uint32_t *iomb,
60611090SDavid.Hollister@Sun.COM size_t amt)
60711090SDavid.Hollister@Sun.COM {
60811090SDavid.Hollister@Sun.COM pmcs_xscsi_t *tgt = pwrk->xp;
60911090SDavid.Hollister@Sun.COM uint32_t event = LE_32(iomb[2]);
61011090SDavid.Hollister@Sun.COM pmcs_phy_t *pptr = pwrk->phy;
61112060SDavid.Hollister@Sun.COM pmcs_cb_t callback;
61211090SDavid.Hollister@Sun.COM uint32_t tag;
61311090SDavid.Hollister@Sun.COM
61411090SDavid.Hollister@Sun.COM if (tgt != NULL) {
61511090SDavid.Hollister@Sun.COM mutex_enter(&tgt->statlock);
61611090SDavid.Hollister@Sun.COM if (!tgt->assigned) {
61711090SDavid.Hollister@Sun.COM if (pptr) {
61811090SDavid.Hollister@Sun.COM pmcs_dec_phy_ref_count(pptr);
61911090SDavid.Hollister@Sun.COM }
62011090SDavid.Hollister@Sun.COM pptr = NULL;
62111090SDavid.Hollister@Sun.COM pwrk->phy = NULL;
62211090SDavid.Hollister@Sun.COM }
62311090SDavid.Hollister@Sun.COM mutex_exit(&tgt->statlock);
62411090SDavid.Hollister@Sun.COM }
62511355SDavid.Hollister@Sun.COM
62611090SDavid.Hollister@Sun.COM if (pptr == NULL) {
62711090SDavid.Hollister@Sun.COM /*
62811090SDavid.Hollister@Sun.COM * No target, need to run RE-DISCOVERY here.
62911090SDavid.Hollister@Sun.COM */
63011090SDavid.Hollister@Sun.COM if (pwrk->state != PMCS_WORK_STATE_TIMED_OUT) {
63111090SDavid.Hollister@Sun.COM pwrk->state = PMCS_WORK_STATE_INTR;
63211090SDavid.Hollister@Sun.COM }
63311090SDavid.Hollister@Sun.COM /*
63411090SDavid.Hollister@Sun.COM * Although we cannot mark phy to force abort nor mark phy
63511090SDavid.Hollister@Sun.COM * as changed, killing of a target would take care of aborting
63611090SDavid.Hollister@Sun.COM * commands for the device.
63711090SDavid.Hollister@Sun.COM */
63811090SDavid.Hollister@Sun.COM pmcs_prt(pwp, PMCS_PRT_DEBUG, pptr, tgt,
63911090SDavid.Hollister@Sun.COM "%s: No valid target for event processing. Reconfigure.",
64011090SDavid.Hollister@Sun.COM __func__);
64111090SDavid.Hollister@Sun.COM pmcs_pwork(pwp, pwrk);
64211090SDavid.Hollister@Sun.COM RESTART_DISCOVERY(pwp);
64311090SDavid.Hollister@Sun.COM return;
64411090SDavid.Hollister@Sun.COM } else {
64512862Sjesse.butler@oracle.com /* We have a phy pointer, we'll need to lock it */
64612862Sjesse.butler@oracle.com mutex_exit(&pwrk->lock);
64711090SDavid.Hollister@Sun.COM pmcs_lock_phy(pptr);
64812862Sjesse.butler@oracle.com mutex_enter(&pwrk->lock);
64912462Sjesse.butler@oracle.com if (tgt != NULL) {
65011355SDavid.Hollister@Sun.COM mutex_enter(&tgt->statlock);
65111355SDavid.Hollister@Sun.COM }
65211090SDavid.Hollister@Sun.COM if (event == PMCOUT_STATUS_OPEN_CNX_ERROR_IT_NEXUS_LOSS) {
65312462Sjesse.butler@oracle.com if ((tgt != NULL) && (tgt->dev_state !=
65412462Sjesse.butler@oracle.com PMCS_DEVICE_STATE_NON_OPERATIONAL)) {
65511090SDavid.Hollister@Sun.COM pmcs_prt(pwp, PMCS_PRT_DEBUG, pptr, tgt,
65611090SDavid.Hollister@Sun.COM "%s: Device at %s is non-operational",
65711090SDavid.Hollister@Sun.COM __func__, pptr->path);
65811090SDavid.Hollister@Sun.COM tgt->dev_state =
65911090SDavid.Hollister@Sun.COM PMCS_DEVICE_STATE_NON_OPERATIONAL;
66011090SDavid.Hollister@Sun.COM }
66111090SDavid.Hollister@Sun.COM pptr->abort_pending = 1;
66212462Sjesse.butler@oracle.com if (tgt != NULL) {
66311355SDavid.Hollister@Sun.COM mutex_exit(&tgt->statlock);
66411355SDavid.Hollister@Sun.COM }
66512862Sjesse.butler@oracle.com mutex_exit(&pwrk->lock);
66611090SDavid.Hollister@Sun.COM pmcs_unlock_phy(pptr);
66711090SDavid.Hollister@Sun.COM SCHEDULE_WORK(pwp, PMCS_WORK_ABORT_HANDLE);
66811090SDavid.Hollister@Sun.COM RESTART_DISCOVERY(pwp);
66911090SDavid.Hollister@Sun.COM return;
67011090SDavid.Hollister@Sun.COM }
67111090SDavid.Hollister@Sun.COM
67211090SDavid.Hollister@Sun.COM /*
67311090SDavid.Hollister@Sun.COM * If this command is run in WAIT mode, it is a failing recovery
67411090SDavid.Hollister@Sun.COM * command. If so, just wake up recovery thread waiting for
67511090SDavid.Hollister@Sun.COM * command completion.
67611090SDavid.Hollister@Sun.COM */
67711090SDavid.Hollister@Sun.COM tag = PMCS_TAG_TYPE(pwrk->htag);
67811090SDavid.Hollister@Sun.COM if (tag == PMCS_TAG_TYPE_WAIT) {
67911090SDavid.Hollister@Sun.COM pwrk->htag |= PMCS_TAG_DONE;
68011090SDavid.Hollister@Sun.COM if (pwrk->arg && amt) {
68111090SDavid.Hollister@Sun.COM (void) memcpy(pwrk->arg, iomb, amt);
68211090SDavid.Hollister@Sun.COM }
68311090SDavid.Hollister@Sun.COM cv_signal(&pwrk->sleep_cv);
68412462Sjesse.butler@oracle.com if (tgt != NULL) {
68511355SDavid.Hollister@Sun.COM mutex_exit(&tgt->statlock);
68611355SDavid.Hollister@Sun.COM }
68712862Sjesse.butler@oracle.com mutex_exit(&pwrk->lock);
68811090SDavid.Hollister@Sun.COM pmcs_unlock_phy(pptr);
68911090SDavid.Hollister@Sun.COM return;
69011090SDavid.Hollister@Sun.COM }
69111090SDavid.Hollister@Sun.COM
69212462Sjesse.butler@oracle.com if (tgt == NULL) {
69311355SDavid.Hollister@Sun.COM pmcs_prt(pwp, PMCS_PRT_DEBUG1, pptr, NULL,
69411355SDavid.Hollister@Sun.COM "%s: Not scheduling SSP event recovery for NULL tgt"
69511355SDavid.Hollister@Sun.COM " pwrk(%p) tag(0x%x)", __func__, (void *)pwrk,
69611355SDavid.Hollister@Sun.COM pwrk->htag);
69712862Sjesse.butler@oracle.com mutex_exit(&pwrk->lock);
69812862Sjesse.butler@oracle.com pmcs_unlock_phy(pptr);
69911355SDavid.Hollister@Sun.COM return;
70011355SDavid.Hollister@Sun.COM }
70111355SDavid.Hollister@Sun.COM
70211090SDavid.Hollister@Sun.COM /*
70312060SDavid.Hollister@Sun.COM * If the SSP event was an OPEN_RETRY_TIMEOUT, we don't want
70412060SDavid.Hollister@Sun.COM * to go through the recovery (abort/LU reset) process.
70512060SDavid.Hollister@Sun.COM * Simply complete the command and return it as STATUS_BUSY.
70612060SDavid.Hollister@Sun.COM * This will cause the target driver to simply retry.
70712060SDavid.Hollister@Sun.COM */
70812060SDavid.Hollister@Sun.COM if (event == PMCOUT_STATUS_IO_XFER_OPEN_RETRY_TIMEOUT) {
70912060SDavid.Hollister@Sun.COM pmcs_prt(pwp, PMCS_PRT_DEBUG, pptr, tgt,
71012060SDavid.Hollister@Sun.COM "%s: Got OPEN_RETRY_TIMEOUT event (htag 0x%08x)",
71112060SDavid.Hollister@Sun.COM __func__, pwrk->htag);
71212060SDavid.Hollister@Sun.COM
71312060SDavid.Hollister@Sun.COM mutex_exit(&tgt->statlock);
71412862Sjesse.butler@oracle.com /* Note: work remains locked for the callback */
71512060SDavid.Hollister@Sun.COM pmcs_unlock_phy(pptr);
71612060SDavid.Hollister@Sun.COM pwrk->ssp_event = event;
71712060SDavid.Hollister@Sun.COM callback = (pmcs_cb_t)pwrk->ptr;
71812060SDavid.Hollister@Sun.COM (*callback)(pwp, pwrk, iomb);
71912060SDavid.Hollister@Sun.COM return;
72012060SDavid.Hollister@Sun.COM }
72112060SDavid.Hollister@Sun.COM
72212060SDavid.Hollister@Sun.COM /*
72311090SDavid.Hollister@Sun.COM * To recover from primary failures,
72411090SDavid.Hollister@Sun.COM * we need to schedule handling events recovery.
72511090SDavid.Hollister@Sun.COM */
72611090SDavid.Hollister@Sun.COM tgt->event_recovery = 1;
72711090SDavid.Hollister@Sun.COM mutex_exit(&tgt->statlock);
72812862Sjesse.butler@oracle.com pwrk->ssp_event = event;
72912862Sjesse.butler@oracle.com mutex_exit(&pwrk->lock);
73011090SDavid.Hollister@Sun.COM pmcs_unlock_phy(pptr);
73111090SDavid.Hollister@Sun.COM pmcs_prt(pwp, PMCS_PRT_DEBUG, pptr, tgt,
73211090SDavid.Hollister@Sun.COM "%s: Scheduling SSP event recovery for tgt(0x%p) "
73311090SDavid.Hollister@Sun.COM "pwrk(%p) tag(0x%x)", __func__, (void *)tgt, (void *)pwrk,
73411090SDavid.Hollister@Sun.COM pwrk->htag);
73511090SDavid.Hollister@Sun.COM SCHEDULE_WORK(pwp, PMCS_WORK_SSP_EVT_RECOVERY);
73611090SDavid.Hollister@Sun.COM }
73711090SDavid.Hollister@Sun.COM
73811090SDavid.Hollister@Sun.COM /* Work cannot be completed until event recovery is completed. */
73911090SDavid.Hollister@Sun.COM }
74011090SDavid.Hollister@Sun.COM
74111090SDavid.Hollister@Sun.COM /*
74211090SDavid.Hollister@Sun.COM * SSP target event recovery
743*13103Ssrikanth.suravajhala@oracle.com * phy->lock should be held upon entry.
744*13103Ssrikanth.suravajhala@oracle.com * pwrk->lock should be held upon entry and gets released by this routine.
745*13103Ssrikanth.suravajhala@oracle.com * tgt->statlock should not be held.
74611090SDavid.Hollister@Sun.COM */
74711090SDavid.Hollister@Sun.COM void
pmcs_tgt_event_recovery(pmcs_hw_t * pwp,pmcwork_t * pwrk)74811090SDavid.Hollister@Sun.COM pmcs_tgt_event_recovery(pmcs_hw_t *pwp, pmcwork_t *pwrk)
74911090SDavid.Hollister@Sun.COM {
75011090SDavid.Hollister@Sun.COM pmcs_phy_t *pptr = pwrk->phy;
75111090SDavid.Hollister@Sun.COM pmcs_cmd_t *sp = pwrk->arg;
75211090SDavid.Hollister@Sun.COM pmcs_lun_t *lun = sp->cmd_lun;
75311090SDavid.Hollister@Sun.COM pmcs_xscsi_t *tgt = pwrk->xp;
75411090SDavid.Hollister@Sun.COM uint32_t event;
75511090SDavid.Hollister@Sun.COM uint32_t htag;
75611090SDavid.Hollister@Sun.COM uint32_t status;
75711090SDavid.Hollister@Sun.COM int rv;
75811090SDavid.Hollister@Sun.COM
75911090SDavid.Hollister@Sun.COM ASSERT(pwrk->arg != NULL);
76011090SDavid.Hollister@Sun.COM ASSERT(pwrk->xp != NULL);
76111090SDavid.Hollister@Sun.COM pmcs_prt(pwp, PMCS_PRT_DEBUG, pptr, tgt,
76211090SDavid.Hollister@Sun.COM "%s: event recovery for target 0x%p", __func__, (void *)pwrk->xp);
76311090SDavid.Hollister@Sun.COM htag = pwrk->htag;
76411090SDavid.Hollister@Sun.COM event = pwrk->ssp_event;
76511090SDavid.Hollister@Sun.COM pwrk->ssp_event = 0xffffffff;
76612060SDavid.Hollister@Sun.COM
767*13103Ssrikanth.suravajhala@oracle.com mutex_exit(&pwrk->lock);
768*13103Ssrikanth.suravajhala@oracle.com
76911090SDavid.Hollister@Sun.COM if (event == PMCOUT_STATUS_XFER_ERR_BREAK ||
77011090SDavid.Hollister@Sun.COM event == PMCOUT_STATUS_XFER_ERR_PHY_NOT_READY ||
77111090SDavid.Hollister@Sun.COM event == PMCOUT_STATUS_XFER_ERROR_CMD_ISSUE_ACK_NAK_TIMEOUT) {
77211090SDavid.Hollister@Sun.COM /* Command may be still pending on device */
77311090SDavid.Hollister@Sun.COM rv = pmcs_ssp_tmf(pwp, pptr, SAS_QUERY_TASK, htag,
77411090SDavid.Hollister@Sun.COM lun->lun_num, &status);
77511090SDavid.Hollister@Sun.COM if (rv != 0) {
77611090SDavid.Hollister@Sun.COM goto out;
77711090SDavid.Hollister@Sun.COM }
77811090SDavid.Hollister@Sun.COM if (status == SAS_RSP_TMF_COMPLETE) {
77911090SDavid.Hollister@Sun.COM /* Command NOT pending on a device */
78011090SDavid.Hollister@Sun.COM pmcs_prt(pwp, PMCS_PRT_DEBUG, pptr, tgt,
78111090SDavid.Hollister@Sun.COM "%s: No pending command for tgt 0x%p",
78211090SDavid.Hollister@Sun.COM __func__, (void *)tgt);
78311090SDavid.Hollister@Sun.COM /* Nothing more to do, just abort it on chip */
78411090SDavid.Hollister@Sun.COM htag = 0;
78511090SDavid.Hollister@Sun.COM }
78611090SDavid.Hollister@Sun.COM }
78711090SDavid.Hollister@Sun.COM /*
78811090SDavid.Hollister@Sun.COM * All other events left the command pending in the host
78911090SDavid.Hollister@Sun.COM * Send abort task and abort it on the chip
79011090SDavid.Hollister@Sun.COM */
79111090SDavid.Hollister@Sun.COM if (htag != 0) {
79211090SDavid.Hollister@Sun.COM if (pmcs_ssp_tmf(pwp, pptr, SAS_ABORT_TASK, htag,
79311090SDavid.Hollister@Sun.COM lun->lun_num, &status))
79411090SDavid.Hollister@Sun.COM goto out;
79511090SDavid.Hollister@Sun.COM }
796*13103Ssrikanth.suravajhala@oracle.com (void) pmcs_abort(pwp, pptr, htag, 0, 1);
79711090SDavid.Hollister@Sun.COM /*
79811090SDavid.Hollister@Sun.COM * Abort either took care of work completion, or put device in
79911090SDavid.Hollister@Sun.COM * a recovery state
80011090SDavid.Hollister@Sun.COM */
80111090SDavid.Hollister@Sun.COM return;
80211090SDavid.Hollister@Sun.COM out:
80311090SDavid.Hollister@Sun.COM /* Abort failed, do full device recovery */
804*13103Ssrikanth.suravajhala@oracle.com mutex_enter(&pwrk->lock);
805*13103Ssrikanth.suravajhala@oracle.com tgt = pwrk->xp;
806*13103Ssrikanth.suravajhala@oracle.com mutex_exit(&pwrk->lock);
807*13103Ssrikanth.suravajhala@oracle.com if (tgt != NULL) {
808*13103Ssrikanth.suravajhala@oracle.com mutex_enter(&tgt->statlock);
809*13103Ssrikanth.suravajhala@oracle.com pmcs_start_dev_state_recovery(tgt, pptr);
810*13103Ssrikanth.suravajhala@oracle.com mutex_exit(&tgt->statlock);
81111090SDavid.Hollister@Sun.COM }
81211090SDavid.Hollister@Sun.COM }
81311090SDavid.Hollister@Sun.COM
81411090SDavid.Hollister@Sun.COM /*
81511090SDavid.Hollister@Sun.COM * SSP event recovery task.
81611090SDavid.Hollister@Sun.COM */
81711090SDavid.Hollister@Sun.COM void
pmcs_ssp_event_recovery(pmcs_hw_t * pwp)81811090SDavid.Hollister@Sun.COM pmcs_ssp_event_recovery(pmcs_hw_t *pwp)
81911090SDavid.Hollister@Sun.COM {
82011090SDavid.Hollister@Sun.COM int idx;
82111090SDavid.Hollister@Sun.COM pmcs_xscsi_t *tgt;
82211090SDavid.Hollister@Sun.COM pmcs_cmd_t *cp;
82311090SDavid.Hollister@Sun.COM pmcwork_t *pwrk;
82411090SDavid.Hollister@Sun.COM pmcs_phy_t *pphy;
82511090SDavid.Hollister@Sun.COM int er_flag;
82611090SDavid.Hollister@Sun.COM uint32_t idxpwrk;
82711090SDavid.Hollister@Sun.COM
82811090SDavid.Hollister@Sun.COM restart:
82911090SDavid.Hollister@Sun.COM for (idx = 0; idx < pwp->max_dev; idx++) {
83011090SDavid.Hollister@Sun.COM mutex_enter(&pwp->lock);
83111090SDavid.Hollister@Sun.COM tgt = pwp->targets[idx];
83211090SDavid.Hollister@Sun.COM mutex_exit(&pwp->lock);
83311347SRamana.Srikanth@Sun.COM if (tgt == NULL) {
83411347SRamana.Srikanth@Sun.COM continue;
83511347SRamana.Srikanth@Sun.COM }
83611347SRamana.Srikanth@Sun.COM
83711347SRamana.Srikanth@Sun.COM mutex_enter(&tgt->statlock);
83811347SRamana.Srikanth@Sun.COM if (!tgt->assigned) {
83911090SDavid.Hollister@Sun.COM mutex_exit(&tgt->statlock);
84011347SRamana.Srikanth@Sun.COM continue;
84111347SRamana.Srikanth@Sun.COM }
84211347SRamana.Srikanth@Sun.COM pphy = tgt->phy;
84311347SRamana.Srikanth@Sun.COM er_flag = tgt->event_recovery;
84411347SRamana.Srikanth@Sun.COM mutex_exit(&tgt->statlock);
84511347SRamana.Srikanth@Sun.COM
84611347SRamana.Srikanth@Sun.COM if ((pphy == NULL) || (er_flag == 0)) {
84711347SRamana.Srikanth@Sun.COM continue;
84811347SRamana.Srikanth@Sun.COM }
84911347SRamana.Srikanth@Sun.COM
85011347SRamana.Srikanth@Sun.COM pmcs_lock_phy(pphy);
85111347SRamana.Srikanth@Sun.COM pmcs_prt(pwp, PMCS_PRT_DEBUG, pphy, tgt,
85211347SRamana.Srikanth@Sun.COM "%s: found target(0x%p)", __func__, (void *) tgt);
85311090SDavid.Hollister@Sun.COM
85411347SRamana.Srikanth@Sun.COM /* Check what cmd expects recovery */
85511347SRamana.Srikanth@Sun.COM mutex_enter(&tgt->aqlock);
85611347SRamana.Srikanth@Sun.COM STAILQ_FOREACH(cp, &tgt->aq, cmd_next) {
85711347SRamana.Srikanth@Sun.COM idxpwrk = PMCS_TAG_INDEX(cp->cmd_tag);
85811347SRamana.Srikanth@Sun.COM pwrk = &pwp->work[idxpwrk];
859*13103Ssrikanth.suravajhala@oracle.com mutex_enter(&pwrk->lock);
86011347SRamana.Srikanth@Sun.COM if (pwrk->htag != cp->cmd_tag) {
86111347SRamana.Srikanth@Sun.COM /*
86211347SRamana.Srikanth@Sun.COM * aq may contain TMF commands, so we
86311347SRamana.Srikanth@Sun.COM * may not find work structure with htag
86411347SRamana.Srikanth@Sun.COM */
865*13103Ssrikanth.suravajhala@oracle.com mutex_exit(&pwrk->lock);
866*13103Ssrikanth.suravajhala@oracle.com continue;
86711347SRamana.Srikanth@Sun.COM }
868*13103Ssrikanth.suravajhala@oracle.com if (!PMCS_COMMAND_DONE(pwrk) &&
869*13103Ssrikanth.suravajhala@oracle.com (pwrk->ssp_event != 0) &&
87011347SRamana.Srikanth@Sun.COM (pwrk->ssp_event != PMCS_REC_EVENT)) {
87111347SRamana.Srikanth@Sun.COM pmcs_prt(pwp, PMCS_PRT_DEBUG, pphy, tgt,
87211347SRamana.Srikanth@Sun.COM "%s: pwrk(%p) htag(0x%x)",
87311347SRamana.Srikanth@Sun.COM __func__, (void *) pwrk, cp->cmd_tag);
87411090SDavid.Hollister@Sun.COM mutex_exit(&tgt->aqlock);
875*13103Ssrikanth.suravajhala@oracle.com /*
876*13103Ssrikanth.suravajhala@oracle.com * pwrk->lock gets dropped in
877*13103Ssrikanth.suravajhala@oracle.com * pmcs_tgt_event_recovery()
878*13103Ssrikanth.suravajhala@oracle.com */
87911347SRamana.Srikanth@Sun.COM pmcs_tgt_event_recovery(pwp, pwrk);
88011090SDavid.Hollister@Sun.COM pmcs_unlock_phy(pphy);
881*13103Ssrikanth.suravajhala@oracle.com /* All bets are off on tgt/aq now, restart */
88211347SRamana.Srikanth@Sun.COM goto restart;
88311090SDavid.Hollister@Sun.COM }
884*13103Ssrikanth.suravajhala@oracle.com mutex_exit(&pwrk->lock);
88511090SDavid.Hollister@Sun.COM }
88611347SRamana.Srikanth@Sun.COM mutex_exit(&tgt->aqlock);
887*13103Ssrikanth.suravajhala@oracle.com mutex_enter(&tgt->statlock);
88811347SRamana.Srikanth@Sun.COM tgt->event_recovery = 0;
88911347SRamana.Srikanth@Sun.COM pmcs_prt(pwp, PMCS_PRT_DEBUG, pphy, tgt,
89011347SRamana.Srikanth@Sun.COM "%s: end of SSP event recovery for target(0x%p)",
89111347SRamana.Srikanth@Sun.COM __func__, (void *) tgt);
89211347SRamana.Srikanth@Sun.COM mutex_exit(&tgt->statlock);
89311347SRamana.Srikanth@Sun.COM pmcs_unlock_phy(pphy);
89411090SDavid.Hollister@Sun.COM }
89511090SDavid.Hollister@Sun.COM pmcs_prt(pwp, PMCS_PRT_DEBUG, NULL, NULL,
89611090SDavid.Hollister@Sun.COM "%s: end of SSP event recovery for pwp(0x%p)", __func__,
89711090SDavid.Hollister@Sun.COM (void *) pwp);
89811090SDavid.Hollister@Sun.COM }
89911090SDavid.Hollister@Sun.COM
90011090SDavid.Hollister@Sun.COM void
pmcs_start_dev_state_recovery(pmcs_xscsi_t * xp,pmcs_phy_t * phyp)90111090SDavid.Hollister@Sun.COM pmcs_start_dev_state_recovery(pmcs_xscsi_t *xp, pmcs_phy_t *phyp)
90211090SDavid.Hollister@Sun.COM {
90311090SDavid.Hollister@Sun.COM ASSERT(mutex_owned(&xp->statlock));
90411090SDavid.Hollister@Sun.COM ASSERT(xp->pwp != NULL);
90511090SDavid.Hollister@Sun.COM
90611090SDavid.Hollister@Sun.COM if (xp->recover_wait == 0) {
90711090SDavid.Hollister@Sun.COM pmcs_prt(xp->pwp, PMCS_PRT_DEBUG_DEV_STATE, phyp, xp,
90811090SDavid.Hollister@Sun.COM "%s: Start ds_recovery for tgt 0x%p/PHY 0x%p (%s)",
90911090SDavid.Hollister@Sun.COM __func__, (void *)xp, (void *)phyp, phyp->path);
91011090SDavid.Hollister@Sun.COM xp->recover_wait = 1;
91111090SDavid.Hollister@Sun.COM
91211090SDavid.Hollister@Sun.COM /*
91311090SDavid.Hollister@Sun.COM * Rather than waiting for the watchdog timer, we'll
91411090SDavid.Hollister@Sun.COM * kick it right now.
91511090SDavid.Hollister@Sun.COM */
91611090SDavid.Hollister@Sun.COM SCHEDULE_WORK(xp->pwp, PMCS_WORK_DS_ERR_RECOVERY);
91711090SDavid.Hollister@Sun.COM (void) ddi_taskq_dispatch(xp->pwp->tq, pmcs_worker, xp->pwp,
91811090SDavid.Hollister@Sun.COM DDI_NOSLEEP);
91911090SDavid.Hollister@Sun.COM }
92011090SDavid.Hollister@Sun.COM }
92111090SDavid.Hollister@Sun.COM
92211090SDavid.Hollister@Sun.COM /*
92311090SDavid.Hollister@Sun.COM * Increment the phy ds error retry count.
92411090SDavid.Hollister@Sun.COM * If too many retries, mark phy dead and restart discovery;
92511090SDavid.Hollister@Sun.COM * otherwise schedule ds recovery.
92611090SDavid.Hollister@Sun.COM */
92711090SDavid.Hollister@Sun.COM static void
pmcs_handle_ds_recovery_error(pmcs_phy_t * phyp,pmcs_xscsi_t * tgt,pmcs_hw_t * pwp,const char * func_name,char * reason_string)92811090SDavid.Hollister@Sun.COM pmcs_handle_ds_recovery_error(pmcs_phy_t *phyp, pmcs_xscsi_t *tgt,
92911347SRamana.Srikanth@Sun.COM pmcs_hw_t *pwp, const char *func_name, char *reason_string)
93011090SDavid.Hollister@Sun.COM {
93111090SDavid.Hollister@Sun.COM ASSERT(mutex_owned(&phyp->phy_lock));
93211090SDavid.Hollister@Sun.COM ASSERT((tgt == NULL) || mutex_owned(&tgt->statlock));
93311090SDavid.Hollister@Sun.COM
93411090SDavid.Hollister@Sun.COM phyp->ds_recovery_retries++;
93511090SDavid.Hollister@Sun.COM
93611090SDavid.Hollister@Sun.COM if (phyp->ds_recovery_retries > PMCS_MAX_DS_RECOVERY_RETRIES) {
93711090SDavid.Hollister@Sun.COM pmcs_prt(pwp, PMCS_PRT_DEBUG, phyp, tgt,
93811090SDavid.Hollister@Sun.COM "%s: retry limit reached after %s to PHY %s failed",
93911090SDavid.Hollister@Sun.COM func_name, reason_string, phyp->path);
94011090SDavid.Hollister@Sun.COM if (tgt != NULL) {
94111090SDavid.Hollister@Sun.COM tgt->recover_wait = 0;
94211090SDavid.Hollister@Sun.COM }
94311347SRamana.Srikanth@Sun.COM /*
94411347SRamana.Srikanth@Sun.COM * Mark the PHY as dead and it and its parent as changed,
94511347SRamana.Srikanth@Sun.COM * then restart discovery
94611347SRamana.Srikanth@Sun.COM */
94711090SDavid.Hollister@Sun.COM phyp->dead = 1;
94811347SRamana.Srikanth@Sun.COM PHY_CHANGED(pwp, phyp);
94911347SRamana.Srikanth@Sun.COM if (phyp->parent)
95011347SRamana.Srikanth@Sun.COM PHY_CHANGED(pwp, phyp->parent);
95111090SDavid.Hollister@Sun.COM RESTART_DISCOVERY(pwp);
95211090SDavid.Hollister@Sun.COM } else if ((phyp->ds_prev_good_recoveries >
95311090SDavid.Hollister@Sun.COM PMCS_MAX_DS_RECOVERY_RETRIES) &&
95411090SDavid.Hollister@Sun.COM (phyp->last_good_recovery + drv_usectohz(PMCS_MAX_DS_RECOVERY_TIME)
95511090SDavid.Hollister@Sun.COM < ddi_get_lbolt())) {
95611090SDavid.Hollister@Sun.COM pmcs_prt(pwp, PMCS_PRT_DEBUG, phyp, tgt, "%s: max number of "
95711090SDavid.Hollister@Sun.COM "successful recoveries reached, declaring PHY %s dead",
95811090SDavid.Hollister@Sun.COM __func__, phyp->path);
95911090SDavid.Hollister@Sun.COM if (tgt != NULL) {
96011090SDavid.Hollister@Sun.COM tgt->recover_wait = 0;
96111090SDavid.Hollister@Sun.COM }
96211347SRamana.Srikanth@Sun.COM /*
96311347SRamana.Srikanth@Sun.COM * Mark the PHY as dead and its parent as changed,
96411347SRamana.Srikanth@Sun.COM * then restart discovery
96511347SRamana.Srikanth@Sun.COM */
96611090SDavid.Hollister@Sun.COM phyp->dead = 1;
96711347SRamana.Srikanth@Sun.COM PHY_CHANGED(pwp, phyp);
96811347SRamana.Srikanth@Sun.COM if (phyp->parent)
96911347SRamana.Srikanth@Sun.COM PHY_CHANGED(pwp, phyp->parent);
97011090SDavid.Hollister@Sun.COM RESTART_DISCOVERY(pwp);
97111090SDavid.Hollister@Sun.COM } else {
97211090SDavid.Hollister@Sun.COM SCHEDULE_WORK(pwp, PMCS_WORK_DS_ERR_RECOVERY);
97311090SDavid.Hollister@Sun.COM }
97411090SDavid.Hollister@Sun.COM }
975