Implement the guts of the XPT_ABORT function code.

Clear residuals for XPT_TARGET_IO/XPT_CONT_TARGET_IO calls just
as we do for XPT_SCSI_IO calls.

Make xpt_release_devq a proper reciprocal of xpt_freeze_devq by
allowing the caller to decrement the count more than once per call.

Change the semantics of xpt_path_cmp to return 1 for a match
with a wildcard from path1 and 2 for a match with wildcards
from path2.  This change doesn't affect most callers as they
only check for >=0 (exact match or one containing a wildcard).

When cleaning up a device node, ensure that there are no timeouts
outstanding that reference it.
This commit is contained in:
Justin T. Gibbs 1999-08-16 22:22:41 +00:00
parent b8b98bc375
commit 2cefde5ff3

View File

@ -26,7 +26,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: cam_xpt.c,v 1.65 1999/07/11 06:10:47 jmg Exp $
* $Id: cam_xpt.c,v 1.66 1999/08/16 17:47:39 mjacob Exp $
*/
#include <sys/param.h>
#include <sys/systm.h>
@ -592,6 +592,7 @@ static u_int bus_generation;
#ifdef CAMDEBUG
struct cam_path *cam_dpath;
u_int32_t cam_dflags;
u_int32_t cam_debug_delay;
#endif
#if defined(CAM_DEBUG_FLAGS) && !defined(CAMDEBUG)
@ -643,6 +644,8 @@ static void xpt_run_dev_sendq(struct cam_eb *bus);
static timeout_t xpt_release_devq_timeout;
static timeout_t xpt_release_simq_timeout;
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 struct cam_et*
xpt_alloc_target(struct cam_eb *bus, target_id_t target_id);
static void xpt_release_target(struct cam_eb *bus, struct cam_et *target);
@ -948,9 +951,6 @@ xptioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p)
}
/* FALLTHROUGH */
case XPT_SCAN_LUN:
case XPT_RESET_DEV:
case XPT_ENG_INQ: /* XXX not implemented yet */
case XPT_ENG_EXEC:
ccb = xpt_alloc_ccb();
@ -2762,17 +2762,18 @@ xpt_action(union ccb *start_ccb)
start_ccb->ccb_h.target_lun << 5;
}
start_ccb->csio.scsi_status = SCSI_STATUS_OK;
start_ccb->csio.sense_resid = 0;
start_ccb->csio.resid = 0;
CAM_DEBUG(path, CAM_DEBUG_CDB,("%s. CDB: %s\n",
scsi_op_desc(start_ccb->csio.cdb_io.cdb_bytes[0],
&path->device->inq_data),
scsi_cdb_string(start_ccb->csio.cdb_io.cdb_bytes,
cdb_str, sizeof(cdb_str))));
/* FALLTRHOUGH */
/* FALLTHROUGH */
}
case XPT_TARGET_IO:
case XPT_CONT_TARGET_IO:
start_ccb->csio.sense_resid = 0;
start_ccb->csio.resid = 0;
/* FALLTHROUGH */
case XPT_ENG_EXEC:
{
struct cam_path *path;
@ -2800,6 +2801,9 @@ xpt_action(union ccb *start_ccb)
break;
}
case XPT_CALC_GEOMETRY:
{
struct cam_sim *sim;
/* Filter out garbage */
if (start_ccb->ccg.block_size == 0
|| start_ccb->ccg.volume_size == 0) {
@ -2823,9 +2827,63 @@ xpt_action(union ccb *start_ccb)
start_ccb->ccb_h.status = CAM_REQ_CMP;
break;
}
/* FALLTHROUGH */
#endif
sim = start_ccb->ccb_h.path->bus->sim;
(*(sim->sim_action))(sim, start_ccb);
break;
}
case XPT_ABORT:
{
union ccb* abort_ccb;
int s;
abort_ccb = start_ccb->cab.abort_ccb;
if (XPT_FC_IS_DEV_QUEUED(abort_ccb)) {
if (abort_ccb->ccb_h.pinfo.index >= 0) {
struct cam_ccbq *ccbq;
ccbq = &abort_ccb->ccb_h.path->device->ccbq;
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);
s = splcam();
xpt_done(abort_ccb);
splx(s);
start_ccb->ccb_h.status = CAM_REQ_CMP;
break;
}
if (abort_ccb->ccb_h.pinfo.index == CAM_UNQUEUED_INDEX
&& (abort_ccb->ccb_h.status & CAM_SIM_QUEUED) == 0) {
/*
* We've caught this ccb en route to
* the SIM. Flag it for abort and the
* SIM will do so just before starting
* real work on the CCB.
*/
abort_ccb->ccb_h.status =
CAM_REQ_ABORTED|CAM_DEV_QFRZN;
xpt_freeze_devq(abort_ccb->ccb_h.path, 1);
start_ccb->ccb_h.status = CAM_REQ_CMP;
break;
}
}
if (XPT_FC_IS_QUEUED(abort_ccb)
&& (abort_ccb->ccb_h.pinfo.index == CAM_DONEQ_INDEX)) {
/*
* It's already completed but waiting
* for our SWI to get to it.
*/
start_ccb->ccb_h.status = CAM_UA_ABORT;
break;
}
/*
* If we weren't able to take care of the abort request
* in the XPT, pass the request down to the SIM for processing.
*/
/* FALLTHROUGH */
}
case XPT_RESET_DEV:
case XPT_ACCEPT_TARGET_IO:
case XPT_EN_LUN:
@ -3224,7 +3282,7 @@ xpt_action(union ccb *start_ccb)
if ((start_ccb->ccb_h.flags & CAM_DEV_QFREEZE) == 0) {
xpt_release_devq(crs->ccb_h.path->device,
xpt_release_devq(crs->ccb_h.path, /*count*/1,
/*run_queue*/TRUE);
}
start_ccb->crs.qfrozen_cnt = dev->qfrozen_cnt;
@ -3244,6 +3302,9 @@ xpt_action(union ccb *start_ccb)
int s;
s = splcam();
#ifdef CAM_DEBUG_DELAY
cam_debug_delay = CAM_DEBUG_DELAY;
#endif
cam_dflags = start_ccb->cdbg.flags;
if (cam_dpath != NULL) {
xpt_free_path(cam_dpath);
@ -3810,7 +3871,8 @@ xpt_free_path(struct cam_path *path)
/*
* Return -1 for failure, 0 for exact match, 1 for match with wildcards.
* Return -1 for failure, 0 for exact match, 1 for match with wildcards
* in path1, 2 for match with wildcards in path2.
*/
int
xpt_path_comp(struct cam_path *path1, struct cam_path *path2)
@ -3818,23 +3880,28 @@ xpt_path_comp(struct cam_path *path1, struct cam_path *path2)
int retval = 0;
if (path1->bus != path2->bus) {
if (path1->bus->path_id == CAM_BUS_WILDCARD
|| path2->bus->path_id == CAM_BUS_WILDCARD)
if (path1->bus->path_id == CAM_BUS_WILDCARD)
retval = 1;
else if (path2->bus->path_id == CAM_BUS_WILDCARD)
retval = 2;
else
return (-1);
}
if (path1->target != path2->target) {
if (path1->target->target_id == CAM_TARGET_WILDCARD
|| path2->target->target_id == CAM_TARGET_WILDCARD)
retval = 1;
if (path1->target->target_id == CAM_TARGET_WILDCARD) {
if (retval == 0)
retval = 1;
} else if (path2->target->target_id == CAM_TARGET_WILDCARD)
retval = 2;
else
return (-1);
}
if (path1->device != path2->device) {
if (path1->device->lun_id == CAM_LUN_WILDCARD
|| path2->device->lun_id == CAM_LUN_WILDCARD)
retval = 1;
if (path1->device->lun_id == CAM_LUN_WILDCARD) {
if (retval == 0)
retval = 1;
} else if (path2->device->lun_id == CAM_LUN_WILDCARD)
retval = 2;
else
return (-1);
}
@ -4280,11 +4347,17 @@ xpt_release_devq_timeout(void *arg)
device = (struct cam_ed *)arg;
xpt_release_devq(device, /*run_queue*/TRUE);
xpt_release_devq_device(device, /*count*/1, /*run_queue*/TRUE);
}
void
xpt_release_devq(struct cam_ed *dev, int run_queue)
xpt_release_devq(struct cam_path *path, u_int count, int run_queue)
{
xpt_release_devq_device(path->device, count, run_queue);
}
static void
xpt_release_devq_device(struct cam_ed *dev, u_int count, int run_queue)
{
int rundevq;
int s;
@ -4293,7 +4366,8 @@ xpt_release_devq(struct cam_ed *dev, int run_queue)
s = splcam();
if (dev->qfrozen_cnt > 0) {
dev->qfrozen_cnt--;
count = (count > dev->qfrozen_cnt) ? dev->qfrozen_cnt : count;
dev->qfrozen_cnt -= count;
if (dev->qfrozen_cnt == 0) {
/*
@ -4620,6 +4694,11 @@ xpt_release_device(struct cam_eb *bus, struct cam_et *target,
if (device->alloc_ccb_entry.pinfo.index != CAM_UNQUEUED_INDEX
|| device->send_ccb_entry.pinfo.index != CAM_UNQUEUED_INDEX)
panic("Removing device while still queued for ccbs");
if ((device->flags & CAM_DEV_REL_TIMEOUT_PENDING) != 0)
untimeout(xpt_release_devq_timeout, device,
device->c_handle);
TAILQ_REMOVE(&target->ed_entries, device,links);
target->generation++;
xpt_max_ccbs -= device->ccbq.devq_openings;
@ -5308,7 +5387,8 @@ probedone(struct cam_periph *periph, union ccb *done_ccb)
return;
else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0)
/* Don't wedge the queue */
xpt_release_devq(done_ccb->ccb_h.path->device,
xpt_release_devq(done_ccb->ccb_h.path,
/*count*/1,
/*run_queue*/TRUE);
}
softc->action = PROBE_INQUIRY;
@ -5360,7 +5440,7 @@ probedone(struct cam_periph *periph, union ccb *done_ccb)
return;
} else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) {
/* Don't wedge the queue */
xpt_release_devq(done_ccb->ccb_h.path->device,
xpt_release_devq(done_ccb->ccb_h.path, /*count*/1,
/*run_queue*/TRUE);
}
/*
@ -5401,8 +5481,8 @@ probedone(struct cam_periph *periph, union ccb *done_ccb)
return;
} else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) {
/* Don't wedge the queue */
xpt_release_devq(done_ccb->ccb_h.path->device,
/*run_queue*/TRUE);
xpt_release_devq(done_ccb->ccb_h.path,
/*count*/1, /*run_queue*/TRUE);
}
xpt_release_ccb(done_ccb);
free(mode_hdr, M_TEMP);
@ -5458,7 +5538,7 @@ probedone(struct cam_periph *periph, union ccb *done_ccb)
return;
} else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) {
/* Don't wedge the queue */
xpt_release_devq(done_ccb->ccb_h.path->device,
xpt_release_devq(done_ccb->ccb_h.path, /*count*/1,
/*run_queue*/TRUE);
}
@ -5522,7 +5602,7 @@ probedone(struct cam_periph *periph, union ccb *done_ccb)
case PROBE_TUR_FOR_NEGOTIATION:
if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) {
/* Don't wedge the queue */
xpt_release_devq(done_ccb->ccb_h.path->device,
xpt_release_devq(done_ccb->ccb_h.path, /*count*/1,
/*run_queue*/TRUE);
}
@ -6095,8 +6175,8 @@ camisr(cam_isrq_t *queue)
STAILQ_REMOVE_HEAD(hphead, xpt_links.stqe);
xpt_release_devq(send_ccb->ccb_h.path->device,
TRUE);
xpt_release_devq(send_ccb->ccb_h.path,
/*count*/1, /*runqueue*/TRUE);
}
}
if ((ccb_h->func_code & XPT_FC_USER_CCB) == 0) {
@ -6115,7 +6195,7 @@ camisr(cam_isrq_t *queue)
|| ((dev->flags & CAM_DEV_REL_ON_QUEUE_EMPTY) != 0
&& (dev->ccbq.dev_active == 0))) {
xpt_release_devq(ccb_h->path->device,
xpt_release_devq(ccb_h->path, /*count*/1,
/*run_queue*/TRUE);
}
@ -6136,7 +6216,7 @@ camisr(cam_isrq_t *queue)
/*run_queue*/TRUE);
} else if ((ccb_h->flags & CAM_DEV_QFRZDIS)
&& (ccb_h->status & CAM_DEV_QFRZN)) {
xpt_release_devq(ccb_h->path->device,
xpt_release_devq(ccb_h->path, /*count*/1,
/*run_queue*/TRUE);
ccb_h->status &= ~CAM_DEV_QFRZN;
} else if (runq) {