507c32411f3f101e90ca2120f042b5ee698ba1d5mlf/*
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * CDDL HEADER START
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf *
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * The contents of this file are subject to the terms of the
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * Common Development and Distribution License (the "License").
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * You may not use this file except in compliance with the License.
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf *
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * or http://www.opensolaris.org/os/licensing.
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * See the License for the specific language governing permissions
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * and limitations under the License.
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf *
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * When distributing Covered Code, include this CDDL HEADER in each
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * If applicable, add the following below this CDDL HEADER, with the
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * fields enclosed by brackets "[]" replaced with your own identifying
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * information: Portions Copyright [yyyy] [name of copyright owner]
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf *
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * CDDL HEADER END
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf/*
903a11ebdc8df157c4700150f41f1f262f4a8ae8rh * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * Use is subject to license terms.
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf#pragma ident "%Z%%M% %I% %E% SMI"
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf#include <sys/types.h>
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf#include <sys/kmem.h>
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf#include <sys/note.h>
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf#include "ghd.h"
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf/*ARGSUSED*/
507c32411f3f101e90ca2120f042b5ee698ba1d5mlfgtgt_t *
507c32411f3f101e90ca2120f042b5ee698ba1d5mlfghd_target_init(dev_info_t *hba_dip,
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf dev_info_t *tgt_dip,
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf ccc_t *cccp,
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf size_t tgt_private_size,
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf void *hba_private,
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf ushort_t target,
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf uchar_t lun)
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf{
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf _NOTE(ARGUNUSED(hba_dip))
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf gtgt_t *gtgtp;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf size_t size = sizeof (*gtgtp) + tgt_private_size;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf gdev_t *gdevp;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf ulong_t maxactive;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf gtgtp = kmem_zalloc(size, KM_SLEEP);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf /*
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * initialize the per instance structure
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf gtgtp->gt_tgt_private = (void *)(gtgtp + 1);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf gtgtp->gt_size = size;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf gtgtp->gt_hba_private = hba_private;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf gtgtp->gt_target = target;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf gtgtp->gt_lun = lun;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf gtgtp->gt_ccc = cccp;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf /*
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * set the queue's maxactive to 1 if
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * property not specified on target or hba devinfo node
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf maxactive = ddi_getprop(DDI_DEV_T_ANY, tgt_dip, 0, "ghd-maxactive", 1);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf gtgtp->gt_maxactive = maxactive;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf /* initialize the linked list pointers */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf GTGT_INIT(gtgtp);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf /*
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * grab both mutexes so the queue structures
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * stay stable while adding this instance to the linked lists
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf mutex_enter(&cccp->ccc_hba_mutex);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf mutex_enter(&cccp->ccc_waitq_mutex);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf /*
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * Search the HBA's linked list of device structures.
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf *
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * If this device is already attached then link this instance
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * to the existing per-device-structure on the ccc_devs list.
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf *
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf gdevp = CCCP2GDEVP(cccp);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf while (gdevp != NULL) {
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf if (gdevp->gd_target == target && gdevp->gd_lun == lun) {
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf GDBG_WAITQ(("ghd_target_init(%d,%d) found gdevp 0x%p"
903a11ebdc8df157c4700150f41f1f262f4a8ae8rh " gtgtp 0x%p max %lu\n", target, lun,
903a11ebdc8df157c4700150f41f1f262f4a8ae8rh (void *)gdevp, (void *)gtgtp, maxactive));
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf goto foundit;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf }
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf gdevp = GDEV_NEXTP(gdevp);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf }
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf /*
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * Not found. This is the first instance for this device.
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf /* allocate the per-device-structure */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf gdevp = kmem_zalloc(sizeof (*gdevp), KM_SLEEP);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf gdevp->gd_target = target;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf gdevp->gd_lun = lun;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf /*
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * link this second level queue to the HBA's first
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * level queue
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf GDEV_QATTACH(gdevp, cccp, maxactive);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf GDBG_WAITQ(("ghd_target_init(%d,%d) new gdevp 0x%p gtgtp 0x%p"
903a11ebdc8df157c4700150f41f1f262f4a8ae8rh " max %lu\n", target, lun, (void *)gdevp, (void *)gtgtp,
903a11ebdc8df157c4700150f41f1f262f4a8ae8rh maxactive));
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlffoundit:
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf /* save the ptr to the per device structure */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf gtgtp->gt_gdevp = gdevp;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf /* Add the per instance structure to the per device list */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf GTGT_ATTACH(gtgtp, gdevp);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf ghd_waitq_process_and_mutex_exit(cccp);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf return (gtgtp);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf}
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf/*ARGSUSED*/
507c32411f3f101e90ca2120f042b5ee698ba1d5mlfvoid
507c32411f3f101e90ca2120f042b5ee698ba1d5mlfghd_target_free(dev_info_t *hba_dip,
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf dev_info_t *tgt_dip,
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf ccc_t *cccp,
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf gtgt_t *gtgtp)
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf{
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf _NOTE(ARGUNUSED(hba_dip,tgt_dip))
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf gdev_t *gdevp = gtgtp->gt_gdevp;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf GDBG_WAITQ(("ghd_target_free(%d,%d) gdevp-0x%p gtgtp 0x%p\n",
903a11ebdc8df157c4700150f41f1f262f4a8ae8rh gtgtp->gt_target, gtgtp->gt_lun, (void *)gdevp, (void *)gtgtp));
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf /*
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * grab both mutexes so the queue structures
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * stay stable while deleting this instance
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf mutex_enter(&cccp->ccc_hba_mutex);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf mutex_enter(&cccp->ccc_waitq_mutex);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf ASSERT(gdevp->gd_ninstances > 0);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf /*
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * remove this per-instance structure from the device list and
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * free the memory
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf GTGT_DEATTACH(gtgtp, gdevp);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf kmem_free((caddr_t)gtgtp, gtgtp->gt_size);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf if (gdevp->gd_ninstances == 1) {
903a11ebdc8df157c4700150f41f1f262f4a8ae8rh GDBG_WAITQ(("ghd_target_free: N=1 gdevp 0x%p\n",
903a11ebdc8df157c4700150f41f1f262f4a8ae8rh (void *)gdevp));
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf /*
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * If there's now just one instance left attached to this
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * device then reset the queue's max active value
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * from that instance's saved value.
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf gtgtp = GDEVP2GTGTP(gdevp);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf GDEV_MAXACTIVE(gdevp) = gtgtp->gt_maxactive;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf } else if (gdevp->gd_ninstances == 0) {
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf /* else no instances left */
903a11ebdc8df157c4700150f41f1f262f4a8ae8rh GDBG_WAITQ(("ghd_target_free: N=0 gdevp 0x%p\n",
903a11ebdc8df157c4700150f41f1f262f4a8ae8rh (void *)gdevp));
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf /* detach this per-dev-structure from the HBA's dev list */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf GDEV_QDETACH(gdevp, cccp);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf kmem_free(gdevp, sizeof (*gdevp));
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf }
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf#if defined(GHD_DEBUG) || defined(__lint)
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf else {
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf /* leave maxactive set to 1 */
903a11ebdc8df157c4700150f41f1f262f4a8ae8rh GDBG_WAITQ(("ghd_target_free: N>1 gdevp 0x%p\n",
903a11ebdc8df157c4700150f41f1f262f4a8ae8rh (void *)gdevp));
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf }
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf#endif
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf ghd_waitq_process_and_mutex_exit(cccp);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf}
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlfvoid
507c32411f3f101e90ca2120f042b5ee698ba1d5mlfghd_waitq_shuffle_up(ccc_t *cccp, gdev_t *gdevp)
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf{
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf gcmd_t *gcmdp;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf ASSERT(mutex_owned(&cccp->ccc_waitq_mutex));
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf GDBG_WAITQ(("ghd_waitq_shuffle_up: cccp 0x%p gdevp 0x%p N %ld "
903a11ebdc8df157c4700150f41f1f262f4a8ae8rh "max %ld\n", (void *)cccp, (void *)gdevp, GDEV_NACTIVE(gdevp),
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf GDEV_MAXACTIVE(gdevp)));
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf for (;;) {
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf /*
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * Now check the device wait queue throttle to see if I can
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * shuffle up a request to the HBA wait queue.
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf if (GDEV_NACTIVE(gdevp) >= GDEV_MAXACTIVE(gdevp)) {
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf GDBG_WAITQ(("ghd_waitq_shuffle_up: N>MAX gdevp 0x%p\n",
903a11ebdc8df157c4700150f41f1f262f4a8ae8rh (void *)gdevp));
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf return;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf }
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf /*
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * single thread requests while multiple instances
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * because the different target drives might have
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * conflicting maxactive throttles.
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf if (gdevp->gd_ninstances > 1 && GDEV_NACTIVE(gdevp) > 0) {
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf GDBG_WAITQ(("ghd_waitq_shuffle_up: multi gdevp 0x%p\n",
903a11ebdc8df157c4700150f41f1f262f4a8ae8rh (void *)gdevp));
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf return;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf }
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf /*
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * promote the topmost request from the device queue to
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * the HBA queue.
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf if ((gcmdp = L2_remove_head(&GDEV_QHEAD(gdevp))) == NULL) {
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf /* the device is empty so we're done */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf GDBG_WAITQ(("ghd_waitq_shuffle_up: MT gdevp 0x%p\n",
903a11ebdc8df157c4700150f41f1f262f4a8ae8rh (void *)gdevp));
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf return;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf }
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf L2_add(&GHBA_QHEAD(cccp), &gcmdp->cmd_q, gcmdp);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf GDEV_NACTIVE(gdevp)++;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf gcmdp->cmd_waitq_level++;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf GDBG_WAITQ(("ghd_waitq_shuffle_up: gdevp 0x%p gcmdp 0x%p\n",
903a11ebdc8df157c4700150f41f1f262f4a8ae8rh (void *)gdevp, (void *)gcmdp));
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf }
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf}
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlfvoid
507c32411f3f101e90ca2120f042b5ee698ba1d5mlfghd_waitq_delete(ccc_t *cccp, gcmd_t *gcmdp)
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf{
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf gtgt_t *gtgtp = GCMDP2GTGTP(gcmdp);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf gdev_t *gdevp = gtgtp->gt_gdevp;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf#if defined(GHD_DEBUG) || defined(__lint)
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf Q_t *qp = &gdevp->gd_waitq;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf#endif
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf ASSERT(mutex_owned(&cccp->ccc_hba_mutex));
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf mutex_enter(&cccp->ccc_waitq_mutex);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf /*
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * Adjust all queue counters. If this request is being aborted
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * it might only have made it to the target queue. Otherwise,
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * both the target and hba queue have to be adjusted when a
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * request is completed normally. The cmd_waitq_level value
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * indicates which queue counters need to be adjusted. It's
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * incremented as the request progresses up the queues.
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf switch (gcmdp->cmd_waitq_level) {
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf case 0:
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf break;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf case 1:
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf /*
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * If this is an early-timeout, or early-abort, the request
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * is still linked onto a waitq. Remove it now. If it's
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * an active request and no longer on the waitq then calling
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * L2_delete a second time does no harm.
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf L2_delete(&gcmdp->cmd_q);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf break;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf case 2:
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf L2_delete(&gcmdp->cmd_q);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf#if defined(GHD_DEBUG) || defined(__lint)
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf if (GDEV_NACTIVE(gdevp) == 0)
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf debug_enter("\n\nGHD WAITQ DELETE\n\n");
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf#endif
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf GDEV_NACTIVE(gdevp)--;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf break;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf case 3:
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf /* it's an active or completed command */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf#if defined(GHD_DEBUG) || defined(__lint)
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf if (GDEV_NACTIVE(gdevp) == 0 || GHBA_NACTIVE(cccp) == 0)
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf debug_enter("\n\nGHD WAITQ DELETE\n\n");
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf#endif
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf GDEV_NACTIVE(gdevp)--;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf GHBA_NACTIVE(cccp)--;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf break;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf default:
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf /* this shouldn't happen */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf#if defined(GHD_DEBUG) || defined(__lint)
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf debug_enter("\n\nGHD WAITQ LEVEL > 3\n\n");
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf#endif
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf break;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf }
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf GDBG_WAITQ(("ghd_waitq_delete: gcmdp 0x%p qp 0x%p level %ld\n",
903a11ebdc8df157c4700150f41f1f262f4a8ae8rh (void *)gcmdp, (void *)qp, gcmdp->cmd_waitq_level));
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf /*
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * There's probably now more room in the HBA queue. Move
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * up as many requests as possible.
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf ghd_waitq_shuffle_up(cccp, gdevp);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf mutex_exit(&cccp->ccc_waitq_mutex);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf}
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlfint
507c32411f3f101e90ca2120f042b5ee698ba1d5mlfghd_waitq_process_and_mutex_hold(ccc_t *cccp)
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf{
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf gcmd_t *gcmdp;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf int rc = FALSE;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf ASSERT(mutex_owned(&cccp->ccc_hba_mutex));
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf ASSERT(mutex_owned(&cccp->ccc_waitq_mutex));
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf for (;;) {
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf if (L2_EMPTY(&GHBA_QHEAD(cccp))) {
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf /* return if the list is empty */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf GDBG_WAITQ(("ghd_waitq_proc: MT cccp 0x%p qp 0x%p\n",
903a11ebdc8df157c4700150f41f1f262f4a8ae8rh (void *)cccp, (void *)&cccp->ccc_waitq));
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf break;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf }
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf if (GHBA_NACTIVE(cccp) >= GHBA_MAXACTIVE(cccp)) {
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf /* return if the HBA is too active */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf GDBG_WAITQ(("ghd_waitq_proc: N>M cccp 0x%p qp 0x%p"
903a11ebdc8df157c4700150f41f1f262f4a8ae8rh " N %ld max %ld\n", (void *)cccp,
903a11ebdc8df157c4700150f41f1f262f4a8ae8rh (void *)&cccp->ccc_waitq,
903a11ebdc8df157c4700150f41f1f262f4a8ae8rh GHBA_NACTIVE(cccp),
903a11ebdc8df157c4700150f41f1f262f4a8ae8rh GHBA_MAXACTIVE(cccp)));
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf break;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf }
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf /*
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * bail out if the wait queue has been
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * "held" by the HBA driver
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf if (cccp->ccc_waitq_held) {
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf GDBG_WAITQ(("ghd_waitq_proc: held"));
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf return (rc);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf }
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf if (cccp->ccc_waitq_frozen) {
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf clock_t lbolt, delay_in_hz, time_to_wait;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf delay_in_hz =
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf drv_usectohz(cccp->ccc_waitq_freezedelay * 1000);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf lbolt = ddi_get_lbolt();
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf time_to_wait = delay_in_hz -
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf (lbolt - cccp->ccc_waitq_freezetime);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf if (time_to_wait > 0) {
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf /*
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * stay frozen; we'll be called again
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * by ghd_timeout_softintr()
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf GDBG_WAITQ(("ghd_waitq_proc: frozen"));
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf return (rc);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf } else {
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf /* unfreeze and continue */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf GDBG_WAITQ(("ghd_waitq_proc: unfreezing"));
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf cccp->ccc_waitq_freezetime = 0;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf cccp->ccc_waitq_freezedelay = 0;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf cccp->ccc_waitq_frozen = 0;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf }
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf }
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf gcmdp = (gcmd_t *)L2_remove_head(&GHBA_QHEAD(cccp));
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf GHBA_NACTIVE(cccp)++;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf gcmdp->cmd_waitq_level++;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf mutex_exit(&cccp->ccc_waitq_mutex);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf /*
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * Start up the next I/O request
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf ASSERT(gcmdp != NULL);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf gcmdp->cmd_state = GCMD_STATE_ACTIVE;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf if (!(*cccp->ccc_hba_start)(cccp->ccc_hba_handle, gcmdp)) {
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf /* if the HBA rejected the request, requeue it */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf gcmdp->cmd_state = GCMD_STATE_WAITQ;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf mutex_enter(&cccp->ccc_waitq_mutex);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf GHBA_NACTIVE(cccp)--;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf gcmdp->cmd_waitq_level--;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf L2_add_head(&GHBA_QHEAD(cccp), &gcmdp->cmd_q, gcmdp);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf GDBG_WAITQ(("ghd_waitq_proc: busy cccp 0x%p gcmdp 0x%p"
903a11ebdc8df157c4700150f41f1f262f4a8ae8rh " handle 0x%p\n", (void *)cccp, (void *)gcmdp,
903a11ebdc8df157c4700150f41f1f262f4a8ae8rh cccp->ccc_hba_handle));
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf break;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf }
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf rc = TRUE;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf mutex_enter(&cccp->ccc_waitq_mutex);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf GDBG_WAITQ(("ghd_waitq_proc: ++ cccp 0x%p gcmdp 0x%p N %ld\n",
903a11ebdc8df157c4700150f41f1f262f4a8ae8rh (void *)cccp, (void *)gcmdp, GHBA_NACTIVE(cccp)));
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf }
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf ASSERT(mutex_owned(&cccp->ccc_hba_mutex));
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf ASSERT(mutex_owned(&cccp->ccc_waitq_mutex));
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf return (rc);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf}
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlfvoid
507c32411f3f101e90ca2120f042b5ee698ba1d5mlfghd_waitq_process_and_mutex_exit(ccc_t *cccp)
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf{
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf ASSERT(mutex_owned(&cccp->ccc_hba_mutex));
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf ASSERT(mutex_owned(&cccp->ccc_waitq_mutex));
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
903a11ebdc8df157c4700150f41f1f262f4a8ae8rh GDBG_WAITQ(("ghd_waitq_process_and_mutex_exit: cccp 0x%p\n",
903a11ebdc8df157c4700150f41f1f262f4a8ae8rh (void *)cccp));
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf (void) ghd_waitq_process_and_mutex_hold(cccp);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf /*
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * Release the mutexes in the opposite order that they
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * were acquired to prevent requests queued by
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * ghd_transport() from getting hung up in the wait queue.
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf mutex_exit(&cccp->ccc_hba_mutex);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf mutex_exit(&cccp->ccc_waitq_mutex);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf}