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
658280b6253b61dbb155f43d0e3cbcffa85ccb90David Hollister * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * This file contains various support routines.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Local static data
60aabb4ce92352f01733c518d6b6bb69e60b9113Chris Hornestatic int tgtmap_stable_usec = MICROSEC; /* 1 second */
60aabb4ce92352f01733c518d6b6bb69e60b9113Chris Hornestatic int tgtmap_csync_usec = 10 * MICROSEC; /* 10 seconds */
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * SAS Topology Configuration
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dhstatic void pmcs_configure_expander(pmcs_hw_t *, pmcs_phy_t *, pmcs_iport_t *);
73a3eccd27d9673a6407274ea0de350699562fd9David Hollisterstatic void 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 *);
3be32c0f0acac4f6258b029f1a27a16a7ec65bb0Jesse Butlerstatic void pmcs_flush_nonio_cmds(pmcs_hw_t *pwp, pmcs_xscsi_t *tgt);
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 *);
601c90f161ff0319c1b4a2c3362b466043a65d8dSrikanth, Ramanastatic void pmcs_begin_observations(pmcs_hw_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 *);
9aed162131f1840d0bc1cd0275f4d7144f3690f0David Hollisterstatic void pmcs_iport_active(pmcs_iport_t *);
9aed162131f1840d0bc1cd0275f4d7144f3690f0David Hollisterstatic void pmcs_tgtmap_activate_cb(void *, char *, scsi_tgtmap_tgt_type_t,
9aed162131f1840d0bc1cd0275f4d7144f3690f0David Hollisterstatic boolean_t pmcs_tgtmap_deactivate_cb(void *, char *,
9aed162131f1840d0bc1cd0275f4d7144f3690f0David Hollister scsi_tgtmap_tgt_type_t, void *, scsi_tgtmap_deact_rsn_t);
9aed162131f1840d0bc1cd0275f4d7144f3690f0David Hollisterstatic void pmcs_add_dead_phys(pmcs_hw_t *, pmcs_phy_t *);
2ac4abe882db38ef90020f7c5ca28586e3d57258David Hollisterstatic void pmcs_get_fw_version(pmcs_hw_t *);
1f81b46471e38fdeb9ab74c25510b2f903f8af12David Hollisterstatic int pmcs_get_time_stamp(pmcs_hw_t *, uint64_t *, hrtime_t *);
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));
658280b6253b61dbb155f43d0e3cbcffa85ccb90David Hollister * If the open retry interval is non-zero, set it.
658280b6253b61dbb155f43d0e3cbcffa85ccb90David Hollister "%s: Setting open retry interval to %d usecs", __func__,
658280b6253b61dbb155f43d0e3cbcffa85ccb90David Hollister for (phynum = 0; phynum < pwp->nphy; phynum ++) {
658280b6253b61dbb155f43d0e3cbcffa85ccb90David Hollister pmcs_wr_gsm_reg(pwp, OPEN_RETRY_INTERVAL(phynum),
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)",
1f81b46471e38fdeb9ab74c25510b2f903f8af12David Hollister rval = pmcs_get_time_stamp(pwp, &pwp->fw_timestamp, &pwp->hrtimestamp);
1f81b46471e38fdeb9ab74c25510b2f903f8af12David Hollister "%s: Failed to obtain firmware timestamp", __func__);
1f81b46471e38fdeb9ab74c25510b2f903f8af12David Hollister "Firmware timestamp: 0x%" PRIx64, pwp->fw_timestamp);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return (0);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Called with PHY locked
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dhpmcs_reset_phy(pmcs_hw_t *pwp, pmcs_phy_t *pptr, uint8_t type)
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh if (level > 0) {
601c90f161ff0319c1b4a2c3362b466043a65d8dSrikanth, Ramana } else if ((level == 0) && (pptr->dtype == EXPANDER)) {
601c90f161ff0319c1b4a2c3362b466043a65d8dSrikanth, Ramana pmcs_prt(pwp, PMCS_PRT_DEBUG, pptr, pptr->target,
601c90f161ff0319c1b4a2c3362b466043a65d8dSrikanth, Ramana "%s: Not resetting HBA PHY @ %s", __func__, pptr->path);
9aed162131f1840d0bc1cd0275f4d7144f3690f0David Hollister if (!pptr->iport || !pptr->valid_device_id) {
9aed162131f1840d0bc1cd0275f4d7144f3690f0David Hollister pmcs_prt(pwp, PMCS_PRT_DEBUG, pptr, pptr->target,
9aed162131f1840d0bc1cd0275f4d7144f3690f0David Hollister "%s: Can't reach PHY %s", __func__, pptr->path);
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 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
1f81b46471e38fdeb9ab74c25510b2f903f8af12David Hollisterpmcs_get_time_stamp(pmcs_hw_t *pwp, uint64_t *fw_ts, hrtime_t *sys_hr_ts)
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);
1f81b46471e38fdeb9ab74c25510b2f903f8af12David Hollister *fw_ts = LE_32(msg[2]) | (((uint64_t)LE_32(msg[3])) << 32);
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
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) {
601c90f161ff0319c1b4a2c3362b466043a65d8dSrikanth, Ramana * If the iport is no longer active, flush the queues
601c90f161ff0319c1b4a2c3362b466043a65d8dSrikanth, Ramana pmcs_prt(pwp, PMCS_PRT_DEBUG_CONFIG, pptr, tgt,
601c90f161ff0319c1b4a2c3362b466043a65d8dSrikanth, Ramana "%s: Clearing target 0x%p, inactive iport",
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
1b94a41b6ff7cb545cabcda970647c0361ed118aChris Horne * destroyed.
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__);
5c45adf04db8ffdcb5dd969bb5203ff9b17677dbJesse Butler * Clear our softstate copies of the MSGU and IOP heartbeats.
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);
2ac4abe882db38ef90020f7c5ca28586e3d57258David Hollister gsm = pmcs_rd_gsm_reg(pwp, 0, GSM_CFG_AND_RESET);
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);
2ac4abe882db38ef90020f7c5ca28586e3d57258David Hollister rapchk = pmcs_rd_gsm_reg(pwp, 0, READ_ADR_PARITY_CHK_EN);
c3bc407cfbd238a18e4728ad5f36f39cecdb062fdh pmcs_prt(pwp, PMCS_PRT_DEBUG2, NULL, NULL, "READ_ADR_PARITY_CHK_EN "
2ac4abe882db38ef90020f7c5ca28586e3d57258David Hollister wapchk = pmcs_rd_gsm_reg(pwp, 0, WRITE_ADR_PARITY_CHK_EN);
c3bc407cfbd238a18e4728ad5f36f39cecdb062fdh pmcs_prt(pwp, PMCS_PRT_DEBUG2, NULL, NULL, "WRITE_ADR_PARITY_CHK_EN "
2ac4abe882db38ef90020f7c5ca28586e3d57258David Hollister wdpchk = pmcs_rd_gsm_reg(pwp, 0, WRITE_DATA_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)
2ac4abe882db38ef90020f7c5ca28586e3d57258David Hollister tsmode = pmcs_rd_gsm_reg(pwp, 0, 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));
2ac4abe882db38ef90020f7c5ca28586e3d57258David Hollister gsm = pmcs_rd_gsm_reg(pwp, 0, GSM_CFG_AND_RESET);
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 "
2ac4abe882db38ef90020f7c5ca28586e3d57258David Hollister "%08x -> %08x", pmcs_rd_gsm_reg(pwp, 0, READ_ADR_PARITY_CHK_EN),
c3bc407cfbd238a18e4728ad5f36f39cecdb062fdh pmcs_prt(pwp, PMCS_PRT_DEBUG2, NULL, NULL, "WRITE_ADR_PARITY_CHK_EN "
2ac4abe882db38ef90020f7c5ca28586e3d57258David Hollister "%08x -> %08x", pmcs_rd_gsm_reg(pwp, 0, WRITE_ADR_PARITY_CHK_EN),
c3bc407cfbd238a18e4728ad5f36f39cecdb062fdh pmcs_prt(pwp, PMCS_PRT_DEBUG2, NULL, NULL, "WRITE_DATA_PARITY_CHK_EN "
2ac4abe882db38ef90020f7c5ca28586e3d57258David Hollister "%08x -> %08x", pmcs_rd_gsm_reg(pwp, 0, 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);
5c45adf04db8ffdcb5dd969bb5203ff9b17677dbJesse Butler /* Clear the firmware log */
5c45adf04db8ffdcb5dd969bb5203ff9b17677dbJesse Butler /* Reset our queue indices and entries */
5c45adf04db8ffdcb5dd969bb5203ff9b17677dbJesse Butler bzero(pwp->shadow_iqpi, sizeof (pwp->shadow_iqpi));
5c45adf04db8ffdcb5dd969bb5203ff9b17677dbJesse Butler bzero(pwp->last_iqci, sizeof (pwp->last_iqci));
d78a6b7e13de1e122f6c7e0d539522698d83ec22Jesse Butler bzero(pwp->last_htag, sizeof (pwp->last_htag));
5c45adf04db8ffdcb5dd969bb5203ff9b17677dbJesse Butler for (i = 0; i < PMCS_NIQ; i++) {
5c45adf04db8ffdcb5dd969bb5203ff9b17677dbJesse Butler bzero(pwp->iqp[i], PMCS_QENTRY_SIZE * pwp->ioq_depth);
5c45adf04db8ffdcb5dd969bb5203ff9b17677dbJesse Butler for (i = 0; i < PMCS_NOQ; i++) {
5c45adf04db8ffdcb5dd969bb5203ff9b17677dbJesse Butler bzero(pwp->oqp[i], PMCS_QENTRY_SIZE * pwp->ioq_depth);
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);
5c45adf04db8ffdcb5dd969bb5203ff9b17677dbJesse Butler * Flush the target queues and clear each target's PHY
5c45adf04db8ffdcb5dd969bb5203ff9b17677dbJesse Butler pmcs_flush_target_queues(pwp, xp, PMCS_TGT_ALL_QUEUES);
5c45adf04db8ffdcb5dd969bb5203ff9b17677dbJesse Butler * Zero out the ports list, free non root phys, clear root phys
5c45adf04db8ffdcb5dd969bb5203ff9b17677dbJesse Butler for (pptr = pwp->root_phys; pptr; pptr = pptr->sibling) {
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);
5c45adf04db8ffdcb5dd969bb5203ff9b17677dbJesse Butler * Perform a 'hot' reset, which will soft reset the chip and
5c45adf04db8ffdcb5dd969bb5203ff9b17677dbJesse Butler * restore the state back to pre-reset context. Called with pwp
5c45adf04db8ffdcb5dd969bb5203ff9b17677dbJesse Butler * lock held.
5c45adf04db8ffdcb5dd969bb5203ff9b17677dbJesse Butler * For any iports on this HBA, report empty target sets and
5c45adf04db8ffdcb5dd969bb5203ff9b17677dbJesse Butler * then tear them down.
5c45adf04db8ffdcb5dd969bb5203ff9b17677dbJesse Butler for (iport = list_head(&pwp->iports); iport != NULL;
5c45adf04db8ffdcb5dd969bb5203ff9b17677dbJesse Butler (void) scsi_hba_tgtmap_set_begin(iport->iss_tgtmap);
5c45adf04db8ffdcb5dd969bb5203ff9b17677dbJesse Butler (void) scsi_hba_tgtmap_set_end(iport->iss_tgtmap, 0);
5c45adf04db8ffdcb5dd969bb5203ff9b17677dbJesse Butler /* Grab a register dump, in the event that reset fails */
32b54db7d7ecdb10cc3178edf2c480c6dc5c5559Jesse Butler /* Ensure discovery is not running before we proceed */
5c45adf04db8ffdcb5dd969bb5203ff9b17677dbJesse Butler /* Issue soft reset and clean up related softstate */
5c45adf04db8ffdcb5dd969bb5203ff9b17677dbJesse Butler * Disable interrupts, in case we got far enough along to
5c45adf04db8ffdcb5dd969bb5203ff9b17677dbJesse Butler * enable them, then fire off ereport and service impact.
5c45adf04db8ffdcb5dd969bb5203ff9b17677dbJesse Butler pmcs_wr_msgunit(pwp, PMCS_MSGU_OBDB_MASK, 0xffffffff);
5c45adf04db8ffdcb5dd969bb5203ff9b17677dbJesse Butler pmcs_wr_msgunit(pwp, PMCS_MSGU_OBDB_CLEAR, 0xffffffff);
5c45adf04db8ffdcb5dd969bb5203ff9b17677dbJesse Butler pmcs_fm_ereport(pwp, DDI_FM_DEVICE_NO_RESPONSE);
5c45adf04db8ffdcb5dd969bb5203ff9b17677dbJesse Butler ddi_fm_service_impact(pwp->dip, DDI_SERVICE_LOST);
5c45adf04db8ffdcb5dd969bb5203ff9b17677dbJesse Butler * Finally, restart the phys, which will bring the iports back
5c45adf04db8ffdcb5dd969bb5203ff9b17677dbJesse Butler * up and eventually result in discovery running.
5c45adf04db8ffdcb5dd969bb5203ff9b17677dbJesse Butler /* We should be up and running now, so retry */
5c45adf04db8ffdcb5dd969bb5203ff9b17677dbJesse Butler /* Apparently unable to restart PHYs, fail */
5c45adf04db8ffdcb5dd969bb5203ff9b17677dbJesse Butler "%s: failed to restart PHYs after soft reset",
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 */
60aabb4ce92352f01733c518d6b6bb69e60b9113Chris Horne if (scsi_hba_tgtmap_create(iport->dip, SCSI_TM_FULLSET,
60aabb4ce92352f01733c518d6b6bb69e60b9113Chris Horne tgtmap_csync_usec, tgtmap_stable_usec, (void *)iport,
60aabb4ce92352f01733c518d6b6bb69e60b9113Chris Horne pmcs_tgtmap_activate_cb, pmcs_tgtmap_deactivate_cb,
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.
5c45adf04db8ffdcb5dd969bb5203ff9b17677dbJesse Butler * Called when a port has been reset by the host (see pmcs_intr.c)
5c45adf04db8ffdcb5dd969bb5203ff9b17677dbJesse Butler * or prior to issuing a soft reset if we detect a stall on the chip
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);
5c45adf04db8ffdcb5dd969bb5203ff9b17677dbJesse Butler while ((phynum = sas_phymap_phys_next(phys)) != -1) {
5c45adf04db8ffdcb5dd969bb5203ff9b17677dbJesse Butler (void) sas_phymap_phy_rem(pwp->hss_phymap, phynum);
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.
9aed162131f1840d0bc1cd0275f4d7144f3690f0David Hollisterpmcs_get_iport_by_wwn(pmcs_hw_t *pwp, uint64_t wwn)
9aed162131f1840d0bc1cd0275f4d7144f3690f0David Hollister ua = sas_phymap_lookup_ua(pwp->hss_phymap, pwp->sas_wwns[0], wwn);
9aed162131f1840d0bc1cd0275f4d7144f3690f0David Hollister pmcs_prt(pwp, PMCS_PRT_DEBUG_CONFIG, NULL, NULL, "%s: "
9aed162131f1840d0bc1cd0275f4d7144f3690f0David Hollister "found iport [0x%p] on ua (%s), refcnt (%d)",
9aed162131f1840d0bc1cd0275f4d7144f3690f0David Hollister __func__, (void *)iport, ua, iport->refcnt);
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;
499cfd156ad653fc27397c5f021047c091dd12c5David Hollister /* Update the phy mask properties for the affected PHYs */
499cfd156ad653fc27397c5f021047c091dd12c5David Hollister /* Clear the current values... */
499cfd156ad653fc27397c5f021047c091dd12c5David Hollister pmcs_update_phy_pm_props(pptr, pptr->att_port_pm_tmp,
499cfd156ad653fc27397c5f021047c091dd12c5David Hollister /* ...replace with the values from prev_primary... */
499cfd156ad653fc27397c5f021047c091dd12c5David Hollister pmcs_update_phy_pm_props(pptr, prev_primary->att_port_pm_tmp,
499cfd156ad653fc27397c5f021047c091dd12c5David Hollister /* ...then clear prev_primary's PHY values from the new primary */
499cfd156ad653fc27397c5f021047c091dd12c5David Hollister pmcs_update_phy_pm_props(pptr, prev_primary->att_port_pm,
499cfd156ad653fc27397c5f021047c091dd12c5David Hollister /* Clear the prev_primary's values */
499cfd156ad653fc27397c5f021047c091dd12c5David Hollister pmcs_update_phy_pm_props(prev_primary, prev_primary->att_port_pm_tmp,
3be32c0f0acac4f6258b029f1a27a16a7ec65bb0Jesse Butler pptr->valid_device_id = prev_primary->valid_device_id;
f73ae3db72a91f9f8759931a1c643c7dad785881Jesse Butler * We call pmcs_unlock_phy() on pptr because it now contains the
f73ae3db72a91f9f8759931a1c643c7dad785881Jesse Butler * list of children.
3be32c0f0acac4f6258b029f1a27a16a7ec65bb0Jesse Butler * Grab a reference to this iport.
3be32c0f0acac4f6258b029f1a27a16a7ec65bb0Jesse Butler pmcs_prt(iport->pwp, PMCS_PRT_DEBUG2, NULL, NULL, "%s: iport "
3be32c0f0acac4f6258b029f1a27a16a7ec65bb0Jesse Butler "[0x%p] refcnt (%d)", __func__, (void *)iport, iport->refcnt);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Release a refcnt on this iport. If this is the last reference,
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * signal the potential waiter in pmcs_iport_unattach().
3be32c0f0acac4f6258b029f1a27a16a7ec65bb0Jesse Butler pmcs_prt(iport->pwp, PMCS_PRT_DEBUG2, NULL, NULL, "%s: iport "
c3bc407cfbd238a18e4728ad5f36f39cecdb062fdh "[0x%p] refcnt (%d)", __func__, (void *)iport, iport->refcnt);
978d7443a924cda8208d6a10e72be89383bc7becSrikanth Suravajhala 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");
601c90f161ff0319c1b4a2c3362b466043a65d8dSrikanth, Ramana * First, tell SCSA that we're beginning set operations.
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.
73a3eccd27d9673a6407274ea0de350699562fd9David Hollister pmcs_prt(pwp, PMCS_PRT_DEBUG_CONFIG, NULL, NULL,
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)) {
601c90f161ff0319c1b4a2c3362b466043a65d8dSrikanth, Ramana * We may (or may not) report observations to SCSA. This is prefaced by
601c90f161ff0319c1b4a2c3362b466043a65d8dSrikanth, Ramana * issuing a set_begin for each iport target map.
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);
0b53804eda5b4c11fc7de70e5c9f243b34fa1245Reed * Tell SCSA to flush the observations we've already sent (if any), as they
0b53804eda5b4c11fc7de70e5c9f243b34fa1245Reed * are no longer valid.
0b53804eda5b4c11fc7de70e5c9f243b34fa1245Reedstatic void
0b53804eda5b4c11fc7de70e5c9f243b34fa1245Reed * Skip this iport if it has no PHYs up.
0b53804eda5b4c11fc7de70e5c9f243b34fa1245Reed if (!sas_phymap_uahasphys(pwp->hss_phymap, iport->ua)) {
0b53804eda5b4c11fc7de70e5c9f243b34fa1245Reed if (scsi_hba_tgtmap_set_flush(tgtmap) != DDI_SUCCESS) {
601c90f161ff0319c1b4a2c3362b466043a65d8dSrikanth, Ramana * Report current observations to SCSA.
601c90f161ff0319c1b4a2c3362b466043a65d8dSrikanth, Ramana * Observation is stable, report what we currently see to the tgtmaps
601c90f161ff0319c1b4a2c3362b466043a65d8dSrikanth, Ramana * for delta processing.
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 */
499cfd156ad653fc27397c5f021047c091dd12c5David Hollister SCSI_ADDR_PROP_ATTACHED_PORT, ap) != DDI_SUCCESS) {
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 */
a25672a1f5bcd6aa4bbce28adab51d84ae202323David Hollister * Validate the PHY's SAS address
a25672a1f5bcd6aa4bbce28adab51d84ae202323David Hollister if (((lphyp->sas_address[0] & 0xf0) >> 4) != NAA_IEEE_REG) {
a25672a1f5bcd6aa4bbce28adab51d84ae202323David Hollister "PHY 0x%p (%s) has invalid SAS address; "
a25672a1f5bcd6aa4bbce28adab51d84ae202323David Hollister "will not enumerate", (void *)lphyp, lphyp->path);
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) {
3be32c0f0acac4f6258b029f1a27a16a7ec65bb0Jesse Butler /* Confirm that this iport is configured */
9aed162131f1840d0bc1cd0275f4d7144f3690f0David Hollister wwn = pmcs_barray2wwn(root_phy->sas_address);
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 */
73a3eccd27d9673a6407274ea0de350699562fd9David Hollister * If the PHY has no target pointer:
73a3eccd27d9673a6407274ea0de350699562fd9David Hollister * If it's a root PHY, see if another PHY in the iport holds the
73a3eccd27d9673a6407274ea0de350699562fd9David Hollister * target pointer (primary PHY changed). If so, move it over.
73a3eccd27d9673a6407274ea0de350699562fd9David Hollister * If it's not a root PHY, see if there's a PHY on the dead_phys
73a3eccd27d9673a6407274ea0de350699562fd9David Hollister * list that matches.
73a3eccd27d9673a6407274ea0de350699562fd9David Hollister /* The target is now on pptr */
73a3eccd27d9673a6407274ea0de350699562fd9David Hollister "%s: Moved target from %s to %s",
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.
499cfd156ad653fc27397c5f021047c091dd12c5David Hollister * Update the primary PHY's attached-port-pm
499cfd156ad653fc27397c5f021047c091dd12c5David Hollister * and target-port-pm information with the info
499cfd156ad653fc27397c5f021047c091dd12c5David Hollister * from this subsidiary
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 */
9aed162131f1840d0bc1cd0275f4d7144f3690f0David Hollister * Step 9: Install the new list on the next level. There should
9aed162131f1840d0bc1cd0275f4d7144f3690f0David Hollister * typically be no children pointer on this PHY. There is one known
9aed162131f1840d0bc1cd0275f4d7144f3690f0David Hollister * case where this can happen, though. If a root PHY goes down and
9aed162131f1840d0bc1cd0275f4d7144f3690f0David Hollister * comes back up before discovery can run, we will fail to remove the
9aed162131f1840d0bc1cd0275f4d7144f3690f0David Hollister * children from that PHY since it will no longer be marked dead.
9aed162131f1840d0bc1cd0275f4d7144f3690f0David Hollister * However, in this case, all children should also be marked dead. If
9aed162131f1840d0bc1cd0275f4d7144f3690f0David Hollister * we see that, take those children and put them on the dead_phys list.
9aed162131f1840d0bc1cd0275f4d7144f3690f0David Hollister "%s: Expander @ %s still has children: Clean up",
9aed162131f1840d0bc1cd0275f4d7144f3690f0David Hollister * Set the new children pointer for this expander
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",
73a3eccd27d9673a6407274ea0de350699562fd9David Hollister * Since this PHY was nothing and is now
73a3eccd27d9673a6407274ea0de350699562fd9David Hollister * something, reset the config_stop timer.
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.
b979a950ca009c700d704545d38e7d934d80d85bSrikanth Suravajhala ctmp->att_port_pm_tmp = local->att_port_pm_tmp;
b979a950ca009c700d704545d38e7d934d80d85bSrikanth Suravajhala ctmp->tgt_port_pm_tmp = local->tgt_port_pm_tmp;
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 * 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 * 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.
9aed162131f1840d0bc1cd0275f4d7144f3690f0David Hollister if (!pptr->iport || !pptr->valid_device_id) {
9aed162131f1840d0bc1cd0275f4d7144f3690f0David Hollister pmcs_prt(pwp, PMCS_PRT_DEBUG_CONFIG, pptr, pptr->target,
9aed162131f1840d0bc1cd0275f4d7144f3690f0David Hollister "%s: Can't reach PHY %s", __func__, pptr->path);
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).
225bf9057f97461ac410ec2e1432d1575360ee18Jesse Butler pmcs_prt(pwp, PMCS_PRT_DEBUG_CONFIG, pptr, NULL,
225bf9057f97461ac410ec2e1432d1575360ee18Jesse Butler "%s: Issuing SMP ABORT for htag 0x%08x", __func__, htag);
225bf9057f97461ac410ec2e1432d1575360ee18Jesse Butler pmcs_prt(pwp, PMCS_PRT_DEBUG_CONFIG, pptr, NULL,
225bf9057f97461ac410ec2e1432d1575360ee18Jesse Butler "%s: SMP ABORT failed for cmd (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 */
a25672a1f5bcd6aa4bbce28adab51d84ae202323David Hollister case PMCOUT_STATUS_IO_OPEN_CNX_ERROR_HW_RESOURCE_BUSY:
a25672a1f5bcd6aa4bbce28adab51d84ae202323David Hollister /* 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",
9aed162131f1840d0bc1cd0275f4d7144f3690f0David Hollister * Save off the REPORT_GENERAL response
9aed162131f1840d0bc1cd0275f4d7144f3690f0David Hollister bcopy(srgr, &pptr->rg_resp, sizeof (smp_report_general_resp_t));
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,
9aed162131f1840d0bc1cd0275f4d7144f3690f0David Hollister if (!expander->iport || !expander->valid_device_id) {
9aed162131f1840d0bc1cd0275f4d7144f3690f0David Hollister pmcs_prt(pwp, PMCS_PRT_DEBUG_CONFIG, expander, expander->target,
9aed162131f1840d0bc1cd0275f4d7144f3690f0David Hollister "%s: Can't reach PHY %s", __func__, expander->path);
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).
225bf9057f97461ac410ec2e1432d1575360ee18Jesse Butler pmcs_prt(pwp, PMCS_PRT_DEBUG_CONFIG, pptr, NULL,
225bf9057f97461ac410ec2e1432d1575360ee18Jesse Butler "%s: Issuing SMP ABORT for htag 0x%08x", __func__, htag);
225bf9057f97461ac410ec2e1432d1575360ee18Jesse Butler pmcs_prt(pwp, PMCS_PRT_DEBUG_CONFIG, pptr, NULL,
225bf9057f97461ac410ec2e1432d1575360ee18Jesse Butler "%s: SMP ABORT failed for cmd (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 */
a25672a1f5bcd6aa4bbce28adab51d84ae202323David Hollister case PMCOUT_STATUS_IO_OPEN_CNX_ERROR_HW_RESOURCE_BUSY:
a25672a1f5bcd6aa4bbce28adab51d84ae202323David Hollister /* 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 */
9aed162131f1840d0bc1cd0275f4d7144f3690f0David Hollister * Save off the DISCOVER response
9aed162131f1840d0bc1cd0275f4d7144f3690f0David Hollister bcopy(sdr, &pptr->disc_resp, sizeof (smp_discover_resp_t));
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh pmcs_wwn2barray(BE_64(sdr->sdr_attached_sas_addr), att_sas_address);
9aed162131f1840d0bc1cd0275f4d7144f3690f0David Hollister * Set the routing attribute regardless of the PHY type.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "exp_content: %s atdt=0x%x lr=%x is=%x ts=%x SAS="
c3bc407cfbd238a18e4728ad5f36f39cecdb062fdh "%s: %s has tgt support=%x init support=(%x)",
9aed162131f1840d0bc1cd0275f4d7144f3690f0David Hollister pptr->routing_method = 0xff; /* Invalid method */
616875b414de63a60e3f732e0d9b5345f07f9221David Hollister pmcs_update_phy_pm_props(pptr, (1ULL << pptr->phynum),
616875b414de63a60e3f732e0d9b5345f07f9221David Hollister (1ULL << sdr->sdr_attached_phy_identifier), B_TRUE);
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)",
9aed162131f1840d0bc1cd0275f4d7144f3690f0David Hollister if (pptr->routing_attr == SMP_ROUTING_DIRECT) {
9aed162131f1840d0bc1cd0275f4d7144f3690f0David Hollister pptr->routing_method = 0xff; /* Invalid method */
616875b414de63a60e3f732e0d9b5345f07f9221David Hollister pmcs_update_phy_pm_props(pptr, (1ULL << pptr->phynum),
616875b414de63a60e3f732e0d9b5345f07f9221David Hollister (1ULL << sdr->sdr_attached_phy_identifier), B_TRUE);
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.
a25672a1f5bcd6aa4bbce28adab51d84ae202323David Hollister (roff[SAS_ATTACHED_NAME_OFFSET] >> 8) == NAA_IEEE_REG) {
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
02b04f6e56ca306b4945eca969f282cfe6999414Srikanth, Ramana * free list (assuming it's not also empty).
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.
978d7443a924cda8208d6a10e72be89383bc7becSrikanth Suravajhala * If lock_phy is B_TRUE, then lock the phy also when returning the work struct
978d7443a924cda8208d6a10e72be89383bc7becSrikanth Suravajhalapmcs_tag2wp(pmcs_hw_t *pwp, uint32_t htag, boolean_t lock_phy)
188eaed9d5f14c73dfba1cd0dabaa430bdfd4a9aSrikanth Suravajhala /* phy lock should be held before work lock */
188eaed9d5f14c73dfba1cd0dabaa430bdfd4a9aSrikanth Suravajhala * Check htag again, in case the work got completed
188eaed9d5f14c73dfba1cd0dabaa430bdfd4a9aSrikanth Suravajhala * while we dropped the work lock and got the phy lock
188eaed9d5f14c73dfba1cd0dabaa430bdfd4a9aSrikanth Suravajhala pmcs_prt(pwp, PMCS_PRT_DEBUG, phyp, NULL, "%s: "
188eaed9d5f14c73dfba1cd0dabaa430bdfd4a9aSrikanth Suravajhala "HTAG (0x%x) found, but work (0x%p) "
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);
39cd77a06f56f308333bd7b2d8aae1b1467be113Jesse Butler "%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 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");
9aed162131f1840d0bc1cd0275f4d7144f3690f0David Hollister case PMCOUT_STATUS_OPEN_CNX_ERROR_UNKNOWN_ERROR:
9aed162131f1840d0bc1cd0275f4d7144f3690f0David Hollister return ("OPEN_CNX_ERROR_UNKNOWN_ERROR");
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");
a25672a1f5bcd6aa4bbce28adab51d84ae202323David Hollister case PMCOUT_STATUS_IO_OPEN_CNX_ERROR_HW_RESOURCE_BUSY:
a25672a1f5bcd6aa4bbce28adab51d84ae202323David Hollister return ("OPEN CNX ERR HW RESOURCE BUSY");
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh for (i = 0; i < 8; i++) {
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh for (i = 0; i < 8; i++) {
2ac4abe882db38ef90020f7c5ca28586e3d57258David Hollister "Chip Revision: %c; F/W Revision %x.%x.%x %s (ILA rev %08x)",
2ac4abe882db38ef90020f7c5ca28586e3d57258David Hollister 'A' + pwp->chiprev, PMCS_FW_MAJOR(pwp), PMCS_FW_MINOR(pwp),
2ac4abe882db38ef90020f7c5ca28586e3d57258David Hollister PMCS_FW_MICRO(pwp), fwsupport, pwp->ila_ver);
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 * 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)
9aed162131f1840d0bc1cd0275f4d7144f3690f0David Hollister * This can still be OK if both of these PHYs actually
9aed162131f1840d0bc1cd0275f4d7144f3690f0David Hollister * represent the same device (e.g. expander). It could
9aed162131f1840d0bc1cd0275f4d7144f3690f0David Hollister * be a case of a new "primary" PHY. If the SAS address
9aed162131f1840d0bc1cd0275f4d7144f3690f0David Hollister * is the same and they have the same parent, we'll
9aed162131f1840d0bc1cd0275f4d7144f3690f0David Hollister * accept this if the PHY to be registered is the
9aed162131f1840d0bc1cd0275f4d7144f3690f0David Hollister pptr->sas_address, 8) == 0) && (phyp->width > 1)) {
9aed162131f1840d0bc1cd0275f4d7144f3690f0David Hollister * Move children over to the new primary and
9aed162131f1840d0bc1cd0275f4d7144f3690f0David Hollister * update both PHYs
9aed162131f1840d0bc1cd0275f4d7144f3690f0David Hollister * device_id, valid_device_id, and configured
9aed162131f1840d0bc1cd0275f4d7144f3690f0David Hollister * will be set by the caller
9aed162131f1840d0bc1cd0275f4d7144f3690f0David Hollister pmcs_prt(pptr->pwp, PMCS_PRT_DEBUG, pptr, NULL,
9aed162131f1840d0bc1cd0275f4d7144f3690f0David Hollister "%s: Moving device_id %d from PHY %s to %s",
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 |
a25672a1f5bcd6aa4bbce28adab51d84ae202323David Hollister "FIS: 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).
3be32c0f0acac4f6258b029f1a27a16a7ec65bb0Jesse Butler pmcs_prt(pwp, PMCS_PRT_DEBUG_CONFIG, tphyp, NULL,
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Abort commands on dead PHYs and deregister them as well as removing
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * the associated targets.
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",
3be32c0f0acac4f6258b029f1a27a16a7ec65bb0Jesse Butler rval = pmcs_abort(pwp, pptr, pptr->device_id, 1, 1);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "%s: ABORT_ALL returned non-zero status (%d) for "
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 * 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) !=
2ac4abe882db38ef90020f7c5ca28586e3d57258David Hollisterpmcs_rd_gsm_reg(pmcs_hw_t *pwp, uint8_t hi, uint32_t off)
c3bc407cfbd238a18e4728ad5f36f39cecdb062fdh "AXIL register update failed");
2ac4abe882db38ef90020f7c5ca28586e3d57258David Hollister &pwp->top_regs[PMCS_AXI_TRANS_UPPER >> 2], hi);
2ac4abe882db38ef90020f7c5ca28586e3d57258David Hollister &pwp->top_regs[PMCS_AXI_TRANS_UPPER >> 2]) != hi) {
2ac4abe882db38ef90020f7c5ca28586e3d57258David Hollister "AXIH register update failed");
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh rv = ddi_get32(pwp->gsm_acc_handle, &pwp->gsm_regs[off >> 2]);
2ac4abe882db38ef90020f7c5ca28586e3d57258David Hollister &pwp->top_regs[PMCS_AXI_TRANS_UPPER >> 2], oldaxih);
2ac4abe882db38ef90020f7c5ca28586e3d57258David Hollister &pwp->top_regs[PMCS_AXI_TRANS_UPPER >> 2]) != oldaxih) {
2ac4abe882db38ef90020f7c5ca28586e3d57258David Hollister "AXIH register restore failed");
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.",
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh /* Don't clear xp->phy */
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh /* Don't clear xp->actv_cnt */
601c90f161ff0319c1b4a2c3362b466043a65d8dSrikanth, Ramana /* Don't clear xp->actv_pkts */
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.
978d7443a924cda8208d6a10e72be89383bc7becSrikanth Suravajhala pwrk = pmcs_tag2wp(pwp, sp->cmd_tag, B_FALSE);
9aed162131f1840d0bc1cd0275f4d7144f3690f0David Hollister * If we don't find a work structure, it's because
9aed162131f1840d0bc1cd0275f4d7144f3690f0David Hollister * the command is already complete. If so, move on
9aed162131f1840d0bc1cd0275f4d7144f3690f0David Hollister * to the next one.
9aed162131f1840d0bc1cd0275f4d7144f3690f0David Hollister pmcs_prt(pwp, PMCS_PRT_DEBUG1, tgt->phy, tgt,
9aed162131f1840d0bc1cd0275f4d7144f3690f0David Hollister "%s: Not removing cmd 0x%p (htag 0x%x) "
9aed162131f1840d0bc1cd0275f4d7144f3690f0David Hollister STAILQ_REMOVE(&tgt->aq, sp, pmcs_cmd, cmd_next);
9aed162131f1840d0bc1cd0275f4d7144f3690f0David Hollister pmcs_prt(pwp, PMCS_PRT_DEBUG1, tgt->phy, tgt,
9aed162131f1840d0bc1cd0275f4d7144f3690f0David Hollister "%s: Removing cmd 0x%p (htag 0x%x) from aq for "
9aed162131f1840d0bc1cd0275f4d7144f3690f0David Hollister "target 0x%p", __func__, (void *)sp, sp->cmd_tag,
9aed162131f1840d0bc1cd0275f4d7144f3690f0David Hollister * Mark the work structure as dead and complete it
9aed162131f1840d0bc1cd0275f4d7144f3690f0David Hollister pmcs_complete_work_impl(pwp, pwrk, NULL, 0);
9aed162131f1840d0bc1cd0275f4d7144f3690f0David Hollister pmcs_prt(pwp, PMCS_PRT_DEBUG1, tgt->phy, tgt,
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "%s: Removing cmd 0x%p from sq for target 0x%p",
3be32c0f0acac4f6258b029f1a27a16a7ec65bb0Jesse Butler * Flush non-IO commands for this target. This cleans up the off-queue
3be32c0f0acac4f6258b029f1a27a16a7ec65bb0Jesse Butler * work with no pmcs_cmd_t associated.
3be32c0f0acac4f6258b029f1a27a16a7ec65bb0Jesse Butlerpmcs_flush_nonio_cmds(pmcs_hw_t *pwp, pmcs_xscsi_t *tgt)
978d7443a924cda8208d6a10e72be89383bc7becSrikanth Suravajhala if (!PMCS_COMMAND_ACTIVE(p) || PMCS_COMMAND_DONE(p)) {
978d7443a924cda8208d6a10e72be89383bc7becSrikanth Suravajhala pmcs_prt(pwp, PMCS_PRT_DEBUG, p->phy, p->xp,
978d7443a924cda8208d6a10e72be89383bc7becSrikanth Suravajhala "%s: Completing non-io cmd with HTAG 0x%x",
978d7443a924cda8208d6a10e72be89383bc7becSrikanth Suravajhala pmcs_complete_work_impl(pwp, p, NULL, 0);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dhpmcs_complete_work_impl(pmcs_hw_t *pwp, pmcwork_t *pwrk, uint32_t *iomb,
3492a3fe3944f9ca1cec72cc39496c7a257b5707Jesse Butler /* If this was an abort all, clean up if needed */
3492a3fe3944f9ca1cec72cc39496c7a257b5707Jesse Butler if ((pwrk->abt_htag == PMCS_ABT_HTAG_ALL) && (pptr != NULL)) {
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.
9aed162131f1840d0bc1cd0275f4d7144f3690f0David Hollister * This function must only be called during discovery in order to ensure that
9aed162131f1840d0bc1cd0275f4d7144f3690f0David Hollister * the chain of PHYs from phyp up to the root PHY doesn't change.
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).
1b94a41b6ff7cb545cabcda970647c0361ed118aChris Horne for (tphyp = pwp->dead_phys; tphyp; tphyp = nphyp) {
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...
188eaed9d5f14c73dfba1cd0dabaa430bdfd4a9aSrikanth Suravajhala local->target_addr = &orig_phy->target;
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
73a3eccd27d9673a6407274ea0de350699562fd9David Hollister * If the iport is NULL, compare against last_iport.
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.
73a3eccd27d9673a6407274ea0de350699562fd9David Hollister "%s: Found match in dead PHY list (0x%p) for new PHY %s",
73a3eccd27d9673a6407274ea0de350699562fd9David Hollister * If there is a pointer to the target in the dead PHY, move
73a3eccd27d9673a6407274ea0de350699562fd9David Hollister * all reference counts to the new PHY.
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,
35dae2328064ca9e149cf5d3a7ba1688ed4629b6Srikanth Suravajhala pmcs_create_one_phy_stats(iport, phyp);
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
5c45adf04db8ffdcb5dd969bb5203ff9b17677dbJesse Butler pmcs_update_phy_pm_props(pptr, pptr->att_port_pm_tmp,
9aed162131f1840d0bc1cd0275f4d7144f3690f0David Hollister pmcs_smhba_add_iport_prop(iport, DATA_TYPE_INT32,
499cfd156ad653fc27397c5f021047c091dd12c5David Hollister pmcs_update_phy_pm_props(phyp, phyp->att_port_pm_tmp,
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 "%s: SMP is active on thread 0x%p, waiting", __func__,
9aed162131f1840d0bc1cd0275f4d7144f3690f0David Hollister pmcs_prt(iport->pwp, PMCS_PRT_DEBUG3, NULL, NULL,
9aed162131f1840d0bc1cd0275f4d7144f3690f0David Hollister pmcs_prt(iport->pwp, PMCS_PRT_DEBUG3, NULL, NULL,
6745c559e4b531cf336a91f4653445c32ee46693Jesse Butler "%s: SMP released by thread 0x%p", __func__, (void *)curthread);
499cfd156ad653fc27397c5f021047c091dd12c5David Hollister * Update a PHY's attached-port-pm and target-port-pm properties
499cfd156ad653fc27397c5f021047c091dd12c5David Hollister * phyp: PHY whose properties are to be updated
499cfd156ad653fc27397c5f021047c091dd12c5David Hollister * att_bv: Bit value of the attached-port-pm property to be updated in the
499cfd156ad653fc27397c5f021047c091dd12c5David Hollister * 64-bit holding area for the PHY.
499cfd156ad653fc27397c5f021047c091dd12c5David Hollister * tgt_bv: Bit value of the target-port-pm property to update in the 64-bit
499cfd156ad653fc27397c5f021047c091dd12c5David Hollister * holding area for the PHY.
499cfd156ad653fc27397c5f021047c091dd12c5David Hollister * prop_add_val: If TRUE, we're adding bits into the property value.
499cfd156ad653fc27397c5f021047c091dd12c5David Hollister * Otherwise, we're taking them out. Either way, the properties for this
499cfd156ad653fc27397c5f021047c091dd12c5David Hollister * PHY will be updated.
499cfd156ad653fc27397c5f021047c091dd12c5David Hollisterpmcs_update_phy_pm_props(pmcs_phy_t *phyp, uint64_t att_bv, uint64_t tgt_bv,
499cfd156ad653fc27397c5f021047c091dd12c5David Hollister * If the values are currently 0, then we're setting the
499cfd156ad653fc27397c5f021047c091dd12c5David Hollister * phymask for just this PHY as well.
499cfd156ad653fc27397c5f021047c091dd12c5David Hollister (void) snprintf(phyp->att_port_pm_str, PMCS_PM_MAX_NAMELEN,
499cfd156ad653fc27397c5f021047c091dd12c5David Hollister (void) snprintf(phyp->tgt_port_pm_str, PMCS_PM_MAX_NAMELEN,
188eaed9d5f14c73dfba1cd0dabaa430bdfd4a9aSrikanth Suravajhala if ((phyp->target_addr) && (*phyp->target_addr != NULL)) {
73a3eccd27d9673a6407274ea0de350699562fd9David Hollister (void) scsi_device_prop_update_string(lunp->sd,
73a3eccd27d9673a6407274ea0de350699562fd9David Hollister (void) scsi_device_prop_update_string(lunp->sd,
188eaed9d5f14c73dfba1cd0dabaa430bdfd4a9aSrikanth Suravajhala lunp = list_next(&tgt->lun_list, lunp);
188eaed9d5f14c73dfba1cd0dabaa430bdfd4a9aSrikanth Suravajhala (void) smp_device_prop_update_string(tgt->smpd,
188eaed9d5f14c73dfba1cd0dabaa430bdfd4a9aSrikanth Suravajhala (void) smp_device_prop_update_string(tgt->smpd,
601c90f161ff0319c1b4a2c3362b466043a65d8dSrikanth, Ramana/* ARGSUSED */
601c90f161ff0319c1b4a2c3362b466043a65d8dSrikanth, Ramanapmcs_deregister_device_work(pmcs_hw_t *pwp, pmcs_phy_t *phyp)
601c90f161ff0319c1b4a2c3362b466043a65d8dSrikanth, Ramana for (pptr = pwp->root_phys; pptr; pptr = pptr->sibling) {
9aed162131f1840d0bc1cd0275f4d7144f3690f0David Hollister * pmcs_iport_active
9aed162131f1840d0bc1cd0275f4d7144f3690f0David Hollister * Mark this iport as active. Called with the iport lock held.
9aed162131f1840d0bc1cd0275f4d7144f3690f0David Hollister/* ARGSUSED */
9aed162131f1840d0bc1cd0275f4d7144f3690f0David Hollisterpmcs_tgtmap_activate_cb(void *tgtmap_priv, char *tgt_addr,
9aed162131f1840d0bc1cd0275f4d7144f3690f0David Hollister scsi_tgtmap_tgt_type_t tgt_type, void **tgt_privp)
9aed162131f1840d0bc1cd0275f4d7144f3690f0David Hollister pmcs_iport_t *iport = (pmcs_iport_t *)tgtmap_priv;
5c45adf04db8ffdcb5dd969bb5203ff9b17677dbJesse Butler * Look up the target. If there is one, and it doesn't have a PHY
5c45adf04db8ffdcb5dd969bb5203ff9b17677dbJesse Butler * pointer, re-establish that linkage here.
5c45adf04db8ffdcb5dd969bb5203ff9b17677dbJesse Butler target = pmcs_get_target(iport, tgt_addr, B_FALSE);
5c45adf04db8ffdcb5dd969bb5203ff9b17677dbJesse Butler * If we got a target, it will now have a PHY pointer and the PHY
5c45adf04db8ffdcb5dd969bb5203ff9b17677dbJesse Butler * will point to the target. The PHY will be locked, so we'll need
5c45adf04db8ffdcb5dd969bb5203ff9b17677dbJesse Butler * to unlock it.
9aed162131f1840d0bc1cd0275f4d7144f3690f0David Hollister * Update config_restart_time so we don't try to restart discovery
9aed162131f1840d0bc1cd0275f4d7144f3690f0David Hollister * while enumeration is still in progress.
9aed162131f1840d0bc1cd0275f4d7144f3690f0David Hollister/* ARGSUSED */
9aed162131f1840d0bc1cd0275f4d7144f3690f0David Hollisterpmcs_tgtmap_deactivate_cb(void *tgtmap_priv, char *tgt_addr,
9aed162131f1840d0bc1cd0275f4d7144f3690f0David Hollister scsi_tgtmap_tgt_type_t tgt_type, void *tgt_priv,
9aed162131f1840d0bc1cd0275f4d7144f3690f0David Hollister pmcs_iport_t *iport = (pmcs_iport_t *)tgtmap_priv;
9aed162131f1840d0bc1cd0275f4d7144f3690f0David Hollister phyp = pmcs_find_phy_by_sas_address(iport->pwp, iport, NULL, tgt_addr);
9aed162131f1840d0bc1cd0275f4d7144f3690f0David Hollister pmcs_prt(iport->pwp, PMCS_PRT_DEBUG_IPORT, NULL, NULL,
9aed162131f1840d0bc1cd0275f4d7144f3690f0David Hollister "%s: Couldn't find PHY at %s", __func__, tgt_addr);
9aed162131f1840d0bc1cd0275f4d7144f3690f0David Hollister /* phyp is locked */
9aed162131f1840d0bc1cd0275f4d7144f3690f0David Hollister if (!phyp->reenumerate && phyp->configured) {
9aed162131f1840d0bc1cd0275f4d7144f3690f0David Hollister pmcs_prt(iport->pwp, PMCS_PRT_DEBUG_CONFIG, phyp, phyp->target,
9aed162131f1840d0bc1cd0275f4d7144f3690f0David Hollister "%s: PHY @ %s is configured... re-enumerate", __func__,
9aed162131f1840d0bc1cd0275f4d7144f3690f0David Hollister * Check to see if reenumerate is set, and if so, if we've reached our
9aed162131f1840d0bc1cd0275f4d7144f3690f0David Hollister * maximum number of retries.
9aed162131f1840d0bc1cd0275f4d7144f3690f0David Hollister if (phyp->enum_attempts == PMCS_MAX_REENUMERATE) {
9aed162131f1840d0bc1cd0275f4d7144f3690f0David Hollister pmcs_prt(iport->pwp, PMCS_PRT_DEBUG_CONFIG, phyp,
9aed162131f1840d0bc1cd0275f4d7144f3690f0David Hollister "%s: No more enumeration attempts for %s", __func__,
9aed162131f1840d0bc1cd0275f4d7144f3690f0David Hollister pmcs_prt(iport->pwp, PMCS_PRT_DEBUG_CONFIG, phyp,
9aed162131f1840d0bc1cd0275f4d7144f3690f0David Hollister phyp->target, "%s: Re-attempt enumeration for %s",
9aed162131f1840d0bc1cd0275f4d7144f3690f0David Hollister iport->pwp->config_restart_time = ddi_get_lbolt() +
9aed162131f1840d0bc1cd0275f4d7144f3690f0David Hollister } else if (iport->pwp->config_restart == B_TRUE) {
9aed162131f1840d0bc1cd0275f4d7144f3690f0David Hollister * If we aren't asking for rediscovery because of this PHY,
9aed162131f1840d0bc1cd0275f4d7144f3690f0David Hollister * check to see if we're already asking for it on behalf of
9aed162131f1840d0bc1cd0275f4d7144f3690f0David Hollister * some other PHY. If so, we'll want to return TRUE, so reset
9aed162131f1840d0bc1cd0275f4d7144f3690f0David Hollister * "rediscover" here.
9aed162131f1840d0bc1cd0275f4d7144f3690f0David Hollisterpmcs_status_disposition(pmcs_phy_t *phyp, uint32_t status)
9aed162131f1840d0bc1cd0275f4d7144f3690f0David Hollister * XXX: Do we need to call this function from an SSP_EVENT?
9aed162131f1840d0bc1cd0275f4d7144f3690f0David Hollister case PMCOUT_STATUS_OPEN_CNX_PROTOCOL_NOT_SUPPORTED:
9aed162131f1840d0bc1cd0275f4d7144f3690f0David Hollister case PMCOUT_STATUS_OPEN_CNX_ERROR_ZONE_VIOLATION:
9aed162131f1840d0bc1cd0275f4d7144f3690f0David Hollister case PMCOUT_STATUS_OPENCNX_ERROR_BAD_DESTINATION:
9aed162131f1840d0bc1cd0275f4d7144f3690f0David Hollister case PMCOUT_STATUS_OPEN_CNX_ERROR_CONNECTION_RATE_NOT_SUPPORTED:
9aed162131f1840d0bc1cd0275f4d7144f3690f0David Hollister case PMCOUT_STATUS_OPEN_CNX_ERROR_STP_RESOURCES_BUSY:
9aed162131f1840d0bc1cd0275f4d7144f3690f0David Hollister case PMCOUT_STATUS_OPEN_CNX_ERROR_WRONG_DESTINATION:
9aed162131f1840d0bc1cd0275f4d7144f3690f0David Hollister case PMCOUT_STATUS_OPEN_CNX_ERROR_UNKNOWN_ERROR:
9aed162131f1840d0bc1cd0275f4d7144f3690f0David Hollister case PMCOUT_STATUS_IO_XFER_ERROR_NAK_RECEIVED:
9aed162131f1840d0bc1cd0275f4d7144f3690f0David Hollister case PMCOUT_STATUS_IO_XFER_OPEN_RETRY_TIMEOUT:
9aed162131f1840d0bc1cd0275f4d7144f3690f0David Hollister case PMCOUT_STATUS_ERROR_INTERNAL_SMP_RESOURCE:
9aed162131f1840d0bc1cd0275f4d7144f3690f0David Hollister case PMCOUT_STATUS_IO_OPEN_CNX_ERROR_HW_RESOURCE_BUSY:
9aed162131f1840d0bc1cd0275f4d7144f3690f0David Hollister pmcs_prt(phyp->pwp, PMCS_PRT_DEBUG, phyp, phyp->target,
9aed162131f1840d0bc1cd0275f4d7144f3690f0David Hollister "%s: status = 0x%x for " SAS_ADDR_FMT ", reenumerate",
9aed162131f1840d0bc1cd0275f4d7144f3690f0David Hollister __func__, status, SAS_ADDR_PRT(phyp->sas_address));
9aed162131f1840d0bc1cd0275f4d7144f3690f0David Hollister pmcs_prt(phyp->pwp, PMCS_PRT_DEBUG, phyp, phyp->target,
9aed162131f1840d0bc1cd0275f4d7144f3690f0David Hollister "%s: status = 0x%x for " SAS_ADDR_FMT ", no reenumeration",
9aed162131f1840d0bc1cd0275f4d7144f3690f0David Hollister __func__, status, SAS_ADDR_PRT(phyp->sas_address));
9aed162131f1840d0bc1cd0275f4d7144f3690f0David Hollister * Add the list of PHYs pointed to by phyp to the dead_phys_list
9aed162131f1840d0bc1cd0275f4d7144f3690f0David Hollister * Called with all PHYs in the list locked
9aed162131f1840d0bc1cd0275f4d7144f3690f0David Hollisterpmcs_add_dead_phys(pmcs_hw_t *pwp, pmcs_phy_t *phyp)
9aed162131f1840d0bc1cd0275f4d7144f3690f0David Hollister pmcs_prt(pwp, PMCS_PRT_DEBUG_CONFIG, phyp, NULL,
9aed162131f1840d0bc1cd0275f4d7144f3690f0David Hollister "%s: dead PHY 0x%p (%s) (ref_count %d)", __func__,
9aed162131f1840d0bc1cd0275f4d7144f3690f0David Hollister * Put this PHY on the dead PHY list for the watchdog to
9aed162131f1840d0bc1cd0275f4d7144f3690f0David Hollister * clean up after any outstanding work has completed.
2ac4abe882db38ef90020f7c5ca28586e3d57258David Hollister /* Firmware version is easy. */
2ac4abe882db38ef90020f7c5ca28586e3d57258David Hollister pwp->fw = pmcs_rd_mpi_tbl(pwp, PMCS_MPI_FW);
2ac4abe882db38ef90020f7c5ca28586e3d57258David Hollister * Get the image size (2nd to last dword)
2ac4abe882db38ef90020f7c5ca28586e3d57258David Hollister * NOTE: The GSM registers are mapped little-endian, but the data
2ac4abe882db38ef90020f7c5ca28586e3d57258David Hollister * on the flash is actually big-endian, so we need to swap these values
2ac4abe882db38ef90020f7c5ca28586e3d57258David Hollister * regardless of which platform we're on.
2ac4abe882db38ef90020f7c5ca28586e3d57258David Hollister ila_len = BSWAP_32(pmcs_rd_gsm_reg(pwp, GSM_FLASH_BASE_UPPER,
2ac4abe882db38ef90020f7c5ca28586e3d57258David Hollister "%s: Invalid ILA image size (0x%x)?", __func__, ila_len);
2ac4abe882db38ef90020f7c5ca28586e3d57258David Hollister * The numeric version is at ila_len - PMCS_ILA_VER_OFFSET
2ac4abe882db38ef90020f7c5ca28586e3d57258David Hollister ver_hi = BSWAP_32(pmcs_rd_gsm_reg(pwp, GSM_FLASH_BASE_UPPER,
2ac4abe882db38ef90020f7c5ca28586e3d57258David Hollister GSM_FLASH_BASE + ila_len - PMCS_ILA_VER_OFFSET));
2ac4abe882db38ef90020f7c5ca28586e3d57258David Hollister ver_lo = BSWAP_32(pmcs_rd_gsm_reg(pwp, GSM_FLASH_BASE_UPPER,
2ac4abe882db38ef90020f7c5ca28586e3d57258David Hollister GSM_FLASH_BASE + ila_len - PMCS_ILA_VER_OFFSET + 4));
2ac4abe882db38ef90020f7c5ca28586e3d57258David Hollister ver_hilo = BE_64(((uint64_t)ver_hi << 32) | ver_lo);
2ac4abe882db38ef90020f7c5ca28586e3d57258David Hollister bcopy((const void *)&ver_hilo, &ila_ver_string[0], 8);
2ac4abe882db38ef90020f7c5ca28586e3d57258David Hollister (void) ddi_strtoul((const char *)ila_ver_string, &ucp, 16, &ila_ver);