pmcs_scsa.c revision 4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * CDDL HEADER START
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * The contents of this file are subject to the terms of the
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Common Development and Distribution License (the "License").
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * You may not use this file except in compliance with the License.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * See the License for the specific language governing permissions
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * and limitations under the License.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * When distributing Covered Code, include this CDDL HEADER in each
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * If applicable, add the following below this CDDL HEADER, with the
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * fields enclosed by brackets "[]" replaced with your own identifying
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * information: Portions Copyright [yyyy] [name of copyright owner]
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * CDDL HEADER END
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Use is subject to license terms.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * SCSI (SCSA) midlayer interface for PMC drier.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dhstatic int pmcs_scsa_tran_tgt_init(dev_info_t *, dev_info_t *,
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dhstatic void pmcs_scsa_tran_tgt_free(dev_info_t *, dev_info_t *,
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dhstatic int pmcs_scsa_start(struct scsi_address *, struct scsi_pkt *);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dhstatic int pmcs_scsa_abort(struct scsi_address *, struct scsi_pkt *);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dhstatic int pmcs_scsi_reset_notify(struct scsi_address *, int,
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dhstatic int pmcs_scsa_getcap(struct scsi_address *, char *, int);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dhstatic int pmcs_scsa_setcap(struct scsi_address *, char *, int, int);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dhstatic int pmcs_scsa_setup_pkt(struct scsi_pkt *, int (*)(caddr_t), caddr_t);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dhstatic int pmcs_smp_init(dev_info_t *, dev_info_t *, sas_hba_tran_t *,
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dhstatic void pmcs_smp_free(dev_info_t *, dev_info_t *, sas_hba_tran_t *,
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dhstatic int pmcs_cap(struct scsi_address *, char *, int, int, int);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh pmcs_addr2xp(struct scsi_address *, uint64_t *, pmcs_cmd_t *);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dhstatic void pmcs_SAS_done(pmcs_hw_t *, pmcwork_t *, uint32_t *);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dhstatic void pmcs_SATA_done(pmcs_hw_t *, pmcwork_t *, uint32_t *);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dhstatic uint8_t pmcs_SATA_rwparm(uint8_t *, uint32_t *, uint64_t *, uint64_t);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dhstatic void pmcs_ioerror(pmcs_hw_t *, pmcs_dtype_t pmcs_dtype,
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh (void) memcpy(&pmcs_scsa_dattr, ap, sizeof (ddi_dma_attr_t));
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh ((PMCS_SGL_NCHUNKS - 1) * (PMCS_MAX_CHUNKS - 1)) + PMCS_SGL_NCHUNKS;
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh pmcs_scsa_dattr.dma_attr_flags = DDI_DMA_RELAXED_ORDERING;
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Allocate a transport structure
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh pmcs_prt(pwp, PMCS_PRT_DEBUG, "scsi_hba_tran_alloc failed");
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Attach this instance of the hba
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh flags = SCSI_HBA_TRAN_SCB | SCSI_HBA_TRAN_CDB | SCSI_HBA_ADDR_COMPLEX |
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh if (scsi_hba_attach_setup(pwp->dip, &pmcs_scsa_dattr, tran, flags)) {
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Attach the SMP part of this hba
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh if (sas_hba_attach_setup(pwp->dip, pwp->smp_tran) != DDI_SUCCESS) {
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * SCSA entry points
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dhpmcs_scsa_tran_tgt_init(dev_info_t *hba_dip, dev_info_t *tgt_dip,
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * First, make sure we're an iport and get the pointer to the HBA
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * node's softstate
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "%s: We don't enumerate devices on the HBA node", __func__);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Get the target address
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh rval = scsi_device_prop_lookup_string(sd, SCSI_DEVICE_PROP_PATH,
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh pmcs_prt(pwp, PMCS_PRT_DEBUG_CONFIG, "Couldn't get target UA");
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh pmcs_prt(pwp, PMCS_PRT_DEBUG3, "got tgt_port '%s'", tgt_port);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Validate that this tran_tgt_init is for an active iport.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "%s: Got tran_tgt_init on inactive iport for '%s'",
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Since we're going to wait for scratch, be sure to acquire it while
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * we're not holding any other locks
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * See if there's already a target softstate. If not, allocate one.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Now get the full "w<WWN>,LUN" unit-address (including LU).
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "Couldn't get LU unit address");
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh lun_num = scsi_device_prop_get_int64(sd, SCSI_DEVICE_PROP_PATH,
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh pmcs_prt(pwp, PMCS_PRT_DEBUG_CONFIG, "No LUN for tgt %p",
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh pmcs_prt(pwp, PMCS_PRT_DEBUG_CONFIG, "%s: @%s tgt 0x%p phy 0x%p (%s)",
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh pmcs_prt(pwp, PMCS_PRT_DEBUG_CONFIG, "PHY 0x%p went away?",
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh /* We don't support SATA devices at LUN > 0. */
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "%s: No support for SATA devices at LUN > 0 "
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Allocate LU soft state. We use ddi_soft_state_bystr_zalloc instead
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * of kmem_alloc because ddi_soft_state_bystr_zalloc allows us to
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * verify that the framework never tries to initialize two scsi_device
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * structures with the same unit-address at the same time.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh if (ddi_soft_state_bystr_zalloc(tgt->lun_sstate, ua) != DDI_SUCCESS) {
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "Couldn't allocate LU soft state");
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh pmcs_prt(pwp, PMCS_PRT_DEBUG2, "Couldn't get LU soft state");
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh /* convert the scsi_lun64_t value to SCSI standard form */
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh bcopy(ua, lun->unit_address, strnlen(ua, PMCS_MAX_UA_SIZE - 1));
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * If this is the first tran_tgt_init, add this target to our list
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "Target list full.");
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "%s: pmcs_assign_device failed for target 0x%p",
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh (void) scsi_device_prop_update_int(sd, SCSI_DEVICE_PROP_PATH,
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh /* SM-HBA */
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh /* TCR in PSARC/1997/281 opinion */
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh (void) scsi_device_prop_update_int(sd, SCSI_DEVICE_PROP_PATH,
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh /* SM-HBA */
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh scsi_device_prop_free(sd, SCSI_DEVICE_PROP_PATH, tgt_port);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * phyp's ref count was incremented in pmcs_new_tport.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * We're failing configuration, we now need to decrement it.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh scsi_device_prop_free(sd, SCSI_DEVICE_PROP_PATH, tgt_port);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dhstatic void
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dhpmcs_scsa_tran_tgt_free(dev_info_t *hba_dip, dev_info_t *tgt_dip,
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "%s: We don't enumerate devices on the HBA node", __func__);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh ddi_soft_state_bystr_free(lun->target->lun_sstate, unit_address);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * If this target still has a PHY pointer and that PHY's target pointer
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * has been cleared, then that PHY has been reaped. In that case, there
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * would be no need to decrement the reference count
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Remove this target from our list. The target soft
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * state will remain, and the device will remain registered
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * with the hardware unless/until we're told the device
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * physically went away.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "%s: Free target 0x%p (vtgt %d)", __func__, (void *)target,
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * If the target still has a PHY pointer, break the linkage
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dhpmcs_scsa_start(struct scsi_address *ap, struct scsi_pkt *pkt)
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh pmcs_prt(pwp, PMCS_PRT_DEBUG2, "%s: pkt %p sd %p cdb0=0x%02x dl=%lu",
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh pmcs_prt(pwp, PMCS_PRT_DEBUG3, "%s: nointr pkt", __func__);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * First, check to see if we're dying or unassigned.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "%s: dropping due to dying/dead target 0x%p",
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * If we're blocked (quiesced) just return.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh pmcs_prt(pwp, PMCS_PRT_DEBUG, "%s: hba blocked", __func__);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * If we're draining or resetting, queue and return.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "%s: draining/resetting/recovering (cnt %u)",
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * By the time we get here, draining or
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * resetting may have come and gone, not
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * yet noticing that we had put something
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * on the wait queue, so schedule a worker
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * to look at this later.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Queue this command to the tail of the wait queue.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * This keeps us getting commands out of order.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Now run the queue for this device.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dhpmcs_scsa_abort(struct scsi_address *ap, struct scsi_pkt *pkt)
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return (0);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return (0);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * See if we have a real work structure associated with this cmd.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return (0);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * XXX: Was the command that was active an
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * NCQ I/O command?
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return (0);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return (1);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Okay, those weren't the droids we were looking for.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * See if the command is on any of the wait queues.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return (1);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return (0);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * SCSA reset functions
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return (0);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh switch (level) {
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Point lp at lun so that pmcs_addr2xp
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * will fill out the 64 bit lun number.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh /* FALLTHROUGH */
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return (0);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh (void *)xp);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return (0);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * If we're already performing this action, or if device
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * state recovery is already running, just return failure.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return (0);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return (scsi_hba_reset_notify_setup(ap, flag, callback, arg,
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dhpmcs_cap(struct scsi_address *ap, char *cap, int val, int tonly, int set)
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return (-1);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return (-1);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh switch (cidx) {
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh if (set == 0) {
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh if (set == 0) {
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh if (set == 0) {
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh if (set == 0) {
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "%s: cap %s val %d set %d rval %d",
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Returns with statlock held if the xp is found.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Fills in pmcs_cmd_t with values if pmcs_cmd_t pointer non-NULL.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dhpmcs_addr2xp(struct scsi_address *ap, uint64_t *lp, pmcs_cmd_t *sp)
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return (xp);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dhpmcs_scsa_getcap(struct scsi_address *ap, char *cap, int whom)
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return (-1);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return (r);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dhpmcs_scsa_setcap(struct scsi_address *ap, char *cap, int value, int whom)
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return (-1);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return (r);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dhpmcs_scsa_setup_pkt(struct scsi_pkt *pkt, int (*callback)(caddr_t),
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return (0);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dhstatic void
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh switch (ckey) {
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh pmcs_hw_t *pwp = pktp->pkt_address->a_hba_tran->tran_hba_private;
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh bcopy(pktp->pkt_address->a_wwn, &wwn, SAS_WWN_BYTE_SIZE);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh pmcs_prt(pwp, PMCS_PRT_DEBUG1, "%s: starting for wwn 0x%" PRIx64,
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * The request size from the SMP driver always includes 4 bytes
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * for the CRC. The PMCS chip, however, doesn't want to see those
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * counts as part of the transfer size.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh /* PHY is now locked */
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh pmcs_prt(pwp, PMCS_PRT_DEBUG, "%s: could not get IQ entry",
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh msg[0] = LE_32(PMCS_HIPRI(pwp, PMCS_OQ_GENERAL, PMCIN_SMP_REQUEST));
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh msg[3] = LE_32(SMP_INDIRECT_RESPONSE | SMP_INDIRECT_REQUEST);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "%s: Unable to issue SMP ABORT for htag 0x%08x",
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "%s: Issuing SMP ABORT for htag 0x%08x",
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh } else if (status ==
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "%s: Got _IT_NEXUS_LOSS SMP status. "
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "Tgt(0x%p) dev_state set to "
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh (void *)xp);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh /* ABORT any pending commands related to this device */
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh /* Get "target-port" prop from devinfo node */
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh pmcs_prt(pwp, PMCS_PRT_DEBUG, "%s: Failed to lookup prop ("
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh /* Dont fail _smp_init() because we couldnt get/set a prop */
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Validate that this tran_tgt_init is for an active iport.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "%s: Init on inactive iport for '%s'",
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh /* Retrieve softstate using unit-address */
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh pmcs_prt(pwp, PMCS_PRT_DEBUG, "%s: tgt softstate not found",
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh /* Expander attached to HBA - don't ref_count it */
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Parent (in topology) is also an expander
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Now that we've increased the ref count on phy, it's OK
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * to drop the lock so we can acquire the parent's lock.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * If this is the 1st smp_init, add this to our list.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "Target list full.");
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "%s: pmcs_assign_device failed for target 0x%p",
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh /* XXX: Update smp devinfo node using ndi_xxx */
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh ddi_soft_state_bystr_free(iport->tgt_sstate, tgt->unit_address);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dhstatic void
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh /* Get "target-port" prop from devinfo node */
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh pmcs_prt(pwp, PMCS_PRT_DEBUG, "%s: Failed to lookup prop ("
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh /* Retrieve softstate using unit-address */
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh tgt = ddi_soft_state_bystr_get(iport->tgt_sstate, tgt_port);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh pmcs_prt(pwp, PMCS_PRT_DEBUG, "%s: tgt softstate not found",
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Remove this target from our list. The softstate
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * will remain, and the device will remain registered
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * with the hardware unless/until we're told that the
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * device physically went away.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "Removing target 0x%p (vtgt %d) from target list",
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh if (ddi_get_soft_state(pmcs_iport_softstate, ddi_get_instance(dip)))
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return (0); /* iport */
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh pwp = ddi_get_soft_state(pmcs_softc_state, ddi_get_instance(dip));
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return (-1);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return (-1);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * The pwp->blocked may have been reset. e.g a SCSI bus reset
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh if (totactive == 0) {
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh pmcs_prt(pwp, PMCS_PRT_DEBUG, "%s drain complete", __func__);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return (0);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh if (ddi_get_soft_state(pmcs_iport_softstate, ddi_get_instance(dip)))
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return (0); /* iport */
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh pwp = ddi_get_soft_state(pmcs_softc_state, ddi_get_instance(dip));
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return (-1);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return (-1);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Run all pending commands.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Complete all completed commands.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * This also unlocks us.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh return (0);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Start commands for a particular device
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * If the actual start of a command fails, return B_FALSE. Any other result
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * is a B_TRUE return.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * First, check to see if we're blocked or resource limited
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * If resource_limited is set, we're resource constrained and
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * we will run only one work request for this target.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh /* Queues will get restarted when we get unblocked */
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Might as well verify the queue is not empty before moving on
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * If we're draining or resetting, just reschedule work queue and bail.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh if (xp->draining || xp->resetting || xp->special_running ||
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Next, check to see if the target is alive
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "%s: Flushing wait queue for dying/dead tgt 0x%p", __func__,
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh (void *)xp);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Increment the PHY's ref_count now so we know it won't go away
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * after we drop the target lock. Drop it before returning. If the
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * PHY dies, the commands we attempt to send will fail, but at least
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * we know we have a real PHY pointer.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Start commands for all devices.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh pwp->resource_limited = 0; /* Not resource-constrained */
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Pull the completion queue, drop the lock and complete all elements.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh DTRACE_PROBE1(pmcs__scsa__cq__run__start, pmcs_cq_thr_info_t *, cqti);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * First, check the I/O completion callback queue.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Grab the lock on the work structure. The callback
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * routine is responsible for clearing it.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Next, run the completion queue
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh while (sp) {
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh DTRACE_PROBE1(pmcs__scsa__cq__run__stop, pmcs_cq_thr_info_t *, cqti);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Run a SAS command. Called with pwrk->lock held, returns unlocked.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * This is a temporary failure not likely to unblocked by
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * commands completing as the test for scheduling the
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * restart of work is a per-device test.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "%s: Failed to get IO IQ entry for tgt %d",
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh LE_32(PMCS_IOMB_IN_SAS(PMCS_OQ_IODONE, PMCIN_SSP_INI_IO_START));
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "%s: Failed to dma_load for tgt %d (QF)",
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Generate a PMCOUT_STATUS_XFER_CMD_FRAME_ISSUED
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * event when this goes out on the wire.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Fill in the SSP IU
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh bcopy((uint8_t *)&sp->cmd_lun->scsi_lun, sc.lun, sizeof (scsi_lun_t));
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh pmcs_print_entry(pwp, PMCS_PRT_DEBUG3, "SAS INI Message", ptr);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * If we just submitted the last command queued from device state
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * recovery, clear the wq_recovery_tail pointer.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Complete a SAS command
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Called with pwrk lock held.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * The free of pwrk releases the lock.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dhstatic void
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dhpmcs_SAS_done(pmcs_hw_t *pwp, pmcwork_t *pwrk, uint32_t *msg)
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh DTRACE_PROBE4(pmcs__io__done, uint64_t, pkt->pkt_dma_len, int,
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh (pkt->pkt_dma_flags & DDI_DMA_READ) != 0, hrtime_t, pwrk->start,
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh if (dead != 0) {
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh pmcs_prt(pwp, PMCS_PRT_DEBUG, "%s: dead cmd tag 0x%x for %s",
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "%s: cmd 0x%p (tag 0x%x) timed out for %s",
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * If the status isn't okay but not underflow,
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * step to the side and parse the (possible) error.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh pmcs_print_entry(pwp, PMCS_PRT_DEBUG3, "Outbound Message", msg);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh switch (sts) {
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "%s: PHY %s requires device state recovery (status=%d)",
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh (void) pmcs_set_resid(pkt, pkt->pkt_dma_len, LE_32(msg[3]));
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "%s: underflow %u for cdb 0x%x",
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh const int lim =
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Transform the the first part of the response
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * to host canonical form. This gives us enough
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * information to figure out what to do with the
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * rest (which remains unchanged in the incoming
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * message which can be up to two queue entries
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * in length).
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "Bad SAS RESPONSE DATA LENGTH",
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * The only response code we should legally get
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * here is an INVALID FRAME response code.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "%s: pkt %p tgt %u path %s "
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "completed: INVALID FRAME response",
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "%s: pkt %p tgt %u path %s "
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "completed: illegal response 0x%x",
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * This is the case for a plain SCSI status.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "%s: pkt %p tgt %u done reason=%x state=%x resid=%ld status=%x",
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "%s: scsi_pkt 0x%p aborted for PHY %s; work = 0x%p",
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh (void *)xp);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh if (dead == 0) {
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "%s: Aborted cmd for tgt 0x%p, signaling waiters",
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * If do_ds_recovery is set, we need to initiate device state
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * recovery. In this case, we put this I/O back on the head of
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * the wait queue to run again after recovery is complete
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh pmcs_prt(pwp, PMCS_PRT_DEBUG1, "%s: Putting cmd 0x%p back on "
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh (void *)xp);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * If there are other I/Os waiting at the head due to
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * device state recovery, add this one in the right spot
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * to maintain proper order.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * If we're not initiating device state recovery and this
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * command was not "dead", put it on the completion queue
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Run a SATA command (normal reads and writes),
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * or block and schedule a SATL interpretation
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * of the command.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Called with pwrk lock held, returns unlocked.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * First, see if this is just a plain read/write command.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * If not, we have to queue it up for processing, block
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * any additional commands from coming in, and wake up
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * the thread that will process this command.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh pmcs_prt(pwp, PMCS_PRT_DEBUG1, "%s: special SATA cmd %p",
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh xp->special_needed = 1; /* Set the special_needed flag */
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh pmcs_prt(pwp, PMCS_PRT_DEBUG2, "%s: regular cmd", __func__);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh if (xp->special_running || xp->special_needed || xp->recover_wait) {
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * By the time we get here the special
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * commands running or waiting to be run
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * may have come and gone, so kick our
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * worker to run the waiting queues
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * just in case.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Extract data length and lba parameters out of the command. The
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * function pmcs_SATA_rwparm returns a non-zero ASC value if the CDB
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * values are considered illegal.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh pmcs_latch_status(pwp, sp, STATUS_CHECK, sns, sizeof (sns),
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * If the command decodes as not moving any data, complete it here.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh if (amt == 0) {
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Get an inbound queue entry for this I/O
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * This is a temporary failure not likely to unblocked by
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * commands completing as the test for scheduling the
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * restart of work is a per-device test.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "%s: Failed to get IO IQ entry for tgt %d",
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Get a tag. At this point, hold statlock until the tagmap is
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * updated (just prior to sending the cmd to the hardware).
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Set up the command
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh LE_32(PMCS_IOMB_IN_SAS(PMCS_OQ_IODONE, PMCIN_SATA_HOST_IO_START));
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh fis[0] = ((nblk & 0xff) << 24) | (C_BIT << 8) | FIS_REG_H2DEV;
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh fis[2] = ((nblk & 0xff00) << 16) | ((lba >> 24) & 0xffffff);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Generate a PMCOUT_STATUS_XFER_CMD_FRAME_ISSUED
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * event when this goes out on the wire.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh for (i = 0; i < (sizeof (fis_t))/(sizeof (uint32_t)); i++) {
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "%s: Failed to dma_load for tgt %d",
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh pmcs_prt(pwp, PMCS_PRT_DEBUG2, "%s: giving pkt %p to hardware",
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh pmcs_print_entry(pwp, PMCS_PRT_DEBUG3, "SATA INI Message", ptr);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Complete a SATA command. Called with pwrk lock held.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dhpmcs_SATA_done(pmcs_hw_t *pwp, pmcwork_t *pwrk, uint32_t *msg)
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh DTRACE_PROBE4(pmcs__io__done, uint64_t, pkt->pkt_dma_len, int,
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh (pkt->pkt_dma_flags & DDI_DMA_READ) != 0, hrtime_t, pwrk->start,
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh if (dead != 0) {
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh pmcs_prt(pwp, PMCS_PRT_DEBUG, "%s: dead cmd tag 0x%x for %s",
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "%s: cmd 0x%p (tag 0x%x) timed out for %s",
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh /* pkt_reason already set to CMD_TIMEOUT */
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh CMD2PKT(sp)->pkt_state |= STATE_GOT_BUS | STATE_GOT_TARGET |
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * If the status isn't okay but not underflow,
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * step to the side and parse the (possible) error.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh pmcs_print_entry(pwp, PMCS_PRT_DEBUG3, "Outbound Message", msg);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * If the status isn't okay or we got a FIS response of some kind,
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * step to the side and parse the (possible) error.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "(%s) Local Control/Link Reset "
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "FAILED as part of error recovery",
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "%s: pkt %p tgt %u done reason=%x state=%x resid=%ld status=%x",
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "%s: scsi_pkt 0x%p aborted for PHY %s; work = 0x%p",
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh (void *)xp);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh if (dead == 0) {
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "%s: Aborted cmd for tgt 0x%p, signaling waiters",
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dhpmcs_SATA_rwparm(uint8_t *cdb, uint32_t *xfr, uint64_t *lba, uint64_t lbamax)
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh switch (cdb[0]) {
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh /* Check for illegal bits */
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh /* Check for illegal bits */
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh /* Check for illegal bits */
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh if (*xfr == 0) {
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh /* Check for illegal bits */
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh if (asc == 0) {
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Called with pwrk lock held.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dhstatic void
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dhpmcs_ioerror(pmcs_hw_t *pwp, pmcs_dtype_t t, pmcwork_t *pwrk, uint32_t *w)
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh const char *msg;
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh (void) snprintf(buf, sizeof (buf), "Error 0x%x", status);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh (unsigned long long)gethrtime());
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh switch (status) {
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh if (t == SATA) {
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh pmcs_latch_status(pwp, sp, STATUS_GOOD, NULL, 0, phyp->path);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Command successfully aborted.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * PMCS_WORK_STATE_TIMED_OUT doesn't need to be preserved past
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * this point, so go ahead and mark it as aborted.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * This will only get called for SATA
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh pmcs_latch_status(pwp, sp, STATUS_GOOD, NULL, 0, phyp->path);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Need to do rediscovery. We probably have
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * the wrong device (disk swap), so kill
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * this one.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh case PMCOUT_STATUS_OPEN_CNX_ERROR_CONNECTION_RATE_NOT_SUPPORTED:
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Need to do rediscovery.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh /* cmd is pending on the target */
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh /* transitory - commands sent while in NCQ failure mode */
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh /* NCQ failure */
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh pmcs_latch_status(pwp, sp, STATUS_BUSY, NULL, 0, phyp->path);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh /* synthesize a RESERVATION CONFLICT */
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh pmcs_latch_status(pwp, sp, STATUS_RESERVATION_CONFLICT, NULL,
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh /* synthesize a power-on/reset */
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh pmcs_latch_status(pwp, sp, STATUS_CHECK, por, sizeof (por),
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh case PMCOUT_STATUS_XFER_ERROR_CMD_ISSUE_BREAK_BEFORE_ACK_NACK:
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh case PMCOUT_STATUS_XFER_ERROR_CMD_ISSUE_PHY_DOWN_BEFORE_ACK_NAK:
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh /* synthesize a PARITY ERROR */
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh case PMCOUT_STATUS_XFER_ERROR_SATA: /* non-NCQ failure */
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Latch up SCSI status
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dhpmcs_latch_status(pmcs_hw_t *pwp, pmcs_cmd_t *sp, uint8_t status,
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh static const char c1[] =
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "%s: Status Byte 0x%02x for CDB0=0x%02x (%02x %02x %02x) "
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "HTAG 0x%x @ %llu";
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh static const char c2[] =
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "%s: Status Byte 0x%02x for CDB0=0x%02x HTAG 0x%x @ %llu";
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh CMD2PKT(sp)->pkt_state |= STATE_GOT_BUS | STATE_GOT_TARGET |
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh (size_t)SCSA_STSLEN(sp) >= sizeof (struct scsi_arq_status)) {
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh pmcs_prt(pwp, PMCS_PRT_DEBUG_SCSI_STATUS, c1, path, status,
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh if (aqp->sts_sensedata.es_class != CLASS_EXTENDED_SENSE) {
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh sizeof (struct scsi_extended_sense);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh } else if (status) {
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Calculate and set packet residual and return the amount
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * left over after applying various filters.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dhpmcs_set_resid(struct scsi_pkt *pkt, size_t amt, uint32_t cdbamt)
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Return the existing target softstate if there is one. If there is,
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * the PHY is locked as well and that lock must be freed by the caller
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * after the target/PHY linkage is established.
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Find the PHY for this target
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh phyp = pmcs_find_phy_by_sas_address(pwp, iport, NULL, tgt_port);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh pmcs_prt(pwp, PMCS_PRT_DEBUG3, "%s: No PHY for target @ %s",
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh tgt = ddi_soft_state_bystr_get(iport->tgt_sstate, tgt_port);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * There's already a target. Check its PHY pointer to see
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * if we need to clear the old linkages
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Make sure the PHY we found is on the correct iport
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "%s: No target at %s on this iport", __func__, tgt_port);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Allocate the new softstate
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh if (ddi_soft_state_bystr_zalloc(iport->tgt_sstate, unit_address) !=
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh "%s: Couldn't alloc softstate for device at %s",
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh tgt = ddi_soft_state_bystr_get(iport->tgt_sstate, unit_address);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh bcopy(unit_address, tgt->unit_address, PMCS_MAX_UA_SIZE);
4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6dh * Don't allocate LUN softstate for SMP targets