From owner-svn-src-all@FreeBSD.ORG Thu May 15 09:55:24 2014 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) (using TLSv1 with cipher ADH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTPS id CC85B7FA; Thu, 15 May 2014 09:55:24 +0000 (UTC) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id B82EE25C5; Thu, 15 May 2014 09:55:24 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.8/8.14.8) with ESMTP id s4F9tOS5095614; Thu, 15 May 2014 09:55:24 GMT (envelope-from marius@svn.freebsd.org) Received: (from marius@localhost) by svn.freebsd.org (8.14.8/8.14.8/Submit) id s4F9tMmh095603; Thu, 15 May 2014 09:55:22 GMT (envelope-from marius@svn.freebsd.org) Message-Id: <201405150955.s4F9tMmh095603@svn.freebsd.org> From: Marius Strobl Date: Thu, 15 May 2014 09:55:22 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-8@freebsd.org Subject: svn commit: r266118 - in stable/8/sys/cam: . ata scsi X-SVN-Group: stable-8 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 15 May 2014 09:55:25 -0000 Author: marius Date: Thu May 15 09:55:21 2014 New Revision: 266118 URL: http://svnweb.freebsd.org/changeset/base/266118 Log: Revert the following MFCs done as part of r265147: r249438, r249466, r249481, r250025, r253958 leaving the MFCs of r241028 and r241444 in place. While the CAM queuing changes in question are pretty much self-contained and work fine with all kinds of SAS, SATA and USB devices, for reasons unknown they cause a hang with Initio INIC-1610P USB disks not seen with later branches containing these rewrites. In turn, r241444 actually is sufficient to fix the panic and problems I was seeing and that lead me to bringing CAM queuing up to date. Reported by: Scott Allendorf Modified: stable/8/sys/cam/ata/ata_da.c stable/8/sys/cam/ata/ata_pmp.c stable/8/sys/cam/ata/ata_xpt.c stable/8/sys/cam/cam.h stable/8/sys/cam/cam_ccb.h stable/8/sys/cam/cam_periph.c stable/8/sys/cam/cam_periph.h stable/8/sys/cam/cam_queue.c stable/8/sys/cam/cam_queue.h stable/8/sys/cam/cam_xpt.c stable/8/sys/cam/cam_xpt_internal.h stable/8/sys/cam/cam_xpt_sim.h stable/8/sys/cam/scsi/scsi_cd.c stable/8/sys/cam/scsi/scsi_pass.c stable/8/sys/cam/scsi/scsi_xpt.c Directory Properties: stable/8/sys/ (props changed) stable/8/sys/cam/ (props changed) Modified: stable/8/sys/cam/ata/ata_da.c ============================================================================== --- stable/8/sys/cam/ata/ata_da.c Thu May 15 05:35:00 2014 (r266117) +++ stable/8/sys/cam/ata/ata_da.c Thu May 15 09:55:21 2014 (r266118) @@ -978,6 +978,8 @@ adaasync(void *callback_arg, u_int32_t c else break; cam_periph_acquire(periph); + cam_freeze_devq_arg(periph->path, + RELSIM_RELEASE_RUNLEVEL, CAM_RL_DEV + 1); xpt_schedule(periph, CAM_PRIORITY_DEV); } default: @@ -1273,11 +1275,15 @@ adaregister(struct cam_periph *periph, v cgd->ident_data.support.command1 & ATA_SUPPORT_LOOKAHEAD) { softc->state = ADA_STATE_RAHEAD; cam_periph_acquire(periph); + cam_freeze_devq_arg(periph->path, + RELSIM_RELEASE_RUNLEVEL, CAM_RL_DEV + 1); xpt_schedule(periph, CAM_PRIORITY_DEV); } else if (ADA_WC >= 0 && cgd->ident_data.support.command1 & ATA_SUPPORT_WRITECACHE) { softc->state = ADA_STATE_WCACHE; cam_periph_acquire(periph); + cam_freeze_devq_arg(periph->path, + RELSIM_RELEASE_RUNLEVEL, CAM_RL_DEV + 1); xpt_schedule(periph, CAM_PRIORITY_DEV); } else softc->state = ADA_STATE_NORMAL; @@ -1561,6 +1567,8 @@ out: if (softc->flags & ADA_FLAG_PACK_INVALID) { softc->state = ADA_STATE_NORMAL; xpt_release_ccb(start_ccb); + cam_release_devq(periph->path, + RELSIM_RELEASE_RUNLEVEL, 0, CAM_RL_DEV + 1, FALSE); adaschedule(periph); cam_periph_release_locked(periph); return; @@ -1584,7 +1592,6 @@ out: ATA_SF_ENAB_WCACHE : ATA_SF_DIS_WCACHE, 0, 0); start_ccb->ccb_h.ccb_state = ADA_CCB_WCACHE; } - start_ccb->ccb_h.flags |= CAM_DEV_QFREEZE; xpt_action(start_ccb); break; } @@ -1597,13 +1604,11 @@ adadone(struct cam_periph *periph, union struct ada_softc *softc; struct ccb_ataio *ataio; struct ccb_getdev *cgd; - struct cam_path *path; softc = (struct ada_softc *)periph->softc; ataio = &done_ccb->ataio; - path = done_ccb->ccb_h.path; - CAM_DEBUG(path, CAM_DEBUG_TRACE, ("adadone\n")); + CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("adadone\n")); switch (ataio->ccb_h.ccb_state & ADA_CCB_TYPE_MASK) { case ADA_CCB_BUFFER_IO: @@ -1631,7 +1636,8 @@ adadone(struct cam_periph *periph, union * XXX See if this is really a media * XXX change first? */ - xpt_print(path, "Invalidating pack\n"); + xpt_print(periph->path, + "Invalidating pack\n"); softc->flags |= ADA_FLAG_PACK_INVALID; } bp->bio_error = error; @@ -1644,7 +1650,7 @@ adadone(struct cam_periph *periph, union bp->bio_flags |= BIO_ERROR; } if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) - cam_release_devq(path, + cam_release_devq(done_ccb->ccb_h.path, /*relsim_flags*/0, /*reduction*/0, /*timeout*/0, @@ -1685,12 +1691,9 @@ adadone(struct cam_periph *periph, union { if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { if (adaerror(done_ccb, 0, 0) == ERESTART) { -out: - /* Drop freeze taken due to CAM_DEV_QFREEZE */ - cam_release_devq(path, 0, 0, 0, FALSE); return; } else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) { - cam_release_devq(path, + cam_release_devq(done_ccb->ccb_h.path, /*relsim_flags*/0, /*reduction*/0, /*timeout*/0, @@ -1707,7 +1710,7 @@ out: * operation. */ cgd = (struct ccb_getdev *)done_ccb; - xpt_setup_ccb(&cgd->ccb_h, path, CAM_PRIORITY_NORMAL); + xpt_setup_ccb(&cgd->ccb_h, periph->path, CAM_PRIORITY_NORMAL); cgd->ccb_h.func_code = XPT_GDEV_TYPE; xpt_action((union ccb *)cgd); if (ADA_WC >= 0 && @@ -1715,12 +1718,12 @@ out: softc->state = ADA_STATE_WCACHE; xpt_release_ccb(done_ccb); xpt_schedule(periph, CAM_PRIORITY_DEV); - goto out; + return; } softc->state = ADA_STATE_NORMAL; xpt_release_ccb(done_ccb); - /* Drop freeze taken due to CAM_DEV_QFREEZE */ - cam_release_devq(path, 0, 0, 0, FALSE); + cam_release_devq(periph->path, + RELSIM_RELEASE_RUNLEVEL, 0, CAM_RL_DEV + 1, FALSE); adaschedule(periph); cam_periph_release_locked(periph); return; @@ -1729,9 +1732,9 @@ out: { if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { if (adaerror(done_ccb, 0, 0) == ERESTART) { - goto out; + return; } else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) { - cam_release_devq(path, + cam_release_devq(done_ccb->ccb_h.path, /*relsim_flags*/0, /*reduction*/0, /*timeout*/0, @@ -1749,8 +1752,8 @@ out: * operation. */ xpt_release_ccb(done_ccb); - /* Drop freeze taken due to CAM_DEV_QFREEZE */ - cam_release_devq(path, 0, 0, 0, FALSE); + cam_release_devq(periph->path, + RELSIM_RELEASE_RUNLEVEL, 0, CAM_RL_DEV + 1, FALSE); adaschedule(periph); cam_periph_release_locked(periph); return; Modified: stable/8/sys/cam/ata/ata_pmp.c ============================================================================== --- stable/8/sys/cam/ata/ata_pmp.c Thu May 15 05:35:00 2014 (r266117) +++ stable/8/sys/cam/ata/ata_pmp.c Thu May 15 09:55:21 2014 (r266118) @@ -193,7 +193,8 @@ pmpfreeze(struct cam_periph *periph, int i, 0) == CAM_REQ_CMP) { softc->frozen |= (1 << i); xpt_acquire_device(dpath->device); - cam_freeze_devq(dpath); + cam_freeze_devq_arg(dpath, + RELSIM_RELEASE_RUNLEVEL, CAM_RL_BUS + 1); xpt_free_path(dpath); } } @@ -214,7 +215,8 @@ pmprelease(struct cam_periph *periph, in xpt_path_path_id(periph->path), i, 0) == CAM_REQ_CMP) { softc->frozen &= ~(1 << i); - cam_release_devq(dpath, 0, 0, 0, FALSE); + cam_release_devq(dpath, + RELSIM_RELEASE_RUNLEVEL, 0, CAM_RL_BUS + 1, FALSE); xpt_release_device(dpath->device); xpt_free_path(dpath); } Modified: stable/8/sys/cam/ata/ata_xpt.c ============================================================================== --- stable/8/sys/cam/ata/ata_xpt.c Thu May 15 05:35:00 2014 (r266117) +++ stable/8/sys/cam/ata/ata_xpt.c Thu May 15 09:55:21 2014 (r266118) @@ -250,6 +250,12 @@ proberegister(struct cam_periph *periph, return (status); } CAM_DEBUG(periph->path, CAM_DEBUG_PROBE, ("Probe started\n")); + + /* + * Ensure nobody slip in until probe finish. + */ + cam_freeze_devq_arg(periph->path, + RELSIM_RELEASE_RUNLEVEL, CAM_RL_XPT + 1); probeschedule(periph); return(CAM_REQ_CMP); } @@ -624,7 +630,6 @@ negotiate: default: panic("probestart: invalid action state 0x%x\n", softc->action); } - start_ccb->ccb_h.flags |= CAM_DEV_QFREEZE; xpt_action(start_ccb); } @@ -670,15 +675,12 @@ probedone(struct cam_periph *periph, uni cam_error_print(done_ccb, CAM_ESF_ALL, CAM_EPF_ALL); } - } else if (cam_periph_error(done_ccb, 0, 0, NULL) == ERESTART) { -out: - /* Drop freeze taken due to CAM_DEV_QFREEZE flag set. */ - cam_release_devq(path, 0, 0, 0, FALSE); + } else if (cam_periph_error(done_ccb, 0, 0, NULL) == ERESTART) return; - } if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) { /* Don't wedge the queue */ - xpt_release_devq(path, /*count*/1, /*run_queue*/TRUE); + xpt_release_devq(done_ccb->ccb_h.path, /*count*/1, + /*run_queue*/TRUE); } status = done_ccb->ccb_h.status & CAM_STATUS_MASK; if (softc->restart) { @@ -771,7 +773,7 @@ noerror: } xpt_release_ccb(done_ccb); xpt_schedule(periph, priority); - goto out; + return; } case PROBE_IDENTIFY: { @@ -806,7 +808,7 @@ noerror: PROBE_SET_ACTION(softc, PROBE_SPINUP); xpt_release_ccb(done_ccb); xpt_schedule(periph, priority); - goto out; + return; } ident_buf = &path->device->ident_data; if ((periph->path->device->flags & CAM_DEV_UNCONFIGURED) == 0) { @@ -879,7 +881,7 @@ noerror: PROBE_SET_ACTION(softc, PROBE_SETMODE); xpt_release_ccb(done_ccb); xpt_schedule(periph, priority); - goto out; + return; } case PROBE_SPINUP: if (bootverbose) @@ -888,7 +890,7 @@ noerror: PROBE_SET_ACTION(softc, PROBE_IDENTIFY); xpt_release_ccb(done_ccb); xpt_schedule(periph, priority); - goto out; + return; case PROBE_SETMODE: if (path->device->transport != XPORT_SATA) goto notsata; @@ -933,7 +935,7 @@ noerror: PROBE_SET_ACTION(softc, PROBE_SETPM); xpt_release_ccb(done_ccb); xpt_schedule(periph, priority); - goto out; + return; } /* FALLTHROUGH */ case PROBE_SETPM: @@ -944,7 +946,7 @@ noerror: PROBE_SET_ACTION(softc, PROBE_SETAPST); xpt_release_ccb(done_ccb); xpt_schedule(periph, priority); - goto out; + return; } /* FALLTHROUGH */ case PROBE_SETAPST: @@ -954,7 +956,7 @@ noerror: PROBE_SET_ACTION(softc, PROBE_SETDMAAA); xpt_release_ccb(done_ccb); xpt_schedule(periph, priority); - goto out; + return; } /* FALLTHROUGH */ case PROBE_SETDMAAA: @@ -964,7 +966,7 @@ noerror: PROBE_SET_ACTION(softc, PROBE_SETAN); xpt_release_ccb(done_ccb); xpt_schedule(periph, priority); - goto out; + return; } /* FALLTHROUGH */ case PROBE_SETAN: @@ -976,14 +978,15 @@ notsata: } xpt_release_ccb(done_ccb); xpt_schedule(periph, priority); - goto out; + return; case PROBE_SET_MULTI: if (periph->path->device->flags & CAM_DEV_UNCONFIGURED) { path->device->flags &= ~CAM_DEV_UNCONFIGURED; xpt_acquire_device(path->device); done_ccb->ccb_h.func_code = XPT_GDEV_TYPE; xpt_action(done_ccb); - xpt_async(AC_FOUND_DEVICE, path, done_ccb); + xpt_async(AC_FOUND_DEVICE, done_ccb->ccb_h.path, + done_ccb); } PROBE_SET_ACTION(softc, PROBE_DONE); break; @@ -1018,7 +1021,7 @@ notsata: PROBE_SET_ACTION(softc, PROBE_FULL_INQUIRY); xpt_release_ccb(done_ccb); xpt_schedule(periph, priority); - goto out; + return; } ata_device_transport(path); @@ -1027,7 +1030,7 @@ notsata: xpt_acquire_device(path->device); done_ccb->ccb_h.func_code = XPT_GDEV_TYPE; xpt_action(done_ccb); - xpt_async(AC_FOUND_DEVICE, path, done_ccb); + xpt_async(AC_FOUND_DEVICE, done_ccb->ccb_h.path, done_ccb); } PROBE_SET_ACTION(softc, PROBE_DONE); break; @@ -1045,7 +1048,7 @@ notsata: PROBE_SET_ACTION(softc, PROBE_PM_PRV); xpt_release_ccb(done_ccb); xpt_schedule(periph, priority); - goto out; + return; case PROBE_PM_PRV: softc->pm_prv = (done_ccb->ataio.res.lba_high << 24) + (done_ccb->ataio.res.lba_mid << 16) + @@ -1094,11 +1097,12 @@ notsata: xpt_acquire_device(path->device); done_ccb->ccb_h.func_code = XPT_GDEV_TYPE; xpt_action(done_ccb); - xpt_async(AC_FOUND_DEVICE, path, done_ccb); + xpt_async(AC_FOUND_DEVICE, done_ccb->ccb_h.path, + done_ccb); } else { done_ccb->ccb_h.func_code = XPT_GDEV_TYPE; xpt_action(done_ccb); - xpt_async(AC_SCSI_AEN, path, done_ccb); + xpt_async(AC_SCSI_AEN, done_ccb->ccb_h.path, done_ccb); } PROBE_SET_ACTION(softc, PROBE_DONE); break; @@ -1110,7 +1114,7 @@ done: softc->restart = 0; xpt_release_ccb(done_ccb); probeschedule(periph); - goto out; + return; } xpt_release_ccb(done_ccb); CAM_DEBUG(periph->path, CAM_DEBUG_PROBE, ("Probe completed\n")); @@ -1120,9 +1124,9 @@ done: done_ccb->ccb_h.status = found ? CAM_REQ_CMP : CAM_REQ_CMP_ERR; xpt_done(done_ccb); } - /* Drop freeze taken due to CAM_DEV_QFREEZE flag set. */ - cam_release_devq(path, 0, 0, 0, FALSE); cam_periph_invalidate(periph); + cam_release_devq(periph->path, + RELSIM_RELEASE_RUNLEVEL, 0, CAM_RL_XPT + 1, FALSE); cam_periph_release_locked(periph); } Modified: stable/8/sys/cam/cam.h ============================================================================== --- stable/8/sys/cam/cam.h Thu May 15 05:35:00 2014 (r266117) +++ stable/8/sys/cam/cam.h Thu May 15 09:55:21 2014 (r266118) @@ -80,15 +80,15 @@ typedef struct { #define CAM_PRIORITY_BUS ((CAM_RL_BUS << 8) + 0x80) #define CAM_PRIORITY_XPT ((CAM_RL_XPT << 8) + 0x80) #define CAM_PRIORITY_DEV ((CAM_RL_DEV << 8) + 0x80) -#define CAM_PRIORITY_OOB (CAM_RL_DEV << 8) #define CAM_PRIORITY_NORMAL ((CAM_RL_NORMAL << 8) + 0x80) #define CAM_PRIORITY_NONE (u_int32_t)-1 +#define CAM_PRIORITY_TO_RL(x) ((x) >> 8) +#define CAM_RL_TO_PRIORITY(x) ((x) << 8) u_int32_t generation; int index; #define CAM_UNQUEUED_INDEX -1 #define CAM_ACTIVE_INDEX -2 #define CAM_DONEQ_INDEX -3 -#define CAM_EXTRAQ_INDEX INT_MAX } cam_pinfo; /* Modified: stable/8/sys/cam/cam_ccb.h ============================================================================== --- stable/8/sys/cam/cam_ccb.h Thu May 15 05:35:00 2014 (r266117) +++ stable/8/sys/cam/cam_ccb.h Thu May 15 09:55:21 2014 (r266118) @@ -142,6 +142,8 @@ typedef enum { /* Path statistics (error counts, etc.) */ XPT_GDEV_STATS = 0x0c, /* Device statistics (error counts, etc.) */ + XPT_FREEZE_QUEUE = 0x0d, + /* Freeze device queue */ /* SCSI Control Functions: 0x10->0x1F */ XPT_ABORT = 0x10, /* Abort the specified CCB */ @@ -698,6 +700,7 @@ struct ccb_relsim { #define RELSIM_RELEASE_AFTER_TIMEOUT 0x02 #define RELSIM_RELEASE_AFTER_CMDCMPLT 0x04 #define RELSIM_RELEASE_AFTER_QEMPTY 0x08 +#define RELSIM_RELEASE_RUNLEVEL 0x10 u_int32_t openings; u_int32_t release_timeout; /* Abstract argument. */ u_int32_t qfrozen_cnt; Modified: stable/8/sys/cam/cam_periph.c ============================================================================== --- stable/8/sys/cam/cam_periph.c Thu May 15 05:35:00 2014 (r266117) +++ stable/8/sys/cam/cam_periph.c Thu May 15 09:55:21 2014 (r266118) @@ -998,12 +998,21 @@ cam_periph_runccb(union ccb *ccb, void cam_freeze_devq(struct cam_path *path) { - struct ccb_hdr ccb_h; - xpt_setup_ccb(&ccb_h, path, /*priority*/1); - ccb_h.func_code = XPT_NOOP; - ccb_h.flags = CAM_DEV_QFREEZE; - xpt_action((union ccb *)&ccb_h); + cam_freeze_devq_arg(path, 0, 0); +} + +void +cam_freeze_devq_arg(struct cam_path *path, uint32_t flags, uint32_t arg) +{ + struct ccb_relsim crs; + + xpt_setup_ccb(&crs.ccb_h, path, CAM_PRIORITY_NONE); + crs.ccb_h.func_code = XPT_FREEZE_QUEUE; + crs.release_flags = flags; + crs.openings = arg; + crs.release_timeout = arg; + xpt_action((union ccb *)&crs); } u_int32_t Modified: stable/8/sys/cam/cam_periph.h ============================================================================== --- stable/8/sys/cam/cam_periph.h Thu May 15 05:35:00 2014 (r266117) +++ stable/8/sys/cam/cam_periph.h Thu May 15 09:55:21 2014 (r266118) @@ -169,6 +169,8 @@ int cam_periph_ioctl(struct cam_periph cam_flags camflags, u_int32_t sense_flags)); void cam_freeze_devq(struct cam_path *path); +void cam_freeze_devq_arg(struct cam_path *path, u_int32_t flags, + uint32_t arg); u_int32_t cam_release_devq(struct cam_path *path, u_int32_t relsim_flags, u_int32_t opening_reduction, u_int32_t arg, int getcount_only); Modified: stable/8/sys/cam/cam_queue.c ============================================================================== --- stable/8/sys/cam/cam_queue.c Thu May 15 05:35:00 2014 (r266117) +++ stable/8/sys/cam/cam_queue.c Thu May 15 09:55:21 2014 (r266118) @@ -230,8 +230,15 @@ int cam_devq_init(struct cam_devq *devq, int devices, int openings) { bzero(devq, sizeof(*devq)); - if (camq_init(&devq->send_queue, devices) != 0) + if (camq_init(&devq->alloc_queue, devices) != 0) { return (1); + } + if (camq_init(&devq->send_queue, devices) != 0) { + camq_fini(&devq->alloc_queue); + return (1); + } + devq->alloc_openings = openings; + devq->alloc_active = 0; devq->send_openings = openings; devq->send_active = 0; return (0); @@ -240,6 +247,7 @@ cam_devq_init(struct cam_devq *devq, int void cam_devq_free(struct cam_devq *devq) { + camq_fini(&devq->alloc_queue); camq_fini(&devq->send_queue); free(devq, M_CAMDEVQ); } @@ -249,7 +257,11 @@ cam_devq_resize(struct cam_devq *camq, i { u_int32_t retval; - retval = camq_resize(&camq->send_queue, devices); + retval = camq_resize(&camq->alloc_queue, devices); + + if (retval == CAM_REQ_CMP) + retval = camq_resize(&camq->send_queue, devices); + return (retval); } @@ -284,27 +296,43 @@ u_int32_t cam_ccbq_resize(struct cam_ccbq *ccbq, int new_size) { int delta; + int space_left; delta = new_size - (ccbq->dev_active + ccbq->dev_openings); - ccbq->devq_openings += delta; - ccbq->dev_openings += delta; - - new_size = imax(64, 1 << fls(new_size + new_size / 2)); - if (new_size > ccbq->queue.array_size) - return (camq_resize(&ccbq->queue, new_size)); - else + space_left = new_size + - ccbq->queue.entries + - ccbq->held + - ccbq->dev_active; + + /* + * Only attempt to change the underlying queue size if we are + * shrinking it and there is space for all outstanding entries + * in the new array or we have been requested to grow the array. + * We don't fail in the case where we can't reduce the array size, + * but clients that care that the queue be "garbage collected" + * should detect this condition and call us again with the + * same size once the outstanding entries have been processed. + */ + if (space_left < 0 + || camq_resize(&ccbq->queue, new_size + (CAM_RL_VALUES - 1)) == + CAM_REQ_CMP) { + ccbq->devq_openings += delta; + ccbq->dev_openings += delta; return (CAM_REQ_CMP); + } else { + return (CAM_RESRC_UNAVAIL); + } } int cam_ccbq_init(struct cam_ccbq *ccbq, int openings) { bzero(ccbq, sizeof(*ccbq)); - if (camq_init(&ccbq->queue, - imax(64, 1 << fls(openings + openings / 2))) != 0) + if (camq_init(&ccbq->queue, openings + (CAM_RL_VALUES - 1)) != 0) { return (1); + } ccbq->devq_openings = openings; - ccbq->dev_openings = openings; + ccbq->dev_openings = openings; return (0); } Modified: stable/8/sys/cam/cam_queue.h ============================================================================== --- stable/8/sys/cam/cam_queue.h Thu May 15 05:35:00 2014 (r266117) +++ stable/8/sys/cam/cam_queue.h Thu May 15 09:55:21 2014 (r266118) @@ -48,7 +48,7 @@ struct camq { int array_size; int entries; u_int32_t generation; - u_int32_t qfrozen_cnt; + u_int32_t qfrozen_cnt[CAM_RL_VALUES]; }; TAILQ_HEAD(ccb_hdr_tailq, ccb_hdr); @@ -57,11 +57,8 @@ SLIST_HEAD(ccb_hdr_slist, ccb_hdr); struct cam_ccbq { struct camq queue; - struct ccb_hdr_tailq queue_extra_head; - int queue_extra_entries; int devq_openings; - int devq_allocating; - int dev_openings; + int dev_openings; int dev_active; int held; }; @@ -69,7 +66,11 @@ struct cam_ccbq { struct cam_ed; struct cam_devq { + struct camq alloc_queue; struct camq send_queue; + struct cam_ed *active_dev; + int alloc_openings; + int alloc_active; int send_openings; int send_active; }; @@ -157,10 +158,10 @@ cam_ccbq_pending_ccb_count(struct cam_cc static __inline void cam_ccbq_take_opening(struct cam_ccbq *ccbq); -static __inline void +static __inline int cam_ccbq_insert_ccb(struct cam_ccbq *ccbq, union ccb *new_ccb); -static __inline void +static __inline int cam_ccbq_remove_ccb(struct cam_ccbq *ccbq, union ccb *ccb); static __inline union ccb * @@ -179,7 +180,7 @@ cam_ccbq_release_opening(struct cam_ccbq static __inline int cam_ccbq_pending_ccb_count(struct cam_ccbq *ccbq) { - return (ccbq->queue.entries + ccbq->queue_extra_entries); + return (ccbq->queue.entries); } static __inline void @@ -189,64 +190,31 @@ cam_ccbq_take_opening(struct cam_ccbq *c ccbq->held++; } -static __inline void +static __inline int cam_ccbq_insert_ccb(struct cam_ccbq *ccbq, union ccb *new_ccb) { - struct ccb_hdr *old_ccb; - struct camq *queue = &ccbq->queue; - ccbq->held--; - - /* - * If queue is already full, try to resize. - * If resize fail, push CCB with lowest priority out to the TAILQ. - */ - if (queue->entries == queue->array_size && - camq_resize(&ccbq->queue, queue->array_size * 2) != CAM_REQ_CMP) { - old_ccb = (struct ccb_hdr *)camq_remove(queue, queue->entries); - TAILQ_INSERT_HEAD(&ccbq->queue_extra_head, old_ccb, - xpt_links.tqe); - old_ccb->pinfo.index = CAM_EXTRAQ_INDEX; - ccbq->queue_extra_entries++; - } - - camq_insert(queue, &new_ccb->ccb_h.pinfo); + camq_insert(&ccbq->queue, &new_ccb->ccb_h.pinfo); + if (ccbq->queue.qfrozen_cnt[CAM_PRIORITY_TO_RL( + new_ccb->ccb_h.pinfo.priority)] > 0) { + ccbq->devq_openings++; + ccbq->held++; + return (1); + } else + return (0); } -static __inline void +static __inline int cam_ccbq_remove_ccb(struct cam_ccbq *ccbq, union ccb *ccb) { - struct ccb_hdr *cccb, *bccb; - struct camq *queue = &ccbq->queue; - - /* If the CCB is on the TAILQ, remove it from there. */ - if (ccb->ccb_h.pinfo.index == CAM_EXTRAQ_INDEX) { - TAILQ_REMOVE(&ccbq->queue_extra_head, &ccb->ccb_h, - xpt_links.tqe); - ccb->ccb_h.pinfo.index = CAM_UNQUEUED_INDEX; - ccbq->queue_extra_entries--; - return; - } - - camq_remove(queue, ccb->ccb_h.pinfo.index); - - /* - * If there are some CCBs on TAILQ, find the best one and move it - * to the emptied space in the queue. - */ - bccb = TAILQ_FIRST(&ccbq->queue_extra_head); - if (bccb == NULL) - return; - TAILQ_FOREACH(cccb, &ccbq->queue_extra_head, xpt_links.tqe) { - if (bccb->pinfo.priority > cccb->pinfo.priority || - (bccb->pinfo.priority == cccb->pinfo.priority && - GENERATIONCMP(bccb->pinfo.generation, >, - cccb->pinfo.generation))) - bccb = cccb; - } - TAILQ_REMOVE(&ccbq->queue_extra_head, bccb, xpt_links.tqe); - ccbq->queue_extra_entries--; - camq_insert(queue, &bccb->pinfo); + camq_remove(&ccbq->queue, ccb->ccb_h.pinfo.index); + if (ccbq->queue.qfrozen_cnt[CAM_PRIORITY_TO_RL( + ccb->ccb_h.pinfo.priority)] > 0) { + ccbq->devq_openings--; + ccbq->held--; + return (1); + } else + return (0); } static __inline union ccb * @@ -280,5 +248,81 @@ cam_ccbq_release_opening(struct cam_ccbq ccbq->devq_openings++; } +static __inline int +cam_ccbq_freeze(struct cam_ccbq *ccbq, cam_rl rl, u_int32_t cnt) +{ + int i, frozen = 0; + cam_rl p, n; + + /* Find pevious run level. */ + for (p = 0; p < CAM_RL_VALUES && ccbq->queue.qfrozen_cnt[p] == 0; p++); + /* Find new run level. */ + n = min(rl, p); + /* Apply new run level. */ + for (i = rl; i < CAM_RL_VALUES; i++) + ccbq->queue.qfrozen_cnt[i] += cnt; + /* Update ccbq statistics. */ + if (n == p) + return (0); + for (i = CAMQ_HEAD; i <= ccbq->queue.entries; i++) { + cam_rl rrl = + CAM_PRIORITY_TO_RL(ccbq->queue.queue_array[i]->priority); + if (rrl < n) + continue; + if (rrl >= p) + break; + ccbq->devq_openings++; + ccbq->held++; + frozen++; + } + return (frozen); +} + +static __inline int +cam_ccbq_release(struct cam_ccbq *ccbq, cam_rl rl, u_int32_t cnt) +{ + int i, released = 0; + cam_rl p, n; + + /* Apply new run level. */ + for (i = rl; i < CAM_RL_VALUES; i++) + ccbq->queue.qfrozen_cnt[i] -= cnt; + /* Find new run level. */ + for (n = 0; n < CAM_RL_VALUES && ccbq->queue.qfrozen_cnt[n] == 0; n++); + /* Find previous run level. */ + p = min(rl, n); + /* Update ccbq statistics. */ + if (n == p) + return (0); + for (i = CAMQ_HEAD; i <= ccbq->queue.entries; i++) { + cam_rl rrl = + CAM_PRIORITY_TO_RL(ccbq->queue.queue_array[i]->priority); + if (rrl < p) + continue; + if (rrl >= n) + break; + ccbq->devq_openings--; + ccbq->held--; + released++; + } + return (released); +} + +static __inline u_int32_t +cam_ccbq_frozen(struct cam_ccbq *ccbq, cam_rl rl) +{ + + return (ccbq->queue.qfrozen_cnt[rl]); +} + +static __inline u_int32_t +cam_ccbq_frozen_top(struct cam_ccbq *ccbq) +{ + cam_rl rl; + + rl = CAM_PRIORITY_TO_RL(CAMQ_GET_PRIO(&ccbq->queue)); + return (ccbq->queue.qfrozen_cnt[rl]); +} + #endif /* _KERNEL */ #endif /* _CAM_CAM_QUEUE_H */ Modified: stable/8/sys/cam/cam_xpt.c ============================================================================== --- stable/8/sys/cam/cam_xpt.c Thu May 15 05:35:00 2014 (r266117) +++ stable/8/sys/cam/cam_xpt.c Thu May 15 09:55:21 2014 (r266118) @@ -96,7 +96,7 @@ struct xpt_softc { u_int32_t xpt_generation; /* number of high powered commands that can go through right now */ - STAILQ_HEAD(highpowerlist, cam_ed) highpowerq; + STAILQ_HEAD(highpowerlist, ccb_hdr) highpowerq; int num_highpower; /* queue for handling async rescan requests. */ @@ -221,13 +221,13 @@ static void xpt_async_bcast(struct asyn static path_id_t xptnextfreepathid(void); static path_id_t xptpathid(const char *sim_name, int sim_unit, int sim_bus); static union ccb *xpt_get_ccb(struct cam_ed *device); -static void xpt_run_dev_allocq(struct cam_ed *device); -static void xpt_run_devq(struct cam_devq *devq); +static void xpt_run_dev_allocq(struct cam_eb *bus); +static void xpt_run_dev_sendq(struct cam_eb *bus); static timeout_t xpt_release_devq_timeout; static void xpt_release_simq_timeout(void *arg) __unused; static void xpt_release_bus(struct cam_eb *bus); -static void xpt_release_devq_device(struct cam_ed *dev, u_int count, - int run_queue); +static void xpt_release_devq_device(struct cam_ed *dev, cam_rl rl, + u_int count, int run_queue); static struct cam_et* xpt_alloc_target(struct cam_eb *bus, target_id_t target_id); static void xpt_release_target(struct cam_et *target); @@ -297,24 +297,49 @@ static xpt_busfunc_t xptsetasyncbusfunc; static cam_status xptregister(struct cam_periph *periph, void *arg); static __inline int periph_is_queued(struct cam_periph *periph); -static __inline int device_is_queued(struct cam_ed *device); +static __inline int device_is_alloc_queued(struct cam_ed *device); +static __inline int device_is_send_queued(struct cam_ed *device); static __inline int -xpt_schedule_devq(struct cam_devq *devq, struct cam_ed *dev) +xpt_schedule_dev_allocq(struct cam_eb *bus, struct cam_ed *dev) +{ + int retval; + + if ((dev->drvq.entries > 0) && + (dev->ccbq.devq_openings > 0) && + (cam_ccbq_frozen(&dev->ccbq, CAM_PRIORITY_TO_RL( + CAMQ_GET_PRIO(&dev->drvq))) == 0)) { + /* + * The priority of a device waiting for CCB resources + * is that of the highest priority peripheral driver + * enqueued. + */ + retval = xpt_schedule_dev(&bus->sim->devq->alloc_queue, + &dev->alloc_ccb_entry.pinfo, + CAMQ_GET_PRIO(&dev->drvq)); + } else { + retval = 0; + } + + return (retval); +} + +static __inline int +xpt_schedule_dev_sendq(struct cam_eb *bus, struct cam_ed *dev) { int retval; if ((dev->ccbq.queue.entries > 0) && (dev->ccbq.dev_openings > 0) && - (dev->ccbq.queue.qfrozen_cnt == 0)) { + (cam_ccbq_frozen_top(&dev->ccbq) == 0)) { /* * The priority of a device waiting for controller * resources is that of the highest priority CCB * enqueued. */ retval = - xpt_schedule_dev(&devq->send_queue, - &dev->devq_entry.pinfo, + xpt_schedule_dev(&bus->sim->devq->send_queue, + &dev->send_ccb_entry.pinfo, CAMQ_GET_PRIO(&dev->ccbq.queue)); } else { retval = 0; @@ -329,9 +354,15 @@ periph_is_queued(struct cam_periph *peri } static __inline int -device_is_queued(struct cam_ed *device) +device_is_alloc_queued(struct cam_ed *device) { - return (device->devq_entry.pinfo.index != CAM_UNQUEUED_INDEX); + return (device->alloc_ccb_entry.pinfo.index != CAM_UNQUEUED_INDEX); +} + +static __inline int +device_is_send_queued(struct cam_ed *device) +{ + return (device->send_ccb_entry.pinfo.index != CAM_UNQUEUED_INDEX); } static void @@ -2456,10 +2487,17 @@ xpt_action_default(union ccb *start_ccb) /* FALLTHROUGH */ case XPT_RESET_DEV: case XPT_ENG_EXEC: - cam_ccbq_insert_ccb(&path->device->ccbq, start_ccb); - if (xpt_schedule_devq(path->bus->sim->devq, path->device)) - xpt_run_devq(path->bus->sim->devq); + { + int frozen; + + frozen = cam_ccbq_insert_ccb(&path->device->ccbq, start_ccb); + path->device->sim->devq->alloc_openings += frozen; + if (frozen > 0) + xpt_run_dev_allocq(path->bus); + if (xpt_schedule_dev_sendq(path->bus, path->device)) + xpt_run_dev_sendq(path->bus); break; + } case XPT_CALC_GEOMETRY: { struct cam_sim *sim; @@ -2508,7 +2546,8 @@ xpt_action_default(union ccb *start_ccb) device = abort_ccb->ccb_h.path->device; ccbq = &device->ccbq; - cam_ccbq_remove_ccb(ccbq, abort_ccb); + device->sim->devq->alloc_openings -= + cam_ccbq_remove_ccb(ccbq, abort_ccb); abort_ccb->ccb_h.status = CAM_REQ_ABORTED|CAM_DEV_QFRZN; xpt_freeze_devq(abort_ccb->ccb_h.path, 1); @@ -2616,7 +2655,7 @@ xpt_action_default(union ccb *start_ccb) cgds->dev_openings = dev->ccbq.dev_openings; cgds->dev_active = dev->ccbq.dev_active; cgds->devq_openings = dev->ccbq.devq_openings; - cgds->devq_queued = cam_ccbq_pending_ccb_count(&dev->ccbq); + cgds->devq_queued = dev->ccbq.queue.entries; cgds->held = dev->ccbq.held; cgds->last_reset = tar->last_reset; cgds->maxtags = dev->maxtags; @@ -2883,9 +2922,13 @@ xpt_action_default(union ccb *start_ccb) } } - if ((start_ccb->ccb_h.flags & CAM_DEV_QFREEZE) == 0) - xpt_release_devq(path, /*count*/1, /*run_queue*/TRUE); - start_ccb->crs.qfrozen_cnt = dev->ccbq.queue.qfrozen_cnt; + if ((start_ccb->ccb_h.flags & CAM_DEV_QFREEZE) == 0) { + xpt_release_devq_rl(path, /*runlevel*/ + (crs->release_flags & RELSIM_RELEASE_RUNLEVEL) ? + crs->release_timeout : 0, + /*count*/1, /*run_queue*/TRUE); + } + start_ccb->crs.qfrozen_cnt = dev->ccbq.queue.qfrozen_cnt[0]; start_ccb->ccb_h.status = CAM_REQ_CMP; break; } @@ -2920,6 +2963,16 @@ xpt_action_default(union ccb *start_ccb) } break; } + case XPT_FREEZE_QUEUE: + { + struct ccb_relsim *crs = &start_ccb->crs; + + xpt_freeze_devq_rl(path, /*runlevel*/ + (crs->release_flags & RELSIM_RELEASE_RUNLEVEL) ? + crs->release_timeout : 0, /*count*/1); + start_ccb->ccb_h.status = CAM_REQ_CMP; + break; + } case XPT_NOOP: if ((start_ccb->ccb_h.flags & CAM_DEV_QFREEZE) != 0) xpt_freeze_devq(path, 1); @@ -3023,7 +3076,7 @@ xpt_schedule(struct cam_periph *perph, u camq_change_priority(&device->drvq, perph->pinfo.index, new_priority); - runq = 1; + runq = xpt_schedule_dev_allocq(perph->path->bus, device); } } else { /* New entry on the queue */ @@ -3032,12 +3085,12 @@ xpt_schedule(struct cam_periph *perph, u perph->pinfo.priority = new_priority; perph->pinfo.generation = ++device->drvq.generation; camq_insert(&device->drvq, &perph->pinfo); - runq = 1; + runq = xpt_schedule_dev_allocq(perph->path->bus, device); } if (runq != 0) { CAM_DEBUG(perph->path, CAM_DEBUG_SUBTRACE, - (" calling xpt_run_dev_allocq\n")); - xpt_run_dev_allocq(device); + (" calling xpt_run_devq\n")); + xpt_run_dev_allocq(perph->path->bus); } } @@ -3090,25 +3143,43 @@ xpt_schedule_dev(struct camq *queue, cam } static void -xpt_run_dev_allocq(struct cam_ed *device) +xpt_run_dev_allocq(struct cam_eb *bus) { - struct camq *drvq; + struct cam_devq *devq; - if (device->ccbq.devq_allocating) - return; - device->ccbq.devq_allocating = 1; - CAM_DEBUG_PRINT(CAM_DEBUG_XPT, ("xpt_run_dev_allocq(%p)\n", device)); - drvq = &device->drvq; - while ((drvq->entries > 0) && - (device->ccbq.devq_openings > 0 || - CAMQ_GET_PRIO(drvq) <= CAM_PRIORITY_OOB) && - (device->ccbq.queue.qfrozen_cnt == 0)) { + CAM_DEBUG_PRINT(CAM_DEBUG_XPT, ("xpt_run_dev_allocq\n")); + devq = bus->sim->devq; + + CAM_DEBUG_PRINT(CAM_DEBUG_XPT, + (" qfrozen_cnt == 0x%x, entries == %d, " + "openings == %d, active == %d\n", + devq->alloc_queue.qfrozen_cnt[0], + devq->alloc_queue.entries, + devq->alloc_openings, + devq->alloc_active)); + + devq->alloc_queue.qfrozen_cnt[0]++; + while ((devq->alloc_queue.entries > 0) + && (devq->alloc_openings > 0) + && (devq->alloc_queue.qfrozen_cnt[0] <= 1)) { + struct cam_ed_qinfo *qinfo; + struct cam_ed *device; union ccb *work_ccb; struct cam_periph *drv; + struct camq *drvq; + + qinfo = (struct cam_ed_qinfo *)camq_remove(&devq->alloc_queue, + CAMQ_HEAD); + device = qinfo->device; + CAM_DEBUG_PRINT(CAM_DEBUG_XPT, + ("running device %p\n", device)); *** DIFF OUTPUT TRUNCATED AT 1000 LINES ***