ghd_waitq.c revision 507c32411f3f101e90ca2120f042b5ee698ba1d5
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * CDDL HEADER START
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 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * See the License for the specific language governing permissions
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * and limitations under the License.
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 * CDDL HEADER END
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * Use is subject to license terms.
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf#pragma ident "%Z%%M% %I% %E% SMI"
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf/*ARGSUSED*/
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * initialize the per instance structure
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * set the queue's maxactive to 1 if
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * property not specified on target or hba devinfo node
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf maxactive = ddi_getprop(DDI_DEV_T_ANY, tgt_dip, 0, "ghd-maxactive", 1);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf /* initialize the linked list pointers */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * grab both mutexes so the queue structures
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * stay stable while adding this instance to the linked lists
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * Search the HBA's linked list of device structures.
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * If this device is already attached then link this instance
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * to the existing per-device-structure on the ccc_devs list.
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf if (gdevp->gd_target == target && gdevp->gd_lun == lun) {
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf " gtgtp 0x%p max %lu\n",
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * Not found. This is the first instance for this device.
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf /* allocate the per-device-structure */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * link this second level queue to the HBA's first
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * level queue
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf GDBG_WAITQ(("ghd_target_init(%d,%d) new gdevp 0x%p gtgtp 0x%p"
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf /* save the ptr to the per device structure */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf /* Add the per instance structure to the per device list */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf/*ARGSUSED*/
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf GDBG_WAITQ(("ghd_target_free(%d,%d) gdevp-0x%p gtgtp 0x%p\n",
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * grab both mutexes so the queue structures
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * stay stable while deleting this instance
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * remove this per-instance structure from the device list and
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * free the memory
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf GDBG_WAITQ(("ghd_target_free: N=1 gdevp 0x%p\n", gdevp));
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 /* else no instances left */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf GDBG_WAITQ(("ghd_target_free: N=0 gdevp 0x%p\n", gdevp));
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf /* detach this per-dev-structure from the HBA's dev list */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf /* leave maxactive set to 1 */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf GDBG_WAITQ(("ghd_target_free: N>1 gdevp 0x%p\n", gdevp));
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf GDBG_WAITQ(("ghd_waitq_shuffle_up: cccp 0x%p gdevp 0x%p N %ld "
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf for (;;) {
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * Now check the device wait queue throttle to see if I can
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * shuffle up a request to the HBA wait queue.
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * single thread requests while multiple instances
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * because the different target drives might have
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * conflicting maxactive throttles.
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf if (gdevp->gd_ninstances > 1 && GDEV_NACTIVE(gdevp) > 0) {
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * promote the topmost request from the device queue to
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * the HBA queue.
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: gdevp 0x%p gcmdp 0x%p\n",
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 * 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 /* it's an active or completed command */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf if (GDEV_NACTIVE(gdevp) == 0 || GHBA_NACTIVE(cccp) == 0)
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf /* this shouldn't happen */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf GDBG_WAITQ(("ghd_waitq_delete: gcmdp 0x%p qp 0x%p level %ld\n",
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * There's probably now more room in the HBA queue. Move
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * up as many requests as possible.
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf for (;;) {
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf /* return if the list is empty */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf /* return if the HBA is too active */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * bail out if the wait queue has been
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * "held" by the HBA driver
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * stay frozen; we'll be called again
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * by ghd_timeout_softintr()
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf /* unfreeze and continue */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * Start up the next I/O request
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf if (!(*cccp->ccc_hba_start)(cccp->ccc_hba_handle, gcmdp)) {
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf /* if the HBA rejected the request, requeue it */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf GDBG_WAITQ(("ghd_waitq_proc: ++ cccp 0x%p gcmdp 0x%p N %ld\n",
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf GDBG_WAITQ(("ghd_waitq_process_and_mutex_exit: cccp 0x%p\n", cccp));
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.