pmcs_subr.c revision 6745c559e4b531cf336a91f4653445c32ee46693
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * CDDL HEADER START
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * The contents of this file are subject to the terms of the
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Common Development and Distribution License (the "License").
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * You may not use this file except in compliance with the License.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * See the License for the specific language governing permissions
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * and limitations under the License.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * When distributing Covered Code, include this CDDL HEADER in each
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * If applicable, add the following below this CDDL HEADER, with the
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * fields enclosed by brackets "[]" replaced with your own identifying
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * information: Portions Copyright [yyyy] [name of copyright owner]
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * CDDL HEADER END
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Use is subject to license terms.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * This file contains various support routines.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Local static data
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * SAS Topology Configuration
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dhstatic void pmcs_configure_expander(pmcs_hw_t *, pmcs_phy_t *, pmcs_iport_t *);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dhstatic boolean_t pmcs_check_expanders(pmcs_hw_t *, pmcs_phy_t *);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dhstatic void pmcs_check_expander(pmcs_hw_t *, pmcs_phy_t *);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dhstatic void pmcs_clear_expander(pmcs_hw_t *, pmcs_phy_t *, int);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dhstatic int pmcs_expander_get_nphy(pmcs_hw_t *, pmcs_phy_t *);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dhstatic int pmcs_expander_content_discover(pmcs_hw_t *, pmcs_phy_t *,
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dhstatic int pmcs_smp_function_result(pmcs_hw_t *, smp_response_frame_t *);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dhstatic boolean_t pmcs_validate_devid(pmcs_phy_t *, pmcs_phy_t *, uint32_t);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dhstatic int pmcs_configure_new_devices(pmcs_hw_t *, pmcs_phy_t *);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dhstatic boolean_t pmcs_report_iport_observations(pmcs_hw_t *, pmcs_iport_t *,
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dhstatic pmcs_phy_t *pmcs_find_phy_needing_work(pmcs_hw_t *, pmcs_phy_t *);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dhstatic boolean_t pmcs_configure_phy(pmcs_hw_t *, pmcs_phy_t *);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dhstatic pmcs_iport_t *pmcs_get_iport_by_ua(pmcs_hw_t *, char *);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Often used strings
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dhconst char pmcs_nowrk[] = "%s: unable to get work structure";
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dhconst char pmcs_nomsg[] = "%s: unable to get Inbound Message entry";
6745c559e4b531cf336a91f4653445c32ee46693Jesse Butlerconst char pmcs_timeo[] = "%s: command timed out";
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Some Initial setup steps.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Check current state. If we're not at READY state,
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * we can't go further.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh if ((scratch & PMCS_MSGU_AAP_STATE_MASK) == PMCS_MSGU_AAP_STATE_ERROR) {
c3bc407cfbd238a18e4728ad5f36f39cecdb062fdh "%s: AAP Error State (0x%x)",
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return (-1);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh if ((scratch & PMCS_MSGU_AAP_STATE_MASK) != PMCS_MSGU_AAP_STATE_READY) {
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "%s: AAP unit not ready (state 0x%x)",
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return (-1);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Read the offset from the Message Unit scratchpad 0 register.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * This allows us to read the MPI Configuration table.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Check its signature for validity.
c3bc407cfbd238a18e4728ad5f36f39cecdb062fdh "%s: bad MPI Table Length (register offset=0x%08x, "
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return (-1);
c3bc407cfbd238a18e4728ad5f36f39cecdb062fdh "%s: bad MPI BAR (register BAROFF=0x%08x, "
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return (-1);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh if (pmcs_rd_mpi_tbl(pwp, PMCS_MPI_AS) != PMCS_SIGNATURE) {
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "%s: Bad MPI Configuration Table Signature 0x%x", __func__,
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return (-1);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh if (pmcs_rd_mpi_tbl(pwp, PMCS_MPI_IR) != PMCS_MPI_REVISION1) {
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return (-1);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Generate offsets for the General System, Inbound Queue Configuration
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * and Outbound Queue configuration tables. This way the macros to
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * access those tables will work correctly.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh pwp->max_dev = pmcs_rd_mpi_tbl(pwp, PMCS_MPI_INFO0) >> 16;
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh pwp->max_iq = PMCS_MNIQ(pmcs_rd_mpi_tbl(pwp, PMCS_MPI_INFO1));
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh pwp->max_oq = PMCS_MNOQ(pmcs_rd_mpi_tbl(pwp, PMCS_MPI_INFO1));
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh pwp->nphy = PMCS_NPHY(pmcs_rd_mpi_tbl(pwp, PMCS_MPI_INFO1));
c3bc407cfbd238a18e4728ad5f36f39cecdb062fdh "%s: not enough Inbound Queues supported "
c3bc407cfbd238a18e4728ad5f36f39cecdb062fdh "(need %d, max_oq=%d)", __func__, pwp->max_iq, PMCS_NIQ);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return (-1);
c3bc407cfbd238a18e4728ad5f36f39cecdb062fdh "%s: not enough Outbound Queues supported "
c3bc407cfbd238a18e4728ad5f36f39cecdb062fdh "(need %d, max_oq=%d)", __func__, pwp->max_oq, PMCS_NOQ);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return (-1);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return (-1);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Verify that ioq_depth is valid (> 0 and not so high that it
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * would cause us to overrun the chip with commands).
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "%s: I/O queue depth set to 0. Setting to %d",
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "%s: I/O queue depth set too low (%d). Setting to %d",
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh if (pwp->ioq_depth > (pwp->max_cmd / (PMCS_IO_IQ_MASK + 1))) {
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "%s: I/O queue depth set too high (%d). Setting to %d",
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Allocate consistent memory for OQs and IQs.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * The Rev C chip has the ability to do PIO to or from consistent
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * memory anywhere in a 64 bit address space, but the firmware is
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * not presently set up to do so.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh pwp->oqp_dma_attr.dma_attr_addr_hi = 0x000000FFFFFFFFFFull;
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh for (i = 0; i < PMCS_NIQ; i++) {
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "Failed to setup DMA for iqp[%d]", i);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return (-1);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh for (i = 0; i < PMCS_NOQ; i++) {
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "Failed to setup DMA for oqp[%d]", i);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return (-1);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Install the IQ and OQ addresses (and null out the rest).
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh pwp->iqpi_offset[i] = pmcs_rd_iqc_tbl(pwp, PMCS_IQPIOFFX(i));
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh pwp->oqci_offset[i] = pmcs_rd_oqc_tbl(pwp, PMCS_OQCIOFFX(i));
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Set up logging, if defined.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh pmcs_wr_mpi_tbl(pwp, PMCS_MPI_MELBS, PMCS_FWLOG_SIZE >> 1);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh pmcs_wr_mpi_tbl(pwp, PMCS_MPI_IELBS, PMCS_FWLOG_SIZE >> 1);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Interrupt vectors, outbound queues, and odb_auto_clear
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * If we got 4 interrupt vectors, we'll assign one to each outbound
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * queue as well as the fatal interrupt, and auto clear can be set
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * for each.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * If we only got 2 vectors, one will be used for I/O completions
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * and the other for the other two vectors. In this case, auto_
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * clear can only be set for I/Os, which is fine. The fatal
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * interrupt will be mapped to the PMCS_FATAL_INTERRUPT bit, which
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * is not an interrupt vector.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * If we only got 1 interrupt vector, auto_clear must be set to 0,
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * and again the fatal interrupt will be mapped to the
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * PMCS_FATAL_INTERRUPT bit (again, not an interrupt vector).
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh PMCS_FERRIE | (PMCS_FATAL_INTERRUPT << PMCS_FERIV_SHIFT));
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Enable Interrupt Reassertion
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Default Delay 1000us
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh pmcs_wr_mpi_tbl(pwp, PMCS_MPI_FERR, ferr | PMCS_MPI_IRAE);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh pmcs_wr_topunit(pwp, PMCS_OBDB_AUTO_CLR, pwp->odb_auto_clear);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return (0);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Start the Message Passing protocol with the PMC chip.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh pmcs_wr_msgunit(pwp, PMCS_MSGU_IBDB, PMCS_MSGU_IBDB_MPIINI);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh for (i = 0; i < 1000; i++) {
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh if (pmcs_rd_msgunit(pwp, PMCS_MSGU_IBDB) & PMCS_MSGU_IBDB_MPIINI) {
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return (-1);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Check to make sure we got to INIT state.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return (-1);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return (0);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Stop the Message Passing protocol with the PMC chip.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh pmcs_wr_msgunit(pwp, PMCS_MSGU_IBDB, PMCS_MSGU_IBDB_MPICTU);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh for (i = 0; i < 2000; i++) {
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh if (pmcs_rd_msgunit(pwp, PMCS_MSGU_IBDB) & PMCS_MSGU_IBDB_MPICTU) {
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return (-1);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return (0);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Do a sequence of ECHO messages to test for MPI functionality,
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * all inbound and outbound queue functionality and interrupts.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * We want iterations to be max_cmd * 3 to ensure that we run the
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * echo test enough times to iterate through every inbound queue
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * at least twice.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh /* This is on the high priority queue */
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "%s: command timed out on echo test #%d",
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * The intr_threshold is adjusted by PMCS_INTR_THRESHOLD in order to
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * remove the overhead of things like the delay in getting signaled
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * for completion.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh if (echo_total != 0) {
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Start the (real) phys
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dhpmcs_start_phy(pmcs_hw_t *pwp, int phynum, int linkmode, int speed)
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return (0);
c3bc407cfbd238a18e4728ad5f36f39cecdb062fdh pmcs_prt(pwp, PMCS_PRT_ERR, pptr, NULL, pmcs_nowrk, __func__);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return (-1);
c3bc407cfbd238a18e4728ad5f36f39cecdb062fdh pmcs_prt(pwp, PMCS_PRT_ERR, pptr, NULL, pmcs_nomsg, __func__);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return (-1);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh msg[0] = LE_32(PMCS_HIPRI(pwp, PMCS_OQ_EVENTS, PMCIN_PHY_START));
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh (void) memcpy(&msg[3], &sap, sizeof (sas_identify_af_t));
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh pptr->state.prog_min_rate = (lowbit((ulong_t)speed) - 1);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh pptr->state.prog_max_rate = (highbit((ulong_t)speed) - 1);
6745c559e4b531cf336a91f4653445c32ee46693Jesse Butler pmcs_prt(pwp, PMCS_PRT_DEBUG, pptr, NULL, pmcs_timeo, __func__);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return (0);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return (-1);
c3bc407cfbd238a18e4728ad5f36f39cecdb062fdh "%s: failed to reset counters on PHY (%d)",
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return (0);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Called with PHY locked
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dhpmcs_reset_phy(pmcs_hw_t *pwp, pmcs_phy_t *pptr, uint8_t type)
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh const char *mbar;
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh if (level > 0) {
c3bc407cfbd238a18e4728ad5f36f39cecdb062fdh pmcs_prt(pwp, PMCS_PRT_ERR, pptr, NULL, pmcs_nowrk, __func__);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * If level > 0, we need to issue an SMP_REQUEST with a PHY_CONTROL
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * function to do either a link reset or hard reset. If level == 0,
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * then we do a LOCAL_PHY_CONTROL IOMB to do link/hard reset to the
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * root (local) PHY
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Send SMP PHY CONTROL/HARD or LINK RESET
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "%s: sending %s to %s for phy 0x%x",
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Unlike most other Outbound messages, status for
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * a local phy operation is in DWORD 3.
c3bc407cfbd238a18e4728ad5f36f39cecdb062fdh pmcs_prt(pwp, PMCS_PRT_ERR, pptr, NULL, pmcs_nomsg, __func__);
6745c559e4b531cf336a91f4653445c32ee46693Jesse Butler /* SMP serialization */
6745c559e4b531cf336a91f4653445c32ee46693Jesse Butler /* SMP serialization */
6745c559e4b531cf336a91f4653445c32ee46693Jesse Butler pmcs_prt(pwp, PMCS_PRT_DEBUG, pptr, NULL, pmcs_timeo, __func__);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "%s: Unable to issue SMP abort for htag 0x%08x",
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "%s: Issuing SMP ABORT for htag 0x%08x",
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return (0);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Stop the (real) phys. No PHY or softstate locks are required as this only
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * happens during detach.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh msg[0] = LE_32(PMCS_HIPRI(pwp, PMCS_OQ_EVENTS, PMCIN_PHY_STOP));
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Make this unconfigured now.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * No locks should be required as this is only called during detach
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Run SAS_DIAG_EXECUTE with cmd and cmd_desc passed.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * ERR_CNT_RESET: return status of cmd
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * DIAG_REPORT_GET: return value of the counter
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dhpmcs_sas_diag_execute(pmcs_hw_t *pwp, uint32_t cmd, uint32_t cmd_desc,
c3bc407cfbd238a18e4728ad5f36f39cecdb062fdh pmcs_prt(pwp, PMCS_PRT_ERR, NULL, NULL, pmcs_nowrk, __func__);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh msg[0] = LE_32(PMCS_HIPRI(pwp, PMCS_OQ_EVENTS, PMCIN_SAS_DIAG_EXECUTE));
c3bc407cfbd238a18e4728ad5f36f39cecdb062fdh pmcs_prt(pwp, PMCS_PRT_ERR, NULL, NULL, pmcs_nomsg, __func__);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh /* Return for counter reset */
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh /* Return for counter value */
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh/* Get the current value of the counter for desc on phynum and return it. */
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dhpmcs_get_diag_report(pmcs_hw_t *pwp, uint32_t desc, uint8_t phynum)
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return (pmcs_sas_diag_execute(pwp, PMCS_DIAG_REPORT_GET, desc, phynum));
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh/* Clear all of the counters for phynum. Returns the status of the command. */
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Get firmware timestamp
c3bc407cfbd238a18e4728ad5f36f39cecdb062fdh pmcs_prt(pwp, PMCS_PRT_ERR, NULL, NULL, pmcs_nowrk, __func__);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return (-1);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh msg[0] = LE_32(PMCS_HIPRI(pwp, PMCS_OQ_EVENTS, PMCIN_GET_TIME_STAMP));
c3bc407cfbd238a18e4728ad5f36f39cecdb062fdh pmcs_prt(pwp, PMCS_PRT_ERR, NULL, NULL, pmcs_nomsg, __func__);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return (-1);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return (-1);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return (0);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Dump all pertinent registers
c3bc407cfbd238a18e4728ad5f36f39cecdb062fdh pmcs_prt(pwp, PMCS_PRT_INFO, NULL, NULL, "pmcs%d: Register dump start",
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "OBDB (intr): 0x%08x (mask): 0x%08x (clear): 0x%08x",
c3bc407cfbd238a18e4728ad5f36f39cecdb062fdh pmcs_prt(pwp, PMCS_PRT_INFO, NULL, NULL, "SCRATCH0: 0x%08x",
c3bc407cfbd238a18e4728ad5f36f39cecdb062fdh pmcs_prt(pwp, PMCS_PRT_INFO, NULL, NULL, "SCRATCH1: 0x%08x",
c3bc407cfbd238a18e4728ad5f36f39cecdb062fdh pmcs_prt(pwp, PMCS_PRT_INFO, NULL, NULL, "SCRATCH2: 0x%08x",
c3bc407cfbd238a18e4728ad5f36f39cecdb062fdh pmcs_prt(pwp, PMCS_PRT_INFO, NULL, NULL, "SCRATCH3: 0x%08x",
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh for (i = 0; i < PMCS_NIQ; i++) {
c3bc407cfbd238a18e4728ad5f36f39cecdb062fdh pmcs_prt(pwp, PMCS_PRT_INFO, NULL, NULL, "IQ %d: CI %u PI %u",
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh for (i = 0; i < PMCS_NOQ; i++) {
c3bc407cfbd238a18e4728ad5f36f39cecdb062fdh pmcs_prt(pwp, PMCS_PRT_INFO, NULL, NULL, "OQ %d: CI %u PI %u",
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "GST TABLE BASE: 0x%08x (STATE=0x%x QF=%d GSTLEN=%d HMI_ERR=0x%x)",
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh val, PMCS_MPI_S(val), PMCS_QF(val), PMCS_GSTLEN(val) * 4,
c3bc407cfbd238a18e4728ad5f36f39cecdb062fdh pmcs_prt(pwp, PMCS_PRT_INFO, NULL, NULL, "GST TABLE IQFRZ0: 0x%08x",
c3bc407cfbd238a18e4728ad5f36f39cecdb062fdh pmcs_prt(pwp, PMCS_PRT_INFO, NULL, NULL, "GST TABLE IQFRZ1: 0x%08x",
c3bc407cfbd238a18e4728ad5f36f39cecdb062fdh pmcs_prt(pwp, PMCS_PRT_INFO, NULL, NULL, "GST TABLE MSGU TICK: 0x%08x",
c3bc407cfbd238a18e4728ad5f36f39cecdb062fdh pmcs_prt(pwp, PMCS_PRT_INFO, NULL, NULL, "GST TABLE IOP TICK: 0x%08x",
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "GST TABLE PHY%d STARTED=%d LINK=%d RERR=0x%08x",
c3bc407cfbd238a18e4728ad5f36f39cecdb062fdh pmcs_prt(pwp, PMCS_PRT_INFO, NULL, NULL, "pmcs%d: Register dump end",
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Handle SATA Abort and other error processing
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh int r, level = 0;
c3bc407cfbd238a18e4728ad5f36f39cecdb062fdh pmcs_prt(pwp, PMCS_PRT_DEBUG, NULL, NULL, "%s", __func__);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * XXX: Need to make sure this doesn't happen
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * XXX: when non-NCQ commands are running.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh if (r == ENOMEM) {
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh if (r == ENOMEM) {
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh /* what if other failures happened? */
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh if (pmcs_abort(pwp, pptr, pptr->device_id, 1, 1) == ENOMEM) {
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return (0);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Register a device (get a device handle for it).
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Called with PHY lock held.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh (pwrk = pmcs_gwork(pwp, PMCS_TAG_TYPE_WAIT, pptr)) == NULL) {
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh msg[0] = LE_32(PMCS_HIPRI(pwp, PMCS_OQ_GENERAL, PMCIN_REGISTER_DEVICE));
6745c559e4b531cf336a91f4653445c32ee46693Jesse Butler pmcs_prt(pwp, PMCS_PRT_DEBUG, pptr, NULL, pmcs_timeo, __func__);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh switch (status) {
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh if (pmcs_validate_devid(pwp->root_phys, pptr, tmp) == B_FALSE) {
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "%s: phy %s already has bogus devid 0x%x",
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "%s: phy %s already has a device id 0x%x",
c3bc407cfbd238a18e4728ad5f36f39cecdb062fdh "%s: status 0x%x when trying to register device %s",
c3bc407cfbd238a18e4728ad5f36f39cecdb062fdh pmcs_prt(pwp, PMCS_PRT_DEBUG_CONFIG, pptr, NULL, "Phy %s/" SAS_ADDR_FMT
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh " registered with device_id 0x%x (portid %d)", pptr->path,
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Deregister a device (remove a device handle).
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Called with PHY locked.
6745c559e4b531cf336a91f4653445c32ee46693Jesse Butler pmcs_prt(pwp, PMCS_PRT_DEBUG, pptr, NULL, pmcs_timeo, __func__);
c3bc407cfbd238a18e4728ad5f36f39cecdb062fdh "%s: status 0x%x when trying to deregister device %s",
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Deregister all registered devices.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Start at the maximum level and walk back to level 0. This only
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * gets done during detach after all threads and timers have been
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * destroyed, so there's no need to hold the softstate or PHY lock.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Perform a 'soft' reset on the PMC chip
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh uint32_t s2, sfrbits, gsm, rapchk, wapchk, wdpchk, spc, tsmode;
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Disable interrupts
c3bc407cfbd238a18e4728ad5f36f39cecdb062fdh pmcs_prt(pwp, PMCS_PRT_INFO, NULL, NULL, "%s", __func__);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh for (i = 0; i < 100; i++) {
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh if (s2 == 0) {
c3bc407cfbd238a18e4728ad5f36f39cecdb062fdh "%s: PMCS_MSGU_HOST_SOFT_RESET_READY never came "
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return (-1);
c3bc407cfbd238a18e4728ad5f36f39cecdb062fdh pmcs_prt(pwp, PMCS_PRT_DEBUG2, NULL, NULL, "PMCS_MSGU_HOST_SCRATCH0 "
c3bc407cfbd238a18e4728ad5f36f39cecdb062fdh "%08x -> %08x", pmcs_rd_msgunit(pwp, PMCS_MSGU_HOST_SCRATCH0),
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh pmcs_wr_msgunit(pwp, PMCS_MSGU_HOST_SCRATCH0, HST_SFT_RESET_SIG);
c3bc407cfbd238a18e4728ad5f36f39cecdb062fdh pmcs_prt(pwp, PMCS_PRT_DEBUG2, NULL, NULL, "GSM %08x -> %08x", gsm,
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh pmcs_wr_gsm_reg(pwp, GSM_CFG_AND_RESET, gsm & ~PMCS_SOFT_RESET_BITS);
c3bc407cfbd238a18e4728ad5f36f39cecdb062fdh pmcs_prt(pwp, PMCS_PRT_DEBUG2, NULL, NULL, "READ_ADR_PARITY_CHK_EN "
c3bc407cfbd238a18e4728ad5f36f39cecdb062fdh pmcs_prt(pwp, PMCS_PRT_DEBUG2, NULL, NULL, "WRITE_ADR_PARITY_CHK_EN "
c3bc407cfbd238a18e4728ad5f36f39cecdb062fdh pmcs_prt(pwp, PMCS_PRT_DEBUG2, NULL, NULL, "WRITE_DATA_PARITY_CHK_EN "
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Step 5.5 (Temporary workaround for 1.07.xx Beta)
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh tsmode = pmcs_rd_gsm_reg(pwp, PMCS_GPIO_TRISTATE_MODE_ADDR);
c3bc407cfbd238a18e4728ad5f36f39cecdb062fdh pmcs_prt(pwp, PMCS_PRT_DEBUG2, NULL, NULL, "GPIO TSMODE %08x -> %08x",
c3bc407cfbd238a18e4728ad5f36f39cecdb062fdh tsmode, tsmode & ~(PMCS_GPIO_TSMODE_BIT0|PMCS_GPIO_TSMODE_BIT1));
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh tsmode & ~(PMCS_GPIO_TSMODE_BIT0|PMCS_GPIO_TSMODE_BIT1));
c3bc407cfbd238a18e4728ad5f36f39cecdb062fdh pmcs_prt(pwp, PMCS_PRT_DEBUG2, NULL, NULL, "SPC_RESET %08x -> %08x",
c3bc407cfbd238a18e4728ad5f36f39cecdb062fdh pmcs_prt(pwp, PMCS_PRT_DEBUG2, NULL, NULL, "SPC_RESET %08x -> %08x",
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh pmcs_wr_topunit(pwp, PMCS_SPC_RESET, spc & ~(BDMA_CORE_RSTB|OSSP_RSTB));
c3bc407cfbd238a18e4728ad5f36f39cecdb062fdh pmcs_prt(pwp, PMCS_PRT_DEBUG2, NULL, NULL, "SPC_RESET %08x -> %08x",
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh pmcs_wr_topunit(pwp, PMCS_SPC_RESET, spc | (BDMA_CORE_RSTB|OSSP_RSTB));
c3bc407cfbd238a18e4728ad5f36f39cecdb062fdh pmcs_prt(pwp, PMCS_PRT_DEBUG2, NULL, NULL, "GSM %08x -> %08x", gsm,
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh pmcs_wr_gsm_reg(pwp, GSM_CFG_AND_RESET, gsm | PMCS_SOFT_RESET_BITS);
c3bc407cfbd238a18e4728ad5f36f39cecdb062fdh pmcs_prt(pwp, PMCS_PRT_DEBUG2, NULL, NULL, "READ_ADR_PARITY_CHK_EN "
c3bc407cfbd238a18e4728ad5f36f39cecdb062fdh "%08x -> %08x", pmcs_rd_gsm_reg(pwp, READ_ADR_PARITY_CHK_EN),
c3bc407cfbd238a18e4728ad5f36f39cecdb062fdh pmcs_prt(pwp, PMCS_PRT_DEBUG2, NULL, NULL, "WRITE_ADR_PARITY_CHK_EN "
c3bc407cfbd238a18e4728ad5f36f39cecdb062fdh "%08x -> %08x", pmcs_rd_gsm_reg(pwp, WRITE_ADR_PARITY_CHK_EN),
c3bc407cfbd238a18e4728ad5f36f39cecdb062fdh pmcs_prt(pwp, PMCS_PRT_DEBUG2, NULL, NULL, "WRITE_DATA_PARITY_CHK_EN "
c3bc407cfbd238a18e4728ad5f36f39cecdb062fdh "%08x -> %08x", pmcs_rd_gsm_reg(pwp, WRITE_DATA_PARITY_CHK_EN),
c3bc407cfbd238a18e4728ad5f36f39cecdb062fdh pmcs_prt(pwp, PMCS_PRT_DEBUG2, NULL, NULL, "SPC_RESET %08x -> %08x",
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return (-1);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Wait for up to 5 seconds for AAP state to come either ready or error.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh for (i = 0; i < 50; i++) {
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh if ((spc & PMCS_MSGU_AAP_STATE_MASK) != PMCS_MSGU_AAP_STATE_READY) {
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return (-1);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh if (pwp->state == STATE_DEAD || pwp->state == STATE_UNPROBING ||
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh pwp->state == STATE_PROBING || pwp->locks_initted == 0) {
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return (0);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Return at this point if we dont need to startup.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return (0);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Clean up various soft state.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh for (pptr = pwp->root_phys; pptr; pptr = pptr->sibling) {
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh for (i = 0; i < PMCS_NIQ; i++) {
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh for (i = 0; i < PMCS_NOQ; i++) {
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Clear out any leftover commands sitting in the work list
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * The other states of NIL, READY and INTR
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * should not be visible outside of a lock being held.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Restore Interrupt Mask
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh pmcs_wr_msgunit(pwp, PMCS_MSGU_OBDB_MASK, pwp->intr_mask);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Set up MPI again.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Restart MPI
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Run any completions
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return (0);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return (-1);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Reset a device or a logical unit.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dhpmcs_reset_dev(pmcs_hw_t *pwp, pmcs_phy_t *pptr, uint64_t lun)
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Some devices do not support SAS_I_T_NEXUS_RESET as
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * it is not a mandatory (in SAM4) task management
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * function, while LOGIC_UNIT_RESET is mandatory.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * The problem here is that we need to iterate over
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * all known LUNs to emulate the semantics of
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * "RESET_TARGET".
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * XXX: FIX ME
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh rval = pmcs_ssp_tmf(pwp, pptr, SAS_LOGICAL_UNIT_RESET, 0, lun,
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "%s: cannot reset a SMP device yet (%s)",
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Now harvest any commands killed by this action
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * by issuing an ABORT for all commands on this device.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * We do this even if the the tmf or reset fails (in case there
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * are any dead commands around to be harvested *anyway*).
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * We don't have to await for the abort to complete.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Called with PHY locked.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * If we changed while registering, punt
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return (-1);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * If we had a failure to register, check against errors.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * An ENOMEM error means we just retry (temp resource shortage).
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return (-1);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * An ETIMEDOUT error means we retry (if our counter isn't
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * exhausted)
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "%s: Retries exhausted for %s, killing",
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return (-1);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Other errors or no valid device id is fatal, but don't
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * preclude a future action.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return (-1);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return (0);
c3bc407cfbd238a18e4728ad5f36f39cecdb062fdh pmcs_prt(iport->pwp, PMCS_PRT_DEBUG_MAP, NULL, NULL, "%s", __func__);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh /* create target map */
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh if (scsi_hba_tgtmap_create(iport->dip, SCSI_TM_FULLSET, tgtmap_usec,
1b115575fbf0d7a1e3876e6886eaeffbeb8d2e61John Danielson NULL, NULL, NULL, &iport->iss_tgtmap) != DDI_SUCCESS) {
c3bc407cfbd238a18e4728ad5f36f39cecdb062fdh pmcs_prt(iport->pwp, PMCS_PRT_DEBUG_MAP, NULL, NULL, "%s", __func__);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh /* destroy target map */
f73ae3db72a91f9f8759931a1c643c7dad785881Jesse Butler * Remove all phys from an iport's phymap and empty it's phylist.
f73ae3db72a91f9f8759931a1c643c7dad785881Jesse Butler * Called when a port has been reset by the host (see pmcs_intr.c).
f73ae3db72a91f9f8759931a1c643c7dad785881Jesse Butler * Remove all phys from the iport handle's phy list, unset its
f73ae3db72a91f9f8759931a1c643c7dad785881Jesse Butler * primary phy and update its state.
f73ae3db72a91f9f8759931a1c643c7dad785881Jesse Butler /* Remove all phys from the phymap */
f73ae3db72a91f9f8759931a1c643c7dad785881Jesse Butler phys = sas_phymap_ua2phys(pwp->hss_phymap, iport->ua);
f73ae3db72a91f9f8759931a1c643c7dad785881Jesse Butler while ((phynum = sas_phymap_phys_next(phys)) != -1) {
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Query the phymap and populate the iport handle passed in.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Called with iport lock held.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Query the phymap regarding the phys in this iport and populate
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * the iport's phys list. Hereafter this list is maintained via
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * port up and down events in pmcs_intr.c
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh /* Grab the phy pointer from root_phys */
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Set a back pointer in the phy to this iport.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * If this phy is the primary, set a pointer to it on our
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * iport handle, and set our portid from it.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Finally, insert the phy into our list
c3bc407cfbd238a18e4728ad5f36f39cecdb062fdh pmcs_prt(pwp, PMCS_PRT_DEBUG_CONFIG, pptr, NULL, "%s: found "
c3bc407cfbd238a18e4728ad5f36f39cecdb062fdh "phy %d [0x%p] on iport%d, refcnt(%d)", __func__, phynum,
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Return the iport that ua is associated with, or NULL. If an iport is
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * returned, it will be held and the caller must release the hold.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Return the iport that pptr is associated with, or NULL.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * If an iport is returned, there is a hold that the caller must release.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh ua = sas_phymap_lookup_ua(pwp->hss_phymap, pwp->sas_wwns[0],
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "found iport [0x%p] on ua (%s) for phy [0x%p], "
6745c559e4b531cf336a91f4653445c32ee46693Jesse Butler * Promote the next phy on this port to primary, and return it.
f73ae3db72a91f9f8759931a1c643c7dad785881Jesse Butler * Called when the primary PHY on a port is going down, but the port
f73ae3db72a91f9f8759931a1c643c7dad785881Jesse Butler * remains up (see pmcs_intr.c).
6745c559e4b531cf336a91f4653445c32ee46693Jesse Butler /* Use the first available phy in this port */
6745c559e4b531cf336a91f4653445c32ee46693Jesse Butler for (pptr = pwp->root_phys; pptr; pptr = pptr->sibling) {
6745c559e4b531cf336a91f4653445c32ee46693Jesse Butler if ((pptr->portid == portid) && (pptr != prev_primary)) {
6745c559e4b531cf336a91f4653445c32ee46693Jesse Butler /* Update the phy handle with the data from the previous primary */
f73ae3db72a91f9f8759931a1c643c7dad785881Jesse Butler pptr->tolerates_sas2 = prev_primary->tolerates_sas2;
f73ae3db72a91f9f8759931a1c643c7dad785881Jesse Butler * We call pmcs_unlock_phy() on pptr because it now contains the
f73ae3db72a91f9f8759931a1c643c7dad785881Jesse Butler * list of children.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Release a refcnt on this iport. If this is the last reference,
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * signal the potential waiter in pmcs_iport_unattach().
c3bc407cfbd238a18e4728ad5f36f39cecdb062fdh pmcs_prt(iport->pwp, PMCS_PRT_DEBUG_CONFIG, NULL, NULL, "%s: iport "
c3bc407cfbd238a18e4728ad5f36f39cecdb062fdh "[0x%p] refcnt (%d)", __func__, (void *)iport, iport->refcnt);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh if ((pwp->state == STATE_UNPROBING) || (pwp->state == STATE_DEAD)) {
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh if (scsi_hba_iportmap_iport_add(pwp->hss_iportmap, ua, NULL) !=
c3bc407cfbd238a18e4728ad5f36f39cecdb062fdh pmcs_prt(pwp, PMCS_PRT_DEBUG_MAP, NULL, NULL, "%s: failed to "
c3bc407cfbd238a18e4728ad5f36f39cecdb062fdh "phymap_active count (%d), added iport handle on unit "
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh /* Set the HBA softstate as our private data for this unit address */
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * We are waiting on attach for this iport node, unless it is still
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * attached. This can happen if a consumer has an outstanding open
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * on our iport node, but the port is down. If this is the case, we
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * need to configure our iport here for reuse.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "failed to configure phys on iport [0x%p] at "
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh pmcs_smhba_add_iport_prop(iport, DATA_TYPE_INT32, PMCS_NUM_PHYS,
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh if (scsi_hba_iportmap_iport_remove(pwp->hss_iportmap, ua) !=
c3bc407cfbd238a18e4728ad5f36f39cecdb062fdh pmcs_prt(pwp, PMCS_PRT_DEBUG_MAP, NULL, NULL, "%s: failed to "
c3bc407cfbd238a18e4728ad5f36f39cecdb062fdh "remove iport handle on unit address [%s]", __func__, ua);
c3bc407cfbd238a18e4728ad5f36f39cecdb062fdh "phymap_active count (%d), removed iport handle on unit "
c3bc407cfbd238a18e4728ad5f36f39cecdb062fdh pmcs_prt(pwp, PMCS_PRT_DEBUG_CONFIG, NULL, NULL, "%s: failed "
c3bc407cfbd238a18e4728ad5f36f39cecdb062fdh "lookup of iport handle on unit addr (%s)", __func__, ua);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Top-level discovery function
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh DTRACE_PROBE2(pmcs__discover__entry, ulong_t, pwp->work_flags,
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh /* Ensure we have at least one phymap active */
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * If no iports have attached, but we have PHYs that are up, we
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * are waiting for iport attach to complete. Restart discovery.
c3bc407cfbd238a18e4728ad5f36f39cecdb062fdh pmcs_prt(pwp, PMCS_PRT_DEBUG_CONFIG, NULL, NULL, "Discovery begin");
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * The order of the following traversals is important.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * The first one checks for changed expanders.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * The second one aborts commands for dead devices and deregisters them.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * The third one clears the contents of dead expanders from the tree
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * The fourth one clears now dead devices in expanders that remain.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * 1. Check expanders marked changed (but not dead) to see if they still
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * have the same number of phys and the same SAS address. Mark them,
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * their subsidiary phys (if wide) and their descendents dead if
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * anything has changed. Check the devices they contain to see if
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * *they* have changed. If they've changed from type NOTHING we leave
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * them marked changed to be configured later (picking up a new SAS
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * address and link rate if possible). Otherwise, any change in type,
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * SAS address or removal of target role will cause us to mark them
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * (and their descendents) as dead (and cause any pending commands
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * and associated devices to be removed).
ec2c44b8ba99d683354835779a251ce942c2dddcdh * NOTE: We don't want to bail on discovery if the config has
ec2c44b8ba99d683354835779a251ce942c2dddcdh * changed until *after* we run pmcs_kill_devices.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * 2. Descend the tree looking for dead devices and kill them
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * by aborting all active commands and then deregistering them.
ec2c44b8ba99d683354835779a251ce942c2dddcdh if (pmcs_kill_devices(pwp, root_phy) || config_changed) {
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * 3. Check for dead expanders and remove their children from the tree.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * By the time we get here, the devices and commands for them have
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * already been terminated and removed.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * We do this independent of the configuration count changing so we can
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * free any dead device PHYs that were discovered while checking
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * expanders. We ignore any subsidiary phys as pmcs_clear_expander
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * will take care of those.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * NOTE: pmcs_clear_expander requires softstate lock
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh for (pptr = pwp->root_phys; pptr; pptr = pptr->sibling) {
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Call pmcs_clear_expander for every root PHY. It will
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * recurse and determine which (if any) expanders actually
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * need to be cleared.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * 4. Check for dead devices and nullify them. By the time we get here,
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * the devices and commands for them have already been terminated
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * and removed. This is different from step 2 in that this just nulls
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * phys that are part of expanders that are still here but used to
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * be something but are no longer something (e.g., after a pulled
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * disk drive). Note that dead expanders had their contained phys
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * removed from the tree- here, the expanders themselves are
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * nullified (unless they were removed by being contained in another
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * expander phy).
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * 5. Now check for and configure new devices.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh DTRACE_PROBE2(pmcs__discover__exit, ulong_t, pwp->work_flags,
c3bc407cfbd238a18e4728ad5f36f39cecdb062fdh pmcs_prt(pwp, PMCS_PRT_DEBUG_CONFIG, NULL, NULL, "Discovery end");
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Observation is stable, report what we currently see to
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * the tgtmaps for delta processing. Start by setting
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * BEGIN on all tgtmaps.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * If config_changed is TRUE, we need to reschedule
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * discovery now.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "%s: Config has changed, will re-run discovery", __func__);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "PHY %s dead=%d changed=%d configured=%d "
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh /* Clean up and restart discovery */
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Return any PHY that needs to have scheduled work done. The PHY is returned
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dhpmcs_find_phy_needing_work(pmcs_hw_t *pwp, pmcs_phy_t *pptr)
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh if (pptr->changed || (pptr->dead && pptr->valid_device_id)) {
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Report current observations to SCSA.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Observation is stable, report what we currently see to the tgtmaps
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * for delta processing. Start by setting BEGIN on all tgtmaps.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Unless we have at least one phy up, skip this iport.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Note we don't need to lock the iport for report_skip
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * since it is only used here. We are doing the skip so that
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * the phymap and iportmap stabilization times are honored -
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * giving us the ability to recover port operation within the
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * stabilization time without unconfiguring targets using the
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh continue; /* skip set_begin */
c3bc407cfbd238a18e4728ad5f36f39cecdb062fdh "%s: set begin on tgtmap [0x%p]", __func__, (void *)tgtmap);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Now, cycle through all levels of all phys and report
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * observations into their respective tgtmaps.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Skip PHYs that have nothing attached or are dead.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "%s: oops, PHY %s changed; restart discovery",
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Get the iport for this root PHY, then call the helper
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * to report observations for this iport's targets
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh /* No iport for this tgt */
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * The observation is complete, end sets. Note we will skip any
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * iports that are active, but have no PHYs in them (i.e. awaiting
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * unconfigure). Set to restart discovery if we find this.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh continue; /* skip set_end */
c3bc407cfbd238a18e4728ad5f36f39cecdb062fdh "%s: set end on tgtmap [0x%p]", __func__, (void *)tgtmap);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Now that discovery is complete, set up the necessary
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * DDI properties on each iport node.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh /* Set up the 'attached-port' property on the iport */
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * This iport is down, but has not been
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * removed from our list (unconfigured).
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Set our value to '0'.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh /* Otherwise, set it to remote phy's wwn */
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Report observations into a particular iport's target map
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Called with phyp (and all descendents) locked
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dhpmcs_report_iport_observations(pmcs_hw_t *pwp, pmcs_iport_t *iport,
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh default: /* Skip unknown PHYs. */
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh /* for non-root phys, skip to sibling */
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "iport_observation: adding %s on tgtmap [0x%p] phy [0x%p]",
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh if (scsi_hba_tgtmap_set_add(tgtmap, tgt_type, ua, NULL) !=
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh /* for non-root phys, report siblings too */
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Check for and configure new devices.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * If the changed device is a SATA device, add a SATA device.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * If the changed device is a SAS device, add a SAS device.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * If the changed device is an EXPANDER device, do a REPORT
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * GENERAL SMP command to find out the number of contained phys.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * For each number of contained phys, allocate a phy, do a
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * DISCOVERY SMP command to find out what kind of device it
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * is and add it to the linked list of phys on the *next* level.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * NOTE: pptr passed in by the caller will be a root PHY
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dhpmcs_configure_new_devices(pmcs_hw_t *pwp, pmcs_phy_t *pptr)
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh pmcs_phy_t *pnext, *orig_pptr = pptr, *root_phy, *pchild;
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * First, walk through each PHY at this level
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Set the new dtype if it has changed
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh if (pptr->changed == 0 || pptr->dead || pptr->configured) {
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Confirm that this target's iport is configured
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh /* No iport for this tgt, restart */
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "%s: iport not yet configured, "
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh if (rval != 0) {
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Now walk through each PHY again, recalling ourselves if they
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * have children
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh if (rval != 0) {
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Set all phys and descendent phys as changed if changed == B_TRUE, otherwise
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * mark them all as not changed.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Called with parent PHY locked.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dhpmcs_set_changed(pmcs_hw_t *pwp, pmcs_phy_t *parent, boolean_t changed,
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh if (level == 0) {
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Take the passed phy mark it and its descendants as dead.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Fire up reconfiguration to abort commands and bury it.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Called with the parent PHY locked.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dhpmcs_kill_changed(pmcs_hw_t *pwp, pmcs_phy_t *parent, int level)
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Only kill siblings at level > 0
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh if (level == 0) {
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Go through every PHY and clear any that are dead (unless they're expanders)
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dhstatic void
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Clear volatile parts of a phy. Called with PHY locked.
c3bc407cfbd238a18e4728ad5f36f39cecdb062fdh pmcs_prt(pwp, PMCS_PRT_DEBUG_CONFIG, pptr, NULL, "%s: %s",
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh /* keep sibling */
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh /* keep children */
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh /* keep parent */
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh /* keep hw_event_ack */
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh /* keep phynum */
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh /* keep dtype */
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh /* keep portid */
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh /* Only mark dead if it's not a root PHY and its dtype isn't NOTHING */
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh /* XXX: What about directly attached disks? */
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh /* keep SAS address */
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh /* keep path */
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh /* keep ref_count */
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh /* Don't clear iport on root PHYs - they are handled in pmcs_intr.c */
b18a19c275d2531444fcd2f66664cbe3c6897f6aJesse Butler /* keep target */
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Allocate softstate for this target if there isn't already one. If there
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * is, just redo our internal configuration. If it is actually "new", we'll
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * soon get a tran_tgt_init for it.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Called with PHY locked.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dhstatic void
c3bc407cfbd238a18e4728ad5f36f39cecdb062fdh pmcs_prt(pwp, PMCS_PRT_DEBUG_CONFIG, pptr, NULL, "%s: phy 0x%p @ %s",
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * If the config failed, mark the PHY as changed.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh /* Mark PHY as no longer changed */
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * If the PHY has no target pointer, see if there's a dead PHY that
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * matches.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Only assign the device if there is a target for this PHY with a
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * matching SAS address. If an iport is disconnected from one piece
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * of storage and connected to another within the iport stabilization
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * time, we can get the PHY/target mismatch situation.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Otherwise, it'll get done in tran_tgt_init.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "%s: Not assigning existing tgt %p for PHY %p "
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "%s: pmcs_assign_device failed for target 0x%p",
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Called with PHY lock held.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Mark this device as no longer changed.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * If we don't have a device handle, get one.
c3bc407cfbd238a18e4728ad5f36f39cecdb062fdh pmcs_prt(pwp, PMCS_PRT_DEBUG_CONFIG, pptr, NULL, "config_dev: %s "
c3bc407cfbd238a18e4728ad5f36f39cecdb062fdh "dev %s " SAS_ADDR_FMT " dev id 0x%x lr 0x%x", dtype, pptr->path,
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh SAS_ADDR_PRT(pptr->sas_address), pptr->device_id, pptr->link_rate);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Called with PHY locked
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dhstatic void
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dhpmcs_configure_expander(pmcs_hw_t *pwp, pmcs_phy_t *pptr, pmcs_iport_t *iport)
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Step 1- clear our "changed" bit. If we need to retry/restart due
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * to resource shortages, we'll set it again. While we're doing
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * configuration, other events may set it again as well. If the PHY
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * is a root PHY and is currently marked as having changed, reset the
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * config_stop timer as well.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Step 2- make sure we don't overflow
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Step 3- Check if this expander is part of a wide phy that has
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * already been configured.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * This is known by checking this level for another EXPANDER device
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * with the same SAS address and isn't already marked as a subsidiary
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * phy and a parent whose SAS address is the same as our SAS address
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * (if there are parents).
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * No need to lock the parent here because we're in discovery
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * and the only time a PHY's children pointer can change is
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * in discovery; either in pmcs_clear_expander (which has
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * already been called) or here, down below. Plus, trying to
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * grab the parent's lock here can cause deadlock.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * If we've checked all PHYs up to pptr, we stop. Otherwise,
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * we'll be checking for a primary PHY with a higher PHY
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * number than pptr, which will never happen. The primary
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * PHY on non-root expanders will ALWAYS be the lowest
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * numbered PHY.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * If pptr and ctmp are root PHYs, just grab the mutex on
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * ctmp. No need to lock the entire tree. If they are not
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * root PHYs, there is no need to lock since a non-root PHY's
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * SAS address and other characteristics can only change in
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * discovery anyway.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * If these phys are not root PHYs, compare their SAS
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * addresses too.
c3bc407cfbd238a18e4728ad5f36f39cecdb062fdh "%s: PHY %s part of wide PHY %s "
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Step 4- If we don't have a device handle, get one. Since this
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * is the primary PHY, make sure subsidiary is cleared.
c3bc407cfbd238a18e4728ad5f36f39cecdb062fdh pmcs_prt(pwp, PMCS_PRT_DEBUG_CONFIG, pptr, NULL, "Config expander %s "
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh SAS_ADDR_PRT(pptr->sas_address), pptr->device_id, pptr->link_rate);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Step 5- figure out how many phys are in this expander.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh if (nphy <= 0) {
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Step 6- Allocate a list of phys for this expander and figure out
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * what each one is.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh for (i = 0; i < nphy; i++) {
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Clean up the newly allocated PHYs and return
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Step 7- Now fill in the rest of the static portions of the phy.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh for (i = 0, ctmp = clist; ctmp; ctmp = ctmp->sibling, i++) {
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh pmcs_phy_name(pwp, ctmp, ctmp->path, sizeof (ctmp->path));
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Step 8- Discover things about each phy in the expander.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh for (i = 0, ctmp = clist; ctmp; ctmp = ctmp->sibling, i++) {
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh result = pmcs_expander_content_discover(pwp, pptr, ctmp);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh if (result <= 0) {
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "%s: Retries exhausted for %s, killing",
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh /* Set pend_dtype to dtype for 1st time initialization */
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Step 9- Install the new list on the next level. There should be
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * no children pointer on this PHY. If there is, we'd need to know
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * how it happened (The expander suddenly got more PHYs?).
c3bc407cfbd238a18e4728ad5f36f39cecdb062fdh pmcs_prt(pwp, PMCS_PRT_DEBUG, pptr, NULL, "%s: Already child "
c3bc407cfbd238a18e4728ad5f36f39cecdb062fdh "PHYs attached to PHY %s: This should never happen",
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * We only set width if we're greater than level 0.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Now tell the rest of the world about us, as an SMP node.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * 2. Check expanders marked changed (but not dead) to see if they still have
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * the same number of phys and the same SAS address. Mark them, their subsidiary
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * phys (if wide) and their descendents dead if anything has changed. Check the
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * the devices they contain to see if *they* have changed. If they've changed
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * from type NOTHING we leave them marked changed to be configured later
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * (picking up a new SAS address and link rate if possible). Otherwise, any
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * change in type, SAS address or removal of target role will cause us to
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * mark them (and their descendents) as dead and cause any pending commands
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * and associated devices to be removed.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Called with PHY (pptr) locked.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dhstatic void
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh pmcs_phy_t *ctmp, *local, *local_list = NULL, *local_tail = NULL;
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Step 1: Mark phy as not changed. We will mark it changed if we need
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * to retry.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Reset the config_stop time. Although we're not actually configuring
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * anything here, we do want some indication of when to give up trying
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * if we can't communicate with the expander.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Step 2: Figure out how many phys are in this expander. If
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * pmcs_expander_get_nphy returns 0 we ran out of resources,
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * so reschedule and try later. If it returns another error,
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * just return.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh if (nphy <= 0) {
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh if ((nphy == 0) && (ddi_get_lbolt() < pptr->config_stop)) {
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Step 3: If the number of phys don't agree, kill the old sub-tree.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "%s: number of contained phys for %s changed from %d to %d",
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Force a rescan of this expander after dead contents
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * are cleared and removed.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Step 4: if we're at the bottom of the stack, we're done
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * (we can't have any levels below us)
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Step 5: Discover things about each phy in this expander. We do
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * this by walking the current list of contained phys and doing a
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * content discovery for it to a local phy.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Allocate a local PHY to contain the proposed new contents
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * and link it to the rest of the local PHYs so that they
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * can all be freed later.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Need to lock the local PHY since pmcs_expander_content_
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * discovery may call pmcs_clear_phy on it, which expects
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * the PHY to be locked.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh result = pmcs_expander_content_discover(pwp, pptr, local);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh if (result <= 0) {
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "%s: Retries exhausted for %s, killing",
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Release all the local PHYs that we allocated.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Step 6: Compare the local PHY's contents to our current PHY. If
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * there are changes, take the appropriate action.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * This is done in two steps (step 5 above, and 6 here) so that if we
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * have to bail during this process (e.g. pmcs_expander_content_discover
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * fails), we haven't actually changed the state of any of the real
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * PHYs. Next time we come through here, we'll be starting over from
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * scratch. This keeps us from marking a changed PHY as no longer
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * changed, but then having to bail only to come back next time and
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * think that the PHY hadn't changed. If this were to happen, we
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * would fail to properly configure the device behind this PHY.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * We set local to local_list prior to this loop so that we
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * can simply walk the local_list while we walk this list. The
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * two lists should be completely in sync.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Clear the changed flag here.
c3bc407cfbd238a18e4728ad5f36f39cecdb062fdh "%s: %s type changed from %s to %s "
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Force a rescan of this expander after dead
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * contents are cleared and removed.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "%s: %s type changed from NOTHING to %s",
c3bc407cfbd238a18e4728ad5f36f39cecdb062fdh "%s attached device type changed from %d to %d "
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Force a rescan of this expander after dead
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * contents are cleared and removed.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh /* If the speed changed from invalid, force rescan */
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh /* Just update to the new link rate */
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Force a rescan of this expander after dead
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * contents are cleared and removed.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "%s: %s looks the same (type %s)",
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * If EXPANDER, still mark it changed so we
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * re-evaluate its contents. If it's not an expander,
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * but it hasn't been configured, also mark it as
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * changed so that it will undergo configuration.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh /* It simply hasn't changed */
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * If the PHY changed, call pmcs_kill_changed if indicated,
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * update its contents to reflect its current state and mark it
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * as changed.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * pmcs_kill_changed will mark the PHY as changed, so
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * only do PHY_CHANGED if we did not do kill_changed.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * If we're not killing the device, it's not
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * dead. Mark the PHY as changed.
c3bc407cfbd238a18e4728ad5f36f39cecdb062fdh "dead, restarting discovery",
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * If the dtype of this PHY is now NOTHING, mark it as
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * unconfigured. Set pend_dtype to what the new dtype
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * is. It'll get updated at the end of the discovery
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * process.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * If we got to here, that means we were able to see all the PHYs
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * and we can now update all of the real PHYs with the information
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * we got on the local PHYs. Once that's done, free all the local
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Top level routine to check expanders. We call pmcs_check_expander for
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * each expander. Since we're not doing any configuration right now, it
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * doesn't matter if this is breadth-first.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Check each expander at this level
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Now check the children
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * We're done
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Called with softstate and PHY locked
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dhstatic void
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dhpmcs_clear_expander(pmcs_hw_t *pwp, pmcs_phy_t *pptr, int level)
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * If the expander is dead, mark its children dead
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * If this expander is not dead, we're done here.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Now snip out the list of children below us and release them
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Put this PHY on the dead PHY list for the watchdog to
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * clean up after any outstanding work has completed.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Clear subsidiary phys as well. Getting the parent's PHY lock
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * is only necessary if level == 0 since otherwise the parent is
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * already locked.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh if (level == 0) {
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh if (level == 0) {
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * We only need to lock subsidiary PHYs on the level 0
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * expander. Any children of that expander, subsidiaries or
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * not, will already be locked.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh if (level == 0) {
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh if (level == 0) {
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh if (level == 0) {
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Called with PHY locked and with scratch acquired. We return 0 if
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * we fail to allocate resources or notice that the configuration
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * count changed while we were running the command. We return
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * less than zero if we had an I/O error or received an unsupported
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * configuration. Otherwise we return the number of phys in the
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * expander.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh msg[0] = LE_32(PMCS_HIPRI(pwp, PMCS_OQ_GENERAL, PMCIN_SMP_REQUEST));
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh msg[3] = LE_32((4 << SMP_REQUEST_LENGTH_SHIFT) | SMP_INDIRECT_RESPONSE);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Send SMP REPORT GENERAL (of either SAS1.1 or SAS2 flavors).
6745c559e4b531cf336a91f4653445c32ee46693Jesse Butler /* SMP serialization */
6745c559e4b531cf336a91f4653445c32ee46693Jesse Butler /* SMP serialization */
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "%s: Issuing SMP ABORT for htag 0x%08x", __func__, htag);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "%s: Unable to issue SMP ABORT for htag 0x%08x",
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "%s: Issuing SMP ABORT for htag 0x%08x",
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh srf = (smp_response_frame_t *)&((uint32_t *)pwp->scratch)[rdoff >> 2];
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh switch (status) {
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh /* FALLTHROUGH */
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh /* FALLTHROUGH */
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh /* FALLTHROUGH */
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh /* FALLTHROUGH */
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh case PMCOUT_STATUS_OPEN_CNX_ERROR_CONNECTION_RATE_NOT_SUPPORTED:
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh /* FALLTHROUGH */
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh /* FALLTHROUGH */
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "%s: expander %s SMP operation failed (%s)",
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * For the IO_DS_NON_OPERATIONAL case, we need to kick off
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * device state recovery and return 0 so that the caller
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * doesn't assume this expander is dead for good.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "%s: expander %s device state non-operational",
6745c559e4b531cf336a91f4653445c32ee46693Jesse Butler * Kick off recovery right now.
6745c559e4b531cf336a91f4653445c32ee46693Jesse Butler (void) ddi_taskq_dispatch(pwp->tq, pmcs_worker,
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh } else if (srf->srf_frame_type != SMP_FRAME_TYPE_RESPONSE) {
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "%s: bad response frame type 0x%x",
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh } else if (srf->srf_function != SMP_FUNC_REPORT_GENERAL) {
c3bc407cfbd238a18e4728ad5f36f39cecdb062fdh "%s: bad response function 0x%x",
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Check to see if we have a value of 3 for failure and
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * whether we were using a SAS2.0 allocation length value
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * and retry without it.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "%s: err 0x%x with SAS2 request- retry with SAS1",
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "%s: expander at phy %s is still configuring",
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh pptr->tolerates_sas2? "tolerates" : "does not tolerate");
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Called with expander locked (and thus, pptr) as well as all PHYs up to
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * the root, and scratch acquired. Return 0 if we fail to allocate resources
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * or notice that the configuration changed while we were running the command.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * We return less than zero if we had an I/O error or received an
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * unsupported configuration.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dhpmcs_expander_content_discover(pmcs_hw_t *pwp, pmcs_phy_t *expander,
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh msg[0] = LE_32(PMCS_HIPRI(pwp, PMCS_OQ_GENERAL, PMCIN_SMP_REQUEST));
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Send SMP DISCOVER (of either SAS1.1 or SAS2 flavors).
6745c559e4b531cf336a91f4653445c32ee46693Jesse Butler /* SMP serialization */
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Drop PHY lock while waiting so other completions aren't potentially
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * blocked.
6745c559e4b531cf336a91f4653445c32ee46693Jesse Butler /* SMP serialization */
6745c559e4b531cf336a91f4653445c32ee46693Jesse Butler pmcs_prt(pwp, PMCS_PRT_DEBUG, pptr, NULL, pmcs_timeo, __func__);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "%s: Unable to issue SMP ABORT for htag 0x%08x",
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "%s: Issuing SMP ABORT for htag 0x%08x",
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Point roff to the DMA offset for returned data
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh switch (status) {
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh /* FALLTHROUGH */
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh /* FALLTHROUGH */
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh /* FALLTHROUGH */
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh case PMCOUT_STATUS_OPEN_CNX_ERROR_CONNECTION_RATE_NOT_SUPPORTED:
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh /* FALLTHROUGH */
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh /* FALLTHROUGH */
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "%s: expander %s SMP operation failed (%s)",
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh } else if (srf->srf_frame_type != SMP_FRAME_TYPE_RESPONSE) {
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "%s: bad response frame type 0x%x",
c3bc407cfbd238a18e4728ad5f36f39cecdb062fdh "%s: bad response function 0x%x",
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh } else if (srf->srf_result != SMP_RES_FUNCTION_ACCEPTED) {
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh /* Need not fail if PHY is Vacant */
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh pmcs_wwn2barray(BE_64(sdr->sdr_attached_sas_addr), att_sas_address);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "exp_content: %s atdt=0x%x lr=%x is=%x ts=%x SAS="
c3bc407cfbd238a18e4728ad5f36f39cecdb062fdh "%s: %s has tgt support=%x init support=(%x)",
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "exp_content: %s atdt=0x%x lr=%x is=%x ts=%x SAS="
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Avoid configuring phys that just point back
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * at a parent phy
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "%s: skipping port back to parent "
c3bc407cfbd238a18e4728ad5f36f39cecdb062fdh "%s has tgt support=%x init support=(%x)",
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * If the attached device is a SATA device and the expander
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * is (possibly) a SAS2 compliant expander, check for whether
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * there is a NAA=5 WWN field starting at this offset and
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * use that for the SAS Address for this device.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Now run up from the expander's parent up to the top to
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * make sure we only use the least common link_rate.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh for (ctmp = expander->parent; ctmp; ctmp = ctmp->parent) {
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "%s: derating link rate from %x to %x due "
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh pptr->state.prog_min_rate = sdr->sdr_prog_min_phys_link_rate;
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh pptr->state.hw_min_rate = sdr->sdr_hw_min_phys_link_rate;
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh pptr->state.prog_max_rate = sdr->sdr_prog_max_phys_link_rate;
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh pptr->state.hw_max_rate = sdr->sdr_hw_max_phys_link_rate;
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Get a work structure and assign it a tag with type and serial number
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * If a structure is returned, it is returned locked.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dhpmcs_gwork(pmcs_hw_t *pwp, uint32_t tag_type, pmcs_phy_t *phyp)
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh if (p == NULL) {
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * If we couldn't get a work structure, it's time to bite
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * the bullet, grab the pfree_lock and copy over all the
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * work structures from the pending free list to the actual
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * free list. This shouldn't happen all that often.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh if (p == NULL) {
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh p->htag = (tag_type << PMCS_TAG_TYPE_SHIFT) & PMCS_TAG_TYPE_MASK;
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh p->htag |= ((snum << PMCS_TAG_SERNO_SHIFT) & PMCS_TAG_SERNO_MASK);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh p->htag |= ((off << PMCS_TAG_INDEX_SHIFT) & PMCS_TAG_INDEX_MASK);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return (p);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Called with pwrk lock held. Returned with lock released.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Find a work structure based upon a tag and make sure that the tag
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * serial number matches the work structure we've found.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * If a structure is found, its lock is held upon return.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return (p);
c3bc407cfbd238a18e4728ad5f36f39cecdb062fdh "INDEX 0x%x HTAG 0x%x got p->htag 0x%x", idx, htag, p->htag);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Issue an abort for a command or for all commands.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Since this can be called from interrupt context,
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * we don't wait for completion if wait is not set.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Called with PHY lock held.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dhpmcs_abort(pmcs_hw_t *pwp, pmcs_phy_t *pptr, uint32_t tag, int all_cmds,
c3bc407cfbd238a18e4728ad5f36f39cecdb062fdh pmcs_prt(pwp, PMCS_PRT_DEBUG, pptr, NULL, "%s: ABORT_ALL for "
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return (0);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh pwrk = pmcs_gwork(pwp, wait ? PMCS_TAG_TYPE_WAIT : PMCS_TAG_TYPE_NONE,
c3bc407cfbd238a18e4728ad5f36f39cecdb062fdh pmcs_prt(pwp, PMCS_PRT_ERR, pptr, NULL, pmcs_nowrk, __func__);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh msg[0] = LE_32(PMCS_HIPRI(pwp, PMCS_OQ_GENERAL, abt_type));
c3bc407cfbd238a18e4728ad5f36f39cecdb062fdh pmcs_prt(pwp, PMCS_PRT_ERR, pptr, NULL, pmcs_nomsg, __func__);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "%s: aborting all commands for %s device %s. (htag=0x%x)",
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "%s: aborting tag 0x%x for %s device %s. (htag=0x%x)",
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh __func__, tag, pmcs_get_typename(pptr->dtype), pptr->path,
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return (0);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "%s: Abort complete (result=0x%x), but "
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "aq not empty (tgt 0x%p), waiting",
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "%s: Abort (htag 0x%08x) request timed out",
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "%s: Trying DS error recovery for tgt 0x%p",
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * The only non-success status are IO_NOT_VALID &
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * IO_ABORT_IN_PROGRESS.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * In case of IO_ABORT_IN_PROGRESS, the other ABORT cmd's
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * status is of concern and this duplicate cmd status can
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * be ignored.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * If IO_NOT_VALID, that's not an error per-se.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * For abort of single I/O complete the command anyway.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * If, however, we were aborting all, that is a problem
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * as IO_NOT_VALID really means that the IO or device is
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * not there. So, discovery process will take of the cleanup.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return (0);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "%s: Restoring OPERATIONAL dev_state for tgt 0x%p",
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return (0);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Issue a task management function to an SSP device.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Called with PHY lock held.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * statlock CANNOT be held upon entry.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dhpmcs_ssp_tmf(pmcs_hw_t *pwp, pmcs_phy_t *pptr, uint8_t tmf, uint32_t tag,
c3bc407cfbd238a18e4728ad5f36f39cecdb062fdh pmcs_prt(pwp, PMCS_PRT_ERR, pptr, NULL, pmcs_nowrk, __func__);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * NB: We use the PMCS_OQ_GENERAL outbound queue
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * NB: so as to not get entangled in normal I/O
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * NB: processing.
c3bc407cfbd238a18e4728ad5f36f39cecdb062fdh pmcs_prt(pwp, PMCS_PRT_ERR, pptr, NULL, pmcs_nomsg, __func__);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh if (xp->dev_state == PMCS_DEVICE_STATE_NON_OPERATIONAL) {
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh pmcs_tmf2str(tmf), pptr->path, (unsigned long long) lun, tag);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * This is a command sent to the target device, so it can take
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * significant amount of time to complete when path & device is busy.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Set a timeout to 20 seconds
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "%s: status %s for TMF %s action to %s, lun %llu",
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh (status == PMCOUT_STATUS_OPEN_CNX_ERROR_IT_NEXUS_LOSS)) {
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * If the status is IN_RECOVERY, it's an indication
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * that it's now time for us to request to have the
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * device state set to OPERATIONAL since we're the ones
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * that requested recovery to begin with.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "%s: Sending err recovery cmd"
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh " for tgt 0x%p (status = %s)",
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "%s: Sending err recovery cmd"
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh " for tgt 0x%p (status = %s)",
c3bc407cfbd238a18e4728ad5f36f39cecdb062fdh "TMF completed with no response");
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh pmcs_endian_transform(pwp, local, &msg[5], ssp_rsp_evec);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "%s: TMF response not RESPONSE DATA (0x%x)",
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * The status is actually in the low-order byte. The upper three
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * bytes contain additional information for the TMFs that support them.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * However, at this time we do not issue any of those. In the other
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * cases, the upper three bytes are supposed to be 0, but it appears
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * they aren't always. Just mask them off.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "%s: TMF returned OVERLAPPED INITIATOR PORT TRANSFER TAG "
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Called with PHY lock held and scratch acquired
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh const char *utag_fail_fmt = "%s: untagged NCQ command failure";
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh const char *tag_fail_fmt = "%s: NCQ command failure (tag 0x%x)";
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh msg[5] = LE_32((READ_LOG_EXT << 16) | (C_BIT << 8) | FIS_REG_H2DEV);
6745c559e4b531cf336a91f4653445c32ee46693Jesse Butler pmcs_prt(pwp, PMCS_PRT_DEBUG, pptr, tgt, pmcs_timeo, __func__);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "%s: cannot find target for phy 0x%p for "
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh pmcs_print_entry(pwp, PMCS_PRT_DEBUG, "READ LOG EXT", msg);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh (status == PMCOUT_STATUS_OPEN_CNX_ERROR_IT_NEXUS_LOSS)) {
c3bc407cfbd238a18e4728ad5f36f39cecdb062fdh "SATA DS Recovery for tgt(0x%p) for status(%s)",
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh fis[0] = (fp[4] << 24) | (fp[3] << 16) | (fp[2] << 8) | FIS_REG_D2H;
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh fis[1] = (fp[8] << 24) | (fp[7] << 16) | (fp[6] << 8) | fp[5];
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh fis[2] = (fp[12] << 24) | (fp[11] << 16) | (fp[10] << 8) | fp[9];
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh fis[3] = (fp[16] << 24) | (fp[15] << 16) | (fp[14] << 8) | fp[13];
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return (0);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Transform a structure from CPU to Device endian format, or
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * vice versa, based upon a transformation vector.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * A transformation vector is an array of bytes, each byte
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * of which is defined thusly:
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * bit 7: from CPU to desired endian, otherwise from desired endian
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * to CPU format
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * bit 6: Big Endian, else Little Endian
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * bits 5-4:
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * 00 Undefined
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * 01 One Byte quantities
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * 02 Two Byte quantities
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * 03 Four Byte quantities
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * bits 3-0:
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * 00 Undefined
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Number of quantities to transform
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * The vector is terminated by a 0 value.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dhpmcs_endian_transform(pmcs_hw_t *pwp, void *orig_out, void *orig_in,
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh while ((c = *xfvec++) != 0) {
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh switch (size) {
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh while (nbyt-- > 0) {
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh while (nbyt-- > 0) {
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh while (nbyt-- > 0) {
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dhconst char *
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh const char *rate;
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh switch (linkrt) {
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dhconst char *
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh switch (type) {
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return ("NIL");
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return ("SATA");
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return ("SSP");
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return ("EXPANDER");
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return ("????");
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dhconst char *
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh switch (tmf) {
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return ("Abort Task");
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return ("Abort Task Set");
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return ("Clear Task Set");
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return ("Logical Unit Reset");
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return ("I_T Nexus Reset");
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return ("Clear ACA");
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return ("Query Task");
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return ("Query Task Set");
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return ("Query Unit Attention");
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return ("Unknown");
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dhconst char *
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh switch (status) {
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return ("OK");
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return ("ABORTED");
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return ("OVERFLOW");
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return ("UNDERFLOW");
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return ("FAILED");
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return ("ABORT_RESET");
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return ("IO_NOT_VALID");
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return ("NO_DEVICE");
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return ("ILLEGAL_PARAMETER");
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return ("LINK_FAILURE");
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return ("PROG_ERROR");
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return ("EDC_IN_ERROR");
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return ("EDC_OUT_ERROR");
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return ("ERROR_HW_TIMEOUT");
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return ("XFER_ERR_BREAK");
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return ("XFER_ERR_PHY_NOT_READY");
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return ("OPEN_CNX_PROTOCOL_NOT_SUPPORTED");
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return ("OPEN_CNX_ERROR_ZONE_VIOLATION");
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return ("OPEN_CNX_ERROR_BREAK");
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return ("OPEN_CNX_ERROR_IT_NEXUS_LOSS");
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return ("OPENCNX_ERROR_BAD_DESTINATION");
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh case PMCOUT_STATUS_OPEN_CNX_ERROR_CONNECTION_RATE_NOT_SUPPORTED:
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return ("OPEN_CNX_ERROR_CONNECTION_RATE_NOT_SUPPORTED");
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return ("OPEN_CNX_ERROR_STP_RESOURCES_BUSY");
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return ("OPEN_CNX_ERROR_WRONG_DESTINATION");
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return ("OPEN_CNX_ERROR_UNKNOWN_EROOR");
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return ("IO_XFER_ERROR_NAK_RECEIVED");
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return ("XFER_ERROR_ACK_NAK_TIMEOUT");
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return ("XFER_ERROR_PEER_ABORTED");
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return ("XFER_ERROR_RX_FRAME");
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return ("IO_XFER_ERROR_DMA");
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return ("XFER_ERROR_CREDIT_TIMEOUT");
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return ("XFER_ERROR_SATA_LINK_TIMEOUT");
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return ("XFER_ERROR_SATA");
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return ("XFER_ERROR_REJECTED_NCQ_MODE");
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return ("XFER_ERROR_ABORTED_DUE_TO_SRST");
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return ("XFER_ERROR_ABORTED_NCQ_MODE");
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return ("IO_XFER_OPEN_RETRY_TIMEOUT");
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return ("SMP_RESP_CONNECTION_ERROR");
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return ("XFER_ERROR_UNEXPECTED_PHASE");
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return ("XFER_ERROR_RDY_OVERRUN");
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return ("XFER_ERROR_RDY_NOT_EXPECTED");
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return ("XFER_ERROR_CMD_ISSUE_ACK_NAK_TIMEOUT");
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh case PMCOUT_STATUS_XFER_ERROR_CMD_ISSUE_BREAK_BEFORE_ACK_NACK:
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return ("XFER_ERROR_CMD_ISSUE_BREAK_BEFORE_ACK_NACK");
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh case PMCOUT_STATUS_XFER_ERROR_CMD_ISSUE_PHY_DOWN_BEFORE_ACK_NAK:
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return ("XFER_ERROR_CMD_ISSUE_PHY_DOWN_BEFORE_ACK_NAK");
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return ("XFER_ERROR_OFFSET_MISMATCH");
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return ("XFER_ERROR_ZERO_DATA_LEN");
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return ("XFER_CMD_FRAME_ISSUED");
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return ("ERROR_INTERNAL_SMP_RESOURCE");
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return ("IO_PORT_IN_RESET");
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return ("DEVICE STATE NON-OPERATIONAL");
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return ("DEVICE STATE IN RECOVERY");
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh for (i = 0; i < 8; i++) {
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh for (i = 0; i < 8; i++) {
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh const char *fwsupport;
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "Chip Revision: %c; F/W Revision %x.%x.%x %s", 'A' + pwp->chiprev,
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh PMCS_FW_MAJOR(pwp), PMCS_FW_MINOR(pwp), PMCS_FW_MICRO(pwp),
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dhpmcs_phy_name(pmcs_hw_t *pwp, pmcs_phy_t *pptr, char *obuf, size_t olen)
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh (void) snprintf(obuf, olen, "%s.%02x", obuf, pptr->phynum);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Implementation for pmcs_find_phy_by_devid.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * If the PHY is found, it is returned locked.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dhpmcs_find_phy_by_devid_impl(pmcs_phy_t *phyp, uint32_t device_id)
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh if ((phyp->valid_device_id) && (phyp->device_id == device_id)) {
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * If the PHY is found, it is returned locked
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dhpmcs_find_phy_by_devid(pmcs_hw_t *pwp, uint32_t device_id)
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * This function is called as a sanity check to ensure that a newly registered
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * PHY doesn't have a device_id that exists with another registered PHY.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dhpmcs_validate_devid(pmcs_phy_t *parent, pmcs_phy_t *phyp, uint32_t device_id)
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "%s: phy %s already exists as %s with "
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh /* This PHY and device_id are valid */
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * If the PHY is found, it is returned locked
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Only iterate through non-root PHYs
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * pmcs_find_phy_by_sas_address
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Find a PHY that both matches "sas_addr" and is on "iport".
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * If a matching PHY is found, it is returned locked.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dhpmcs_find_phy_by_sas_address(pmcs_hw_t *pwp, pmcs_iport_t *iport,
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * If the PHY is dead or does not have a valid device ID,
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * skip it.
c3bc407cfbd238a18e4728ad5f36f39cecdb062fdh "FIS REGISTER HOST TO DEVICE: "
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "OP=0x%02x Feature=0x%04x Count=0x%04x Device=0x%02x "
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh (unsigned long long)
c3bc407cfbd238a18e4728ad5f36f39cecdb062fdh "FIS REGISTER DEVICE TO HOST: Status=0x%02x "
c3bc407cfbd238a18e4728ad5f36f39cecdb062fdh "Error=0x%02x Dev=0x%02x Count=0x%04x LBA=%llu",
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh BYTE2(fis[0]), BYTE3(fis[0]), BYTE3(fis[1]), WORD0(fis[3]),
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh (unsigned long long)(((uint64_t)fis[2] & 0x00ffffff) << 24 |
c3bc407cfbd238a18e4728ad5f36f39cecdb062fdh "FIS: 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x",
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dhpmcs_print_entry(pmcs_hw_t *pwp, int level, char *msg, void *arg)
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh for (i = 0; i < (PMCS_QENTRY_SIZE / sizeof (uint32_t)); i += 4) {
c3bc407cfbd238a18e4728ad5f36f39cecdb062fdh "Offset %2lu: 0x%08x 0x%08x 0x%08x 0x%08x",
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * If phyp == NULL we're being called from the worker thread, in which
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * case we need to check all the PHYs. In this case, the softstate lock
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * will be held.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * If phyp is non-NULL, just issue the spinup release for the specified PHY
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * (which will already be locked).
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Abort commands on dead PHYs and deregister them as well as removing
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * the associated targets.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * pmcs_remove_device requires the softstate lock.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Called with PHY locked
c3bc407cfbd238a18e4728ad5f36f39cecdb062fdh pmcs_prt(pwp, PMCS_PRT_DEBUG, pptr, NULL, "kill %s device @ %s",
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * There may be an outstanding ABORT_ALL running, which we wouldn't
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * know just by checking abort_pending. We can, however, check
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * abort_all_start. If it's non-zero, there is one, and we'll just
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * sit here and wait for it to complete. If we don't, we'll remove
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * the device while there are still commands pending.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "%s: Waiting for outstanding ABORT_ALL on PHY 0x%p",
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "%s: ABORT_ALL returned non-zero status (%d) for "
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return (r);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return (0);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh if ((pwrk = pmcs_gwork(pwp, PMCS_TAG_TYPE_WAIT, pptr)) == NULL) {
c3bc407cfbd238a18e4728ad5f36f39cecdb062fdh pmcs_prt(pwp, PMCS_PRT_ERR, pptr, NULL, pmcs_nowrk, __func__);
c3bc407cfbd238a18e4728ad5f36f39cecdb062fdh pmcs_prt(pwp, PMCS_PRT_ERR, pptr, NULL, pmcs_nomsg, __func__);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "%s: status 0x%x when trying to deregister device %s",
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return (0);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Acknowledge the SAS h/w events that need acknowledgement.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * This is only needed for first level PHYs.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh for (pptr = pwp->root_phys; pptr; pptr = pptr->sibling) {
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Load DMA
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dhpmcs_dma_load(pmcs_hw_t *pwp, pmcs_cmd_t *sp, uint32_t *msg)
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * If we have no data segments, we're done.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return (0);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Get the S/G list pointer.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * If we only have one dma segment, we can directly address that
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * data within the Inbound message itself.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return (0);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Otherwise, we'll need one or more external S/G list chunks.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Get the first one and its dma address into the Inbound message.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return (-1);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh for (seg = 0; seg < CMD2PKT(sp)->pkt_numcookies; seg++) {
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * If the current segment count for this chunk is one less than
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * the number s/g lists per chunk and we have more than one seg
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * to go, we need another chunk. Get it, and make sure that the
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * tail end of the the previous chunk points the new chunk
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * (if remembering an offset can be called 'pointing to').
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Note that we can store the offset into our command area that
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * represents the new chunk in the length field of the part
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * that points the PMC chip at the next chunk- the PMC chip
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * ignores this field when the EXTENSION bit is set.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * This is required for dma unloads later.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return (-1);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return (0);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Unload DMA
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Take a chunk of consistent memory that has just been allocated and inserted
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * into the cip indices and prepare it for DMA chunk usage and add it to the
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * freelist.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Called with dma_lock locked (except during attach when it's unnecessary)
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh unsigned long off, n;
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Install offsets into chunk lists.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh for (n = 0, off = 0; off < lim; off += PMCS_SGL_CHUNKSZ, n++) {
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "added %lu DMA chunks ", n);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Change the value of the interrupt coalescing timer. This is done currently
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * only for I/O completions. If we're using the "auto clear" feature, it can
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * be turned back on when interrupt coalescing is turned off and must be
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * turned off when the coalescing timer is on.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * NOTE: PMCS_MSIX_GENERAL and PMCS_OQ_IODONE are the same value. As long
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * as that's true, we don't need to distinguish between them.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dhpmcs_set_intr_coal_timer(pmcs_hw_t *pwp, pmcs_coal_timer_adj_t adj)
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh /* If the timer is already off, nothing to do. */
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh pwp->io_intr_coal.intr_coal_timer -= PMCS_COAL_TIMER_GRAN;
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh /* Disable the timer */
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * If the timer isn't on yet, do the setup for it now.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh /* If auto clear is being used, turn it off. */
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh if (pwp->io_intr_coal.intr_coal_timer > PMCS_MAX_COAL_TIMER) {
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Adjust the interrupt threshold based on the current timer value
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Register Access functions
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh if (ddi_dma_sync(pwp->cip_handles, 0, 0, DDI_DMA_SYNC_FORKERNEL) !=
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh if (ddi_dma_sync(pwp->cip_handles, 0, 0, DDI_DMA_SYNC_FORKERNEL) !=
c3bc407cfbd238a18e4728ad5f36f39cecdb062fdh "AXIL register update failed");
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh rv = ddi_get32(pwp->gsm_acc_handle, &pwp->gsm_regs[off >> 2]);
c3bc407cfbd238a18e4728ad5f36f39cecdb062fdh "AXIL register restore failed");
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return (rv);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dhpmcs_wr_gsm_reg(pmcs_hw_t *pwp, uint32_t off, uint32_t val)
c3bc407cfbd238a18e4728ad5f36f39cecdb062fdh "AXIL register update failed");
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh ddi_put32(pwp->gsm_acc_handle, &pwp->gsm_regs[off >> 2], val);
c3bc407cfbd238a18e4728ad5f36f39cecdb062fdh "AXIL register restore failed");
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh switch (off) {
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dhpmcs_wr_topunit(pmcs_hw_t *pwp, uint32_t off, uint32_t val)
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh switch (off) {
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh ddi_put32(pwp->top_acc_handle, &pwp->top_regs[off >> 2], val);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return (ddi_get32(pwp->msg_acc_handle, &pwp->msg_regs[off >> 2]));
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dhpmcs_wr_msgunit(pmcs_hw_t *pwp, uint32_t off, uint32_t val)
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh ddi_put32(pwp->msg_acc_handle, &pwp->msg_regs[off >> 2], val);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dhpmcs_wr_mpi_tbl(pmcs_hw_t *pwp, uint32_t off, uint32_t val)
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dhpmcs_wr_gst_tbl(pmcs_hw_t *pwp, uint32_t off, uint32_t val)
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dhpmcs_wr_iqc_tbl(pmcs_hw_t *pwp, uint32_t off, uint32_t val)
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dhpmcs_wr_oqc_tbl(pmcs_hw_t *pwp, uint32_t off, uint32_t val)
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh ((uint32_t *)((void *)pwp->cip))[IQ_OFFSET(qnum) >> 2] = val;
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh if (ddi_dma_sync(pwp->cip_handles, 0, 0, DDI_DMA_SYNC_FORDEV) !=
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh ((uint32_t *)((void *)pwp->cip))[OQ_OFFSET(qnum) >> 2] = val;
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh if (ddi_dma_sync(pwp->cip_handles, 0, 0, DDI_DMA_SYNC_FORDEV) !=
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Check the status value of an outbound IOMB and report anything bad
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh switch (opcode) {
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * The following have no status field, so ignore them
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh case PMCOUT_GET_NVMD_DATA: /* Actually lower 16 bits of word 3 */
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh case PMCOUT_SET_NVMD_DATA: /* but ignore - we don't use these */
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Called with statlock held
c3bc407cfbd238a18e4728ad5f36f39cecdb062fdh pmcs_prt(pwp, PMCS_PRT_DEBUG, NULL, xp, "%s: Device 0x%p is gone.",
b18a19c275d2531444fcd2f66664cbe3c6897f6aJesse Butler * Clear the dip now. This keeps pmcs_remove_device from attempting
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * to call us on the same device while we're still flushing queues.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * The only side effect is we can no longer update SM-HBA properties,
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * but this device is going away anyway, so no matter.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh /* Don't clear xp->phy */
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh /* Don't clear xp->actv_cnt */
b18a19c275d2531444fcd2f66664cbe3c6897f6aJesse Butler * Flush all target queues
b18a19c275d2531444fcd2f66664cbe3c6897f6aJesse Butler pmcs_flush_target_queues(pwp, xp, PMCS_TGT_ALL_QUEUES);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dhpmcs_smp_function_result(pmcs_hw_t *pwp, smp_response_frame_t *srf)
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh switch (result) {
c3bc407cfbd238a18e4728ad5f36f39cecdb062fdh "%s: SMP DISCOVER Response "
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "Function Result: Unknown SMP Function(0x%x)",
c3bc407cfbd238a18e4728ad5f36f39cecdb062fdh "%s: SMP DISCOVER Response "
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "Function Result: SMP Function Failed(0x%x)",
c3bc407cfbd238a18e4728ad5f36f39cecdb062fdh "%s: SMP DISCOVER Response "
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "Function Result: Invalid Request Frame Length(0x%x)",
c3bc407cfbd238a18e4728ad5f36f39cecdb062fdh "%s: SMP DISCOVER Response "
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "Function Result: Incomplete Descriptor List(0x%x)",
c3bc407cfbd238a18e4728ad5f36f39cecdb062fdh "%s: SMP DISCOVER Response "
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "Function Result: PHY does not exist(0x%x)",
c3bc407cfbd238a18e4728ad5f36f39cecdb062fdh "%s: SMP DISCOVER Response "
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "Function Result: PHY Vacant(0x%x)",
c3bc407cfbd238a18e4728ad5f36f39cecdb062fdh "%s: SMP DISCOVER Response "
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "Function Result: (0x%x)",
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Do all the repetitive stuff necessary to setup for DMA
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * pwp: Used for dip
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * dma_attr: ddi_dma_attr_t to use for the mapping
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * acch: ddi_acc_handle_t to use for the mapping
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * dmah: ddi_dma_handle_t to use
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * length: Amount of memory for mapping
af4c679f647cf088543c762e33d41a3ac52cfa14Sean McEnroe * kvap: Pointer filled in with kernel virtual address on successful return
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * dma_addr: Pointer filled in with DMA address on successful return
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dhpmcs_dma_setup(pmcs_hw_t *pwp, ddi_dma_attr_t *dma_attr, ddi_acc_handle_t *acch,
af4c679f647cf088543c762e33d41a3ac52cfa14Sean McEnroe ddi_dma_handle_t *dmah, size_t length, caddr_t *kvap, uint64_t *dma_addr)
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh if (ddi_dma_alloc_handle(dip, dma_attr, DDI_DMA_SLEEP, NULL, dmah) !=
c3bc407cfbd238a18e4728ad5f36f39cecdb062fdh "Failed to allocate DMA handle");
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh if (ddi_dma_mem_alloc(*dmah, length, &mattr, ddma_flag, DDI_DMA_SLEEP,
af4c679f647cf088543c762e33d41a3ac52cfa14Sean McEnroe NULL, kvap, &real_length, acch) != DDI_SUCCESS) {
c3bc407cfbd238a18e4728ad5f36f39cecdb062fdh "Failed to allocate DMA mem");
af4c679f647cf088543c762e33d41a3ac52cfa14Sean McEnroe if (ddi_dma_addr_bind_handle(*dmah, NULL, *kvap, real_length,
c3bc407cfbd238a18e4728ad5f36f39cecdb062fdh pmcs_prt(pwp, PMCS_PRT_DEBUG, NULL, NULL, "Failed to bind DMA");
c3bc407cfbd238a18e4728ad5f36f39cecdb062fdh pmcs_prt(pwp, PMCS_PRT_DEBUG, NULL, NULL, "Multiple cookies");
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Flush requested queues for a particular target. Called with statlock held
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dhpmcs_flush_target_queues(pmcs_hw_t *pwp, pmcs_xscsi_t *tgt, uint8_t queues)
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Commands on the wait queue (or the special queue below) don't have
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * work structures associated with them.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "%s: Removing cmd 0x%p from wq for target 0x%p",
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Commands on the active queue will have work structures associated
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * with them.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * If we found a work structure, mark it as dead
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * and complete it
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "%s: Removing cmd 0x%p from aq for target 0x%p",
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "%s: Removing cmd 0x%p from sq for target 0x%p",
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dhpmcs_complete_work_impl(pmcs_hw_t *pwp, pmcwork_t *pwrk, uint32_t *iomb,
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * We will leak a structure here if we don't know
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * what happened
c3bc407cfbd238a18e4728ad5f36f39cecdb062fdh "%s: Unknown PMCS_TAG_TYPE (%x)",
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Determine if iport still has targets. During detach(9E), if SCSA is
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * successfull in its guarantee of tran_tgt_free(9E) before detach(9E),
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * this should always return B_FALSE.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dhpmcs_iport_has_targets(pmcs_hw_t *pwp, pmcs_iport_t *iport)
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Called with softstate lock held
c3bc407cfbd238a18e4728ad5f36f39cecdb062fdh "%s: target %p iport address is null",
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "%s: no iport associated with tgt(0x%p)",
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh ddi_soft_state_bystr_free(iport->tgt_sstate, target->unit_address);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * pmcs_lock_phy_impl
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * This function is what does the actual work for pmcs_lock_phy. It will
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * lock all PHYs from phyp down in a top-down fashion.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Locking notes:
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * 1. level starts from 0 for the PHY ("parent") that's passed in. It is
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * not a reflection of the actual level of the PHY in the SAS topology.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * 2. If parent is an expander, then parent is locked along with all its
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * descendents.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * 3. Expander subsidiary PHYs at level 0 are not locked. It is the
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * responsibility of the caller to individually lock expander subsidiary PHYs
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * at level 0 if necessary.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * 4. Siblings at level 0 are not traversed due to the possibility that we're
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * locking a PHY on the dead list. The siblings could be pointing to invalid
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * PHYs. We don't lock siblings at level 0 anyway.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dhstatic void
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Start walking the PHYs.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * If we're at the top level, only lock ourselves. For anything
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * at level > 0, traverse children while locking everything.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh if (level == 0) {
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * pmcs_lock_phy
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * This function is responsible for locking a PHY and all its descendents
c3bc407cfbd238a18e4728ad5f36f39cecdb062fdh pmcs_prt(phyp->pwp, PMCS_PRT_DEBUG_PHY_LOCKING, phyp, NULL,
c3bc407cfbd238a18e4728ad5f36f39cecdb062fdh pmcs_prt(phyp->pwp, PMCS_PRT_DEBUG_PHY_LOCKING, phyp, NULL,
c3bc407cfbd238a18e4728ad5f36f39cecdb062fdh pmcs_prt(phyp->pwp, PMCS_PRT_DEBUG_PHY_LOCKING, phyp, NULL,
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "%s: PHY 0x%p path %s", __func__, (void *)phyp, phyp->path);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * pmcs_unlock_phy_impl
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Unlock all PHYs from phyp down in a bottom-up fashion.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dhstatic void
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Recurse down to the bottom PHYs
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh if (level == 0) {
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Iterate through PHYs unlocking all at level > 0 as well the top PHY
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "%s: PHY 0x%p parent 0x%p path %s lvl %d",
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh if (level == 0) {
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * pmcs_unlock_phy
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Unlock a PHY and all its descendents
c3bc407cfbd238a18e4728ad5f36f39cecdb062fdh pmcs_prt(phyp->pwp, PMCS_PRT_DEBUG_PHY_LOCKING, phyp, NULL,
c3bc407cfbd238a18e4728ad5f36f39cecdb062fdh pmcs_prt(phyp->pwp, PMCS_PRT_DEBUG_PHY_LOCKING, phyp, NULL,
c3bc407cfbd238a18e4728ad5f36f39cecdb062fdh pmcs_prt(phyp->pwp, PMCS_PRT_DEBUG_PHY_LOCKING, phyp, NULL,
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "%s: PHY 0x%p path %s", __func__, (void *)phyp, phyp->path);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * pmcs_get_root_phy
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * For a given phy pointer return its root phy.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * The caller must be holding the lock on every PHY from phyp up to the root.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * pmcs_free_dma_chunklist
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Free DMA S/G chunk list
c3bc407cfbd238a18e4728ad5f36f39cecdb062fdh "Condition failed at %s():%d",
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh/*ARGSUSED2*/
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return (0);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh/*ARGSUSED1*/
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Free all PHYs from the kmem_cache starting at phyp as well as everything
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * on the dead_phys list.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * NOTE: This function does not free root PHYs as they are not allocated
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * from the kmem_cache.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * No PHY locks are acquired as this should only be called during DDI_DETACH
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * or soft reset (while pmcs interrupts are disabled).
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Free a list of PHYs linked together by the sibling pointer back to the
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * kmem cache from whence they came. This function does not recurse, so the
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * caller must ensure there are no children.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Make a copy of an existing PHY structure. This is used primarily in
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * discovery to compare the contents of an existing PHY with what gets
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * reported back by an expander.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * This function must not be called from any context where sleeping is
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * not possible.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * The new PHY is returned unlocked.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh local = kmem_cache_alloc(orig_phy->pwp->phy_cache, KM_SLEEP);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Go ahead and just copy everything...
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * But the following must be set appropriately for this copy
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh (void) snprintf(buf, FM_MAX_CLASS, "%s.%s", DDI_FM_DEVICE, detail);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh /* check all acc & dma handles allocated in attach */
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh if ((pmcs_check_acc_handle(pwp->pci_acc_handle) != DDI_SUCCESS) ||
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh (pmcs_check_acc_handle(pwp->msg_acc_handle) != DDI_SUCCESS) ||
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh (pmcs_check_acc_handle(pwp->top_acc_handle) != DDI_SUCCESS) ||
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh (pmcs_check_acc_handle(pwp->mpi_acc_handle) != DDI_SUCCESS) ||
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh (pmcs_check_acc_handle(pwp->gsm_acc_handle) != DDI_SUCCESS)) {
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh for (i = 0; i < PMCS_NIQ; i++) {
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh for (i = 0; i < PMCS_NOQ; i++) {
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh if ((pmcs_check_dma_handle(pwp->cip_handles) != DDI_SUCCESS) ||
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh (pmcs_check_acc_handle(pwp->cip_acchdls) != DDI_SUCCESS)) {
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh ((pmcs_check_dma_handle(pwp->fwlog_hndl) != DDI_SUCCESS) ||
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh (pmcs_check_acc_handle(pwp->fwlog_acchdl) != DDI_SUCCESS))) {
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh ((pmcs_check_dma_handle(pwp->regdump_hndl) != DDI_SUCCESS) ||
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return (0);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return (1);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * pmcs_handle_dead_phys
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * If the PHY has no outstanding work associated with it, remove it from
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * the dead PHY list and free it.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * If pwp->ds_err_recovering or pwp->configuring is set, don't run.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * This keeps routines that need to submit work to the chip from having to
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * hold PHY locks to ensure that PHYs don't disappear while they do their work.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Check every PHY in the dead PHY list
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Check for outstanding work
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "%s: Not freeing PHY 0x%p: target 0x%p is not free",
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * No outstanding work or target references. Remove it
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * from the list and free it
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "%s: Freeing inactive dead PHY 0x%p @ %s "
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * If pphyp is NULL, then phyp was the head of the list,
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * so just reset the head to nphyp. Otherwise, the
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * previous PHY will now point to nphyp (the next PHY)
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * If the target still points to this PHY, remove
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * that linkage now.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * pmcs_reap_dead_phy
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * This function is called from pmcs_new_tport when we have a PHY
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * without a target pointer. It's possible in that case that this PHY
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * may have a "brother" on the dead_phys list. That is, it may be the same as
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * this one but with a different root PHY number (e.g. pp05 vs. pp04). If
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * that's the case, update the dead PHY and this new PHY. If that's not the
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * case, we should get a tran_tgt_init on this after it's reported to SCSA.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Called with PHY locked.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dhstatic void
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Check the dead PHYs list
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Same SAS address on same iport. Now check to see if
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * the PHY path is the same with the possible exception
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * of the root PHY number.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * The "5" is the string length of "pp00."
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Found a match. Remove the target linkage and drop the
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * ref count on the old PHY. Then, increment the ref count
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * on the new PHY to compensate.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "%s: Found match in dead PHY list for new PHY %s",
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * If there is a pointer to the target in the dead
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * PHY, and that PHY's ref_count drops to 0, we can
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * clear the target linkage now. If the PHY's
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * ref_count is > 1, then there may be multiple
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * LUNs still remaining, so leave the linkage.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Update the target's linkage as well
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Called with iport lock held
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dhpmcs_add_phy_to_iport(pmcs_iport_t *iport, pmcs_phy_t *phyp)
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh pmcs_smhba_add_iport_prop(iport, DATA_TYPE_INT32, PMCS_NUM_PHYS,
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Called with the iport lock held
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dhpmcs_remove_phy_from_iport(pmcs_iport_t *iport, pmcs_phy_t *phyp)
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * If phyp is NULL, remove all PHYs from the iport
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh pmcs_smhba_add_iport_prop(iport, DATA_TYPE_INT32, PMCS_NUM_PHYS,
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * This function checks to see if the target pointed to by phyp is still
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * correct. This is done by comparing the target's unit address with the
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * SAS address in phyp.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Called with PHY locked and target statlock held
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh if (memcmp((void *)unit_address, (void *)phyp->target->unit_address,
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh strnlen(phyp->target->unit_address, PMCS_MAX_UA_SIZE)) == 0) {
6745c559e4b531cf336a91f4653445c32ee46693Jesse Butler * Commands used to serialize SMP requests.
6745c559e4b531cf336a91f4653445c32ee46693Jesse Butler * The SPC only allows 2 SMP commands per SMP target: 1 cmd pending and 1 cmd
6745c559e4b531cf336a91f4653445c32ee46693Jesse Butler * queued for the same SMP target. If a third SMP cmd is sent to the SPC for an
6745c559e4b531cf336a91f4653445c32ee46693Jesse Butler * SMP target that already has a SMP cmd pending and one queued, then the
6745c559e4b531cf336a91f4653445c32ee46693Jesse Butler * SPC responds with the ERROR_INTERNAL_SMP_RESOURCE response.
6745c559e4b531cf336a91f4653445c32ee46693Jesse Butler * Additionally, the SPC has an 8 entry deep cmd queue and the number of SMP
6745c559e4b531cf336a91f4653445c32ee46693Jesse Butler * cmds that can be queued is controlled by the PORT_CONTROL IOMB. The
6745c559e4b531cf336a91f4653445c32ee46693Jesse Butler * SPC default is 1 SMP command/port (iport). These 2 queued SMP cmds would
6745c559e4b531cf336a91f4653445c32ee46693Jesse Butler * have to be for different SMP targets. The INTERNAL_SMP_RESOURCE error will
6745c559e4b531cf336a91f4653445c32ee46693Jesse Butler * also be returned if a 2nd SMP cmd is sent to the controller when there is
6745c559e4b531cf336a91f4653445c32ee46693Jesse Butler * already 1 SMP cmd queued for that port or if a 3rd SMP cmd is sent to the
6745c559e4b531cf336a91f4653445c32ee46693Jesse Butler * queue if there are already 2 queued SMP cmds.
6745c559e4b531cf336a91f4653445c32ee46693Jesse Butler pmcs_prt(iport->pwp, PMCS_PRT_DEBUG_IPORT, NULL, NULL,
6745c559e4b531cf336a91f4653445c32ee46693Jesse Butler pmcs_prt(iport->pwp, PMCS_PRT_DEBUG_IPORT, NULL, NULL,
6745c559e4b531cf336a91f4653445c32ee46693Jesse Butler "%s: SMP is active on thread 0x%p, waiting", __func__,
6745c559e4b531cf336a91f4653445c32ee46693Jesse Butler pmcs_prt(iport->pwp, PMCS_PRT_DEBUG_IPORT, NULL, NULL,
6745c559e4b531cf336a91f4653445c32ee46693Jesse Butler pmcs_prt(iport->pwp, PMCS_PRT_DEBUG_IPORT, NULL, NULL,
6745c559e4b531cf336a91f4653445c32ee46693Jesse Butler pmcs_prt(iport->pwp, PMCS_PRT_DEBUG_IPORT, NULL, NULL,
6745c559e4b531cf336a91f4653445c32ee46693Jesse Butler "%s: SMP released by thread 0x%p", __func__, (void *)curthread);