Sync CAM with FreeBSD using lockmgr locks instead of mutexes. Note: This is mostly a code sync with FreeBSD which improves stability in addition to the items listed below. This provides a framework for releasing the mplock, but for now it's still there. Add an xpt_print function to reduce most of the xpt_print_path/printf pairs. Convert the core code to use it. Initial cut at Basic Domain Validation. Make cam_xpt's pronouncements match camcontrol (Tagged -> Command) Queueing. Pay attention to return value from xpt_bus_register in xpt_init. Add an xpt_rescan function and a thread that will field rescan requests. The purpose of this is to allow a SIM (or other entities) to request a bus rescan and have it then fielded in a different (process) context from the caller. Check the return value from cam_periph_acquire. Drop the periph/sim lock when calling disk_destroy(). Drop the topology lock before calling the periph oninvalidate and dtor vectors. For the XPT_SASYNC_CB operation, only decouple the broadcast to the bus and device lists instead of decoupling the whole operation. This avoids problems with SIMs going away. Split the camisr into per-SIM done queues. This optimizes the locking a little bit and allows for direct dispatch of the doneq from certain contexts that would otherwise face recursive locking problems. Zero the CCBs when mallocing them. Only schedule the xpt_finishconfig_task once. Eliminate the use of M_TEMP. Add a helper function for registering async callbacks. Release the bus reference that is acquired when doing a CAMIOCOMMAND ioctl. Zero scsi_readcapacity allocations so we can really tell if there has been data returned. Remove duplicate includes and fix typos. Add a bunch of definitions and structures to support newer drivers. When probing a newly found device, don't automatically assume that the device supports retrieving a serial number. Instead, first query the list of VPD pages it does support, and only query the serial number if it's supported, else silently move on. This eliminates a lot of noise during verbose booting, and will likely eliminate the need for most NOSERIAL quirks. Reduce diffs from FreeBSD. Obtained-from: FreeBSD diff --git a/sys/bus/cam/cam_periph.c b/sys/bus/cam/cam_periph.c index 21143d9..9bf0b80 100644 --- a/sys/bus/cam/cam_periph.c +++ b/sys/bus/cam/cam_periph.c @@ -26,7 +26,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $FreeBSD: src/sys/cam/cam_periph.c,v 1.24.2.3 2003/01/25 19:04:40 dillon Exp $ + * $FreeBSD: src/sys/cam/cam_periph.c,v 1.70 2008/02/12 11:07:33 raj Exp $ * $DragonFly: src/sys/bus/cam/cam_periph.c,v 1.39 2007/12/02 04:54:40 pavalos Exp $ */ @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include @@ -49,6 +50,7 @@ #include "cam_xpt_periph.h" #include "cam_periph.h" #include "cam_debug.h" +#include "cam_sim.h" #include #include @@ -99,7 +101,8 @@ periphdriver_register(void *data) int ndrivers; ndrivers = nperiph_drivers + 2; - newdrivers = kmalloc(sizeof(*newdrivers) * ndrivers, M_TEMP, M_WAITOK); + newdrivers = kmalloc(sizeof(*newdrivers) * ndrivers, M_CAMPERIPH, + M_WAITOK); if (periph_drivers) bcopy(periph_drivers, newdrivers, sizeof(*newdrivers) * nperiph_drivers); @@ -108,7 +111,7 @@ periphdriver_register(void *data) old = periph_drivers; periph_drivers = newdrivers; if (old) - kfree(old, M_TEMP); + kfree(old, M_CAMPERIPH); nperiph_drivers++; } @@ -120,6 +123,7 @@ cam_periph_alloc(periph_ctor_t *periph_ctor, ac_callback_t *ac_callback, ac_code code, void *arg) { struct periph_driver **p_drv; + struct cam_sim *sim; struct cam_periph *periph; struct cam_periph *cur_periph; path_id_t path_id; @@ -156,11 +160,14 @@ cam_periph_alloc(periph_ctor_t *periph_ctor, init_level++; + xpt_lock_buses(); for (p_drv = periph_drivers; *p_drv != NULL; p_drv++) { if (strcmp((*p_drv)->driver_name, name) == 0) break; } - + xpt_unlock_buses(); + + sim = xpt_path_sim(path); path_id = xpt_path_path_id(path); target_id = xpt_path_target_id(path); lun_id = xpt_path_lun_id(path); @@ -173,6 +180,7 @@ cam_periph_alloc(periph_ctor_t *periph_ctor, periph->unit_number = camperiphunit(*p_drv, path_id, target_id, lun_id); periph->immediate_priority = CAM_PRIORITY_NONE; periph->refcount = 0; + periph->sim = sim; SLIST_INIT(&periph->ccb_list); status = xpt_create_path(&path, periph, path_id, target_id, lun_id); if (status != CAM_REQ_CMP) @@ -186,7 +194,6 @@ cam_periph_alloc(periph_ctor_t *periph_ctor, if (status != CAM_REQ_CMP) goto failure; - crit_enter(); cur_periph = TAILQ_FIRST(&(*p_drv)->units); while (cur_periph != NULL && cur_periph->unit_number < periph->unit_number) @@ -199,8 +206,6 @@ cam_periph_alloc(periph_ctor_t *periph_ctor, (*p_drv)->generation++; } - crit_exit(); - init_level++; status = periph_ctor(periph, arg); @@ -214,14 +219,15 @@ failure: /* Initialized successfully */ break; case 3: - crit_enter(); TAILQ_REMOVE(&(*p_drv)->units, periph, unit_links); - crit_exit(); xpt_remove_periph(periph); + /* FALLTHROUGH */ case 2: xpt_free_path(periph->path); + /* FALLTHROUGH */ case 1: kfree(periph, M_CAMPERIPH); + /* FALLTHROUGH */ case 0: /* No cleanup to perform. */ break; @@ -242,21 +248,23 @@ cam_periph_find(struct cam_path *path, char *name) struct periph_driver **p_drv; struct cam_periph *periph; + xpt_lock_buses(); for (p_drv = periph_drivers; *p_drv != NULL; p_drv++) { if (name != NULL && (strcmp((*p_drv)->driver_name, name) != 0)) continue; - crit_enter(); TAILQ_FOREACH(periph, &(*p_drv)->units, unit_links) { if (xpt_path_comp(periph->path, path) == 0) { - crit_exit(); + xpt_unlock_buses(); return(periph); } } - crit_exit(); - if (name != NULL) + if (name != NULL) { + xpt_unlock_buses(); return(NULL); + } } + xpt_unlock_buses(); return(NULL); } @@ -266,9 +274,9 @@ cam_periph_acquire(struct cam_periph *periph) if (periph == NULL) return(CAM_REQ_CMP_ERR); - crit_enter(); + xpt_lock_buses(); periph->refcount++; - crit_exit(); + xpt_unlock_buses(); return(CAM_REQ_CMP); } @@ -276,15 +284,62 @@ cam_periph_acquire(struct cam_periph *periph) void cam_periph_release(struct cam_periph *periph) { + if (periph == NULL) return; - crit_enter(); + xpt_lock_buses(); if ((--periph->refcount == 0) && (periph->flags & CAM_PERIPH_INVALID)) { camperiphfree(periph); } - crit_exit(); + xpt_unlock_buses(); + +} + +int +cam_periph_hold(struct cam_periph *periph, int flags) +{ + int error; + + sim_lock_assert_owned(periph->sim->lock); + + /* + * Increment the reference count on the peripheral + * while we wait for our lock attempt to succeed + * to ensure the peripheral doesn't disappear out + * from user us while we sleep. + */ + + if (cam_periph_acquire(periph) != CAM_REQ_CMP) + return (ENXIO); + + while ((periph->flags & CAM_PERIPH_LOCKED) != 0) { + periph->flags |= CAM_PERIPH_LOCK_WANTED; + if ((error = sim_lock_sleep(periph, flags, "caplck", 0, + periph->sim->lock)) != 0) { + cam_periph_release(periph); + return (error); + } + } + + periph->flags |= CAM_PERIPH_LOCKED; + return (0); +} + +void +cam_periph_unhold(struct cam_periph *periph) +{ + + sim_lock_assert_owned(periph->sim->lock); + + periph->flags &= ~CAM_PERIPH_LOCKED; + if ((periph->flags & CAM_PERIPH_LOCK_WANTED) != 0) { + periph->flags &= ~CAM_PERIPH_LOCK_WANTED; + wakeup(periph); + } + + cam_periph_release(periph); } /* @@ -304,7 +359,6 @@ camperiphnextunit(struct periph_driver *p_drv, u_int newunit, int wired, int i, val, dunit; const char *dname; - crit_enter(); periph_name = p_drv->driver_name; for (;;newunit++) { @@ -315,12 +369,12 @@ camperiphnextunit(struct periph_driver *p_drv, u_int newunit, int wired, if (periph != NULL && periph->unit_number == newunit) { if (wired != 0) { - xpt_print_path(periph->path); - kprintf("Duplicate Wired Device entry!\n"); - xpt_print_path(periph->path); - kprintf("Second device (%s device at scbus%d " - "target %d lun %d) will not be wired\n", - periph_name, pathid, target, lun); + xpt_print(periph->path, "Duplicate Wired " + "Device entry!\n"); + xpt_print(periph->path, "Second device (%s " + "device at scbus%d target %d lun %d) will " + "not be wired\n", periph_name, pathid, + target, lun); wired = 0; } continue; @@ -348,7 +402,6 @@ camperiphnextunit(struct periph_driver *p_drv, u_int newunit, int wired, if (i == -1) break; } - crit_exit(); return (newunit); } @@ -407,10 +460,8 @@ cam_periph_invalidate(struct cam_periph *periph) { /* * We only call this routine the first time a peripheral is - * invalidated. The oninvalidate() routine is always called in - * a critical section. + * invalidated. */ - crit_enter(); if (((periph->flags & CAM_PERIPH_INVALID) == 0) && (periph->periph_oninval != NULL)) periph->periph_oninval(periph); @@ -418,11 +469,12 @@ cam_periph_invalidate(struct cam_periph *periph) periph->flags |= CAM_PERIPH_INVALID; periph->flags &= ~CAM_PERIPH_NEW_DEV_FOUND; + xpt_lock_buses(); if (periph->refcount == 0) camperiphfree(periph); else if (periph->refcount < 0) kprintf("cam_invalidate_periph: refcount < 0!!\n"); - crit_exit(); + xpt_unlock_buses(); } static void @@ -436,19 +488,16 @@ camperiphfree(struct cam_periph *periph) } if (*p_drv == NULL) { - kprintf("camperiphfree: attempt to free " - "non-existent periph: %s\n", periph->periph_name); + kprintf("camperiphfree: attempt to free non-existent periph\n"); return; } - - if (periph->periph_dtor != NULL) - periph->periph_dtor(periph); - - crit_enter(); + TAILQ_REMOVE(&(*p_drv)->units, periph, unit_links); (*p_drv)->generation++; - crit_exit(); + xpt_unlock_buses(); + if (periph->periph_dtor != NULL) + periph->periph_dtor(periph); xpt_remove_periph(periph); if (periph->flags & CAM_PERIPH_NEW_DEV_FOUND) { @@ -477,50 +526,7 @@ camperiphfree(struct cam_periph *periph) } xpt_free_path(periph->path); kfree(periph, M_CAMPERIPH); -} - -/* - * Wait interruptibly for an exclusive lock. - */ -int -cam_periph_lock(struct cam_periph *periph, int flags) -{ - int error; - - /* - * Increment the reference count on the peripheral - * while we wait for our lock attempt to succeed - * to ensure the peripheral doesn't disappear out - * from under us while we sleep. - */ - if (cam_periph_acquire(periph) != CAM_REQ_CMP) - return(ENXIO); - - while ((periph->flags & CAM_PERIPH_LOCKED) != 0) { - periph->flags |= CAM_PERIPH_LOCK_WANTED; - if ((error = tsleep(periph, flags, "caplck", 0)) != 0) { - cam_periph_release(periph); - return error; - } - } - - periph->flags |= CAM_PERIPH_LOCKED; - return 0; -} - -/* - * Unlock and wake up any waiters. - */ -void -cam_periph_unlock(struct cam_periph *periph) -{ - periph->flags &= ~CAM_PERIPH_LOCKED; - if ((periph->flags & CAM_PERIPH_LOCK_WANTED) != 0) { - periph->flags &= ~CAM_PERIPH_LOCK_WANTED; - wakeup(periph); - } - - cam_periph_release(periph); + xpt_lock_buses(); } /* @@ -727,10 +733,9 @@ cam_periph_getccb(struct cam_periph *periph, u_int32_t priority) { struct ccb_hdr *ccb_h; + sim_lock_assert_owned(periph->sim->lock); CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("entering cdgetccb\n")); - crit_enter(); - while (SLIST_FIRST(&periph->ccb_list) == NULL) { if (periph->immediate_priority > priority) periph->immediate_priority = priority; @@ -738,23 +743,24 @@ cam_periph_getccb(struct cam_periph *periph, u_int32_t priority) if ((SLIST_FIRST(&periph->ccb_list) != NULL) && (SLIST_FIRST(&periph->ccb_list)->pinfo.priority == priority)) break; - tsleep(&periph->ccb_list, 0, "cgticb", 0); + sim_lock_sleep(&periph->ccb_list, 0, "cgticb", 0, + periph->sim->lock); } ccb_h = SLIST_FIRST(&periph->ccb_list); SLIST_REMOVE_HEAD(&periph->ccb_list, periph_links.sle); - crit_exit(); return ((union ccb *)ccb_h); } void cam_periph_ccbwait(union ccb *ccb) { - crit_enter(); + struct cam_sim *sim; + + sim = xpt_path_sim(ccb->ccb_h.path); if ((ccb->ccb_h.pinfo.index != CAM_UNQUEUED_INDEX) || ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_INPROG)) - tsleep(&ccb->ccb_h.cbfcnp, 0, "cbwait", 0); - crit_exit(); + sim_lock_sleep(&ccb->ccb_h.cbfcnp, 0, "cbwait", 0, sim->lock); } int @@ -827,10 +833,13 @@ cam_periph_runccb(union ccb *ccb, cam_flags camflags, u_int32_t sense_flags, struct devstat *ds) { + struct cam_sim *sim; int error; error = 0; - + sim = xpt_path_sim(ccb->ccb_h.path); + sim_lock_assert_owned(sim->lock); + /* * If the user has supplied a stats structure, and if we understand * this particular type of ccb, record the transaction start. @@ -965,8 +974,8 @@ camperiphdone(struct cam_periph *periph, union ccb *done_ccb) saved_ccb->ccb_h.status |= CAM_AUTOSNS_VALID; #if 0 - xpt_print_path(saved_ccb->ccb_h.path); - kprintf("Recovered Sense\n"); + xpt_print(saved_ccb->ccb_h.path, + "Recovered Sense\n"); scsi_sense_print(&saved_ccb->csio); cam_error_print(saved_ccb, CAM_ESF_ALL, CAM_EPF_ALL); @@ -1254,8 +1263,7 @@ camperiphscsistatuserror(union ccb *ccb, cam_flags camflags, *timeout = 0; error = ERESTART; if (bootverbose) { - xpt_print_path(ccb->ccb_h.path); - kprintf("Queue Full\n"); + xpt_print(ccb->ccb_h.path, "Queue Full\n"); } break; } @@ -1267,8 +1275,7 @@ camperiphscsistatuserror(union ccb *ccb, cam_flags camflags, * command completes or a 1 second timeout. */ if (bootverbose) { - xpt_print_path(ccb->ccb_h.path); - kprintf("Device Busy\n"); + xpt_print(ccb->ccb_h.path, "Device Busy\n"); } if (ccb->ccb_h.retry_count > 0) { ccb->ccb_h.retry_count--; @@ -1281,13 +1288,12 @@ camperiphscsistatuserror(union ccb *ccb, cam_flags camflags, } break; case SCSI_STATUS_RESERV_CONFLICT: - xpt_print_path(ccb->ccb_h.path); - kprintf("Reservation Conflict\n"); + xpt_print(ccb->ccb_h.path, "Reservation Conflict\n"); error = EIO; break; default: - xpt_print_path(ccb->ccb_h.path); - kprintf("SCSI Status 0x%x\n", ccb->csio.scsi_status); + xpt_print(ccb->ccb_h.path, "SCSI Status 0x%x\n", + ccb->csio.scsi_status); error = EIO; break; } @@ -1541,38 +1547,38 @@ cam_periph_error(union ccb *ccb, cam_flags camflags, &timeout); break; case CAM_AUTOSENSE_FAIL: - xpt_print_path(ccb->ccb_h.path); - kprintf("AutoSense Failed\n"); + xpt_print(ccb->ccb_h.path, "AutoSense Failed\n"); error = EIO; /* we have to kill the command */ break; case CAM_REQ_CMP_ERR: if (bootverbose && printed == 0) { - xpt_print_path(ccb->ccb_h.path); - kprintf("Request completed with CAM_REQ_CMP_ERR\n"); + xpt_print(ccb->ccb_h.path, + "Request completed with CAM_REQ_CMP_ERR\n"); printed++; } + /* FALLTHROUGH */ case CAM_CMD_TIMEOUT: if (bootverbose && printed == 0) { - xpt_print_path(ccb->ccb_h.path); - kprintf("Command timed out\n"); + xpt_print(ccb->ccb_h.path, "Command timed out\n"); printed++; } + /* FALLTHROUGH */ case CAM_UNEXP_BUSFREE: if (bootverbose && printed == 0) { - xpt_print_path(ccb->ccb_h.path); - kprintf("Unexpected Bus Free\n"); + xpt_print(ccb->ccb_h.path, "Unexpected Bus Free\n"); printed++; } + /* FALLTHROUGH */ case CAM_UNCOR_PARITY: if (bootverbose && printed == 0) { - xpt_print_path(ccb->ccb_h.path); - kprintf("Uncorrected Parity Error\n"); + xpt_print(ccb->ccb_h.path, + "Uncorrected Parity Error\n"); printed++; } + /* FALLTHROUGH */ case CAM_DATA_RUN_ERR: if (bootverbose && printed == 0) { - xpt_print_path(ccb->ccb_h.path); - kprintf("Data Overrun\n"); + xpt_print(ccb->ccb_h.path, "Data Overrun\n"); printed++; } error = EIO; /* we have to kill the command */ @@ -1581,7 +1587,7 @@ cam_periph_error(union ccb *ccb, cam_flags camflags, ccb->ccb_h.retry_count--; error = ERESTART; } else { - action_string = "Retries Exausted"; + action_string = "Retries Exhausted"; error = EIO; } break; @@ -1601,8 +1607,8 @@ cam_periph_error(union ccb *ccb, cam_flags camflags, ccb->ccb_h.retry_count--; error = ERESTART; if (bootverbose && printed == 0) { - xpt_print_path(ccb->ccb_h.path); - kprintf("Selection Timeout\n"); + xpt_print(ccb->ccb_h.path, + "Selection Timeout\n"); printed++; } @@ -1664,8 +1670,7 @@ cam_periph_error(union ccb *ccb, cam_flags camflags, /* Unconditional requeue */ error = ERESTART; if (bootverbose && printed == 0) { - xpt_print_path(ccb->ccb_h.path); - kprintf("Request Requeued\n"); + xpt_print(ccb->ccb_h.path, "Request Requeued\n"); printed++; } break; @@ -1686,8 +1691,8 @@ cam_periph_error(union ccb *ccb, cam_flags camflags, ccb->ccb_h.retry_count--; error = ERESTART; if (bootverbose && printed == 0) { - xpt_print_path(ccb->ccb_h.path); - kprintf("CAM Status 0x%x\n", status); + xpt_print(ccb->ccb_h.path, "CAM Status 0x%x\n", + status); printed++; } } else { @@ -1726,11 +1731,9 @@ cam_periph_error(union ccb *ccb, cam_flags camflags, if (action_string == NULL) action_string = "Unretryable Error"; if (error != ERESTART) { - xpt_print_path(ccb->ccb_h.path); - kprintf("error %d\n", error); + xpt_print(ccb->ccb_h.path, "error %d\n", error); } - xpt_print_path(ccb->ccb_h.path); - kprintf("%s\n", action_string); + xpt_print(ccb->ccb_h.path, "%s\n", action_string); } return (error); diff --git a/sys/bus/cam/cam_periph.h b/sys/bus/cam/cam_periph.h index 88ba1b8..aa52a44 100644 --- a/sys/bus/cam/cam_periph.h +++ b/sys/bus/cam/cam_periph.h @@ -1,4 +1,4 @@ -/* +/*- * Data structures and definitions for CAM peripheral ("type") drivers. * * Copyright (c) 1997, 1998 Justin T. Gibbs. @@ -25,7 +25,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $FreeBSD: src/sys/cam/cam_periph.h,v 1.6.2.1 2000/05/07 18:16:49 n_hibma Exp $ + * $FreeBSD: src/sys/cam/cam_periph.h,v 1.18 2007/04/19 22:46:26 scottl Exp $ * $DragonFly: src/sys/bus/cam/cam_periph.h,v 1.9 2007/11/28 22:11:02 pavalos Exp $ */ @@ -33,6 +33,7 @@ #define _CAM_CAM_PERIPH_H 1 #include +#include "cam_sim.h" #ifdef _KERNEL @@ -103,6 +104,7 @@ struct cam_periph { char *periph_name; struct cam_path *path; /* Compiled path to device */ void *softc; + struct cam_sim *sim; u_int32_t unit_number; cam_periph_type type; u_int32_t flags; @@ -112,6 +114,7 @@ struct cam_periph { #define CAM_PERIPH_INVALID 0x08 #define CAM_PERIPH_NEW_DEV_FOUND 0x10 #define CAM_PERIPH_RECOVERY_INPROG 0x20 +#define CAM_PERIPH_POLLED 0x40 u_int32_t immediate_priority; u_int32_t refcount; SLIST_HEAD(, ccb_hdr) ccb_list; /* For "immediate" requests */ @@ -138,10 +141,10 @@ cam_status cam_periph_alloc(periph_ctor_t *periph_ctor, char *name, cam_periph_type type, struct cam_path *, ac_callback_t *, ac_code, void *arg); struct cam_periph *cam_periph_find(struct cam_path *path, char *name); -int cam_periph_lock(struct cam_periph *periph, int flags); -void cam_periph_unlock(struct cam_periph *periph); cam_status cam_periph_acquire(struct cam_periph *periph); void cam_periph_release(struct cam_periph *periph); +int cam_periph_hold(struct cam_periph *periph, int flags); +void cam_periph_unhold(struct cam_periph *periph); void cam_periph_invalidate(struct cam_periph *periph); int cam_periph_mapmem(union ccb *ccb, struct cam_periph_map_info *mapinfo); @@ -175,5 +178,17 @@ void cam_periph_freeze_after_event(struct cam_periph *periph, int cam_periph_error(union ccb *ccb, cam_flags camflags, u_int32_t sense_flags, union ccb *save_ccb); +static __inline void +cam_periph_lock(struct cam_periph *periph) +{ + CAM_SIM_LOCK(periph->sim); +} + +static __inline void +cam_periph_unlock(struct cam_periph *periph) +{ + CAM_SIM_UNLOCK(periph->sim); +} + #endif /* _KERNEL */ #endif /* _CAM_CAM_PERIPH_H */ diff --git a/sys/bus/cam/cam_queue.c b/sys/bus/cam/cam_queue.c index 03e57ae..67edc41 100644 --- a/sys/bus/cam/cam_queue.c +++ b/sys/bus/cam/cam_queue.c @@ -1,4 +1,4 @@ -/* +/*- * CAM request queue management functions. * * Copyright (c) 1997 Justin T. Gibbs. @@ -25,7 +25,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $FreeBSD: src/sys/cam/cam_queue.c,v 1.5 1999/08/28 00:40:41 peter Exp $ + * $FreeBSD: src/sys/cam/cam_queue.c,v 1.9 2005/07/01 15:21:29 avatar Exp $ * $DragonFly: src/sys/bus/cam/cam_queue.c,v 1.11 2007/12/01 22:21:17 pavalos Exp $ */ #include diff --git a/sys/bus/cam/cam_sim.c b/sys/bus/cam/cam_sim.c index febc7f4..eca0cc5 100644 --- a/sys/bus/cam/cam_sim.c +++ b/sys/bus/cam/cam_sim.c @@ -33,6 +33,8 @@ #include #include #include +#include +#include #include "cam.h" #include "cam_ccb.h" @@ -44,6 +46,58 @@ MALLOC_DEFINE(M_CAMSIM, "CAM SIM", "CAM SIM buffers"); +/* Drivers will use sim_mplock if they need the BGL */ +sim_lock sim_mplock; + +void +cam_sim_lock(sim_lock *lock) +{ + if (lock == &sim_mplock) + get_mplock(); + else + lockmgr(lock, LK_EXCLUSIVE); +} + +void +cam_sim_unlock(sim_lock *lock) +{ + if (lock == &sim_mplock) + rel_mplock(); + else + lockmgr(lock, LK_RELEASE); +} + +void +sim_lock_assert_owned(sim_lock *lock) +{ + if (lock == &sim_mplock) + ASSERT_MP_LOCK_HELD(curthread); + else + KKASSERT(lockstatus(lock, curthread) != 0); +} + +int +sim_lock_sleep(void *ident, int flags, const char *wmesg, int timo, + sim_lock *lock) +{ + int retval; + + if (lock != &sim_mplock) { + crit_enter(); + tsleep_interlock(ident); + lockmgr(lock, LK_RELEASE); + } + + retval = tsleep(ident, flags, wmesg, timo); + + if (lock != &sim_mplock) { + lockmgr(lock, LK_EXCLUSIVE); + crit_exit(); + } + + return (retval); +} + struct cam_devq * cam_simq_alloc(u_int32_t max_sim_transactions) { @@ -64,7 +118,7 @@ cam_simq_release(struct cam_devq *devq) struct cam_sim * cam_sim_alloc(sim_action_func sim_action, sim_poll_func sim_poll, const char *sim_name, void *softc, u_int32_t unit, - int max_dev_transactions, + sim_lock *lock, int max_dev_transactions, int max_tagged_dev_transactions, struct cam_devq *queue) { struct cam_sim *sim; @@ -87,6 +141,9 @@ cam_sim_alloc(sim_action_func sim_action, sim_poll_func sim_poll, else cam_devq_reference(queue); + if (lock == NULL) + return (NULL); + sim = kmalloc(sizeof(struct cam_sim), M_CAMSIM, M_INTWAIT | M_ZERO); sim->sim_action = sim_action; sim->sim_poll = sim_poll; @@ -99,8 +156,18 @@ cam_sim_alloc(sim_action_func sim_action, sim_poll_func sim_poll, sim->max_dev_openings = max_dev_transactions; sim->flags = 0; sim->refcount = 1; - callout_init(&sim->c_handle); sim->devq = queue; + sim->lock = lock; + if (lock == &sim_mplock) { + sim->flags |= 0; + callout_init(&sim->callout); + } else { + sim->flags |= CAM_SIM_MPSAFE; + callout_init_mp(&sim->callout); + } + + SLIST_INIT(&sim->ccb_freeq); + TAILQ_INIT(&sim->sim_doneq); return (sim); } diff --git a/sys/bus/cam/cam_sim.h b/sys/bus/cam/cam_sim.h index 63dbd8c..4a69ac0 100644 --- a/sys/bus/cam/cam_sim.h +++ b/sys/bus/cam/cam_sim.h @@ -49,6 +49,14 @@ struct cam_devq; typedef void (*sim_action_func)(struct cam_sim *sim, union ccb *ccb); typedef void (*sim_poll_func)(struct cam_sim *sim); +typedef struct lock sim_lock; +extern sim_lock sim_mplock; + +void cam_sim_lock(sim_lock *lock); +void cam_sim_unlock(sim_lock *lock); +void sim_lock_assert_owned(sim_lock *lock); +int sim_lock_sleep(void *ident, int flags, const char *wmesg, + int timo, sim_lock *lock); struct cam_devq * cam_simq_alloc(u_int32_t max_sim_transactions); void cam_simq_release(struct cam_devq *devq); @@ -57,6 +65,7 @@ struct cam_sim * cam_sim_alloc(sim_action_func sim_action, const char *sim_name, void *softc, u_int32_t unit, + sim_lock *lock, int max_dev_transactions, int max_tagged_dev_transactions, struct cam_devq *queue); @@ -94,18 +103,37 @@ struct cam_sim { sim_poll_func sim_poll; const char *sim_name; void *softc; /* might be NULL */ + sim_lock *lock; + TAILQ_HEAD(, ccb_hdr) sim_doneq; + TAILQ_ENTRY(cam_sim) links; u_int32_t path_id; /* bootdev may set this to 0? */ u_int32_t unit_number; u_int32_t bus_id; int max_tagged_dev_openings; int max_dev_openings; u_int32_t flags; -#define CAM_SIM_REL_TIMEOUT_PENDING 0x01 - struct callout c_handle; +#define CAM_SIM_REL_TIMEOUT_PENDING 0x01 +#define CAM_SIM_MPSAFE 0x02 +#define CAM_SIM_ON_DONEQ 0x04 + struct callout callout; struct cam_devq *devq; /* Device Queue to use for this SIM */ int refcount; /* References to the sim */ + + /* "Pool" of inactive ccbs managed by xpt_alloc_ccb and xpt_free_ccb */ + SLIST_HEAD(,ccb_hdr) ccb_freeq; + /* + * Maximum size of ccb pool. Modified as devices are added/removed + * or have their * opening counts changed. + */ + u_int max_ccbs; + /* Current count of allocated ccbs */ + u_int ccb_count; + }; +#define CAM_SIM_LOCK(sim) cam_sim_lock((sim)->lock); +#define CAM_SIM_UNLOCK(sim) cam_sim_unlock((sim)->lock); + static __inline u_int32_t cam_sim_path(struct cam_sim *sim) { diff --git a/sys/bus/cam/cam_xpt.c b/sys/bus/cam/cam_xpt.c index 8a8e1b2..746027d 100644 --- a/sys/bus/cam/cam_xpt.c +++ b/sys/bus/cam/cam_xpt.c @@ -42,11 +42,14 @@ #include #include #include +#include #include #include #include +#include #include +#include #include "cam.h" #include "cam_ccb.h" @@ -60,11 +63,19 @@ #include "scsi/scsi_all.h" #include "scsi/scsi_message.h" #include "scsi/scsi_pass.h" +#include #include "opt_cam.h" /* Datastructures internal to the xpt layer */ MALLOC_DEFINE(M_CAMXPT, "CAM XPT", "CAM XPT buffers"); +/* Object for defering XPT actions to a taskqueue */ +struct xpt_task { + struct task task; + void *data1; + uintptr_t data2; +}; + /* * Definition of an async handler callback block. These are used to add * SIMs and peripherals to the async callback lists. @@ -79,7 +90,6 @@ struct async_node { SLIST_HEAD(async_list, async_node); SLIST_HEAD(periph_list, cam_periph); -static STAILQ_HEAD(highpowerlist, ccb_hdr) highpowerq; /* * This is the maximum number of high powered commands (e.g. start unit) @@ -89,9 +99,6 @@ static STAILQ_HEAD(highpowerlist, ccb_hdr) highpowerq; #define CAM_MAX_HIGHPOWER 4 #endif -/* number of high powered commands that can go through right now */ -static int num_highpower = CAM_MAX_HIGHPOWER; - /* * Structure for queueing a device in a run queue. * There is one run queue for allocating new ccbs, @@ -112,6 +119,7 @@ struct cam_ed { struct cam_ed_qinfo alloc_ccb_entry; struct cam_ed_qinfo send_ccb_entry; struct cam_et *target; + struct cam_sim *sim; lun_id_t lun_id; struct camq drvq; /* * Queue of type drivers wanting to do @@ -147,11 +155,13 @@ struct cam_ed { #define CAM_DEV_RESIZE_QUEUE_NEEDED 0x10 #define CAM_DEV_TAG_AFTER_COUNT 0x20 #define CAM_DEV_INQUIRY_DATA_VALID 0x40 +#define CAM_DEV_IN_DV 0x80 +#define CAM_DEV_DV_HIT_BOTTOM 0x100 u_int32_t tag_delay_count; #define CAM_TAG_DELAY_COUNT 5 u_int32_t tag_saved_openings; u_int32_t refcount; - struct callout c_handle; + struct callout callout; }; /* @@ -160,12 +170,12 @@ struct cam_ed { * identify, and removed when a device fails to respond after a number * of retries, or a bus rescan finds the device missing. */ -struct cam_et { +struct cam_et { TAILQ_HEAD(, cam_ed) ed_entries; TAILQ_ENTRY(cam_et) links; - struct cam_eb *bus; + struct cam_eb *bus; target_id_t target_id; - u_int32_t refcount; + u_int32_t refcount; u_int generation; struct timeval last_reset; /* uptime of last reset */ }; @@ -175,7 +185,7 @@ struct cam_et { * are created by calls to xpt_bus_register and deleted by calls to * xpt_bus_deregister. */ -struct cam_eb { +struct cam_eb { TAILQ_HEAD(, cam_et) et_entries; TAILQ_ENTRY(cam_eb) links; path_id_t path_id; @@ -235,8 +245,24 @@ typedef enum { } xpt_flags; struct xpt_softc { - xpt_flags flags; - u_int32_t generation; + xpt_flags flags; + u_int32_t xpt_generation; + + /* number of high powered commands that can go through right now */ + STAILQ_HEAD(highpowerlist, ccb_hdr) highpowerq; + int num_highpower; + + /* queue for handling async rescan requests. */ + TAILQ_HEAD(, ccb_hdr) ccb_scanq; + + /* Registered busses */ + TAILQ_HEAD(,cam_eb) xpt_busses; + u_int bus_generation; + + struct intr_config_hook *xpt_config_hook; + + struct lock xpt_topo_lock; + struct lock xpt_lock; }; static const char quantum[] = "QUANTUM"; @@ -246,7 +272,7 @@ static const char samsung[] = "SAMSUNG"; static const char seagate[] = "SEAGATE"; static const char microp[] = "MICROP"; -static struct xpt_quirk_entry xpt_quirk_table[] = +static struct xpt_quirk_entry xpt_quirk_table[] = { { /* Reports QUEUE FULL for temporary resource shortages */ @@ -286,12 +312,12 @@ static struct xpt_quirk_entry xpt_quirk_table[] = * * For future reference, the drive with the problem was: * QUANTUM QM39100TD-SW N1B0 - * + * * It's possible that Quantum will fix the problem in later * firmware revisions. If that happens, the quirk entry * will need to be made specific to the firmware revisions * with the problem. - * + * */ /* Reports QUEUE FULL for temporary resource shortages */ { T_DIRECT, SIP_MEDIA_FIXED, quantum, "QM39100*", "*" }, @@ -322,7 +348,7 @@ static struct xpt_quirk_entry xpt_quirk_table[] = /* * The Seagate Medalist Pro drives have very poor write * performance with anything more than 2 tags. - * + * * Reported by: Paul van der Zwan * Drive: * @@ -377,7 +403,7 @@ static struct xpt_quirk_entry xpt_quirk_table[] = /*quirks*/0, /*mintags*/0, /*maxtags*/0 }, { - /* Broken tagged queuing drive */ + /* Broken tagged queuing drive */ { T_DIRECT, SIP_MEDIA_FIXED, "CONNER", "CFP2107*", "*" }, /*quirks*/0, /*mintags*/0, /*maxtags*/0 }, @@ -435,7 +461,7 @@ static struct xpt_quirk_entry xpt_quirk_table[] = { /* I can't believe we need a quirk for DPT volumes. */ { T_ANY, SIP_MEDIA_FIXED|SIP_MEDIA_REMOVABLE, "DPT", "*", "*" }, - CAM_QUIRK_NOSERIAL|CAM_QUIRK_NOLUNS, + CAM_QUIRK_NOLUNS, /*mintags*/0, /*maxtags*/255 }, { @@ -466,7 +492,7 @@ static struct xpt_quirk_entry xpt_quirk_table[] = T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "EXABYTE", "EXB-8200*", "*" }, - CAM_QUIRK_NOSERIAL|CAM_QUIRK_NOLUNS, /*mintags*/0, /*maxtags*/0 + CAM_QUIRK_NOLUNS, /*mintags*/0, /*maxtags*/0 }, { /* @@ -477,7 +503,7 @@ static struct xpt_quirk_entry xpt_quirk_table[] = T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "EXABYTE", "IPL-6860*", "*" }, - CAM_QUIRK_NOSERIAL|CAM_QUIRK_NOLUNS, /*mintags*/0, /*maxtags*/0 + CAM_QUIRK_NOLUNS, /*mintags*/0, /*maxtags*/0 }, { /* @@ -522,17 +548,6 @@ static struct xpt_quirk_entry xpt_quirk_table[] = }, { /* - * Maxtor Personal Storage 3000XT (Firewire) - * hangs upon serial number probing. - */ - { - T_DIRECT, SIP_MEDIA_FIXED, "Maxtor", - "1394 storage", "*" - }, - CAM_QUIRK_NOSERIAL, /*mintags*/0, /*maxtags*/0 - }, - { - /* * Would repond to all LUNs if asked for. */ { @@ -591,18 +606,6 @@ static struct xpt_quirk_entry xpt_quirk_table[] = CAM_QUIRK_NOLUNS, /*mintags*/0, /*maxtags*/0 }, { - /* - * Western Digital My Book 250GB (USB) - * hangs upon serial number probing. - * PR: 107495 - */ - { - T_DIRECT, SIP_MEDIA_FIXED, "WD", - "2500JB External", "*" - }, - CAM_QUIRK_NOSERIAL, /*mintags*/0, /*maxtags*/0 - }, - { /* Default tagged queuing parameters for all devices */ { T_ANY, SIP_MEDIA_REMOVABLE|SIP_MEDIA_FIXED, @@ -649,16 +652,9 @@ static struct xpt_softc xsoftc; /* Queues for our software interrupt handler */ typedef TAILQ_HEAD(cam_isrq, ccb_hdr) cam_isrq_t; -static cam_isrq_t cam_bioq; - -/* "Pool" of inactive ccbs managed by xpt_alloc_ccb and xpt_free_ccb */ -static SLIST_HEAD(,ccb_hdr) ccb_freeq; -static u_int xpt_max_ccbs; /* - * Maximum size of ccb pool. Modified as - * devices are added/removed or have their - * opening counts changed. - */ -static u_int xpt_ccb_count; /* Current count of allocated ccbs */ +typedef TAILQ_HEAD(cam_simq, cam_sim) cam_simq_t; +static cam_simq_t cam_simq; +static struct lock cam_simq_lock; struct cam_periph *xpt_periph; @@ -694,8 +690,6 @@ static struct dev_ops xpt_ops = { .d_ioctl = xptioctl }; -static struct intr_config_hook *xpt_config_hook; - static void dead_sim_action(struct cam_sim *sim, union ccb *ccb); static void dead_sim_poll(struct cam_sim *sim); @@ -708,10 +702,6 @@ static struct cam_sim cam_dead_sim = { #define SIM_DEAD(sim) ((sim) == &cam_dead_sim) -/* Registered busses */ -static TAILQ_HEAD(,cam_eb) xpt_busses; -static u_int bus_generation; - /* Storage for debugging datastructures */ #ifdef CAMDEBUG struct cam_path *cam_dpath; @@ -750,7 +740,7 @@ static moduledata_t cam_moduledata = { NULL }; -static void xpt_init(void *); +static int xpt_init(void *); DECLARE_MODULE(cam, cam_moduledata, SI_SUB_CONFIGURE, SI_ORDER_SECOND); MODULE_VERSION(cam, 1); @@ -812,12 +802,8 @@ static void xpt_finishconfig(struct cam_periph *periph, union ccb *ccb); static void xptaction(struct cam_sim *sim, union ccb *work_ccb); static void xptpoll(struct cam_sim *sim); static inthand2_t swi_cambio; -static void camisr(cam_isrq_t *queue); -#if 0 -static void xptstart(struct cam_periph *periph, union ccb *work_ccb); -static void xptasync(struct cam_periph *periph, - u_int32_t code, cam_path *path); -#endif +static void camisr(void *); +static void camisr_runqueue(void *); static dev_match_ret xptbusmatch(struct dev_match_pattern *patterns, u_int num_patterns, struct cam_eb *bus); static dev_match_ret xptdevicematch(struct dev_match_pattern *patterns, @@ -856,16 +842,8 @@ static xpt_targetfunc_t xptdeftargetfunc; static xpt_devicefunc_t xptdefdevicefunc; static xpt_periphfunc_t xptdefperiphfunc; static int xpt_for_all_busses(xpt_busfunc_t *tr_func, void *arg); -#ifdef notusedyet -static int xpt_for_all_targets(xpt_targetfunc_t *tr_func, - void *arg); -#endif static int xpt_for_all_devices(xpt_devicefunc_t *tr_func, void *arg); -#ifdef notusedyet -static int xpt_for_all_periphs(xpt_periphfunc_t *tr_func, - void *arg); -#endif static xpt_devicefunc_t xptsetasyncfunc; static xpt_busfunc_t xptsetasyncbusfunc; static cam_status xptregister(struct cam_periph *periph, @@ -875,6 +853,8 @@ static cam_status proberegister(struct cam_periph *periph, static void probeschedule(struct cam_periph *probe_periph); static void probestart(struct cam_periph *periph, union ccb *start_ccb); static void proberequestdefaultnegotiation(struct cam_periph *periph); +static int proberequestbackoff(struct cam_periph *periph, + struct cam_ed *device); static void probedone(struct cam_periph *periph, union ccb *done_ccb); static void probecleanup(struct cam_periph *periph); static void xpt_find_quirk(struct cam_ed *device); @@ -912,7 +892,7 @@ xpt_schedule_dev_allocq(struct cam_eb *bus, struct cam_ed *dev) */ retval = xpt_schedule_dev(&bus->sim->devq->alloc_queue, &dev->alloc_ccb_entry.pinfo, - CAMQ_GET_HEAD(&dev->drvq)->priority); + CAMQ_GET_HEAD(&dev->drvq)->priority); } else { retval = 0; } @@ -996,9 +976,6 @@ static int xptopen(struct dev_open_args *ap) { cdev_t dev = ap->a_head.a_dev; - int unit; - - unit = minor(dev) & 0xff; /* * Only allow read-write access. @@ -1010,68 +987,42 @@ xptopen(struct dev_open_args *ap) * We don't allow nonblocking access. */ if ((ap->a_oflags & O_NONBLOCK) != 0) { - kprintf("xpt%d: can't do nonblocking access\n", unit); + kprintf("%s: can't do nonblocking access\n", devtoname(dev)); return(ENODEV); } - /* - * We only have one transport layer right now. If someone accesses - * us via something other than minor number 1, point out their - * mistake. - */ - if (unit != 0) { - kprintf("xptopen: got invalid xpt unit %d\n", unit); - return(ENXIO); - } - /* Mark ourselves open */ + lockmgr(&xsoftc.xpt_lock, LK_EXCLUSIVE); xsoftc.flags |= XPT_FLAG_OPEN; - + lockmgr(&xsoftc.xpt_lock, LK_RELEASE); + return(0); } static int xptclose(struct dev_close_args *ap) { - cdev_t dev = ap->a_head.a_dev; - int unit; - - unit = minor(dev) & 0xff; - - /* - * We only have one transport layer right now. If someone accesses - * us via something other than minor number 1, point out their - * mistake. - */ - if (unit != 0) { - kprintf("xptclose: got invalid xpt unit %d\n", unit); - return(ENXIO); - } /* Mark ourselves closed */ + lockmgr(&xsoftc.xpt_lock, LK_EXCLUSIVE); xsoftc.flags &= ~XPT_FLAG_OPEN; + lockmgr(&xsoftc.xpt_lock, LK_RELEASE); return(0); } +/* + * Don't automatically grab the xpt softc lock here even though this is going + * through the xpt device. The xpt device is really just a back door for + * accessing other devices and SIMs, so the right thing to do is to grab + * the appropriate SIM lock once the bus/SIM is located. + */ static int xptioctl(struct dev_ioctl_args *ap) { - cdev_t dev = ap->a_head.a_dev; - int unit, error; + int error; error = 0; - unit = minor(dev) & 0xff; - - /* - * We only have one transport layer right now. If someone accesses - * us via something other than minor number 1, point out their - * mistake. - */ - if (unit != 0) { - kprintf("xptioctl: got invalid xpt unit %d\n", unit); - return(ENXIO); - } switch(ap->a_cmd) { /* @@ -1082,9 +1033,16 @@ xptioctl(struct dev_ioctl_args *ap) case CAMIOCOMMAND: { union ccb *ccb; union ccb *inccb; + struct cam_eb *bus; inccb = (union ccb *)ap->a_data; + bus = xpt_find_bus(inccb->ccb_h.path_id); + if (bus == NULL) { + error = EINVAL; + break; + } + switch(inccb->ccb_h.func_code) { case XPT_SCAN_BUS: case XPT_RESET_BUS: @@ -1100,6 +1058,8 @@ xptioctl(struct dev_ioctl_args *ap) ccb = xpt_alloc_ccb(); + CAM_SIM_LOCK(bus->sim); + /* * Create a path using the bus, target, and lun the * user passed in. @@ -1110,6 +1070,7 @@ xptioctl(struct dev_ioctl_args *ap) inccb->ccb_h.target_lun) != CAM_REQ_CMP){ error = EINVAL; + CAM_SIM_UNLOCK(bus->sim); xpt_free_ccb(ccb); break; } @@ -1122,6 +1083,7 @@ xptioctl(struct dev_ioctl_args *ap) bcopy(ccb, inccb, sizeof(union ccb)); xpt_free_path(ccb->ccb_h.path); xpt_free_ccb(ccb); + CAM_SIM_UNLOCK(bus->sim); break; case XPT_DEBUG: { @@ -1132,6 +1094,8 @@ xptioctl(struct dev_ioctl_args *ap) * allocate it on the stack. */ + CAM_SIM_LOCK(bus->sim); + /* * Create a path using the bus, target, and lun the * user passed in. @@ -1142,6 +1106,7 @@ xptioctl(struct dev_ioctl_args *ap) inccb->ccb_h.target_lun) != CAM_REQ_CMP){ error = EINVAL; + CAM_SIM_UNLOCK(bus->sim); break; } /* Ensure all of our fields are correct */ @@ -1150,6 +1115,7 @@ xptioctl(struct dev_ioctl_args *ap) xpt_merge_ccb(&ccb, inccb); ccb.ccb_h.cbfcnp = xptdone; xpt_action(&ccb); + CAM_SIM_UNLOCK(bus->sim); bcopy(&ccb, inccb, sizeof(union ccb)); xpt_free_path(ccb.ccb_h.path); break; @@ -1214,6 +1180,7 @@ xptioctl(struct dev_ioctl_args *ap) error = ENOTSUP; break; } + xpt_release_bus(bus); break; } /* @@ -1227,8 +1194,8 @@ xptioctl(struct dev_ioctl_args *ap) * we never return a status of CAM_GDEVLIST_LIST_CHANGED. It is * (or rather should be) impossible for the device peripheral driver * list to change since we look at the whole thing in one pass, and - * we do it within a critical section. - * + * we do it with lock protection. + * */ case CAMGETPASSTHRU: { union ccb *ccb; @@ -1244,9 +1211,8 @@ xptioctl(struct dev_ioctl_args *ap) unit = ccb->cgdl.unit_number; name = ccb->cgdl.periph_name; /* - * Every 100 devices, we want to call splz() to check for - * and allow the software interrupt handler a chance to run. - * + * Every 100 devices, we want to drop our lock protection to + * give the software interrupt handler a chance to run. * Most systems won't run into this check, but this should * avoid starvation in the software interrupt handler in * large systems. @@ -1267,9 +1233,9 @@ xptioctl(struct dev_ioctl_args *ap) } /* Keep the list from changing while we traverse it */ - crit_enter(); + lockmgr(&xsoftc.xpt_topo_lock, LK_EXCLUSIVE); ptstartover: - cur_generation = xsoftc.generation; + cur_generation = xsoftc.xpt_generation; /* first find our driver in the list of drivers */ for (p_drv = periph_drivers; *p_drv != NULL; p_drv++) { @@ -1278,14 +1244,14 @@ ptstartover: } if (*p_drv == NULL) { - crit_exit(); + lockmgr(&xsoftc.xpt_topo_lock, LK_RELEASE); ccb->ccb_h.status = CAM_REQ_CMP_ERR; ccb->cgdl.status = CAM_GDEVLIST_ERROR; *ccb->cgdl.periph_name = '\0'; ccb->cgdl.unit_number = 0; error = ENOENT; break; - } + } /* * Run through every peripheral instance of this driver @@ -1299,9 +1265,10 @@ ptstartover: if (periph->unit_number == unit) { break; } else if (--splbreaknum == 0) { - splz(); + lockmgr(&xsoftc.xpt_topo_lock, LK_RELEASE); + lockmgr(&xsoftc.xpt_topo_lock, LK_EXCLUSIVE); splbreaknum = 100; - if (cur_generation != xsoftc.generation) + if (cur_generation != xsoftc.xpt_generation) goto ptstartover; } } @@ -1321,7 +1288,7 @@ ptstartover: periph = SLIST_NEXT(periph, periph_links), i++) { /* * Check to see whether we have a - * passthrough device or not. + * passthrough device or not. */ if (strcmp(periph->periph_name, "pass") == 0) { /* @@ -1384,11 +1351,11 @@ ptstartover: if (base_periph_found == 1) { kprintf("xptioctl: pass driver is not in the " "kernel\n"); - kprintf("xptioctl: put \"device pass0\" in " + kprintf("xptioctl: put \"device pass\" in " "your kernel config file\n"); } } - crit_exit(); + lockmgr(&xsoftc.xpt_topo_lock, LK_RELEASE); break; } default: @@ -1402,19 +1369,90 @@ ptstartover: static int cam_module_event_handler(module_t mod, int what, void *arg) { - if (what == MOD_LOAD) { - xpt_init(NULL); - } else if (what == MOD_UNLOAD) { + int error; + + switch (what) { + case MOD_LOAD: + if ((error = xpt_init(NULL)) != 0) + return (error); + break; + case MOD_UNLOAD: return EBUSY; - } else { + default: return EOPNOTSUPP; } return 0; } -/* Functions accessed by the peripheral drivers */ +/* thread to handle bus rescans */ static void +xpt_scanner_thread(void *dummy) +{ + cam_isrq_t queue; + union ccb *ccb; + struct cam_sim *sim; + + for (;;) { + /* + * Wait for a rescan request to come in. When it does, splice + * it onto a queue from local storage so that the xpt lock + * doesn't need to be held while the requests are being + * processed. + */ + crit_enter(); + tsleep_interlock(&xsoftc.ccb_scanq); + xpt_unlock_buses(); + tsleep(&xsoftc.ccb_scanq, 0, "ccb_scanq", 0); + xpt_lock_buses(); + crit_exit(); + TAILQ_INIT(&queue); + TAILQ_CONCAT(&queue, &xsoftc.ccb_scanq, sim_links.tqe); + xpt_unlock_buses(); + + while ((ccb = (union ccb *)TAILQ_FIRST(&queue)) != NULL) { + TAILQ_REMOVE(&queue, &ccb->ccb_h, sim_links.tqe); + + sim = ccb->ccb_h.path->bus->sim; + CAM_SIM_LOCK(sim); + + ccb->ccb_h.func_code = XPT_SCAN_BUS; + ccb->ccb_h.cbfcnp = xptdone; + xpt_setup_ccb(&ccb->ccb_h, ccb->ccb_h.path, 5); + cam_periph_runccb(ccb, NULL, 0, 0, NULL); + xpt_free_path(ccb->ccb_h.path); + xpt_free_ccb(ccb); + CAM_SIM_UNLOCK(sim); + } + } +} + +void +xpt_rescan(union ccb *ccb) +{ + struct ccb_hdr *hdr; + + /* + * Don't make duplicate entries for the same paths. + */ + xpt_lock_buses(); + TAILQ_FOREACH(hdr, &xsoftc.ccb_scanq, sim_links.tqe) { + if (xpt_path_comp(hdr->path, ccb->ccb_h.path) == 0) { + xpt_unlock_buses(); + xpt_print(ccb->ccb_h.path, "rescan already queued\n"); + xpt_free_path(ccb->ccb_h.path); + xpt_free_ccb(ccb); + return; + } + } + TAILQ_INSERT_TAIL(&xsoftc.ccb_scanq, &ccb->ccb_h, sim_links.tqe); + wakeup(&xsoftc.ccb_scanq); + xpt_unlock_buses(); +} + + +/* Functions accessed by the peripheral drivers */ +static int xpt_init(void *dummy) { struct cam_sim *xpt_sim; @@ -1422,10 +1460,15 @@ xpt_init(void *dummy) struct cam_devq *devq; cam_status status; - TAILQ_INIT(&xpt_busses); - TAILQ_INIT(&cam_bioq); - SLIST_INIT(&ccb_freeq); - STAILQ_INIT(&highpowerq); + TAILQ_INIT(&xsoftc.xpt_busses); + TAILQ_INIT(&cam_simq); + TAILQ_INIT(&xsoftc.ccb_scanq); + STAILQ_INIT(&xsoftc.highpowerq); + xsoftc.num_highpower = CAM_MAX_HIGHPOWER; + + lockinit(&cam_simq_lock, "CAM SIMQ lock", 0, LK_CANRECURSE); + lockinit(&xsoftc.xpt_lock, "XPT lock", 0, LK_CANRECURSE); + lockinit(&xsoftc.xpt_topo_lock, "XPT topology lock", 0, LK_CANRECURSE); /* * The xpt layer is, itself, the equivelent of a SIM. @@ -1439,13 +1482,22 @@ xpt_init(void *dummy) "xpt", /*softc*/NULL, /*unit*/0, + /*lock*/&xsoftc.xpt_lock, /*max_dev_transactions*/0, /*max_tagged_dev_transactions*/0, devq); cam_simq_release(devq); - xpt_max_ccbs = 16; - - xpt_bus_register(xpt_sim, /*bus #*/0); + if (xpt_sim == NULL) + return (ENOMEM); + + xpt_sim->max_ccbs = 16; + + lockmgr(&xsoftc.xpt_lock, LK_EXCLUSIVE); + if ((status = xpt_bus_register(xpt_sim, /*bus #*/0)) != CAM_SUCCESS) { + kprintf("xpt_init: xpt_bus_register failed with status %#x," + " failing attach\n", status); + return (EINVAL); + } /* * Looking at the XPT from the SIM layer, the XPT is @@ -1457,44 +1509,53 @@ xpt_init(void *dummy) CAM_LUN_WILDCARD)) != CAM_REQ_CMP) { kprintf("xpt_init: xpt_create_path failed with status %#x," " failing attach\n", status); - return; + return (EINVAL); } cam_periph_alloc(xptregister, NULL, NULL, NULL, "xpt", CAM_PERIPH_BIO, - path, NULL, 0, NULL); + path, NULL, 0, xpt_sim); xpt_free_path(path); - xpt_sim->softc = xpt_periph; + lockmgr(&xsoftc.xpt_lock, LK_RELEASE); /* * Register a callback for when interrupts are enabled. */ - xpt_config_hook = kmalloc(sizeof(struct intr_config_hook), - M_TEMP, M_INTWAIT | M_ZERO); - xpt_config_hook->ich_func = xpt_config; - xpt_config_hook->ich_desc = "xpt"; - xpt_config_hook->ich_order = 1000; - if (config_intrhook_establish(xpt_config_hook) != 0) { - kfree (xpt_config_hook, M_TEMP); + xsoftc.xpt_config_hook = kmalloc(sizeof(struct intr_config_hook), + M_CAMXPT, M_INTWAIT | M_ZERO); + xsoftc.xpt_config_hook->ich_func = xpt_config; + xsoftc.xpt_config_hook->ich_desc = "xpt"; + xsoftc.xpt_config_hook->ich_order = 1000; + if (config_intrhook_establish(xsoftc.xpt_config_hook) != 0) { + kfree (xsoftc.xpt_config_hook, M_CAMXPT); kprintf("xpt_init: config_intrhook_establish failed " "- failing attach\n"); } + /* fire up rescan thread */ + if (kthread_create(xpt_scanner_thread, NULL, NULL, "xpt_thrd")) { + kprintf("xpt_init: failed to create rescan thread\n"); + } /* Install our software interrupt handlers */ register_swi(SWI_CAMBIO, swi_cambio, NULL, "swi_cambio", NULL); + + return (0); } static cam_status xptregister(struct cam_periph *periph, void *arg) { + struct cam_sim *xpt_sim; + if (periph == NULL) { kprintf("xptregister: periph was NULL!!\n"); return(CAM_REQ_CMP_ERR); } - periph->softc = NULL; - + xpt_sim = (struct cam_sim *)arg; + xpt_sim->softc = periph; xpt_periph = periph; + periph->softc = NULL; return(CAM_REQ_CMP); } @@ -1506,6 +1567,8 @@ xpt_add_periph(struct cam_periph *periph) int32_t status; struct periph_list *periph_head; + sim_lock_assert_owned(periph->sim->lock); + device = periph->path->device; periph_head = &device->periphs; @@ -1518,17 +1581,17 @@ xpt_add_periph(struct cam_periph *periph) * so it will fit in the queue * when it's scheduled to run */ - crit_enter(); status = camq_resize(&device->drvq, device->drvq.array_size + 1); device->generation++; SLIST_INSERT_HEAD(periph_head, periph, periph_links); - crit_exit(); } - xsoftc.generation++; + lockmgr(&xsoftc.xpt_topo_lock, LK_EXCLUSIVE); + xsoftc.xpt_generation++; + lockmgr(&xsoftc.xpt_topo_lock, LK_RELEASE); return (status); } @@ -1538,25 +1601,26 @@ xpt_remove_periph(struct cam_periph *periph) { struct cam_ed *device; + sim_lock_assert_owned(periph->sim->lock); + device = periph->path->device; if (device != NULL) { struct periph_list *periph_head; periph_head = &device->periphs; - + /* Release the slot for this peripheral */ - crit_enter(); camq_resize(&device->drvq, device->drvq.array_size - 1); device->generation++; SLIST_REMOVE(periph_head, periph, cam_periph, periph_links); - crit_exit(); } - xsoftc.generation++; - + lockmgr(&xsoftc.xpt_topo_lock, LK_EXCLUSIVE); + xsoftc.xpt_generation++; + lockmgr(&xsoftc.xpt_topo_lock, LK_RELEASE); } void @@ -1569,12 +1633,13 @@ xpt_announce_periph(struct cam_periph *periph, char *announce_string) u_int freq; u_int mb; + sim_lock_assert_owned(periph->sim->lock); + path = periph->path; /* * To ensure that this is printed in one piece, * mask out CAM interrupts. */ - crit_enter(); kprintf("%s%d at %s%d bus %d target %d lun %d\n", periph->periph_name, periph->unit_number, path->bus->sim->sim_name, @@ -1677,7 +1742,7 @@ xpt_announce_periph(struct cam_periph *periph, char *announce_string) if (path->device->inq_flags & SID_CmdQue || path->device->flags & CAM_DEV_TAG_AFTER_COUNT) { - kprintf("\n%s%d: Tagged Queueing Enabled", + kprintf("\n%s%d: Command Queueing Enabled", periph->periph_name, periph->unit_number); } kprintf("\n"); @@ -1689,7 +1754,6 @@ xpt_announce_periph(struct cam_periph *periph, char *announce_string) if (announce_string != NULL) kprintf("%s%d: %s\n", periph->periph_name, periph->unit_number, announce_string); - crit_exit(); } static dev_match_ret @@ -1772,7 +1836,7 @@ xptbusmatch(struct dev_match_pattern *patterns, u_int num_patterns, continue; /* - * If we get to this point, the user definitely wants + * If we get to this point, the user definitely wants * information on this bus. So tell the caller to copy the * data out. */ @@ -1850,7 +1914,7 @@ xptdevicematch(struct dev_match_pattern *patterns, u_int num_patterns, /* set the copy flag */ retval |= DM_RET_COPY; - + /* * If we've already decided on an action, go ahead * and return. @@ -1885,7 +1949,7 @@ xptdevicematch(struct dev_match_pattern *patterns, u_int num_patterns, continue; /* - * If we get to this point, the user definitely wants + * If we get to this point, the user definitely wants * information on this device. So tell the caller to copy * the data out. */ @@ -2008,7 +2072,7 @@ xptperiphmatch(struct dev_match_pattern *patterns, u_int num_patterns, continue; /* - * If we get to this point, the user definitely wants + * If we get to this point, the user definitely wants * information on this peripheral. So tell the caller to * copy the data out. */ @@ -2072,12 +2136,12 @@ xptedtbusfunc(struct cam_eb *bus, void *arg) */ if (spaceleft < sizeof(struct dev_match_result)) { bzero(&cdm->pos, sizeof(cdm->pos)); - cdm->pos.position_type = + cdm->pos.position_type = CAM_DEV_POS_EDT | CAM_DEV_POS_BUS; cdm->pos.cookie.bus = bus; cdm->pos.generations[CAM_BUS_GENERATION]= - bus_generation; + xsoftc.bus_generation; cdm->status = CAM_DEV_MATCH_MORE; return(0); } @@ -2203,18 +2267,18 @@ xptedtdevicefunc(struct cam_ed *device, void *arg) */ if (spaceleft < sizeof(struct dev_match_result)) { bzero(&cdm->pos, sizeof(cdm->pos)); - cdm->pos.position_type = + cdm->pos.position_type = CAM_DEV_POS_EDT | CAM_DEV_POS_BUS | CAM_DEV_POS_TARGET | CAM_DEV_POS_DEVICE; cdm->pos.cookie.bus = device->target->bus; cdm->pos.generations[CAM_BUS_GENERATION]= - bus_generation; + xsoftc.bus_generation; cdm->pos.cookie.target = device->target; cdm->pos.generations[CAM_TARGET_GENERATION] = device->target->bus->generation; cdm->pos.cookie.device = device; - cdm->pos.generations[CAM_DEV_GENERATION] = + cdm->pos.generations[CAM_DEV_GENERATION] = device->target->generation; cdm->status = CAM_DEV_MATCH_MORE; return(0); @@ -2312,19 +2376,19 @@ xptedtperiphfunc(struct cam_periph *periph, void *arg) */ if (spaceleft < sizeof(struct dev_match_result)) { bzero(&cdm->pos, sizeof(cdm->pos)); - cdm->pos.position_type = + cdm->pos.position_type = CAM_DEV_POS_EDT | CAM_DEV_POS_BUS | CAM_DEV_POS_TARGET | CAM_DEV_POS_DEVICE | CAM_DEV_POS_PERIPH; cdm->pos.cookie.bus = periph->path->bus; cdm->pos.generations[CAM_BUS_GENERATION]= - bus_generation; + xsoftc.bus_generation; cdm->pos.cookie.target = periph->path->target; cdm->pos.generations[CAM_TARGET_GENERATION] = periph->path->bus->generation; cdm->pos.cookie.device = periph->path->device; - cdm->pos.generations[CAM_DEV_GENERATION] = + cdm->pos.generations[CAM_DEV_GENERATION] = periph->path->target->generation; cdm->pos.cookie.periph = periph; cdm->pos.generations[CAM_PERIPH_GENERATION] = @@ -2364,7 +2428,7 @@ xptedtmatch(struct ccb_dev_match *cdm) */ if ((cdm->pos.position_type & CAM_DEV_POS_BUS) && (cdm->pos.generations[CAM_BUS_GENERATION] != 0) - && (cdm->pos.generations[CAM_BUS_GENERATION] != bus_generation)) { + && (cdm->pos.generations[CAM_BUS_GENERATION] != xsoftc.bus_generation)) { cdm->status = CAM_DEV_MATCH_LIST_CHANGED; return(0); } @@ -2450,7 +2514,7 @@ xptplistperiphfunc(struct cam_periph *periph, void *arg) pdrv = NULL; bzero(&cdm->pos, sizeof(cdm->pos)); - cdm->pos.position_type = + cdm->pos.position_type = CAM_DEV_POS_PDRV | CAM_DEV_POS_PDPTR | CAM_DEV_POS_PERIPH; @@ -2563,15 +2627,21 @@ xptbustraverse(struct cam_eb *start_bus, xpt_busfunc_t *tr_func, void *arg) retval = 1; - for (bus = (start_bus ? start_bus : TAILQ_FIRST(&xpt_busses)); + lockmgr(&xsoftc.xpt_topo_lock, LK_EXCLUSIVE); + for (bus = (start_bus ? start_bus : TAILQ_FIRST(&xsoftc.xpt_busses)); bus != NULL; bus = next_bus) { next_bus = TAILQ_NEXT(bus, links); + lockmgr(&xsoftc.xpt_topo_lock, LK_RELEASE); + CAM_SIM_LOCK(bus->sim); retval = tr_func(bus, arg); + CAM_SIM_UNLOCK(bus->sim); if (retval == 0) return(retval); + lockmgr(&xsoftc.xpt_topo_lock, LK_EXCLUSIVE); } + lockmgr(&xsoftc.xpt_topo_lock, LK_RELEASE); return(retval); } @@ -2782,23 +2852,6 @@ xpt_for_all_busses(xpt_busfunc_t *tr_func, void *arg) return(xptbustraverse(NULL, xptdefbusfunc, &tr_config)); } -#ifdef notusedyet -/* - * Execute the given function for every target in the EDT. - */ -static int -xpt_for_all_targets(xpt_targetfunc_t *tr_func, void *arg) -{ - struct xpt_traverse_config tr_config; - - tr_config.depth = XPT_DEPTH_TARGET; - tr_config.tr_func = tr_func; - tr_config.tr_arg = arg; - - return(xptbustraverse(NULL, xptdefbusfunc, &tr_config)); -} -#endif /* notusedyet */ - /* * Execute the given function for every device in the EDT. */ @@ -2814,23 +2867,6 @@ xpt_for_all_devices(xpt_devicefunc_t *tr_func, void *arg) return(xptbustraverse(NULL, xptdefbusfunc, &tr_config)); } -#ifdef notusedyet -/* - * Execute the given function for every peripheral in the EDT. - */ -static int -xpt_for_all_periphs(xpt_periphfunc_t *tr_func, void *arg) -{ - struct xpt_traverse_config tr_config; - - tr_config.depth = XPT_DEPTH_PERIPH; - tr_config.tr_func = tr_func; - tr_config.tr_arg = arg; - - return(xptbustraverse(NULL, xptdefbusfunc, &tr_config)); -} -#endif /* notusedyet */ - static int xptsetasyncfunc(struct cam_ed *device, void *arg) { @@ -2889,6 +2925,35 @@ xptsetasyncbusfunc(struct cam_eb *bus, void *arg) return(1); } +static void +xpt_action_sasync_cb(void *context, int pending) +{ + struct async_node *cur_entry; + struct xpt_task *task; + uint32_t added; + + task = (struct xpt_task *)context; + cur_entry = (struct async_node *)task->data1; + added = task->data2; + + if ((added & AC_FOUND_DEVICE) != 0) { + /* + * Get this peripheral up to date with all + * the currently existing devices. + */ + xpt_for_all_devices(xptsetasyncfunc, cur_entry); + } + if ((added & AC_PATH_REGISTERED) != 0) { + /* + * Get this peripheral up to date with all + * the currently existing busses. + */ + xpt_for_all_busses(xptsetasyncbusfunc, cur_entry); + } + + kfree(task, M_CAMXPT); +} + void xpt_action(union ccb *start_ccb) { @@ -2896,8 +2961,6 @@ xpt_action(union ccb *start_ccb) start_ccb->ccb_h.status = CAM_REQ_INPROG; - crit_enter(); - switch (start_ccb->ccb_h.func_code) { case XPT_SCSI_IO: { @@ -3029,7 +3092,7 @@ xpt_action(union ccb *start_ccb) 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)) { /* @@ -3094,7 +3157,7 @@ xpt_action(union ccb *start_ccb) bcopy(dev->serial_num, cgd->serial_num, dev->serial_num_len); } - break; + break; } case XPT_GDEV_STATS: { @@ -3147,17 +3210,17 @@ xpt_action(union ccb *start_ccb) /* * Check and see if the list has changed since the user * last requested a list member. If so, tell them that the - * list has changed, and therefore they need to start over + * list has changed, and therefore they need to start over * from the beginning. */ - if ((cgdl->index != 0) && + if ((cgdl->index != 0) && (cgdl->generation != device->generation)) { cgdl->status = CAM_GDEVLIST_LIST_CHANGED; break; } /* - * Traverse the list of peripherals and attempt to find + * Traverse the list of peripherals and attempt to find * the requested peripheral. */ for (nperiph = SLIST_FIRST(periph_head), i = 0; @@ -3196,9 +3259,6 @@ xpt_action(union ccb *start_ccb) cdm = &start_ccb->cdm; /* - * Prevent EDT changes while we traverse it. - */ - /* * There are two ways of getting at information in the EDT. * The first way is via the primary EDT tree. It starts * with a list of busses, then a list of targets on a bus, @@ -3290,8 +3350,8 @@ xpt_action(union ccb *start_ccb) cur_entry->event_enable = csa->event_enable; } } else { - cur_entry = kmalloc(sizeof(*cur_entry), - M_CAMXPT, M_INTWAIT); + cur_entry = kmalloc(sizeof(*cur_entry), M_CAMXPT, + M_INTWAIT); cur_entry->event_enable = csa->event_enable; cur_entry->callback_arg = csa->callback_arg; cur_entry->callback = csa->callback; @@ -3299,20 +3359,23 @@ xpt_action(union ccb *start_ccb) csa->ccb_h.path->device->refcount++; } - if ((added & AC_FOUND_DEVICE) != 0) { - /* - * Get this peripheral up to date with all - * the currently existing devices. - */ - xpt_for_all_devices(xptsetasyncfunc, cur_entry); - } - if ((added & AC_PATH_REGISTERED) != 0) { - /* - * Get this peripheral up to date with all - * the currently existing busses. - */ - xpt_for_all_busses(xptsetasyncbusfunc, cur_entry); + /* + * Need to decouple this operation via a taskqueue so that + * the locking doesn't become a mess. + */ + if ((added & (AC_FOUND_DEVICE | AC_PATH_REGISTERED)) != 0) { + struct xpt_task *task; + + task = kmalloc(sizeof(struct xpt_task), M_CAMXPT, + M_INTWAIT); + + TASK_INIT(&task->task, 0, xpt_action_sasync_cb, task); + task->data1 = cur_entry; + task->data2 = added; + taskqueue_enqueue(taskqueue_thread[mycpuid], + &task->task); } + start_ccb->ccb_h.status = CAM_REQ_CMP; break; } @@ -3338,10 +3401,9 @@ xpt_action(union ccb *start_ccb) crs->openings); if (bootverbose) { - xpt_print_path(crs->ccb_h.path); - kprintf("tagged openings " - "now %d\n", - crs->openings); + xpt_print(crs->ccb_h.path, + "tagged openings now %d\n", + crs->openings); } } } @@ -3357,13 +3419,13 @@ xpt_action(union ccb *start_ccb) * is sufficient for releasing the queue. */ start_ccb->ccb_h.flags &= ~CAM_DEV_QFREEZE; - callout_stop(&dev->c_handle); + callout_stop(&dev->callout); } else { start_ccb->ccb_h.flags |= CAM_DEV_QFREEZE; } - callout_reset(&dev->c_handle, + callout_reset(&dev->callout, (crs->release_timeout * hz) / 1000, xpt_release_devq_timeout, dev); @@ -3381,7 +3443,7 @@ xpt_action(union ccb *start_ccb) */ start_ccb->ccb_h.flags &= ~CAM_DEV_QFREEZE; } else { - + dev->flags |= CAM_DEV_REL_ON_COMPLETE; start_ccb->ccb_h.flags |= CAM_DEV_QFREEZE; } @@ -3394,7 +3456,7 @@ xpt_action(union ccb *start_ccb) start_ccb->ccb_h.flags &= ~CAM_DEV_QFREEZE; } else { - + dev->flags |= CAM_DEV_REL_ON_QUEUE_EMPTY; start_ccb->ccb_h.flags |= CAM_DEV_QFREEZE; } @@ -3438,8 +3500,8 @@ xpt_action(union ccb *start_ccb) cam_dflags = CAM_DEBUG_NONE; } else { start_ccb->ccb_h.status = CAM_REQ_CMP; - xpt_print_path(cam_dpath); - kprintf("debugging flags now %x\n", cam_dflags); + xpt_print(cam_dpath, "debugging flags now %x\n", + cam_dflags); } } else { cam_dpath = NULL; @@ -3463,14 +3525,13 @@ xpt_action(union ccb *start_ccb) start_ccb->ccb_h.status = CAM_PROVIDE_FAIL; break; } - crit_exit(); } void xpt_polled_action(union ccb *start_ccb) { u_int32_t timeout; - struct cam_sim *sim; + struct cam_sim *sim; struct cam_devq *devq; struct cam_ed *dev; @@ -3479,30 +3540,30 @@ xpt_polled_action(union ccb *start_ccb) devq = sim->devq; dev = start_ccb->ccb_h.path->device; - crit_enter(); + sim_lock_assert_owned(sim->lock); /* * Steal an opening so that no other queued requests * can get it before us while we simulate interrupts. */ dev->ccbq.devq_openings--; - dev->ccbq.dev_openings--; - + dev->ccbq.dev_openings--; + while(((devq && devq->send_openings <= 0) || dev->ccbq.dev_openings < 0) && (--timeout > 0)) { DELAY(1000); (*(sim->sim_poll))(sim); - swi_cambio(NULL, NULL); + camisr_runqueue(&sim->sim_doneq); } - + dev->ccbq.devq_openings++; dev->ccbq.dev_openings++; - + if (timeout != 0) { xpt_action(start_ccb); while(--timeout > 0) { (*(sim->sim_poll))(sim); - swi_cambio(NULL, NULL); + camisr_runqueue(&sim->sim_doneq); if ((start_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_INPROG) break; @@ -3520,9 +3581,8 @@ xpt_polled_action(union ccb *start_ccb) } else { start_ccb->ccb_h.status = CAM_RESRC_UNAVAIL; } - crit_exit(); } - + /* * Schedule a peripheral driver to receive a ccb when it's * target device has space for more transactions. @@ -3534,9 +3594,10 @@ xpt_schedule(struct cam_periph *perph, u_int32_t new_priority) union ccb *work_ccb; int runq; + sim_lock_assert_owned(perph->sim->lock); + CAM_DEBUG(perph->path, CAM_DEBUG_TRACE, ("xpt_schedule\n")); device = perph->path->device; - crit_enter(); if (periph_is_queued(perph)) { /* Simply reorder based on new priority */ CAM_DEBUG(perph->path, CAM_DEBUG_SUBTRACE, @@ -3550,7 +3611,6 @@ xpt_schedule(struct cam_periph *perph, u_int32_t new_priority) } else if (SIM_DEAD(perph->path->bus->sim)) { /* The SIM is gone so just call periph_start directly. */ work_ccb = xpt_get_ccb(perph->path->device); - crit_exit(); if (work_ccb == NULL) return; /* XXX */ xpt_setup_ccb(&work_ccb->ccb_h, perph->path, new_priority); @@ -3566,7 +3626,6 @@ xpt_schedule(struct cam_periph *perph, u_int32_t new_priority) camq_insert(&device->drvq, &perph->pinfo); runq = xpt_schedule_dev_allocq(perph->path->bus, device); } - crit_exit(); if (runq != 0) { CAM_DEBUG(perph->path, CAM_DEBUG_SUBTRACE, (" calling xpt_run_devq\n")); @@ -3581,7 +3640,7 @@ xpt_schedule(struct cam_periph *perph, u_int32_t new_priority) * return 1 meaning the device queue should be run. If we * were already queued, implying someone else has already * started the queue, return 0 so the caller doesn't attempt - * to run the queue. Must be run in a critical section. + * to run the queue. */ static int xpt_schedule_dev(struct camq *queue, cam_pinfo *pinfo, @@ -3640,7 +3699,6 @@ xpt_run_dev_allocq(struct cam_eb *bus) devq->alloc_openings, devq->alloc_active)); - crit_enter(); devq->alloc_queue.qfrozen_cnt++; while ((devq->alloc_queue.entries > 0) && (devq->alloc_openings > 0) @@ -3650,7 +3708,7 @@ xpt_run_dev_allocq(struct cam_eb *bus) 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; @@ -3670,7 +3728,6 @@ xpt_run_dev_allocq(struct cam_eb *bus) devq->alloc_openings--; devq->alloc_active++; drv = (struct cam_periph*)camq_remove(drvq, CAMQ_HEAD); - crit_exit(); xpt_setup_ccb(&work_ccb->ccb_h, drv->path, drv->pinfo.priority); CAM_DEBUG_PRINT(CAM_DEBUG_XPT, @@ -3688,9 +3745,6 @@ xpt_run_dev_allocq(struct cam_eb *bus) */ break; } - - /* Raise IPL for possible insertion and test at top of loop */ - crit_enter(); if (drvq->entries > 0) { /* We have more work. Attempt to reschedule */ @@ -3698,7 +3752,6 @@ xpt_run_dev_allocq(struct cam_eb *bus) } } devq->alloc_queue.qfrozen_cnt--; - crit_exit(); } static void @@ -3712,7 +3765,6 @@ xpt_run_dev_sendq(struct cam_eb *bus) } CAM_DEBUG_PRINT(CAM_DEBUG_XPT, ("xpt_run_dev_sendq\n")); - crit_enter(); devq->send_queue.qfrozen_cnt++; while ((devq->send_queue.entries > 0) && (devq->send_openings > 0)) { @@ -3748,7 +3800,8 @@ xpt_run_dev_sendq(struct cam_eb *bus) if ((work_ccb->ccb_h.flags & CAM_HIGH_POWER) != 0) { - if (num_highpower <= 0) { + lockmgr(&xsoftc.xpt_lock, LK_EXCLUSIVE); + if (xsoftc.num_highpower <= 0) { /* * We got a high power command, but we * don't have any available slots. Freeze @@ -3756,18 +3809,20 @@ xpt_run_dev_sendq(struct cam_eb *bus) * available. */ device->qfrozen_cnt++; - STAILQ_INSERT_TAIL(&highpowerq, - &work_ccb->ccb_h, + STAILQ_INSERT_TAIL(&xsoftc.highpowerq, + &work_ccb->ccb_h, xpt_links.stqe); + lockmgr(&xsoftc.xpt_lock, LK_RELEASE); continue; } else { /* * Consume a high power slot while * this ccb runs. */ - num_highpower--; + xsoftc.num_highpower--; } + lockmgr(&xsoftc.xpt_lock, LK_RELEASE); } devq->active_dev = device; cam_ccbq_remove_ccb(&device->ccbq, work_ccb); @@ -3775,8 +3830,8 @@ xpt_run_dev_sendq(struct cam_eb *bus) cam_ccbq_send_ccb(&device->ccbq, work_ccb); devq->send_openings--; - devq->send_active++; - + devq->send_active++; + if (device->ccbq.queue.entries > 0) xpt_schedule_dev_sendq(bus, device); @@ -3811,10 +3866,8 @@ xpt_run_dev_sendq(struct cam_eb *bus) (*(sim->sim_action))(sim, work_ccb); devq->active_dev = NULL; - /* Raise IPL for possible insertion and test at top of loop */ } devq->send_queue.qfrozen_cnt--; - crit_exit(); } /* @@ -3876,6 +3929,36 @@ xpt_create_path(struct cam_path **new_path_ptr, struct cam_periph *perph, return (status); } +cam_status +xpt_create_path_unlocked(struct cam_path **new_path_ptr, + struct cam_periph *periph, path_id_t path_id, + target_id_t target_id, lun_id_t lun_id) +{ + struct cam_path *path; + struct cam_eb *bus = NULL; + cam_status status; + int need_unlock = 0; + + path = (struct cam_path *)kmalloc(sizeof(*path), M_CAMXPT, M_WAITOK); + + if (path_id != CAM_BUS_WILDCARD) { + bus = xpt_find_bus(path_id); + if (bus != NULL) { + need_unlock = 1; + CAM_SIM_LOCK(bus->sim); + } + } + status = xpt_compile_path(path, periph, path_id, target_id, lun_id); + if (need_unlock) + CAM_SIM_UNLOCK(bus->sim); + if (status != CAM_REQ_CMP) { + kfree(path, M_CAMXPT); + path = NULL; + } + *new_path_ptr = path; + return (status); +} + static cam_status xpt_compile_path(struct cam_path *new_path, struct cam_periph *perph, path_id_t path_id, target_id_t target_id, lun_id_t lun_id) @@ -3893,7 +3976,6 @@ xpt_compile_path(struct cam_path *new_path, struct cam_periph *perph, * We will potentially modify the EDT, so block interrupts * that may attempt to create cam paths. */ - crit_enter(); bus = xpt_find_bus(path_id); if (bus == NULL) { status = CAM_PATH_INVALID; @@ -3927,7 +4009,6 @@ xpt_compile_path(struct cam_path *new_path, struct cam_periph *perph, } } } - crit_exit(); /* * Only touch the user's data if we are successful. @@ -4017,6 +4098,7 @@ xpt_path_comp(struct cam_path *path1, struct cam_path *path2) void xpt_print_path(struct cam_path *path) { + if (path == NULL) kprintf("(nopath): "); else { @@ -4045,11 +4127,23 @@ xpt_print_path(struct cam_path *path) } } +void +xpt_print(struct cam_path *path, const char *fmt, ...) +{ + __va_list ap; + xpt_print_path(path); + __va_start(ap, fmt); + kvprintf(fmt, ap); + __va_end(ap); +} + int xpt_path_string(struct cam_path *path, char *str, size_t str_len) { struct sbuf sb; + sim_lock_assert_owned(path->bus->sim->lock); + sbuf_new(&sb, str, str_len, 0); if (path == NULL) @@ -4086,12 +4180,16 @@ xpt_path_string(struct cam_path *path, char *str, size_t str_len) path_id_t xpt_path_path_id(struct cam_path *path) { + sim_lock_assert_owned(path->bus->sim->lock); + return(path->bus->path_id); } target_id_t xpt_path_target_id(struct cam_path *path) { + sim_lock_assert_owned(path->bus->sim->lock); + if (path->target != NULL) return (path->target->target_id); else @@ -4101,6 +4199,8 @@ xpt_path_target_id(struct cam_path *path) lun_id_t xpt_path_lun_id(struct cam_path *path) { + sim_lock_assert_owned(path->bus->sim->lock); + if (path->device != NULL) return (path->device->lun_id); else @@ -4116,6 +4216,8 @@ xpt_path_sim(struct cam_path *path) struct cam_periph* xpt_path_periph(struct cam_path *path) { + sim_lock_assert_owned(path->bus->sim->lock); + return (path->periph); } @@ -4131,32 +4233,35 @@ xpt_release_ccb(union ccb *free_ccb) struct cam_path *path; struct cam_ed *device; struct cam_eb *bus; + struct cam_sim *sim; CAM_DEBUG_PRINT(CAM_DEBUG_XPT, ("xpt_release_ccb\n")); path = free_ccb->ccb_h.path; device = path->device; bus = path->bus; - crit_enter(); + sim = bus->sim; + + sim_lock_assert_owned(sim->lock); + cam_ccbq_release_opening(&device->ccbq); - if (xpt_ccb_count > xpt_max_ccbs) { + if (sim->ccb_count > sim->max_ccbs) { xpt_free_ccb(free_ccb); - xpt_ccb_count--; + sim->ccb_count--; } else { - SLIST_INSERT_HEAD(&ccb_freeq, &free_ccb->ccb_h, xpt_links.sle); + SLIST_INSERT_HEAD(&sim->ccb_freeq, &free_ccb->ccb_h, + xpt_links.sle); } - if (bus->sim->devq == NULL) { - crit_exit(); + if (sim->devq == NULL) { return; } - bus->sim->devq->alloc_openings++; - bus->sim->devq->alloc_active--; + sim->devq->alloc_openings++; + sim->devq->alloc_active--; /* XXX Turn this into an inline function - xpt_run_device?? */ if ((device_is_alloc_queued(device) == 0) && (device->drvq.entries > 0)) { xpt_schedule_dev_allocq(bus, device); } - crit_exit(); - if (bus->sim->devq && dev_allocq_is_runnable(bus->sim->devq)) + if (dev_allocq_is_runnable(sim->devq)) xpt_run_dev_allocq(bus); } @@ -4178,6 +4283,8 @@ xpt_bus_register(struct cam_sim *sim, u_int32_t bus) struct cam_eb *old_bus; struct ccb_pathinq cpi; + sim_lock_assert_owned(sim->lock); + sim->bus_id = bus; new_bus = kmalloc(sizeof(*new_bus), M_CAMXPT, M_INTWAIT); @@ -4194,17 +4301,17 @@ xpt_bus_register(struct cam_sim *sim, u_int32_t bus) new_bus->flags = 0; new_bus->refcount = 1; /* Held until a bus_deregister event */ new_bus->generation = 0; - crit_enter(); - old_bus = TAILQ_FIRST(&xpt_busses); + lockmgr(&xsoftc.xpt_topo_lock, LK_EXCLUSIVE); + old_bus = TAILQ_FIRST(&xsoftc.xpt_busses); while (old_bus != NULL && old_bus->path_id < new_bus->path_id) old_bus = TAILQ_NEXT(old_bus, links); if (old_bus != NULL) TAILQ_INSERT_BEFORE(old_bus, new_bus, links); else - TAILQ_INSERT_TAIL(&xpt_busses, new_bus, links); - bus_generation++; - crit_exit(); + TAILQ_INSERT_TAIL(&xsoftc.xpt_busses, new_bus, links); + xsoftc.bus_generation++; + lockmgr(&xsoftc.xpt_topo_lock, LK_RELEASE); /* Notify interested parties */ if (sim->path_id != CAM_XPT_PATH_ID) { @@ -4255,6 +4362,7 @@ xpt_bus_deregister(path_id_t pathid) /* The SIM may be gone, so use a dummy SIM for any stray operations. */ devq = bus_path.bus->sim->devq; + ccbsim = bus_path.bus->sim; bus_path.bus->sim = &cam_dead_sim; /* Execute any pending operations now. */ @@ -4269,7 +4377,6 @@ xpt_bus_deregister(path_id_t pathid) devq->active_dev = device; cam_ccbq_remove_ccb(&device->ccbq, work_ccb); cam_ccbq_send_ccb(&device->ccbq, work_ccb); - ccbsim = work_ccb->ccb_h.path->bus->sim; (*(ccbsim->sim_action))(ccbsim, work_ccb); } @@ -4281,8 +4388,8 @@ xpt_bus_deregister(path_id_t pathid) } /* Make sure all completed CCBs are processed. */ - while (!TAILQ_EMPTY(&cam_bioq)) { - camisr(&cam_bioq); + while (!TAILQ_EMPTY(&ccbsim->sim_doneq)) { + camisr_runqueue(&ccbsim->sim_doneq); /* Repeat the async's for the benefit of any new devices. */ xpt_async(AC_LOST_DEVICE, &bus_path, NULL); @@ -4293,10 +4400,6 @@ xpt_bus_deregister(path_id_t pathid) xpt_release_bus(bus_path.bus); xpt_release_path(&bus_path); - /* Recheck for more completed CCBs. */ - while (!TAILQ_EMPTY(&cam_bioq)) - camisr(&cam_bioq); - return (CAM_REQ_CMP); } @@ -4308,15 +4411,16 @@ xptnextfreepathid(void) char *strval; pathid = 0; - bus = TAILQ_FIRST(&xpt_busses); + lockmgr(&xsoftc.xpt_topo_lock, LK_EXCLUSIVE); + bus = TAILQ_FIRST(&xsoftc.xpt_busses); retry: /* Find an unoccupied pathid */ - while (bus != NULL - && bus->path_id <= pathid) { + while (bus != NULL && bus->path_id <= pathid) { if (bus->path_id == pathid) pathid++; bus = TAILQ_NEXT(bus, links); } + lockmgr(&xsoftc.xpt_topo_lock, LK_RELEASE); /* * Ensure that this pathid is not reserved for @@ -4325,6 +4429,7 @@ retry: if (resource_string_value("scbus", pathid, "at", &strval) == 0) { ++pathid; /* Start the search over */ + lockmgr(&xsoftc.xpt_topo_lock, LK_EXCLUSIVE); goto retry; } return (pathid); @@ -4380,20 +4485,20 @@ xpt_async(u_int32_t async_code, struct cam_path *path, void *async_arg) struct cam_et *target, *next_target; struct cam_ed *device, *next_device; + sim_lock_assert_owned(path->bus->sim->lock); + CAM_DEBUG(path, CAM_DEBUG_TRACE, ("xpt_async\n")); /* * Most async events come from a CAM interrupt context. In * a few cases, the error recovery code at the peripheral layer, * which may run from our SWI or a process context, may signal - * deferred events with a call to xpt_async. Ensure async - * notifications are serialized by blocking cam interrupts. + * deferred events with a call to xpt_async. */ - crit_enter(); bus = path->bus; - if (async_code == AC_BUS_RESET) { + if (async_code == AC_BUS_RESET) { /* Update our notion of when the last reset occurred */ microuptime(&bus->last_reset); } @@ -4420,7 +4525,7 @@ xpt_async(u_int32_t async_code, struct cam_path *path, void *async_arg) next_device = TAILQ_NEXT(device, links); - if (path->device != device + if (path->device != device && path->device->lun_id != CAM_LUN_WILDCARD && device->lun_id != CAM_LUN_WILDCARD) continue; @@ -4432,7 +4537,7 @@ xpt_async(u_int32_t async_code, struct cam_path *path, void *async_arg) path, async_arg); } } - + /* * If this wasn't a fully wildcarded async, tell all * clients that want all async events. @@ -4440,7 +4545,6 @@ xpt_async(u_int32_t async_code, struct cam_path *path, void *async_arg) if (bus != xpt_periph->path->bus) xpt_async_bcast(&xpt_periph->path->device->asyncs, async_code, path, async_arg); - crit_exit(); } static void @@ -4546,7 +4650,8 @@ xpt_freeze_devq(struct cam_path *path, u_int count) { struct ccb_hdr *ccbh; - crit_enter(); + sim_lock_assert_owned(path->bus->sim->lock); + path->device->qfrozen_cnt += count; /* @@ -4558,26 +4663,27 @@ xpt_freeze_devq(struct cam_path *path, u_int count) * freezes the queue. To completly close the * hole, controller drives must check to see * if a ccb's status is still CAM_REQ_INPROG - * under critical section protection just before they queue + * just before they queue * the CCB. See ahc_action/ahc_freeze_devq for * an example. */ ccbh = TAILQ_LAST(&path->device->ccbq.active_ccbs, ccb_hdr_tailq); if (ccbh && ccbh->status == CAM_REQ_INPROG) ccbh->status = CAM_REQUEUE_REQ; - crit_exit(); return (path->device->qfrozen_cnt); } u_int32_t xpt_freeze_simq(struct cam_sim *sim, u_int count) { + sim_lock_assert_owned(sim->lock); + if (sim->devq == NULL) return(count); sim->devq->send_queue.qfrozen_cnt += count; if (sim->devq->active_dev != NULL) { struct ccb_hdr *ccbh; - + ccbh = TAILQ_LAST(&sim->devq->active_dev->ccbq.active_ccbs, ccb_hdr_tailq); if (ccbh && ccbh->status == CAM_REQ_INPROG) @@ -4608,6 +4714,8 @@ xpt_release_devq_timeout(void *arg) void xpt_release_devq(struct cam_path *path, u_int count, int run_queue) { + sim_lock_assert_owned(path->bus->sim->lock); + xpt_release_devq_device(path->device, count, run_queue); } @@ -4617,7 +4725,6 @@ xpt_release_devq_device(struct cam_ed *dev, u_int count, int run_queue) int rundevq; rundevq = 0; - crit_enter(); if (dev->qfrozen_cnt > 0) { @@ -4636,7 +4743,7 @@ xpt_release_devq_device(struct cam_ed *dev, u_int count, int run_queue) * to release this queue. */ if ((dev->flags & CAM_DEV_REL_TIMEOUT_PENDING) != 0) { - callout_stop(&dev->c_handle); + callout_stop(&dev->callout); dev->flags &= ~CAM_DEV_REL_TIMEOUT_PENDING; } @@ -4654,7 +4761,6 @@ xpt_release_devq_device(struct cam_ed *dev, u_int count, int run_queue) } if (rundevq != 0) xpt_run_dev_sendq(dev->target->bus); - crit_exit(); } void @@ -4662,12 +4768,12 @@ xpt_release_simq(struct cam_sim *sim, int run_queue) { struct camq *sendq; + sim_lock_assert_owned(sim->lock); + if (sim->devq == NULL) return; sendq = &(sim->devq->send_queue); - crit_enter(); - if (sendq->qfrozen_cnt > 0) { sendq->qfrozen_cnt--; if (sendq->qfrozen_cnt == 0) { @@ -4679,11 +4785,10 @@ xpt_release_simq(struct cam_sim *sim, int run_queue) * already at 0. */ if ((sim->flags & CAM_SIM_REL_TIMEOUT_PENDING) != 0){ - callout_stop(&sim->c_handle); + callout_stop(&sim->callout); sim->flags &= ~CAM_SIM_REL_TIMEOUT_PENDING; } bus = xpt_find_bus(sim->path_id); - crit_exit(); if (run_queue) { /* @@ -4692,18 +4797,14 @@ xpt_release_simq(struct cam_sim *sim, int run_queue) xpt_run_dev_sendq(bus); } xpt_release_bus(bus); - } else { - crit_exit(); } - } else { - crit_exit(); } } void xpt_done(union ccb *done_ccb) { - crit_enter(); + struct cam_sim *sim; CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_TRACE, ("xpt_done\n")); if ((done_ccb->ccb_h.func_code & XPT_FC_QUEUED) != 0) { @@ -4711,19 +4812,28 @@ xpt_done(union ccb *done_ccb) * Queue up the request for handling by our SWI handler * any of the "non-immediate" type of ccbs. */ + sim = done_ccb->ccb_h.path->bus->sim; switch (done_ccb->ccb_h.path->periph->type) { case CAM_PERIPH_BIO: - TAILQ_INSERT_TAIL(&cam_bioq, &done_ccb->ccb_h, + TAILQ_INSERT_TAIL(&sim->sim_doneq, &done_ccb->ccb_h, sim_links.tqe); done_ccb->ccb_h.pinfo.index = CAM_DONEQ_INDEX; - setsoftcambio(); + if ((sim->flags & CAM_SIM_ON_DONEQ) == 0) { + lockmgr(&cam_simq_lock, LK_EXCLUSIVE); + TAILQ_INSERT_TAIL(&cam_simq, sim, + links); + sim->flags |= CAM_SIM_ON_DONEQ; + lockmgr(&cam_simq_lock, LK_RELEASE); + } + if ((done_ccb->ccb_h.path->periph->flags & + CAM_PERIPH_POLLED) == 0) + setsoftcambio(); break; default: panic("unknown periph type %d", done_ccb->ccb_h.path->periph->type); } } - crit_exit(); } union ccb * @@ -4731,7 +4841,7 @@ xpt_alloc_ccb(void) { union ccb *new_ccb; - new_ccb = kmalloc(sizeof(*new_ccb), M_CAMXPT, M_INTWAIT); + new_ccb = kmalloc(sizeof(*new_ccb), M_CAMXPT, M_INTWAIT | M_ZERO); return (new_ccb); } @@ -4756,17 +4866,19 @@ static union ccb * xpt_get_ccb(struct cam_ed *device) { union ccb *new_ccb; + struct cam_sim *sim; - crit_enter(); - if ((new_ccb = (union ccb *)SLIST_FIRST(&ccb_freeq)) == NULL) { - new_ccb = kmalloc(sizeof(*new_ccb), M_CAMXPT, M_INTWAIT); - SLIST_INSERT_HEAD(&ccb_freeq, &new_ccb->ccb_h, + sim = device->sim; + if ((new_ccb = (union ccb *)SLIST_FIRST(&sim->ccb_freeq)) == NULL) { + new_ccb = xpt_alloc_ccb(); + if ((sim->flags & CAM_SIM_MPSAFE) == 0) + callout_init(&new_ccb->ccb_h.timeout_ch); + SLIST_INSERT_HEAD(&sim->ccb_freeq, &new_ccb->ccb_h, xpt_links.sle); - xpt_ccb_count++; + sim->ccb_count++; } cam_ccbq_take_opening(&device->ccbq); - SLIST_REMOVE_HEAD(&ccb_freeq, xpt_links.sle); - crit_exit(); + SLIST_REMOVE_HEAD(&sim->ccb_freeq, xpt_links.sle); return (new_ccb); } @@ -4774,21 +4886,14 @@ static void xpt_release_bus(struct cam_eb *bus) { - crit_enter(); - if (bus->refcount == 1) { - KKASSERT(TAILQ_FIRST(&bus->et_entries) == NULL); - TAILQ_REMOVE(&xpt_busses, bus, links); - if (bus->sim) { - cam_sim_release(bus->sim, 0); - bus->sim = NULL; - } - bus_generation++; - KKASSERT(bus->refcount == 1); + if ((--bus->refcount == 0) + && (TAILQ_FIRST(&bus->et_entries) == NULL)) { + lockmgr(&xsoftc.xpt_topo_lock, LK_EXCLUSIVE); + TAILQ_REMOVE(&xsoftc.xpt_busses, bus, links); + xsoftc.bus_generation++; + lockmgr(&xsoftc.xpt_topo_lock, LK_RELEASE); kfree(bus, M_CAMXPT); - } else { - --bus->refcount; } - crit_exit(); } static struct cam_et * @@ -4828,7 +4933,6 @@ 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) { - crit_enter(); if (target->refcount == 1) { KKASSERT(TAILQ_FIRST(&target->ed_entries) == NULL); TAILQ_REMOVE(&bus->et_entries, target, links); @@ -4839,7 +4943,6 @@ xpt_release_target(struct cam_eb *bus, struct cam_et *target) } else { --target->refcount; } - crit_exit(); } static struct cam_ed * @@ -4874,6 +4977,7 @@ xpt_alloc_device(struct cam_eb *bus, struct cam_et *target, lun_id_t lun_id) device->send_ccb_entry.device = device; device->target = target; device->lun_id = lun_id; + device->sim = bus->sim; /* Initialize our queues */ if (camq_init(&device->drvq, 0) != 0) { kfree(device, M_CAMXPT); @@ -4904,7 +5008,7 @@ xpt_alloc_device(struct cam_eb *bus, struct cam_et *target, lun_id_t lun_id) device->tag_delay_count = 0; device->tag_saved_openings = 0; device->refcount = 1; - callout_init(&device->c_handle); + callout_init(&device->callout); /* * Hold a reference to our parent target so it @@ -4916,7 +5020,7 @@ xpt_alloc_device(struct cam_eb *bus, struct cam_et *target, lun_id_t lun_id) * XXX should be limited by number of CCBs this bus can * do. */ - xpt_max_ccbs += device->ccbq.devq_openings; + bus->sim->max_ccbs += device->ccbq.devq_openings; /* Insertion sort into our target's device list */ cur_device = TAILQ_FIRST(&target->ed_entries); while (cur_device != NULL && cur_device->lun_id < lun_id) @@ -4952,7 +5056,6 @@ xpt_release_device(struct cam_eb *bus, struct cam_et *target, { struct cam_devq *devq; - crit_enter(); if (device->refcount == 1) { KKASSERT(device->flags & CAM_DEV_UNCONFIGURED); @@ -4962,12 +5065,12 @@ xpt_release_device(struct cam_eb *bus, struct cam_et *target, if ((device->flags & CAM_DEV_REL_TIMEOUT_PENDING) != 0) { device->flags &= ~CAM_DEV_REL_TIMEOUT_PENDING; - callout_stop(&device->c_handle); + callout_stop(&device->callout); } TAILQ_REMOVE(&target->ed_entries, device,links); target->generation++; - xpt_max_ccbs -= device->ccbq.devq_openings; + bus->sim->max_ccbs -= device->ccbq.devq_openings; if (!SIM_DEAD(bus->sim)) { /* Release our slot in the devq */ devq = bus->sim->devq; @@ -4981,7 +5084,6 @@ xpt_release_device(struct cam_eb *bus, struct cam_et *target, } else { --device->refcount; } - crit_exit(); } static u_int32_t @@ -4993,8 +5095,6 @@ xpt_dev_ccbq_resize(struct cam_path *path, int newopenings) dev = path->device; - crit_enter(); - diff = newopenings - (dev->ccbq.dev_active + dev->ccbq.dev_openings); result = cam_ccbq_resize(&dev->ccbq, newopenings); if (result == CAM_REQ_CMP && (diff < 0)) { @@ -5004,8 +5104,7 @@ xpt_dev_ccbq_resize(struct cam_path *path, int newopenings) || (dev->inq_flags & SID_CmdQue) != 0) dev->tag_saved_openings = newopenings; /* Adjust the global limit */ - xpt_max_ccbs += diff; - crit_exit(); + dev->sim->max_ccbs += diff; return (result); } @@ -5014,12 +5113,14 @@ xpt_find_bus(path_id_t path_id) { struct cam_eb *bus; - TAILQ_FOREACH(bus, &xpt_busses, links) { + lockmgr(&xsoftc.xpt_topo_lock, LK_EXCLUSIVE); + TAILQ_FOREACH(bus, &xsoftc.xpt_busses, links) { if (bus->path_id == path_id) { bus->refcount++; break; } } + lockmgr(&xsoftc.xpt_topo_lock, LK_RELEASE); return (bus); } @@ -5103,7 +5204,7 @@ xpt_scan_bus(struct cam_periph *periph, union ccb *request_ccb) /* Save some state for use while we probe for devices */ scan_info = (xpt_scan_bus_info *) - kmalloc(sizeof(xpt_scan_bus_info), M_TEMP, M_INTWAIT); + kmalloc(sizeof(xpt_scan_bus_info), M_CAMXPT, M_INTWAIT); scan_info->request_ccb = request_ccb; scan_info->cpi = &work_ccb->cpi; @@ -5124,7 +5225,7 @@ xpt_scan_bus(struct cam_periph *periph, union ccb *request_ccb) scan_info->counter--; } } - + for (i = 0; i <= max_target; i++) { cam_status status; if (i == initiator_id) @@ -5137,7 +5238,7 @@ xpt_scan_bus(struct cam_periph *periph, union ccb *request_ccb) kprintf("xpt_scan_bus: xpt_create_path failed" " with status %#x, bus scan halted\n", status); - kfree(scan_info, M_TEMP); + kfree(scan_info, M_CAMXPT); request_ccb->ccb_h.status = status; xpt_free_ccb(work_ccb); xpt_done(request_ccb); @@ -5194,21 +5295,19 @@ xpt_scan_bus(struct cam_periph *periph, union ccb *request_ccb) * path in the request ccb. */ phl = 0; - crit_enter(); device = TAILQ_FIRST(&target->ed_entries); if (device != NULL) { phl = CAN_SRCH_HI_SPARSE(device); if (device->lun_id == 0) device = TAILQ_NEXT(device, links); } - crit_exit(); if ((lun_id != 0) || (device != NULL)) { if (lun_id < (CAM_SCSI2_MAXLUN-1) || phl) lun_id++; } } else { struct cam_ed *device; - + device = request_ccb->ccb_h.path->device; if ((device->quirk->quirks & CAM_QUIRK_NOLUNS) == 0) { @@ -5235,7 +5334,7 @@ xpt_scan_bus(struct cam_periph *periph, union ccb *request_ccb) done = 0; if (scan_info->cpi->hba_misc & PIM_SEQSCAN) { scan_info->counter++; - if (scan_info->counter == + if (scan_info->counter == scan_info->cpi->initiator_id) { scan_info->counter++; } @@ -5253,7 +5352,7 @@ xpt_scan_bus(struct cam_periph *periph, union ccb *request_ccb) xpt_free_ccb(request_ccb); xpt_free_ccb((union ccb *)scan_info->cpi); request_ccb = scan_info->request_ccb; - kfree(scan_info, M_TEMP); + kfree(scan_info, M_CAMXPT); request_ccb->ccb_h.status = CAM_REQ_CMP; xpt_done(request_ccb); break; @@ -5272,7 +5371,7 @@ xpt_scan_bus(struct cam_periph *periph, union ccb *request_ccb) xpt_free_ccb(request_ccb); xpt_free_ccb((union ccb *)scan_info->cpi); request_ccb = scan_info->request_ccb; - kfree(scan_info, M_TEMP); + kfree(scan_info, M_CAMXPT); request_ccb->ccb_h.status = status; xpt_done(request_ccb); break; @@ -5311,11 +5410,15 @@ xpt_scan_bus(struct cam_periph *periph, union ccb *request_ccb) typedef enum { PROBE_TUR, - PROBE_INQUIRY, + PROBE_INQUIRY, /* this counts as DV0 for Basic Domain Validation */ PROBE_FULL_INQUIRY, PROBE_MODE_SENSE, - PROBE_SERIAL_NUM, - PROBE_TUR_FOR_NEGOTIATION + PROBE_SERIAL_NUM_0, + PROBE_SERIAL_NUM_1, + PROBE_TUR_FOR_NEGOTIATION, + PROBE_INQUIRY_BASIC_DV1, + PROBE_INQUIRY_BASIC_DV2, + PROBE_DV_EXIT } probe_action; typedef enum { @@ -5344,7 +5447,7 @@ xpt_scan_lun(struct cam_periph *periph, struct cam_path *path, CAM_DEBUG(request_ccb->ccb_h.path, CAM_DEBUG_TRACE, ("xpt_scan_lun\n")); - + xpt_setup_ccb(&cpi.ccb_h, path, /*priority*/1); cpi.ccb_h.func_code = XPT_PATH_INQ; xpt_action((union ccb *)&cpi); @@ -5370,19 +5473,18 @@ xpt_scan_lun(struct cam_periph *periph, struct cam_path *path, } if (request_ccb == NULL) { - request_ccb = kmalloc(sizeof(union ccb), M_TEMP, M_INTWAIT); - new_path = kmalloc(sizeof(*new_path), M_TEMP, M_INTWAIT); + request_ccb = kmalloc(sizeof(union ccb), M_CAMXPT, M_INTWAIT); + new_path = kmalloc(sizeof(*new_path), M_CAMXPT, M_INTWAIT); status = xpt_compile_path(new_path, xpt_periph, path->bus->path_id, path->target->target_id, path->device->lun_id); if (status != CAM_REQ_CMP) { - xpt_print_path(path); - kprintf("xpt_scan_lun: can't compile path, can't " - "continue\n"); - kfree(request_ccb, M_TEMP); - kfree(new_path, M_TEMP); + xpt_print(path, "xpt_scan_lun: can't compile path, " + "can't continue\n"); + kfree(request_ccb, M_CAMXPT); + kfree(new_path, M_CAMXPT); return; } xpt_setup_ccb(&request_ccb->ccb_h, new_path, /*priority*/ 1); @@ -5391,7 +5493,6 @@ xpt_scan_lun(struct cam_periph *periph, struct cam_path *path, request_ccb->crcn.flags = flags; } - crit_enter(); if ((old_periph = cam_periph_find(path, "probe")) != NULL) { probe_softc *softc; @@ -5406,28 +5507,27 @@ xpt_scan_lun(struct cam_periph *periph, struct cam_path *path, request_ccb); if (status != CAM_REQ_CMP) { - xpt_print_path(path); - kprintf("xpt_scan_lun: cam_alloc_periph returned an " - "error, can't continue probe\n"); + xpt_print(path, "xpt_scan_lun: cam_alloc_periph " + "returned an error, can't continue probe\n"); request_ccb->ccb_h.status = status; xpt_done(request_ccb); } } - crit_exit(); } static void xptscandone(struct cam_periph *periph, union ccb *done_ccb) { xpt_release_path(done_ccb->ccb_h.path); - kfree(done_ccb->ccb_h.path, M_TEMP); - kfree(done_ccb, M_TEMP); + kfree(done_ccb->ccb_h.path, M_CAMXPT); + kfree(done_ccb, M_CAMXPT); } static cam_status proberegister(struct cam_periph *periph, void *arg) { union ccb *request_ccb; /* CCB representing the probe request */ + cam_status status; probe_softc *softc; request_ccb = (union ccb *)arg; @@ -5442,13 +5542,18 @@ proberegister(struct cam_periph *periph, void *arg) return(CAM_REQ_CMP_ERR); } - softc = kmalloc(sizeof(*softc), M_TEMP, M_INTWAIT | M_ZERO); + softc = kmalloc(sizeof(*softc), M_CAMXPT, M_INTWAIT | M_ZERO); TAILQ_INIT(&softc->request_ccbs); TAILQ_INSERT_TAIL(&softc->request_ccbs, &request_ccb->ccb_h, periph_links.tqe); softc->flags = 0; periph->softc = softc; - cam_periph_acquire(periph); + status = cam_periph_acquire(periph); + if (status != CAM_REQ_CMP) { + return (status); + } + + /* * Ensure we've waited at least a bus settle * delay before attempting to probe the device. @@ -5480,7 +5585,7 @@ probeschedule(struct cam_periph *periph) * condition pending. It will not report the unit attention in * response to an inquiry, which may leave invalid transfer * negotiations in effect. The TUR will reveal the unit attention - * condition. Only send the TUR for lun 0, since some devices + * condition. Only send the TUR for lun 0, since some devices * will get confused by commands other than inquiry to non-existent * luns. If you think a device has gone away start your scan from * lun 0. This will insure that any bogus transfer settings are @@ -5526,6 +5631,7 @@ probestart(struct cam_periph *periph, union ccb *start_ccb) switch (softc->action) { case PROBE_TUR: case PROBE_TUR_FOR_NEGOTIATION: + case PROBE_DV_EXIT: { scsi_test_unit_ready(csio, /*retries*/4, @@ -5537,11 +5643,14 @@ probestart(struct cam_periph *periph, union ccb *start_ccb) } case PROBE_INQUIRY: case PROBE_FULL_INQUIRY: + case PROBE_INQUIRY_BASIC_DV1: + case PROBE_INQUIRY_BASIC_DV2: { u_int inquiry_len; struct scsi_inquiry_data *inq_buf; inq_buf = &periph->path->device->inq_data; + /* * If the device is currently configured, we calculate an * MD5 checksum of the inquiry data, and if the serial number @@ -5551,7 +5660,7 @@ probestart(struct cam_periph *periph, union ccb *start_ccb) * whether we still have the same device. */ if ((periph->path->device->flags & CAM_DEV_UNCONFIGURED) == 0) { - + MD5Init(&softc->context); MD5Update(&softc->context, (unsigned char *)inq_buf, sizeof(struct scsi_inquiry_data)); @@ -5563,14 +5672,12 @@ probestart(struct cam_periph *periph, union ccb *start_ccb) softc->flags |= PROBE_SERIAL_CKSUM; } MD5Final(softc->digest, &softc->context); - } + } if (softc->action == PROBE_INQUIRY) inquiry_len = SHORT_INQUIRY_LENGTH; else - inquiry_len = inq_buf->additional_length - + offsetof(struct scsi_inquiry_data, - additional_length) + 1; + inquiry_len = SID_ADDITIONAL_LENGTH(inq_buf); /* * Some parallel SCSI devices fail to send an @@ -5579,7 +5686,11 @@ probestart(struct cam_periph *periph, union ccb *start_ccb) * safe. */ inquiry_len = roundup2(inquiry_len, 2); - + + if (softc->action == PROBE_INQUIRY_BASIC_DV1 + || softc->action == PROBE_INQUIRY_BASIC_DV2) { + inq_buf = kmalloc(inquiry_len, M_CAMXPT, M_INTWAIT); + } scsi_inquiry(csio, /*retries*/4, probedone, @@ -5600,7 +5711,7 @@ probestart(struct cam_periph *periph, union ccb *start_ccb) mode_buf_len = sizeof(struct scsi_mode_header_6) + sizeof(struct scsi_mode_blk_desc) + sizeof(struct scsi_control_page); - mode_buf = kmalloc(mode_buf_len, M_TEMP, M_INTWAIT); + mode_buf = kmalloc(mode_buf_len, M_CAMXPT, M_INTWAIT); scsi_mode_sense(csio, /*retries*/4, probedone, @@ -5614,27 +5725,26 @@ probestart(struct cam_periph *periph, union ccb *start_ccb) /*timeout*/60000); break; } - case PROBE_SERIAL_NUM: + case PROBE_SERIAL_NUM_0: { - struct scsi_vpd_unit_serial_number *serial_buf; - struct cam_ed* device; + struct scsi_vpd_supported_page_list *vpd_list = NULL; + struct cam_ed *device; - serial_buf = NULL; device = periph->path->device; - device->serial_num = NULL; - device->serial_num_len = 0; - if ((device->quirk->quirks & CAM_QUIRK_NOSERIAL) == 0) { - serial_buf = kmalloc(sizeof(*serial_buf), M_TEMP, - M_INTWAIT | M_ZERO); + vpd_list = kmalloc(sizeof(*vpd_list), M_CAMXPT, + M_INTWAIT | M_ZERO); + } + + if (vpd_list != NULL) { scsi_inquiry(csio, /*retries*/4, probedone, MSG_SIMPLE_Q_TAG, - (u_int8_t *)serial_buf, - sizeof(*serial_buf), + (u_int8_t *)vpd_list, + sizeof(*vpd_list), /*evpd*/TRUE, - SVPD_UNIT_SERIAL_NUMBER, + SVPD_SUPPORTED_PAGE_LIST, SSD_MIN_SIZE, /*timeout*/60 * 1000); break; @@ -5647,6 +5757,31 @@ probestart(struct cam_periph *periph, union ccb *start_ccb) probedone(periph, start_ccb); return; } + case PROBE_SERIAL_NUM_1: + { + struct scsi_vpd_unit_serial_number *serial_buf; + struct cam_ed* device; + + serial_buf = NULL; + device = periph->path->device; + device->serial_num = NULL; + device->serial_num_len = 0; + + serial_buf = (struct scsi_vpd_unit_serial_number *) + kmalloc(sizeof(*serial_buf), M_CAMXPT, + M_INTWAIT | M_ZERO); + scsi_inquiry(csio, + /*retries*/4, + probedone, + MSG_SIMPLE_Q_TAG, + (u_int8_t *)serial_buf, + sizeof(*serial_buf), + /*evpd*/TRUE, + SVPD_UNIT_SERIAL_NUMBER, + SSD_MIN_SIZE, + /*timeout*/60 * 1000); + break; + } } xpt_action(start_ccb); } @@ -5668,6 +5803,111 @@ proberequestdefaultnegotiation(struct cam_periph *periph) xpt_action((union ccb *)&cts); } +/* + * Backoff Negotiation Code- only pertinent for SPI devices. + */ +static int +proberequestbackoff(struct cam_periph *periph, struct cam_ed *device) +{ + struct ccb_trans_settings cts; + struct ccb_trans_settings_spi *spi; + + memset(&cts, 0, sizeof (cts)); + xpt_setup_ccb(&cts.ccb_h, periph->path, /*priority*/1); + cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS; + cts.type = CTS_TYPE_CURRENT_SETTINGS; + xpt_action((union ccb *)&cts); + if ((cts.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { + if (bootverbose) { + xpt_print(periph->path, + "failed to get current device settings\n"); + } + return (0); + } + if (cts.transport != XPORT_SPI) { + if (bootverbose) { + xpt_print(periph->path, "not SPI transport\n"); + } + return (0); + } + spi = &cts.xport_specific.spi; + + /* + * We cannot renegotiate sync rate if we don't have one. + */ + if ((spi->valid & CTS_SPI_VALID_SYNC_RATE) == 0) { + if (bootverbose) { + xpt_print(periph->path, "no sync rate known\n"); + } + return (0); + } + + /* + * We'll assert that we don't have to touch PPR options- the + * SIM will see what we do with period and offset and adjust + * the PPR options as appropriate. + */ + + /* + * A sync rate with unknown or zero offset is nonsensical. + * A sync period of zero means Async. + */ + if ((spi->valid & CTS_SPI_VALID_SYNC_OFFSET) == 0 + || spi->sync_offset == 0 || spi->sync_period == 0) { + if (bootverbose) { + xpt_print(periph->path, "no sync rate available\n"); + } + return (0); + } + + if (device->flags & CAM_DEV_DV_HIT_BOTTOM) { + CAM_DEBUG(periph->path, CAM_DEBUG_INFO, + ("hit async: giving up on DV\n")); + return (0); + } + + + /* + * Jump sync_period up by one, but stop at 5MHz and fall back to Async. + * We don't try to remember 'last' settings to see if the SIM actually + * gets into the speed we want to set. We check on the SIM telling + * us that a requested speed is bad, but otherwise don't try and + * check the speed due to the asynchronous and handshake nature + * of speed setting. + */ + spi->valid = CTS_SPI_VALID_SYNC_RATE | CTS_SPI_VALID_SYNC_OFFSET; + for (;;) { + spi->sync_period++; + if (spi->sync_period >= 0xf) { + spi->sync_period = 0; + spi->sync_offset = 0; + CAM_DEBUG(periph->path, CAM_DEBUG_INFO, + ("setting to async for DV\n")); + /* + * Once we hit async, we don't want to try + * any more settings. + */ + device->flags |= CAM_DEV_DV_HIT_BOTTOM; + } else if (bootverbose) { + CAM_DEBUG(periph->path, CAM_DEBUG_INFO, + ("DV: period 0x%x\n", spi->sync_period)); + kprintf("setting period to 0x%x\n", spi->sync_period); + } + cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS; + cts.type = CTS_TYPE_CURRENT_SETTINGS; + xpt_action((union ccb *)&cts); + if ((cts.ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) { + break; + } + CAM_DEBUG(periph->path, CAM_DEBUG_INFO, + ("DV: failed to set period 0x%x\n", spi->sync_period)); + if (spi->sync_period == 0) { + return (0); + } + } + return (1); +} + static void probedone(struct cam_periph *periph, union ccb *done_ccb) { @@ -5711,7 +5951,7 @@ probedone(struct cam_periph *periph, union ccb *done_ccb) inq_buf = &path->device->inq_data; periph_qual = SID_QUAL(inq_buf); - + switch(periph_qual) { case SID_QUAL_LU_CONNECTED: { @@ -5731,7 +5971,7 @@ probedone(struct cam_periph *periph, union ccb *done_ccb) + offsetof(struct scsi_inquiry_data, additional_length) + 1; if (softc->action == PROBE_INQUIRY - && len > SHORT_INQUIRY_LENGTH) { + && len > SHORT_INQUIRY_LENGTH) { softc->action = PROBE_FULL_INQUIRY; xpt_release_ccb(done_ccb); xpt_schedule(periph, priority); @@ -5744,7 +5984,7 @@ probedone(struct cam_periph *periph, union ccb *done_ccb) if (INQ_DATA_TQ_ENABLED(inq_buf)) softc->action = PROBE_MODE_SENSE; else - softc->action = PROBE_SERIAL_NUM; + softc->action = PROBE_SERIAL_NUM_0; path->device->flags &= ~CAM_DEV_UNCONFIGURED; xpt_reference_device(path->device); @@ -5810,12 +6050,63 @@ probedone(struct cam_periph *periph, union ccb *done_ccb) /*count*/1, /*run_queue*/TRUE); } xpt_release_ccb(done_ccb); - kfree(mode_hdr, M_TEMP); - softc->action = PROBE_SERIAL_NUM; + kfree(mode_hdr, M_CAMXPT); + softc->action = PROBE_SERIAL_NUM_0; xpt_schedule(periph, priority); return; } - case PROBE_SERIAL_NUM: + case PROBE_SERIAL_NUM_0: + { + struct ccb_scsiio *csio; + struct scsi_vpd_supported_page_list *page_list; + int length, serialnum_supported, i; + + serialnum_supported = 0; + csio = &done_ccb->csio; + page_list = + (struct scsi_vpd_supported_page_list *)csio->data_ptr; + + if (page_list == NULL) { + /* + * Don't process the command as it was never sent + */ + } else if ((csio->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP + && (page_list->length > 0)) { + length = min(page_list->length, + SVPD_SUPPORTED_PAGES_SIZE); + for (i = 0; i < length; i++) { + if (page_list->list[i] == + SVPD_UNIT_SERIAL_NUMBER) { + serialnum_supported = 1; + break; + } + } + } else if (cam_periph_error(done_ccb, 0, + SF_RETRY_UA|SF_NO_PRINT, + &softc->saved_ccb) == ERESTART) { + 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, /*count*/1, + /*run_queue*/TRUE); + } + + if (page_list != NULL) + kfree(page_list, M_DEVBUF); + + if (serialnum_supported) { + xpt_release_ccb(done_ccb); + softc->action = PROBE_SERIAL_NUM_1; + xpt_schedule(periph, priority); + return; + } + xpt_release_ccb(done_ccb); + softc->action = PROBE_TUR_FOR_NEGOTIATION; + xpt_schedule(periph, done_ccb->ccb_h.pinfo.priority); + return; + } + + case PROBE_SERIAL_NUM_1: { struct ccb_scsiio *csio; struct scsi_vpd_unit_serial_number *serial_buf; @@ -5862,7 +6153,7 @@ probedone(struct cam_periph *periph, union ccb *done_ccb) xpt_release_devq(done_ccb->ccb_h.path, /*count*/1, /*run_queue*/TRUE); } - + /* * Let's see if we have seen this device before. */ @@ -5871,7 +6162,7 @@ probedone(struct cam_periph *periph, union ccb *done_ccb) u_int8_t digest[16]; MD5Init(&context); - + MD5Update(&context, (unsigned char *)&path->device->inq_data, sizeof(struct scsi_inquiry_data)); @@ -5893,7 +6184,7 @@ probedone(struct cam_periph *periph, union ccb *done_ccb) xpt_async(AC_LOST_DEVICE, path, NULL); } if (serial_buf != NULL) - kfree(serial_buf, M_TEMP); + kfree(serial_buf, M_CAMXPT); if (changed != 0) { /* @@ -5902,7 +6193,7 @@ probedone(struct cam_periph *periph, union ccb *done_ccb) * negotiations... Controllers don't perform * any negotiation or tagged queuing until * after the first XPT_SET_TRAN_SETTINGS ccb is - * received. So, on a new device, just retreive + * received. So, on a new device, just retrieve * the user settings, and set them as the current * settings to set the device up. */ @@ -5921,26 +6212,98 @@ probedone(struct cam_periph *periph, union ccb *done_ccb) break; } case PROBE_TUR_FOR_NEGOTIATION: + case PROBE_DV_EXIT: if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) { /* Don't wedge the queue */ xpt_release_devq(done_ccb->ccb_h.path, /*count*/1, /*run_queue*/TRUE); } - path->device->flags &= ~CAM_DEV_UNCONFIGURED; xpt_reference_device(path->device); - + /* + * Do Domain Validation for lun 0 on devices that claim + * to support Synchronous Transfer modes. + */ + if (softc->action == PROBE_TUR_FOR_NEGOTIATION + && done_ccb->ccb_h.target_lun == 0 + && (path->device->inq_data.flags & SID_Sync) != 0 + && (path->device->flags & CAM_DEV_IN_DV) == 0) { + CAM_DEBUG(periph->path, CAM_DEBUG_INFO, + ("Begin Domain Validation\n")); + path->device->flags |= CAM_DEV_IN_DV; + xpt_release_ccb(done_ccb); + softc->action = PROBE_INQUIRY_BASIC_DV1; + xpt_schedule(periph, priority); + return; + } + if (softc->action == PROBE_DV_EXIT) { + CAM_DEBUG(periph->path, CAM_DEBUG_INFO, + ("Leave Domain Validation\n")); + } + path->device->flags &= + ~(CAM_DEV_UNCONFIGURED|CAM_DEV_IN_DV|CAM_DEV_DV_HIT_BOTTOM); if ((softc->flags & PROBE_NO_ANNOUNCE) == 0) { /* Inform the XPT that a new device has been found */ done_ccb->ccb_h.func_code = XPT_GDEV_TYPE; xpt_action(done_ccb); + xpt_async(AC_FOUND_DEVICE, done_ccb->ccb_h.path, + done_ccb); + } + xpt_release_ccb(done_ccb); + break; + case PROBE_INQUIRY_BASIC_DV1: + case PROBE_INQUIRY_BASIC_DV2: + { + struct scsi_inquiry_data *nbuf; + struct ccb_scsiio *csio; + if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) { + /* Don't wedge the queue */ + xpt_release_devq(done_ccb->ccb_h.path, /*count*/1, + /*run_queue*/TRUE); + } + csio = &done_ccb->csio; + nbuf = (struct scsi_inquiry_data *)csio->data_ptr; + if (bcmp(nbuf, &path->device->inq_data, SHORT_INQUIRY_LENGTH)) { + xpt_print(path, + "inquiry data fails comparison at DV%d step\n", + softc->action == PROBE_INQUIRY_BASIC_DV1 ? 1 : 2); + if (proberequestbackoff(periph, path->device)) { + path->device->flags &= ~CAM_DEV_IN_DV; + softc->action = PROBE_TUR_FOR_NEGOTIATION; + } else { + /* give up */ + softc->action = PROBE_DV_EXIT; + } + kfree(nbuf, M_CAMXPT); + xpt_release_ccb(done_ccb); + xpt_schedule(periph, priority); + return; + } + kfree(nbuf, M_CAMXPT); + if (softc->action == PROBE_INQUIRY_BASIC_DV1) { + softc->action = PROBE_INQUIRY_BASIC_DV2; + xpt_release_ccb(done_ccb); + xpt_schedule(periph, priority); + return; + } + if (softc->action == PROBE_DV_EXIT) { + CAM_DEBUG(periph->path, CAM_DEBUG_INFO, + ("Leave Domain Validation Successfully\n")); + } + path->device->flags &= + ~(CAM_DEV_UNCONFIGURED|CAM_DEV_IN_DV|CAM_DEV_DV_HIT_BOTTOM); + if ((softc->flags & PROBE_NO_ANNOUNCE) == 0) { + /* Inform the XPT that a new device has been found */ + done_ccb->ccb_h.func_code = XPT_GDEV_TYPE; + xpt_action(done_ccb); xpt_async(AC_FOUND_DEVICE, done_ccb->ccb_h.path, done_ccb); } xpt_release_ccb(done_ccb); break; } + } done_ccb = (union ccb *)TAILQ_FIRST(&softc->request_ccbs); TAILQ_REMOVE(&softc->request_ccbs, &done_ccb->ccb_h, periph_links.tqe); done_ccb->ccb_h.status = CAM_REQ_CMP; @@ -5956,7 +6319,7 @@ probedone(struct cam_periph *periph, union ccb *done_ccb) static void probecleanup(struct cam_periph *periph) { - kfree(periph->softc, M_TEMP); + kfree(periph->softc, M_CAMXPT); } static void @@ -5981,7 +6344,7 @@ sysctl_cam_search_luns(SYSCTL_HANDLER_ARGS) int error, bool; bool = cam_srch_hi; - error = sysctl_handle_int(oidp, &bool, sizeof(bool), req); + error = sysctl_handle_int(oidp, &bool, 0, req); if (error != 0 || req->newptr == NULL) return (error); if (bool == 0 || bool == 1) { @@ -6100,17 +6463,16 @@ xpt_set_transfer_settings(struct ccb_trans_settings *cts, struct cam_ed *device, cts->protocol_version = device->protocol_version; if (cts->protocol != device->protocol) { - xpt_print_path(cts->ccb_h.path); - kprintf("Uninitialized Protocol %x:%x?\n", + xpt_print(cts->ccb_h.path, "Uninitialized Protocol %x:%x?\n", cts->protocol, device->protocol); cts->protocol = device->protocol; } if (cts->protocol_version > device->protocol_version) { if (bootverbose) { - xpt_print_path(cts->ccb_h.path); - kprintf("Down reving Protocol Version from %d to %d?\n", - cts->protocol_version, device->protocol_version); + xpt_print(cts->ccb_h.path, "Down reving Protocol " + "Version from %d to %d?\n", cts->protocol_version, + device->protocol_version); } cts->protocol_version = device->protocol_version; } @@ -6126,18 +6488,16 @@ xpt_set_transfer_settings(struct ccb_trans_settings *cts, struct cam_ed *device, cts->transport_version = device->transport_version; if (cts->transport != device->transport) { - xpt_print_path(cts->ccb_h.path); - kprintf("Uninitialized Transport %x:%x?\n", - cts->transport, device->transport); + xpt_print(cts->ccb_h.path, "Uninitialized Transport %x:%x?\n", + cts->transport, device->transport); cts->transport = device->transport; } if (cts->transport_version > device->transport_version) { if (bootverbose) { - xpt_print_path(cts->ccb_h.path); - kprintf("Down reving Transport Version from %d to %d?\n", - cts->transport_version, - device->transport_version); + xpt_print(cts->ccb_h.path, "Down reving Transport " + "Version from %d to %d?\n", cts->transport_version, + device->transport_version); } cts->transport_version = device->transport_version; } @@ -6418,7 +6778,7 @@ xpt_start_tags(struct cam_path *path) crs.ccb_h.func_code = XPT_REL_SIMQ; crs.release_flags = RELSIM_RELEASE_AFTER_QEMPTY; crs.openings - = crs.release_timeout + = crs.release_timeout = crs.qfrozen_cnt = 0; xpt_action((union ccb *)&crs); @@ -6430,6 +6790,9 @@ static int busses_to_reset; static int xptconfigbuscountfunc(struct cam_eb *bus, void *arg) { + + sim_lock_assert_owned(bus->sim->lock); + if (bus->path_id != CAM_XPT_PATH_ID) { struct cam_path path; struct ccb_pathinq cpi; @@ -6458,6 +6821,8 @@ xptconfigfunc(struct cam_eb *bus, void *arg) struct cam_path *path; union ccb *work_ccb; + sim_lock_assert_owned(bus->sim->lock); + if (bus->path_id != CAM_XPT_PATH_ID) { cam_status status; int can_negotiate; @@ -6522,6 +6887,11 @@ xpt_config(void *arg) #endif /* CAM_DEBUG_FLAGS */ #ifdef CAM_DEBUG_BUS if (cam_dflags != CAM_DEBUG_NONE) { + /* + * Locking is specifically omitted here. No SIMs have + * registered yet, so xpt_create_path will only be searching + * empty lists of targets and devices. + */ if (xpt_create_path(&cam_dpath, xpt_periph, CAM_DEBUG_BUS, CAM_DEBUG_TARGET, CAM_DEBUG_LUN) != CAM_REQ_CMP) { @@ -6577,11 +6947,40 @@ xptpassannouncefunc(struct cam_ed *device, void *arg) } static void -xpt_finishconfig(struct cam_periph *periph, union ccb *done_ccb) +xpt_finishconfig_task(void *context, int pending) { struct periph_driver **p_drv; int i; + if (busses_to_config == 0) { + /* Register all the peripheral drivers */ + /* XXX This will have to change when we have loadable modules */ + p_drv = periph_drivers; + for (i = 0; p_drv[i] != NULL; i++) { + (*p_drv[i]->init)(); + } + + /* + * Check for devices with no "standard" peripheral driver + * attached. For any devices like that, announce the + * passthrough driver so the user will see something. + */ + xpt_for_all_devices(xptpassannouncefunc, NULL); + + /* Release our hook so that the boot can continue. */ + config_intrhook_disestablish(xsoftc.xpt_config_hook); + kfree(xsoftc.xpt_config_hook, M_CAMXPT); + xsoftc.xpt_config_hook = NULL; + } + + kfree(context, M_CAMXPT); +} + +static void +xpt_finishconfig(struct cam_periph *periph, union ccb *done_ccb) +{ + struct xpt_task *task; + if (done_ccb != NULL) { CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_TRACE, ("xpt_finishconfig\n")); @@ -6604,29 +7003,48 @@ xpt_finishconfig(struct cam_periph *periph, union ccb *done_ccb) } if (busses_to_config == 0) { - /* Register all the peripheral drivers */ - /* XXX This will have to change when we have loadable modules */ - p_drv = periph_drivers; - for (i = 0; p_drv[i] != NULL; i++) { - (*p_drv[i]->init)(); - } - - /* - * Check for devices with no "standard" peripheral driver - * attached. For any devices like that, announce the - * passthrough driver so the user will see something. - */ - xpt_for_all_devices(xptpassannouncefunc, NULL); - - /* Release our hook so that the boot can continue. */ - config_intrhook_disestablish(xpt_config_hook); - kfree(xpt_config_hook, M_TEMP); - xpt_config_hook = NULL; + task = kmalloc(sizeof(struct xpt_task), M_CAMXPT, M_INTWAIT); + TASK_INIT(&task->task, 0, xpt_finishconfig_task, task); + taskqueue_enqueue(taskqueue_thread[mycpuid], &task->task); } + if (done_ccb != NULL) xpt_free_ccb(done_ccb); } +cam_status +xpt_register_async(int event, ac_callback_t *cbfunc, void *cbarg, + struct cam_path *path) +{ + struct ccb_setasync csa; + cam_status status; + int xptpath = 0; + + if (path == NULL) { + lockmgr(&xsoftc.xpt_lock, LK_EXCLUSIVE); + status = xpt_create_path(&path, /*periph*/NULL, CAM_XPT_PATH_ID, + CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD); + if (status != CAM_REQ_CMP) { + lockmgr(&xsoftc.xpt_lock, LK_RELEASE); + return (status); + } + xptpath = 1; + } + + xpt_setup_ccb(&csa.ccb_h, path, /*priority*/5); + csa.ccb_h.func_code = XPT_SASYNC_CB; + csa.event_enable = event; + csa.callback = cbfunc; + csa.callback_arg = cbarg; + xpt_action((union ccb *)&csa); + status = csa.ccb_h.status; + if (xptpath) { + xpt_free_path(path); + lockmgr(&xsoftc.xpt_lock, LK_RELEASE); + } + return (status); +} + static void xptaction(struct cam_sim *sim, union ccb *work_ccb) { @@ -6677,6 +7095,19 @@ xptpoll(struct cam_sim *sim) { } +void +xpt_lock_buses(void) +{ + lockmgr(&xsoftc.xpt_topo_lock, LK_EXCLUSIVE); +} + +void +xpt_unlock_buses(void) +{ + lockmgr(&xsoftc.xpt_topo_lock, LK_RELEASE); +} + + /* * Should only be called by the machine interrupt dispatch routines, * so put these prototypes here instead of in the header. @@ -6685,21 +7116,40 @@ xptpoll(struct cam_sim *sim) static void swi_cambio(void *arg, void *frame) { - camisr(&cam_bioq); + camisr(NULL); } static void -camisr(cam_isrq_t *queue) +camisr(void *dummy) { + cam_simq_t queue; + struct cam_sim *sim; + + lockmgr(&cam_simq_lock, LK_EXCLUSIVE); + TAILQ_INIT(&queue); + TAILQ_CONCAT(&queue, &cam_simq, links); + lockmgr(&cam_simq_lock, LK_RELEASE); + + while ((sim = TAILQ_FIRST(&queue)) != NULL) { + TAILQ_REMOVE(&queue, sim, links); + CAM_SIM_LOCK(sim); + sim->flags &= ~CAM_SIM_ON_DONEQ; + camisr_runqueue(&sim->sim_doneq); + CAM_SIM_UNLOCK(sim); + } +} + +static void +camisr_runqueue(void *V_queue) +{ + cam_isrq_t *queue = V_queue; struct ccb_hdr *ccb_h; - crit_enter(); while ((ccb_h = TAILQ_FIRST(queue)) != NULL) { int runq; TAILQ_REMOVE(queue, ccb_h, sim_links.tqe); ccb_h->pinfo.index = CAM_UNQUEUED_INDEX; - splz(); CAM_DEBUG(ccb_h->path, CAM_DEBUG_TRACE, ("camisr\n")); @@ -6711,27 +7161,31 @@ camisr(cam_isrq_t *queue) struct cam_ed *device; union ccb *send_ccb; - hphead = &highpowerq; + lockmgr(&xsoftc.xpt_lock, LK_EXCLUSIVE); + hphead = &xsoftc.highpowerq; send_ccb = (union ccb *)STAILQ_FIRST(hphead); /* * Increment the count since this command is done. */ - num_highpower++; + xsoftc.num_highpower++; - /* + /* * Any high powered commands queued up? */ if (send_ccb != NULL) { device = send_ccb->ccb_h.path->device; STAILQ_REMOVE_HEAD(hphead, xpt_links.stqe); + lockmgr(&xsoftc.xpt_lock, LK_RELEASE); xpt_release_devq(send_ccb->ccb_h.path, /*count*/1, /*runqueue*/TRUE); - } + } else + lockmgr(&xsoftc.xpt_lock, LK_RELEASE); } + if ((ccb_h->func_code & XPT_FC_USER_CCB) == 0) { struct cam_ed *dev; @@ -6743,12 +7197,12 @@ camisr(cam_isrq_t *queue) ccb_h->path->bus->sim->devq->send_active--; ccb_h->path->bus->sim->devq->send_openings++; } - + if (((dev->flags & CAM_DEV_REL_ON_COMPLETE) != 0 && (ccb_h->status&CAM_STATUS_MASK) != CAM_REQUEUE_REQ) || ((dev->flags & CAM_DEV_REL_ON_QUEUE_EMPTY) != 0 && (dev->ccbq.dev_active == 0))) { - + xpt_release_devq(ccb_h->path, /*count*/1, /*run_queue*/TRUE); } @@ -6770,7 +7224,7 @@ camisr(cam_isrq_t *queue) /*run_queue*/TRUE); ccb_h->status &= ~CAM_RELEASE_SIMQ; runq = FALSE; - } + } if ((ccb_h->flags & CAM_DEV_QFRZDIS) && (ccb_h->status & CAM_DEV_QFRZN)) { @@ -6784,7 +7238,6 @@ camisr(cam_isrq_t *queue) /* Call the peripheral driver's callback */ (*ccb_h->cbfcnp)(ccb_h->path->periph, (union ccb *)ccb_h); } - crit_exit(); } static void diff --git a/sys/bus/cam/cam_xpt.h b/sys/bus/cam/cam_xpt.h index 7b132b7..4d6cfe3 100644 --- a/sys/bus/cam/cam_xpt.h +++ b/sys/bus/cam/cam_xpt.h @@ -59,10 +59,15 @@ cam_status xpt_create_path(struct cam_path **new_path_ptr, struct cam_periph *perph, path_id_t path_id, target_id_t target_id, lun_id_t lun_id); +cam_status xpt_create_path_unlocked(struct cam_path **new_path_ptr, + struct cam_periph *perph, + path_id_t path_id, + target_id_t target_id, lun_id_t lun_id); void xpt_free_path(struct cam_path *path); int xpt_path_comp(struct cam_path *path1, struct cam_path *path2); void xpt_print_path(struct cam_path *path); +void xpt_print(struct cam_path *path, const char *fmt, ...); int xpt_path_string(struct cam_path *path, char *str, size_t str_len); path_id_t xpt_path_path_id(struct cam_path *path); @@ -72,6 +77,11 @@ struct cam_sim *xpt_path_sim(struct cam_path *path); struct cam_periph *xpt_path_periph(struct cam_path *path); void xpt_async(u_int32_t async_code, struct cam_path *path, void *async_arg); +void xpt_rescan(union ccb *ccb); +void xpt_lock_buses(void); +void xpt_unlock_buses(void); +cam_status xpt_register_async(int event, ac_callback_t *cbfunc, + void *cbarg, struct cam_path *path); #endif /* _KERNEL */ #endif /* _CAM_CAM_XPT_H */ diff --git a/sys/bus/cam/scsi/scsi_all.c b/sys/bus/cam/scsi/scsi_all.c index 3f209d5..a8a615f 100644 --- a/sys/bus/cam/scsi/scsi_all.c +++ b/sys/bus/cam/scsi/scsi_all.c @@ -732,8 +732,6 @@ scsi_op_desc(u_int16_t opcode, struct scsi_inquiry_data *inq_data) #endif -#include - #if !defined(SCSI_NO_SENSE_STRINGS) #define SST(asc, ascq, action, desc) \ asc, ascq, action, desc @@ -2997,7 +2995,7 @@ sysctl_scsi_delay(SYSCTL_HANDLER_ARGS) int error, delay; delay = scsi_delay; - error = sysctl_handle_int(oidp, &delay, sizeof(delay), req); + error = sysctl_handle_int(oidp, &delay, 0, req); if (error != 0 || req->newptr == NULL) return (error); return (set_scsi_delay(delay)); diff --git a/sys/bus/cam/scsi/scsi_all.h b/sys/bus/cam/scsi/scsi_all.h index 8a4852c..63cac41 100644 --- a/sys/bus/cam/scsi/scsi_all.h +++ b/sys/bus/cam/scsi/scsi_all.h @@ -176,8 +176,11 @@ struct scsi_mode_sense_6 #define SMS_PAGE_CODE 0x3F #define SMS_VENDOR_SPECIFIC_PAGE 0x00 #define SMS_DISCONNECT_RECONNECT_PAGE 0x02 +#define SMS_CACHE_PAGE 0x08 #define SMS_PERIPHERAL_DEVICE_PAGE 0x09 #define SMS_CONTROL_MODE_PAGE 0x0A +#define SMS_PROTO_SPECIFIC_PAGE 0x19 +#define SMS_INFO_EXCEPTIONS_PAGE 0x1C #define SMS_ALL_PAGES_PAGE 0x3F #define SMS_PAGE_CTRL_MASK 0xC0 #define SMS_PAGE_CTRL_CURRENT 0x00 @@ -263,6 +266,8 @@ struct scsi_log_sense #define SLS_ERROR_VERIFY_PAGE 0x05 #define SLS_ERROR_NONMEDIUM_PAGE 0x06 #define SLS_ERROR_LASTN_PAGE 0x07 +#define SLS_SELF_TEST_PAGE 0x10 +#define SLS_IE_PAGE 0x2f #define SLS_PAGE_CTRL_MASK 0xC0 #define SLS_PAGE_CTRL_THRESHOLD 0x00 #define SLS_PAGE_CTRL_CUMULATIVE 0x40 @@ -335,6 +340,55 @@ struct scsi_control_page { u_int8_t aen_holdoff_period[2]; }; +struct scsi_cache_page { + u_int8_t page_code; +#define SCHP_PAGE_SAVABLE 0x80 /* Page is savable */ + u_int8_t page_length; + u_int8_t cache_flags; +#define SCHP_FLAGS_WCE 0x04 /* Write Cache Enable */ +#define SCHP_FLAGS_MF 0x02 /* Multiplication factor */ +#define SCHP_FLAGS_RCD 0x01 /* Read Cache Disable */ + u_int8_t rw_cache_policy; + u_int8_t dis_prefetch[2]; + u_int8_t min_prefetch[2]; + u_int8_t max_prefetch[2]; + u_int8_t max_prefetch_ceil[2]; +}; + +struct scsi_info_exceptions_page { + u_int8_t page_code; +#define SIEP_PAGE_SAVABLE 0x80 /* Page is savable */ + u_int8_t page_length; + u_int8_t info_flags; +#define SIEP_FLAGS_PERF 0x80 +#define SIEP_FLAGS_EBF 0x20 +#define SIEP_FLAGS_EWASC 0x10 +#define SIEP_FLAGS_DEXCPT 0x08 +#define SIEP_FLAGS_TEST 0x04 +#define SIEP_FLAGS_EBACKERR 0x02 +#define SIEP_FLAGS_LOGERR 0x01 + u_int8_t mrie; + u_int8_t interval_timer[4]; + u_int8_t report_count[4]; +}; + +struct scsi_proto_specific_page { + u_int8_t page_code; +#define SPSP_PAGE_SAVABLE 0x80 /* Page is savable */ + u_int8_t page_length; + u_int8_t protocol; +#define SPSP_PROTO_FC 0x00 +#define SPSP_PROTO_SPI 0x01 +#define SPSP_PROTO_SSA 0x02 +#define SPSP_PROTO_1394 0x03 +#define SPSP_PROTO_RDMA 0x04 +#define SPSP_PROTO_ISCSI 0x05 +#define SPSP_PROTO_SAS 0x06 +#define SPSP_PROTO_ADT 0x07 +#define SPSP_PROTO_ATA 0x08 +#define SPSP_PROTO_NONE 0x0f +}; + struct scsi_reserve { u_int8_t opcode; @@ -475,6 +529,47 @@ struct scsi_start_stop_unit u_int8_t control; }; +struct ata_pass_12 { + u_int8_t opcode; + u_int8_t protocol; +#define AP_MULTI 0xe0 + u_int8_t flags; +#define AP_T_LEN 0x03 +#define AP_BB 0x04 +#define AP_T_DIR 0x08 +#define AP_CK_COND 0x20 +#define AP_OFFLINE 0x60 + u_int8_t features; + u_int8_t sector_count; + u_int8_t lba_low; + u_int8_t lba_mid; + u_int8_t lba_high; + u_int8_t device; + u_int8_t command; + u_int8_t reserved; + u_int8_t control; +}; + +struct ata_pass_16 { + u_int8_t opcode; + u_int8_t protocol; +#define AP_EXTEND 0x01 + u_int8_t flags; + u_int8_t features_ext; + u_int8_t features; + u_int8_t sector_count_ext; + u_int8_t sector_count; + u_int8_t lba_low_ext; + u_int8_t lba_low; + u_int8_t lba_mid_ext; + u_int8_t lba_mid; + u_int8_t lba_high_ext; + u_int8_t lba_high; + u_int8_t device; + u_int8_t command; + u_int8_t control; +}; + #define SC_SCSI_1 0x01 #define SC_SCSI_2 0x03 @@ -501,17 +596,20 @@ struct scsi_start_stop_unit #define WRITE_10 0x2a #define POSITION_TO_ELEMENT 0x2b #define SYNCHRONIZE_CACHE 0x35 +#define READ_DEFECT_DATA_10 0x37 #define WRITE_BUFFER 0x3b #define READ_BUFFER 0x3c #define CHANGE_DEFINITION 0x40 #define LOG_SELECT 0x4c #define LOG_SENSE 0x4d #define MODE_SELECT_10 0x55 -#define MODE_SENSE_10 0x5A +#define MODE_SENSE_10 0x5a +#define ATA_PASS_16 0x85 #define READ_16 0x88 #define WRITE_16 0x8a #define SERVICE_ACTION_IN 0x9e #define REPORT_LUNS 0xa0 +#define ATA_PASS_12 0xa1 #define MOVE_MEDIUM 0xa5 #define READ_12 0xa8 #define WRITE_12 0xaa @@ -605,6 +703,9 @@ struct scsi_inquiry_data #define SID_AENC 0x80 #define SID_TrmIOP 0x40 u_int8_t additional_length; +#define SID_ADDITIONAL_LENGTH(iqd) \ + ((iqd)->additional_length + \ + offsetof(struct scsi_inquiry_data, additional_length) + 1) u_int8_t reserved; u_int8_t spc2_flags; #define SPC2_SID_MChngr 0x08 @@ -667,6 +768,17 @@ struct scsi_inquiry_data u_int8_t vendor_specific1[SID_VENDOR_SPECIFIC_1_SIZE]; }; +struct scsi_vpd_supported_page_list +{ + u_int8_t device; + u_int8_t page_code; +#define SVPD_SUPPORTED_PAGE_LIST 0x00 + u_int8_t reserved; + u_int8_t length; /* number of VPD entries */ +#define SVPD_SUPPORTED_PAGES_SIZE 251 + u_int8_t list[SVPD_SUPPORTED_PAGES_SIZE]; +}; + struct scsi_vpd_unit_serial_number { u_int8_t device; diff --git a/sys/bus/cam/scsi/scsi_cd.c b/sys/bus/cam/scsi/scsi_cd.c index 7c8ae1f..4155fbc 100644 --- a/sys/bus/cam/scsi/scsi_cd.c +++ b/sys/bus/cam/scsi/scsi_cd.c @@ -74,6 +74,7 @@ #include "../cam_periph.h" #include "../cam_xpt_periph.h" #include "../cam_queue.h" +#include "../cam_sim.h" #include "scsi_message.h" #include "scsi_da.h" @@ -107,8 +108,8 @@ typedef enum { CD_FLAG_RETRY_UA = 0x0200, CD_FLAG_VALID_MEDIA = 0x0400, CD_FLAG_VALID_TOC = 0x0800, - CD_FLAG_OPEN = 0x1000, - CD_FLAG_SCTX_INIT = 0x2000 + CD_FLAG_SCTX_INIT = 0x1000, + CD_FLAG_OPEN = 0x2000 } cd_flags; typedef enum { @@ -296,10 +297,6 @@ static struct periph_driver cddriver = PERIPHDRIVER_DECLARE(cd, cddriver); -/* For 2.2-stable support */ -#ifndef D_DISK -#define D_DISK 0 -#endif static struct dev_ops cd_ops = { { "cd", SCSICD_CDEV_MAJOR, D_DISK }, .d_open = cdopen, @@ -311,7 +308,6 @@ static struct dev_ops cd_ops = { }; static struct extend_array *cdperiphs; -static int num_changers; #ifndef CHANGER_MIN_BUSY_SECONDS #define CHANGER_MIN_BUSY_SECONDS 5 @@ -346,13 +342,19 @@ struct cdchanger { STAILQ_HEAD(chdevlist, cd_softc) chluns; }; +static struct lock changerq_lock; static STAILQ_HEAD(changerlist, cdchanger) changerq; +static int num_changers; + +MALLOC_DEFINE(M_SCSICD, "scsi_cd", "scsi_cd buffers"); static void cdinit(void) { cam_status status; - struct cam_path *path; + + lockinit(&changerq_lock, "cdchangerq", 0, LK_CANRECURSE); + STAILQ_INIT(&changerq); /* * Create our extend array for storing the devices we attach to. @@ -367,21 +369,7 @@ cdinit(void) * Install a global async callback. This callback will * receive async callbacks like "new device found". */ - status = xpt_create_path(&path, /*periph*/NULL, CAM_XPT_PATH_ID, - CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD); - - if (status == CAM_REQ_CMP) { - struct ccb_setasync csa; - - xpt_setup_ccb(&csa.ccb_h, path, /*priority*/5); - csa.ccb_h.func_code = XPT_SASYNC_CB; - csa.event_enable = AC_FOUND_DEVICE; - csa.callback = cdasync; - csa.callback_arg = NULL; - xpt_action((union ccb *)&csa); - status = csa.ccb_h.status; - xpt_free_path(path); - } + status = xpt_register_async(AC_FOUND_DEVICE, cdasync, NULL, NULL); if (status != CAM_REQ_CMP) { kprintf("cd: Failed to attach master async callback " @@ -395,31 +383,17 @@ cdoninvalidate(struct cam_periph *periph) struct cd_softc *softc; struct buf *q_bp; struct bio *q_bio; - struct ccb_setasync csa; softc = (struct cd_softc *)periph->softc; /* * De-register any async callbacks. */ - xpt_setup_ccb(&csa.ccb_h, periph->path, - /* priority */ 5); - csa.ccb_h.func_code = XPT_SASYNC_CB; - csa.event_enable = 0; - csa.callback = cdasync; - csa.callback_arg = periph; - xpt_action((union ccb *)&csa); + xpt_register_async(0, cdasync, periph, periph->path); softc->flags |= CD_FLAG_INVALID; /* - * Although the oninvalidate() routines are always while in a - * critical section, we need to be in a critical section here to - * keep the buffer queue from being modified while we traverse it. - */ - crit_enter(); - - /* * Return all queued I/O with ENXIO. * XXX Handle any transactions queued to the card * with XPT_ABORT_CCB. @@ -432,7 +406,6 @@ cdoninvalidate(struct cam_periph *periph) q_bp->b_flags |= B_ERROR; biodone(q_bio); } - crit_exit(); /* * If this device is part of a changer, and it was scheduled @@ -443,8 +416,7 @@ cdoninvalidate(struct cam_periph *periph) && (softc->pinfo.index != CAM_UNQUEUED_INDEX)) camq_remove(&softc->changer->devq, softc->pinfo.index); - xpt_print_path(periph->path); - kprintf("lost device\n"); + xpt_print(periph->path, "lost device\n"); } static void @@ -454,16 +426,13 @@ cdcleanup(struct cam_periph *periph) softc = (struct cd_softc *)periph->softc; - xpt_print_path(periph->path); - kprintf("removing device entry\n"); + xpt_print(periph->path, "removing device entry\n"); if ((softc->flags & CD_FLAG_SCTX_INIT) != 0 && sysctl_ctx_free(&softc->sysctl_ctx) != 0) { - xpt_print_path(periph->path); - kprintf("can't remove sysctl context\n"); + xpt_print(periph->path, "can't remove sysctl context\n"); } - crit_enter(); /* * In the queued, non-active case, the device in question * has already been removed from the changer run queue. Since this @@ -523,20 +492,22 @@ cdcleanup(struct cam_periph *periph) softc->changer->flags &= ~CHANGER_SHORT_TMOUT_SCHED; } + lockmgr(&changerq_lock, LK_EXCLUSIVE); STAILQ_REMOVE(&changerq, softc->changer, cdchanger, changer_links); - xpt_print_path(periph->path); - kprintf("removing changer entry\n"); - kfree(softc->changer, M_DEVBUF); num_changers--; + lockmgr(&changerq_lock, LK_RELEASE); + xpt_print(periph->path, "removing changer entry\n"); + kfree(softc->changer, M_DEVBUF); } devstat_remove_entry(&softc->device_stats); cam_extend_release(cdperiphs, periph->unit_number); if (softc->disk.d_rawdev) { + cam_periph_unlock(periph); disk_destroy(&softc->disk); + cam_periph_lock(periph); } kfree(softc, M_DEVBUF); - crit_exit(); } static void @@ -585,7 +556,6 @@ cdasync(void *callback_arg, u_int32_t code, struct ccb_hdr *ccbh; softc = (struct cd_softc *)periph->softc; - crit_enter(); /* * Don't fail on the expected unit attention * that will occur. @@ -593,7 +563,6 @@ cdasync(void *callback_arg, u_int32_t code, softc->flags |= CD_FLAG_RETRY_UA; LIST_FOREACH(ccbh, &softc->pending_ccbs, periph_links.le) ccbh->ccb_state |= CD_CCB_RETRY_UA; - crit_exit(); /* FALLTHROUGH */ } default: @@ -610,8 +579,10 @@ cdsysctlinit(void *context, int pending) char tmpstr[80], tmpstr2[80]; periph = (struct cam_periph *)context; - softc = (struct cd_softc *)periph->softc; + if (cam_periph_acquire(periph) != CAM_REQ_CMP) + return; + softc = (struct cd_softc *)periph->softc; ksnprintf(tmpstr, sizeof(tmpstr), "CAM CD unit %d", periph->unit_number); ksnprintf(tmpstr2, sizeof(tmpstr2), "%d", periph->unit_number); @@ -623,6 +594,7 @@ cdsysctlinit(void *context, int pending) if (softc->sysctl_tree == NULL) { kprintf("cdsysctlinit: unable to allocate sysctl tree\n"); + cam_periph_release(periph); return; } @@ -634,6 +606,8 @@ cdsysctlinit(void *context, int pending) OID_AUTO, "minimum_cmd_size", CTLTYPE_INT | CTLFLAG_RW, &softc->minimum_command_size, 0, cdcmdsizesysctl, "I", "Minimum CDB size"); + + cam_periph_release(periph); } /* @@ -677,7 +651,6 @@ static cam_status cdregister(struct cam_periph *periph, void *arg) { struct cd_softc *softc; - struct ccb_setasync csa; struct ccb_pathinq cpi; struct ccb_getdev *cgd; char tmpstr[80]; @@ -761,6 +734,7 @@ cdregister(struct cam_periph *periph, void *arg) * WORM peripheral driver. WORM drives will also have the WORM * driver attached to them. */ + cam_periph_unlock(periph); devstat_add_entry(&softc->device_stats, "cd", periph->unit_number, 0, DEVSTAT_BS_UNAVAILABLE, @@ -770,18 +744,14 @@ cdregister(struct cam_periph *periph, void *arg) softc->disk.d_rawdev->si_iosize_max = MAXPHYS; softc->disk.d_info.d_dsflags = DSO_ONESLICE | DSO_COMPATLABEL | DSO_COMPATPARTA; + cam_periph_lock(periph); /* * Add an async callback so that we get * notified if this device goes away. */ - xpt_setup_ccb(&csa.ccb_h, periph->path, - /* priority */ 5); - csa.ccb_h.func_code = XPT_SASYNC_CB; - csa.event_enable = AC_SENT_BDR | AC_BUS_RESET | AC_LOST_DEVICE; - csa.callback = cdasync; - csa.callback_arg = periph; - xpt_action((union ccb *)&csa); + xpt_register_async(AC_SENT_BDR | AC_BUS_RESET | AC_LOST_DEVICE, + cdasync, periph, periph->path); /* * If the target lun is greater than 0, we most likely have a CD @@ -804,13 +774,11 @@ cdregister(struct cam_periph *periph, void *arg) /* Set the changer flag in the current device's softc */ softc->flags |= CD_FLAG_CHANGER; - if (num_changers == 0) - STAILQ_INIT(&changerq); - /* * Now, look around for an existing changer device with the * same path and target ID as the current device. */ + lockmgr(&changerq_lock, LK_EXCLUSIVE); for (found = 0, nchanger = (struct cdchanger *)STAILQ_FIRST(&changerq); nchanger != NULL; @@ -821,6 +789,7 @@ cdregister(struct cam_periph *periph, void *arg) break; } } + lockmgr(&changerq_lock, LK_RELEASE); /* * If we found a matching entry, just add this device to @@ -911,8 +880,6 @@ cdregister(struct cam_periph *periph, void *arg) goto cdregisterexit; } - num_changers++; - nchanger->path_id = cgd->ccb_h.path_id; nchanger->target_id = cgd->ccb_h.target_id; @@ -921,8 +888,14 @@ cdregister(struct cam_periph *periph, void *arg) STAILQ_INIT(&nchanger->chluns); + callout_init(&nchanger->long_handle); + callout_init(&nchanger->short_handle); + + lockmgr(&changerq_lock, LK_EXCLUSIVE); + num_changers++; STAILQ_INSERT_TAIL(&changerq, nchanger, changer_links); + lockmgr(&changerq_lock, LK_RELEASE); /* * Create a path with lun id 0, and see if we can @@ -984,9 +957,11 @@ cdregister(struct cam_periph *periph, void *arg) cdregisterexit: - /* Lock this peripheral until we are setup */ - /* Can't block */ - cam_periph_lock(periph, 0); + /* + * Refcount and block open attempts until we are setup + * Can't block + */ + cam_periph_hold(periph, 0); if ((softc->flags & CD_FLAG_CHANGER) == 0) xpt_schedule(periph, /*priority*/5); @@ -1012,24 +987,28 @@ cdopen(struct dev_open_args *ap) softc = (struct cd_softc *)periph->softc; - /* - * Grab a critical section and hold it until we lock the peripheral. - */ - crit_enter(); + if (cam_periph_acquire(periph) != CAM_REQ_CMP) + return(ENXIO); + + cam_periph_lock(periph); + if (softc->flags & CD_FLAG_INVALID) { - crit_exit(); + cam_periph_unlock(periph); + cam_periph_release(periph); return(ENXIO); } - if ((error = cam_periph_lock(periph, PCATCH)) != 0) { - crit_exit(); + if ((error = cam_periph_hold(periph, PCATCH)) != 0) { + cam_periph_unlock(periph); + cam_periph_release(periph); return (error); } - crit_exit(); - - if (cam_periph_acquire(periph) != CAM_REQ_CMP) - return(ENXIO); + /* Closes aren't symmetrical with opens, so fix up the refcounting. */ + if (softc->flags & CD_FLAG_OPEN) + cam_periph_release(periph); + else + softc->flags |= CD_FLAG_OPEN; /* * Check for media, and set the appropriate flags. We don't bail @@ -1045,11 +1024,11 @@ cdopen(struct dev_open_args *ap) if (error == 0) softc->flags |= CD_FLAG_OPEN; - cam_periph_unlock(periph); - CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("leaving cdopen\n")); + cam_periph_unhold(periph); + cam_periph_unlock(periph); - return (error); + return (0); } static int @@ -1059,7 +1038,7 @@ cdclose(struct dev_close_args *ap) struct cam_periph *periph; struct cd_softc *softc; struct disk_info *info; - int unit, error; + int unit; unit = dkunit(dev); periph = cam_extend_get(cdperiphs, unit); @@ -1068,8 +1047,8 @@ cdclose(struct dev_close_args *ap) softc = (struct cd_softc *)periph->softc; - if ((error = cam_periph_lock(periph, 0)) != 0) - return (error); + cam_periph_lock(periph); + cam_periph_hold(periph, 0); if ((softc->flags & CD_FLAG_DISC_REMOVABLE) != 0) cdprevent(periph, PR_ALLOW); @@ -1091,10 +1070,9 @@ cdclose(struct dev_close_args *ap) /* * We'll check the media and toc again at the next open(). */ - softc->flags &= ~(CD_FLAG_VALID_MEDIA|CD_FLAG_VALID_TOC); - - softc->flags &= ~CD_FLAG_OPEN; + softc->flags &= ~(CD_FLAG_VALID_MEDIA|CD_FLAG_VALID_TOC|CD_FLAG_OPEN); + cam_periph_unhold(periph); cam_periph_unlock(periph); cam_periph_release(periph); @@ -1106,8 +1084,6 @@ cdshorttimeout(void *arg) { struct cdchanger *changer; - crit_enter(); - changer = (struct cdchanger *)arg; /* Always clear the short timeout flag, since that's what we're in */ @@ -1122,7 +1098,6 @@ cdshorttimeout(void *arg) changer->flags |= CHANGER_MANUAL_CALL; cdrunchangerqueue(changer); } - crit_exit(); } /* @@ -1133,8 +1108,6 @@ cdschedule(struct cam_periph *periph, int priority) { struct cd_softc *softc; - crit_enter(); - softc = (struct cd_softc *)periph->softc; /* @@ -1173,7 +1146,6 @@ cdschedule(struct cam_periph *periph, int priority) && ((softc->flags & CD_FLAG_SCHED_ON_COMP) == 0)) { xpt_schedule(periph, priority); } - crit_exit(); } static void @@ -1183,8 +1155,6 @@ cdrunchangerqueue(void *arg) struct cdchanger *changer; int called_from_timeout; - crit_enter(); - changer = (struct cdchanger *)arg; /* @@ -1203,7 +1173,6 @@ cdrunchangerqueue(void *arg) /* nothing to do if the queue is empty */ if (changer->devq.entries <= 0) { - crit_exit(); return; } @@ -1213,6 +1182,14 @@ cdrunchangerqueue(void *arg) */ if (changer->devq.qfrozen_cnt > 0) { + /* + * We always need to reset the frozen count and clear the + * active flag. + */ + changer->devq.qfrozen_cnt--; + changer->cur_device->flags &= ~CD_FLAG_ACTIVE; + changer->cur_device->flags &= ~CD_FLAG_SCHED_ON_COMP; + if (changer->cur_device->outstanding_cmds > 0) { changer->cur_device->flags |= CD_FLAG_SCHED_ON_COMP; changer->cur_device->bufs_left = @@ -1223,19 +1200,10 @@ cdrunchangerqueue(void *arg) cdrunchangerqueue, changer); changer->flags |= CHANGER_TIMEOUT_SCHED; } - crit_exit(); return; } /* - * We always need to reset the frozen count and clear the - * active flag. - */ - changer->devq.qfrozen_cnt--; - changer->cur_device->flags &= ~CD_FLAG_ACTIVE; - changer->cur_device->flags &= ~CD_FLAG_SCHED_ON_COMP; - - /* * Check to see whether the current device has any I/O left * to do. If so, requeue it at the end of the queue. If * not, there is no need to requeue it. @@ -1280,8 +1248,6 @@ cdrunchangerqueue(void *arg) * switch time. */ changer->flags |= CHANGER_NEED_TIMEOUT; - - crit_exit(); } static void @@ -1289,8 +1255,6 @@ cdchangerschedule(struct cd_softc *softc) { struct cdchanger *changer; - crit_enter(); - changer = softc->changer; /* @@ -1359,7 +1323,6 @@ cdchangerschedule(struct cd_softc *softc) changer->flags &= ~CHANGER_NEED_TIMEOUT; } - crit_exit(); } static int @@ -1392,8 +1355,6 @@ cdgetccb(struct cam_periph *periph, u_int32_t priority) softc = (struct cd_softc *)periph->softc; if (softc->flags & CD_FLAG_CHANGER) { - crit_enter(); - /* * This should work the first time this device is woken up, * but just in case it doesn't, we use a while loop. @@ -1416,9 +1377,9 @@ cdgetccb(struct cam_periph *periph, u_int32_t priority) softc->changer->flags |= CHANGER_MANUAL_CALL; cdrunchangerqueue(softc->changer); } else - tsleep(&softc->changer, 0, "cgticb", 0); + sim_lock_sleep(&softc->changer, 0, "cgticb", 0, + periph->sim->lock); } - crit_exit(); } return(cam_periph_getccb(periph, priority)); } @@ -1445,22 +1406,16 @@ cdstrategy(struct dev_strategy_args *ap) goto bad; } + cam_periph_lock(periph); CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("entering cdstrategy\n")); softc = (struct cd_softc *)periph->softc; /* - * Mask interrupts so that the pack cannot be invalidated until - * after we are in the queue. Otherwise, we might not properly - * clean up one of the buffers. - */ - crit_enter(); - - /* * If the device has been made invalid, error out */ if ((softc->flags & CD_FLAG_INVALID)) { - crit_exit(); + cam_periph_unlock(periph); bp->b_error = ENXIO; goto bad; } @@ -1474,7 +1429,7 @@ cdstrategy(struct dev_strategy_args *ap) error = cdcheckmedia(periph); if (error != 0) { - crit_exit(); + cam_periph_unlock(periph); bp->b_error = error; goto bad; } @@ -1485,8 +1440,6 @@ cdstrategy(struct dev_strategy_args *ap) */ bioqdisksort(&softc->bio_queue, bio); - crit_exit(); - /* * Schedule ourselves for performing the work. We do things * differently for changers. @@ -1496,6 +1449,7 @@ cdstrategy(struct dev_strategy_args *ap) else cdschedule(periph, /* priority */ 1); + cam_periph_unlock(periph); return(0); bad: bp->b_flags |= B_ERROR; @@ -1523,7 +1477,6 @@ cdstart(struct cam_periph *periph, union ccb *start_ccb) switch (softc->state) { case CD_STATE_NORMAL: { - crit_enter(); bio = bioq_first(&softc->bio_queue); if (periph->immediate_priority <= periph->pinfo.priority) { start_ccb->ccb_h.ccb_state = CD_CCB_WAITING; @@ -1531,10 +1484,8 @@ cdstart(struct cam_periph *periph, union ccb *start_ccb) SLIST_INSERT_HEAD(&periph->ccb_list, &start_ccb->ccb_h, periph_links.sle); periph->immediate_priority = CAM_PRIORITY_NONE; - crit_exit(); wakeup(&periph->ccb_list); } else if (bio == NULL) { - crit_exit(); xpt_release_ccb(start_ccb); } else { bp = bio->bio_buf; @@ -1563,10 +1514,6 @@ cdstart(struct cam_periph *periph, union ccb *start_ccb) start_ccb->ccb_h.ccb_state = CD_CCB_BUFFER_IO; - /* - * Block out any asyncronous callbacks - * while we touch the pending ccb list. - */ LIST_INSERT_HEAD(&softc->pending_ccbs, &start_ccb->ccb_h, periph_links.le); @@ -1579,7 +1526,6 @@ cdstart(struct cam_periph *periph, union ccb *start_ccb) start_ccb->ccb_h.ccb_bio = bio; bio = bioq_first(&softc->bio_queue); - crit_exit(); xpt_action(start_ccb); } @@ -1592,7 +1538,7 @@ cdstart(struct cam_periph *periph, union ccb *start_ccb) case CD_STATE_PROBE: { - rcap = kmalloc(sizeof(*rcap), M_TEMP, M_INTWAIT); + rcap = kmalloc(sizeof(*rcap), M_SCSICD, M_INTWAIT); csio = &start_ccb->csio; scsi_read_capacity(csio, /*retries*/1, @@ -1653,9 +1599,8 @@ cddone(struct cam_periph *periph, union ccb *done_ccb) struct bio *q_bio; struct buf *q_bp; - xpt_print_path(periph->path); - kprintf("cddone: got error %#x back\n", error); - crit_enter(); + xpt_print(periph->path, + "cddone: got error %#x back\n", error); while ((q_bio = bioq_first(&softc->bio_queue)) != NULL) { bioq_remove(&softc->bio_queue, q_bio); q_bp = q_bio->bio_buf; @@ -1664,7 +1609,6 @@ cddone(struct cam_periph *periph, union ccb *done_ccb) q_bp->b_flags |= B_ERROR; biodone(q_bio); } - crit_exit(); bp->b_resid = bp->b_bcount; bp->b_error = error; bp->b_flags |= B_ERROR; @@ -1683,14 +1627,8 @@ cddone(struct cam_periph *periph, union ccb *done_ccb) } } - /* - * Block out any asyncronous callbacks - * while we touch the pending ccb list. - */ - crit_enter(); LIST_REMOVE(&done_ccb->ccb_h, periph_links.le); softc->outstanding_cmds--; - crit_exit(); if (softc->flags & CD_FLAG_CHANGER) cdchangerschedule(softc); @@ -1829,14 +1767,12 @@ cddone(struct cam_periph *periph, union ccb *done_ccb) scsi_sense_print( &done_ccb->csio); else { - xpt_print_path(periph->path); - kprintf("got CAM status %#x\n", - done_ccb->ccb_h.status); + xpt_print(periph->path, + "got CAM status %#x\n", + done_ccb->ccb_h.status); } - xpt_print_path(periph->path); - kprintf("fatal error, failed" - " to attach to device\n"); - + xpt_print(periph->path, "fatal error, " + "failed to attach to device\n"); /* * Invalidate this peripheral. */ @@ -1853,7 +1789,7 @@ cddone(struct cam_periph *periph, union ccb *done_ccb) } } } - kfree(rdcap, M_TEMP); + kfree(rdcap, M_SCSICD); if (announce_buf[0] != '\0') { xpt_announce_periph(periph, announce_buf); if (softc->flags & CD_FLAG_CHANGER) @@ -1875,7 +1811,7 @@ cddone(struct cam_periph *periph, union ccb *done_ccb) * operation. */ xpt_release_ccb(done_ccb); - cam_periph_unlock(periph); + cam_periph_unhold(periph); return; } case CD_CCB_WAITING: @@ -1928,7 +1864,7 @@ cdioctl(struct dev_ioctl_args *ap) caddr_t addr = ap->a_data; struct cam_periph *periph; struct cd_softc *softc; - int error, unit; + int unit, error = 0; unit = dkunit(dev); @@ -1936,6 +1872,7 @@ cdioctl(struct dev_ioctl_args *ap) if (periph == NULL) return(ENXIO); + cam_periph_lock(periph); CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("entering cdioctl\n")); softc = (struct cd_softc *)periph->softc; @@ -1943,10 +1880,11 @@ cdioctl(struct dev_ioctl_args *ap) CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("trying to do ioctl %#lx\n", ap->a_cmd)); - error = cam_periph_lock(periph, PCATCH); - - if (error != 0) - return(error); + if ((error = cam_periph_hold(periph, PCATCH)) != 0) { + cam_periph_unlock(periph); + cam_periph_release(periph); + return (error); + } /* * If we don't have media loaded, check for it. If still don't @@ -1963,10 +1901,16 @@ cdioctl(struct dev_ioctl_args *ap) && (IOCGROUP(ap->a_cmd) == 'c')) { error = cdcheckmedia(periph); if (error != 0) { + cam_periph_unhold(periph); cam_periph_unlock(periph); return (error); } } + /* + * Drop the lock here so later mallocs can use WAITOK. The periph + * is essentially locked still with the cam_periph_hold call above. + */ + cam_periph_unlock(periph); switch (ap->a_cmd) { @@ -1978,15 +1922,17 @@ cdioctl(struct dev_ioctl_args *ap) union cd_pages *page; params.alloc_len = sizeof(union cd_mode_data_6_10); - params.mode_buf = kmalloc(params.alloc_len, M_TEMP, + params.mode_buf = kmalloc(params.alloc_len, M_SCSICD, M_WAITOK | M_ZERO); + cam_periph_lock(periph); CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, ("trying to do CDIOCPLAYTRACKS\n")); error = cdgetmode(periph, ¶ms, AUDIO_PAGE); if (error) { - kfree(params.mode_buf, M_TEMP); + kfree(params.mode_buf, M_SCSICD); + cam_periph_unlock(periph); break; } page = cdgetpage(¶ms); @@ -1994,9 +1940,11 @@ cdioctl(struct dev_ioctl_args *ap) page->audio.flags &= ~CD_PA_SOTC; page->audio.flags |= CD_PA_IMMED; error = cdsetmode(periph, ¶ms); - kfree(params.mode_buf, M_TEMP); - if (error) + kfree(params.mode_buf, M_SCSICD); + if (error) { + cam_periph_unlock(periph); break; + } /* * This was originally implemented with the PLAY @@ -2058,6 +2006,7 @@ cdioctl(struct dev_ioctl_args *ap) args->end_track, args->end_index); } + cam_periph_unlock(periph); } break; case CDIOCPLAYMSF: @@ -2068,15 +2017,17 @@ cdioctl(struct dev_ioctl_args *ap) union cd_pages *page; params.alloc_len = sizeof(union cd_mode_data_6_10); - params.mode_buf = kmalloc(params.alloc_len, M_TEMP, + params.mode_buf = kmalloc(params.alloc_len, M_SCSICD, M_WAITOK | M_ZERO); + cam_periph_lock(periph); CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, ("trying to do CDIOCPLAYMSF\n")); error = cdgetmode(periph, ¶ms, AUDIO_PAGE); if (error) { - kfree(params.mode_buf, M_TEMP); + kfree(params.mode_buf, M_SCSICD); + cam_periph_unlock(periph); break; } page = cdgetpage(¶ms); @@ -2084,9 +2035,11 @@ cdioctl(struct dev_ioctl_args *ap) page->audio.flags &= ~CD_PA_SOTC; page->audio.flags |= CD_PA_IMMED; error = cdsetmode(periph, ¶ms); - kfree(params.mode_buf, M_TEMP); - if (error) + kfree(params.mode_buf, M_SCSICD); + if (error) { + cam_periph_unlock(periph); break; + } error = cdplaymsf(periph, args->start_m, args->start_s, @@ -2094,6 +2047,7 @@ cdioctl(struct dev_ioctl_args *ap) args->end_m, args->end_s, args->end_f); + cam_periph_unlock(periph); } break; case CDIOCPLAYBLOCKS: @@ -2103,16 +2057,18 @@ cdioctl(struct dev_ioctl_args *ap) struct cd_mode_params params; union cd_pages *page; + params.alloc_len = sizeof(union cd_mode_data_6_10); + params.mode_buf = kmalloc(params.alloc_len, M_SCSICD, + M_WAITOK | M_ZERO); + cam_periph_lock(periph); CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, ("trying to do CDIOCPLAYBLOCKS\n")); - params.alloc_len = sizeof(union cd_mode_data_6_10); - params.mode_buf = kmalloc(params.alloc_len, M_TEMP, - M_WAITOK | M_ZERO); error = cdgetmode(periph, ¶ms, AUDIO_PAGE); if (error) { - kfree(params.mode_buf, M_TEMP); + kfree(params.mode_buf, M_SCSICD); + cam_periph_unlock(periph); break; } page = cdgetpage(¶ms); @@ -2120,10 +2076,13 @@ cdioctl(struct dev_ioctl_args *ap) page->audio.flags &= ~CD_PA_SOTC; page->audio.flags |= CD_PA_IMMED; error = cdsetmode(periph, ¶ms); - kfree(params.mode_buf, M_TEMP); - if (error) + kfree(params.mode_buf, M_SCSICD); + if (error) { + cam_periph_unlock(periph); break; + } error = cdplay(periph, args->blk, args->len); + cam_periph_unlock(periph); } break; case CDIOCREADSUBCHANNEL: @@ -2133,12 +2092,13 @@ cdioctl(struct dev_ioctl_args *ap) struct cd_sub_channel_info *data; u_int32_t len = args->data_len; + data = kmalloc(sizeof(struct cd_sub_channel_info), + M_SCSICD, M_WAITOK); + + cam_periph_lock(periph); CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, ("trying to do CDIOCREADSUBCHANNEL\n")); - data = kmalloc(sizeof(struct cd_sub_channel_info), - M_TEMP, M_WAITOK); - if ((len > sizeof(struct cd_sub_channel_info)) || (len < sizeof(struct cd_sub_channel_header))) { kprintf( @@ -2146,7 +2106,8 @@ cdioctl(struct dev_ioctl_args *ap) "cdioreadsubchannel: error, len=%d\n", len); error = EINVAL; - kfree(data, M_TEMP); + kfree(data, M_SCSICD); + cam_periph_unlock(periph); break; } @@ -2157,7 +2118,8 @@ cdioctl(struct dev_ioctl_args *ap) args->data_format, args->track, data, len); if (error) { - kfree(data, M_TEMP); + kfree(data, M_SCSICD); + cam_periph_unlock(periph); break; } if (softc->quirks & CD_Q_BCD_TRACKS) @@ -2166,10 +2128,11 @@ cdioctl(struct dev_ioctl_args *ap) len = min(len, ((data->header.data_len[0] << 8) + data->header.data_len[1] + sizeof(struct cd_sub_channel_header))); + cam_periph_unlock(periph); if (copyout(data, args->data, len) != 0) { error = EFAULT; } - kfree(data, M_TEMP); + kfree(data, M_SCSICD); } break; @@ -2177,15 +2140,18 @@ cdioctl(struct dev_ioctl_args *ap) { struct ioc_toc_header *th; + th = kmalloc(sizeof(struct ioc_toc_header), M_SCSICD, + M_WAITOK); + + cam_periph_lock(periph); CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, ("trying to do CDIOREADTOCHEADER\n")); - th = kmalloc(sizeof(struct ioc_toc_header), M_TEMP, - M_WAITOK); error = cdreadtoc(periph, 0, 0, (u_int8_t *)th, sizeof (*th), /*sense_flags*/0); if (error) { - kfree(th, M_TEMP); + kfree(th, M_SCSICD); + cam_periph_unlock(periph); break; } if (softc->quirks & CD_Q_BCD_TRACKS) { @@ -2198,7 +2164,8 @@ cdioctl(struct dev_ioctl_args *ap) } th->len = ntohs(th->len); bcopy(th, addr, sizeof(*th)); - kfree(th, M_TEMP); + kfree(th, M_SCSICD); + cam_periph_unlock(periph); } break; case CDIOREADTOCENTRYS: @@ -2211,12 +2178,13 @@ cdioctl(struct dev_ioctl_args *ap) u_int32_t len, readlen, idx, num; u_int32_t starting_track = te->starting_track; + data = kmalloc(sizeof(*data), M_SCSICD, M_WAITOK); + lead = kmalloc(sizeof(*lead), M_SCSICD, M_WAITOK); + + cam_periph_lock(periph); CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, ("trying to do CDIOREADTOCENTRYS\n")); - data = kmalloc(sizeof(*data), M_TEMP, M_WAITOK); - lead = kmalloc(sizeof(*lead), M_TEMP, M_WAITOK); - if (te->data_len < sizeof(struct cd_toc_entry) || (te->data_len % sizeof(struct cd_toc_entry)) != 0 || (te->address_format != CD_MSF_FORMAT @@ -2224,8 +2192,9 @@ cdioctl(struct dev_ioctl_args *ap) error = EINVAL; kprintf("scsi_cd: error in readtocentries, " "returning EINVAL\n"); - kfree(data, M_TEMP); - kfree(lead, M_TEMP); + kfree(data, M_SCSICD); + kfree(lead, M_SCSICD); + cam_periph_unlock(periph); break; } @@ -2233,8 +2202,9 @@ cdioctl(struct dev_ioctl_args *ap) error = cdreadtoc(periph, 0, 0, (u_int8_t *)th, sizeof (*th), /*sense_flags*/0); if (error) { - kfree(data, M_TEMP); - kfree(lead, M_TEMP); + kfree(data, M_SCSICD); + kfree(lead, M_SCSICD); + cam_periph_unlock(periph); break; } @@ -2255,8 +2225,9 @@ cdioctl(struct dev_ioctl_args *ap) starting_track > th->ending_track + 1) { kprintf("scsi_cd: error in readtocentries, " "returning EINVAL\n"); - kfree(data, M_TEMP); - kfree(lead, M_TEMP); + kfree(data, M_SCSICD); + kfree(lead, M_SCSICD); + cam_periph_unlock(periph); error = EINVAL; break; } @@ -2276,8 +2247,9 @@ cdioctl(struct dev_ioctl_args *ap) kprintf("scsi_cd: error in readtocentries, " "returning EINVAL\n"); error = EINVAL; - kfree(data, M_TEMP); - kfree(lead, M_TEMP); + kfree(data, M_SCSICD); + kfree(lead, M_SCSICD); + cam_periph_unlock(periph); break; } num = len / sizeof(struct cd_toc_entry); @@ -2289,8 +2261,9 @@ cdioctl(struct dev_ioctl_args *ap) readlen + sizeof (*th), /*sense_flags*/0); if (error) { - kfree(data, M_TEMP); - kfree(lead, M_TEMP); + kfree(data, M_SCSICD); + kfree(lead, M_SCSICD); + cam_periph_unlock(periph); break; } } @@ -2305,8 +2278,9 @@ cdioctl(struct dev_ioctl_args *ap) sizeof(*lead), /*sense_flags*/0); if (error) { - kfree(data, M_TEMP); - kfree(lead, M_TEMP); + kfree(data, M_SCSICD); + kfree(lead, M_SCSICD); + cam_periph_unlock(periph); break; } data->entries[idx - starting_track] = @@ -2319,9 +2293,10 @@ cdioctl(struct dev_ioctl_args *ap) } } + cam_periph_unlock(periph); error = copyout(data->entries, te->data, len); - kfree(data, M_TEMP); - kfree(lead, M_TEMP); + kfree(data, M_SCSICD); + kfree(lead, M_SCSICD); } break; case CDIOREADTOCENTRY: @@ -2332,17 +2307,19 @@ cdioctl(struct dev_ioctl_args *ap) struct ioc_toc_header *th; u_int32_t track; - CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, - ("trying to do CDIOREADTOCENTRY\n")); + data = kmalloc(sizeof(*data), M_SCSICD, M_WAITOK); - data = kmalloc(sizeof(*data), M_TEMP, M_WAITOK); + cam_periph_lock(periph); + CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, + ("trying to do CDIOREADTOCENTRY\n")); if (te->address_format != CD_MSF_FORMAT && te->address_format != CD_LBA_FORMAT) { kprintf("error in readtocentry, " " returning EINVAL\n"); - kfree(data, M_TEMP); + kfree(data, M_SCSICD); error = EINVAL; + cam_periph_unlock(periph); break; } @@ -2350,7 +2327,8 @@ cdioctl(struct dev_ioctl_args *ap) error = cdreadtoc(periph, 0, 0, (u_int8_t *)th, sizeof (*th), /*sense_flags*/0); if (error) { - kfree(data, M_TEMP); + kfree(data, M_SCSICD); + cam_periph_unlock(periph); break; } @@ -2371,8 +2349,9 @@ cdioctl(struct dev_ioctl_args *ap) track > th->ending_track + 1) { kprintf("error in readtocentry, " " returning EINVAL\n"); - kfree(data, M_TEMP); + kfree(data, M_SCSICD); error = EINVAL; + cam_periph_unlock(periph); break; } @@ -2380,7 +2359,8 @@ cdioctl(struct dev_ioctl_args *ap) (u_int8_t *)data, sizeof(*data), /*sense_flags*/0); if (error) { - kfree(data, M_TEMP); + kfree(data, M_SCSICD); + cam_periph_unlock(periph); break; } @@ -2388,7 +2368,8 @@ cdioctl(struct dev_ioctl_args *ap) data->entry.track = bcd2bin(data->entry.track); bcopy(&data->entry, &te->entry, sizeof(struct cd_toc_entry)); - kfree(data, M_TEMP); + kfree(data, M_SCSICD); + cam_periph_unlock(periph); } break; case CDIOCSETPATCH: @@ -2397,15 +2378,18 @@ cdioctl(struct dev_ioctl_args *ap) struct cd_mode_params params; union cd_pages *page; + params.alloc_len = sizeof(union cd_mode_data_6_10); + params.mode_buf = kmalloc(params.alloc_len, M_SCSICD, + M_WAITOK | M_ZERO); + + cam_periph_lock(periph); CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, ("trying to do CDIOCSETPATCH\n")); - params.alloc_len = sizeof(union cd_mode_data_6_10); - params.mode_buf = kmalloc(params.alloc_len, M_TEMP, - M_WAITOK | M_ZERO); error = cdgetmode(periph, ¶ms, AUDIO_PAGE); if (error) { - kfree(params.mode_buf, M_TEMP); + kfree(params.mode_buf, M_SCSICD); + cam_periph_unlock(periph); break; } page = cdgetpage(¶ms); @@ -2417,7 +2401,8 @@ cdioctl(struct dev_ioctl_args *ap) page->audio.port[2].channels = arg->patch[2]; page->audio.port[3].channels = arg->patch[3]; error = cdsetmode(periph, ¶ms); - kfree(params.mode_buf, M_TEMP); + kfree(params.mode_buf, M_SCSICD); + cam_periph_unlock(periph); } break; case CDIOCGETVOL: @@ -2426,15 +2411,18 @@ cdioctl(struct dev_ioctl_args *ap) struct cd_mode_params params; union cd_pages *page; + params.alloc_len = sizeof(union cd_mode_data_6_10); + params.mode_buf = kmalloc(params.alloc_len, M_SCSICD, + M_WAITOK | M_ZERO); + + cam_periph_lock(periph); CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, ("trying to do CDIOCGETVOL\n")); - params.alloc_len = sizeof(union cd_mode_data_6_10); - params.mode_buf = kmalloc(params.alloc_len, M_TEMP, - M_WAITOK | M_ZERO); error = cdgetmode(periph, ¶ms, AUDIO_PAGE); if (error) { - kfree(params.mode_buf, M_TEMP); + kfree(params.mode_buf, M_SCSICD); + cam_periph_unlock(periph); break; } page = cdgetpage(¶ms); @@ -2445,7 +2433,8 @@ cdioctl(struct dev_ioctl_args *ap) page->audio.port[RIGHT_PORT].volume; arg->vol[2] = page->audio.port[2].volume; arg->vol[3] = page->audio.port[3].volume; - kfree(params.mode_buf, M_TEMP); + kfree(params.mode_buf, M_SCSICD); + cam_periph_unlock(periph); } break; case CDIOCSETVOL: @@ -2454,15 +2443,18 @@ cdioctl(struct dev_ioctl_args *ap) struct cd_mode_params params; union cd_pages *page; + params.alloc_len = sizeof(union cd_mode_data_6_10); + params.mode_buf = kmalloc(params.alloc_len, M_SCSICD, + M_WAITOK | M_ZERO); + + cam_periph_lock(periph); CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, ("trying to do CDIOCSETVOL\n")); - params.alloc_len = sizeof(union cd_mode_data_6_10); - params.mode_buf = kmalloc(params.alloc_len, M_TEMP, - M_WAITOK | M_ZERO); error = cdgetmode(periph, ¶ms, AUDIO_PAGE); if (error) { - kfree(params.mode_buf, M_TEMP); + kfree(params.mode_buf, M_SCSICD); + cam_periph_unlock(periph); break; } page = cdgetpage(¶ms); @@ -2476,7 +2468,8 @@ cdioctl(struct dev_ioctl_args *ap) page->audio.port[2].volume = arg->vol[2]; page->audio.port[3].volume = arg->vol[3]; error = cdsetmode(periph, ¶ms); - kfree(params.mode_buf, M_TEMP); + cam_periph_unlock(periph); + kfree(params.mode_buf, M_SCSICD); } break; case CDIOCSETMONO: @@ -2484,15 +2477,18 @@ cdioctl(struct dev_ioctl_args *ap) struct cd_mode_params params; union cd_pages *page; + params.alloc_len = sizeof(union cd_mode_data_6_10); + params.mode_buf = kmalloc(params.alloc_len, M_SCSICD, + M_WAITOK | M_ZERO); + + cam_periph_lock(periph); CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, ("trying to do CDIOCSETMONO\n")); - params.alloc_len = sizeof(union cd_mode_data_6_10); - params.mode_buf = kmalloc(params.alloc_len, M_TEMP, - M_WAITOK | M_ZERO); error = cdgetmode(periph, ¶ms, AUDIO_PAGE); if (error) { - kfree(params.mode_buf, M_TEMP); + kfree(params.mode_buf, M_SCSICD); + cam_periph_unlock(periph); break; } page = cdgetpage(¶ms); @@ -2504,7 +2500,8 @@ cdioctl(struct dev_ioctl_args *ap) page->audio.port[2].channels = 0; page->audio.port[3].channels = 0; error = cdsetmode(periph, ¶ms); - kfree(params.mode_buf, M_TEMP); + cam_periph_unlock(periph); + kfree(params.mode_buf, M_SCSICD); } break; case CDIOCSETSTEREO: @@ -2512,15 +2509,18 @@ cdioctl(struct dev_ioctl_args *ap) struct cd_mode_params params; union cd_pages *page; + params.alloc_len = sizeof(union cd_mode_data_6_10); + params.mode_buf = kmalloc(params.alloc_len, M_SCSICD, + M_WAITOK | M_ZERO); + + cam_periph_lock(periph); CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, ("trying to do CDIOCSETSTEREO\n")); - params.alloc_len = sizeof(union cd_mode_data_6_10); - params.mode_buf = kmalloc(params.alloc_len, M_TEMP, - M_WAITOK | M_ZERO); error = cdgetmode(periph, ¶ms, AUDIO_PAGE); if (error) { - kfree(params.mode_buf, M_TEMP); + kfree(params.mode_buf, M_SCSICD); + cam_periph_unlock(periph); break; } page = cdgetpage(¶ms); @@ -2532,7 +2532,8 @@ cdioctl(struct dev_ioctl_args *ap) page->audio.port[2].channels = 0; page->audio.port[3].channels = 0; error = cdsetmode(periph, ¶ms); - kfree(params.mode_buf, M_TEMP); + kfree(params.mode_buf, M_SCSICD); + cam_periph_unlock(periph); } break; case CDIOCSETMUTE: @@ -2540,15 +2541,18 @@ cdioctl(struct dev_ioctl_args *ap) struct cd_mode_params params; union cd_pages *page; + params.alloc_len = sizeof(union cd_mode_data_6_10); + params.mode_buf = kmalloc(params.alloc_len, M_SCSICD, + M_WAITOK | M_ZERO); + + cam_periph_lock(periph); CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, ("trying to do CDIOCSETMUTE\n")); - params.alloc_len = sizeof(union cd_mode_data_6_10); - params.mode_buf = kmalloc(params.alloc_len, M_TEMP, - M_WAITOK | M_ZERO); error = cdgetmode(periph, ¶ms, AUDIO_PAGE); if (error) { - kfree(¶ms, M_TEMP); + kfree(¶ms, M_SCSICD); + cam_periph_unlock(periph); break; } page = cdgetpage(¶ms); @@ -2558,7 +2562,8 @@ cdioctl(struct dev_ioctl_args *ap) page->audio.port[2].channels = 0; page->audio.port[3].channels = 0; error = cdsetmode(periph, ¶ms); - kfree(params.mode_buf, M_TEMP); + kfree(params.mode_buf, M_SCSICD); + cam_periph_unlock(periph); } break; case CDIOCSETLEFT: @@ -2566,16 +2571,18 @@ cdioctl(struct dev_ioctl_args *ap) struct cd_mode_params params; union cd_pages *page; + params.alloc_len = sizeof(union cd_mode_data_6_10); + params.mode_buf = kmalloc(params.alloc_len, M_SCSICD, + M_WAITOK | M_ZERO); + + cam_periph_lock(periph); CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, ("trying to do CDIOCSETLEFT\n")); - params.alloc_len = sizeof(union cd_mode_data_6_10); - params.mode_buf = kmalloc(params.alloc_len, M_TEMP, - M_WAITOK | M_ZERO); - error = cdgetmode(periph, ¶ms, AUDIO_PAGE); if (error) { - kfree(params.mode_buf, M_TEMP); + kfree(params.mode_buf, M_SCSICD); + cam_periph_unlock(periph); break; } page = cdgetpage(¶ms); @@ -2585,7 +2592,8 @@ cdioctl(struct dev_ioctl_args *ap) page->audio.port[2].channels = 0; page->audio.port[3].channels = 0; error = cdsetmode(periph, ¶ms); - kfree(params.mode_buf, M_TEMP); + kfree(params.mode_buf, M_SCSICD); + cam_periph_unlock(periph); } break; case CDIOCSETRIGHT: @@ -2593,16 +2601,18 @@ cdioctl(struct dev_ioctl_args *ap) struct cd_mode_params params; union cd_pages *page; - CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, - ("trying to do CDIOCSETRIGHT\n")); - params.alloc_len = sizeof(union cd_mode_data_6_10); - params.mode_buf = kmalloc(params.alloc_len, M_TEMP, + params.mode_buf = kmalloc(params.alloc_len, M_SCSICD, M_WAITOK | M_ZERO); + cam_periph_lock(periph); + CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, + ("trying to do CDIOCSETRIGHT\n")); + error = cdgetmode(periph, ¶ms, AUDIO_PAGE); if (error) { - kfree(params.mode_buf, M_TEMP); + kfree(params.mode_buf, M_SCSICD); + cam_periph_unlock(periph); break; } page = cdgetpage(¶ms); @@ -2612,56 +2622,49 @@ cdioctl(struct dev_ioctl_args *ap) page->audio.port[2].channels = 0; page->audio.port[3].channels = 0; error = cdsetmode(periph, ¶ms); - kfree(params.mode_buf, M_TEMP); + kfree(params.mode_buf, M_SCSICD); + cam_periph_unlock(periph); } break; case CDIOCRESUME: + cam_periph_lock(periph); error = cdpause(periph, 1); + cam_periph_unlock(periph); break; case CDIOCPAUSE: + cam_periph_lock(periph); error = cdpause(periph, 0); + cam_periph_unlock(periph); break; case CDIOCSTART: + cam_periph_lock(periph); error = cdstartunit(periph, 0); + cam_periph_unlock(periph); break; case CDIOCCLOSE: + cam_periph_lock(periph); error = cdstartunit(periph, 1); - -#ifdef notyet - if (error != 0) - break; - - /* - * The user successfully closed the tray, run - * cdcheckmedia() again so we can re-sync the disklabel - * information. - */ - cdcheckmedia(periph); -#endif /* notyet */ + cam_periph_unlock(periph); break; case CDIOCSTOP: + cam_periph_lock(periph); error = cdstopunit(periph, 0); + cam_periph_unlock(periph); break; case CDIOCEJECT: + cam_periph_lock(periph); error = cdstopunit(periph, 1); - -#ifdef notyet - if (error != 0) - break; - - /* - * Since we've successfully ejected the media, run - * cdcheckmedia() again so we re-sync the disklabel - * information. - */ - cdcheckmedia(periph); -#endif /* notyet */ + cam_periph_unlock(periph); break; case CDIOCALLOW: + cam_periph_lock(periph); cdprevent(periph, PR_ALLOW); + cam_periph_unlock(periph); break; case CDIOCPREVENT: + cam_periph_lock(periph); cdprevent(periph, PR_PREVENT); + cam_periph_unlock(periph); break; case CDIOCSETDEBUG: /* sc_link->flags |= (SDEV_DB1 | SDEV_DB2); */ @@ -2676,10 +2679,14 @@ cdioctl(struct dev_ioctl_args *ap) error = ENOTTY; break; case CDRIOCREADSPEED: + cam_periph_lock(periph); error = cdsetspeed(periph, *(u_int32_t *)addr, CDR_MAX_SPEED); + cam_periph_unlock(periph); break; case CDRIOCWRITESPEED: + cam_periph_lock(periph); error = cdsetspeed(periph, CDR_MAX_SPEED, *(u_int32_t *)addr); + cam_periph_unlock(periph); break; case DVDIOCSENDKEY: case DVDIOCREPORTKEY: { @@ -2687,10 +2694,12 @@ cdioctl(struct dev_ioctl_args *ap) authinfo = (struct dvd_authinfo *)addr; + cam_periph_lock(periph); if (ap->a_cmd == DVDIOCREPORTKEY) error = cdreportkey(periph, authinfo); else error = cdsendkey(periph, authinfo); + cam_periph_unlock(periph); break; } case DVDIOCREADSTRUCTURE: { @@ -2698,19 +2707,26 @@ cdioctl(struct dev_ioctl_args *ap) dvdstruct = (struct dvd_struct *)addr; + cam_periph_lock(periph); error = cdreaddvdstructure(periph, dvdstruct); + cam_periph_unlock(periph); break; } default: + cam_periph_lock(periph); error = cam_periph_ioctl(periph, ap->a_cmd, addr, cderror); + cam_periph_unlock(periph); break; } - cam_periph_unlock(periph); + cam_periph_lock(periph); + cam_periph_unhold(periph); CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("leaving cdioctl\n")); + cam_periph_unlock(periph); + return (error); } @@ -3034,7 +3050,7 @@ cdsize(struct cam_periph *periph, u_int32_t *size) ccb = cdgetccb(periph, /* priority */ 1); rcap_buf = kmalloc(sizeof(struct scsi_read_capacity_data), - M_TEMP, M_INTWAIT | M_ZERO); + M_SCSICD, M_INTWAIT | M_ZERO); scsi_read_capacity(&ccb->csio, /*retries*/ 1, @@ -3062,7 +3078,7 @@ cdsize(struct cam_periph *periph, u_int32_t *size) if (softc->params.blksize > 2048 && softc->params.blksize <= 2352) softc->params.blksize = 2048; - kfree(rcap_buf, M_TEMP); + kfree(rcap_buf, M_SCSICD); *size = softc->params.disksize; return (error); @@ -3113,16 +3129,16 @@ cd6byteworkaround(union ccb *ccb) * cdsetmode()! */ if (found == 0) { - xpt_print_path(periph->path); - kprintf("mode buffer not found in mode queue!\n"); + xpt_print(periph->path, + "mode buffer not found in mode queue!\n"); return (0); } params->cdb_size = 10; softc->minimum_command_size = 10; - xpt_print_path(ccb->ccb_h.path); - kprintf("%s(6) failed, increasing minimum CDB size to 10 bytes\n", - (cdb[0] == MODE_SENSE_6) ? "MODE_SENSE" : "MODE_SELECT"); + xpt_print(ccb->ccb_h.path, + "%s(6) failed, increasing minimum CDB size to 10 bytes\n", + (cdb[0] == MODE_SENSE_6) ? "MODE_SENSE" : "MODE_SELECT"); if (cdb[0] == MODE_SENSE_6) { struct scsi_mode_sense_10 ms10; @@ -3453,10 +3469,9 @@ cdgetmode(struct cam_periph *periph, struct cd_mode_params *data, * the data length incorrectly. */ if (data_len > data->alloc_len) { - xpt_print_path(periph->path); - kprintf("allocated modepage %d length %d < returned " - "length %d\n", page, data->alloc_len, data_len); - + xpt_print(periph->path, "allocated modepage %d length " + "%d < returned length %d\n", page, data->alloc_len, + data_len); error = ENOSPC; } } @@ -3916,9 +3931,8 @@ cdreportkey(struct cam_periph *periph, struct dvd_authinfo *authinfo) goto bailout; if (ccb->csio.resid != 0) { - xpt_print_path(periph->path); - kprintf("warning, residual for report key command is %d\n", - ccb->csio.resid); + xpt_print(periph->path, "warning, residual for report key " + "command is %d\n", ccb->csio.resid); } switch(authinfo->format) { diff --git a/sys/bus/cam/scsi/scsi_ch.c b/sys/bus/cam/scsi/scsi_ch.c index 7707918..053087d 100644 --- a/sys/bus/cam/scsi/scsi_ch.c +++ b/sys/bus/cam/scsi/scsi_ch.c @@ -223,11 +223,12 @@ static struct dev_ops ch_ops = { static struct extend_array *chperiphs; +MALLOC_DEFINE(M_SCSICH, "scsi_ch", "scsi_ch buffers"); + static void chinit(void) { cam_status status; - struct cam_path *path; /* * Create our extend array for storing the devices we attach to. @@ -242,21 +243,7 @@ chinit(void) * Install a global async callback. This callback will * receive async callbacks like "new device found". */ - status = xpt_create_path(&path, /*periph*/NULL, CAM_XPT_PATH_ID, - CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD); - - if (status == CAM_REQ_CMP) { - struct ccb_setasync csa; - - xpt_setup_ccb(&csa.ccb_h, path, /*priority*/5); - csa.ccb_h.func_code = XPT_SASYNC_CB; - csa.event_enable = AC_FOUND_DEVICE; - csa.callback = chasync; - csa.callback_arg = NULL; - xpt_action((union ccb *)&csa); - status = csa.ccb_h.status; - xpt_free_path(path); - } + status = xpt_register_async(AC_FOUND_DEVICE, chasync, NULL, NULL); if (status != CAM_REQ_CMP) { kprintf("ch: Failed to attach master async callback " @@ -268,25 +255,17 @@ static void choninvalidate(struct cam_periph *periph) { struct ch_softc *softc; - struct ccb_setasync csa; softc = (struct ch_softc *)periph->softc; /* * De-register any async callbacks. */ - xpt_setup_ccb(&csa.ccb_h, periph->path, - /* priority */ 5); - csa.ccb_h.func_code = XPT_SASYNC_CB; - csa.event_enable = 0; - csa.callback = chasync; - csa.callback_arg = periph; - xpt_action((union ccb *)&csa); + xpt_register_async(0, chasync, periph, periph->path); softc->flags |= CH_FLAG_INVALID; - xpt_print_path(periph->path); - kprintf("lost device\n"); + xpt_print(periph->path, "lost device\n"); } @@ -299,8 +278,7 @@ chcleanup(struct cam_periph *periph) devstat_remove_entry(&softc->device_stats); cam_extend_release(chperiphs, periph->unit_number); - xpt_print_path(periph->path); - kprintf("removing device entry\n"); + xpt_print(periph->path, "removing device entry\n"); dev_ops_remove(&ch_ops, -1, periph->unit_number); kfree(softc, M_DEVBUF); } @@ -353,7 +331,6 @@ static cam_status chregister(struct cam_periph *periph, void *arg) { struct ch_softc *softc; - struct ccb_setasync csa; struct ccb_getdev *cgd; cgd = (struct ccb_getdev *)arg; @@ -377,6 +354,7 @@ chregister(struct cam_periph *periph, void *arg) * Changers don't have a blocksize, and obviously don't support * tagged queueing. */ + cam_periph_unlock(periph); devstat_add_entry(&softc->device_stats, "ch", periph->unit_number, 0, DEVSTAT_NO_BLOCKSIZE | DEVSTAT_NO_ORDERED_TAGS, @@ -388,23 +366,19 @@ chregister(struct cam_periph *periph, void *arg) make_dev(&ch_ops, periph->unit_number, UID_ROOT, GID_OPERATOR, 0600, "%s%d", periph->periph_name, periph->unit_number); + cam_periph_lock(periph); /* * Add an async callback so that we get * notified if this device goes away. */ - xpt_setup_ccb(&csa.ccb_h, periph->path, /* priority */ 5); - csa.ccb_h.func_code = XPT_SASYNC_CB; - csa.event_enable = AC_LOST_DEVICE; - csa.callback = chasync; - csa.callback_arg = periph; - xpt_action((union ccb *)&csa); + xpt_register_async(AC_LOST_DEVICE, chasync, periph, periph->path); /* - * Lock this peripheral until we are setup. + * Lock this periph until we are setup. * This first call can't block */ - cam_periph_lock(periph, 0); + cam_periph_hold(periph, 0); xpt_schedule(periph, /*priority*/5); return(CAM_REQ_CMP); @@ -421,28 +395,28 @@ chopen(struct dev_open_args *ap) unit = CHUNIT(dev); periph = cam_extend_get(chperiphs, unit); - if (periph == NULL) - return(ENXIO); + if (cam_periph_acquire(periph) != CAM_REQ_CMP) + return (ENXIO); softc = (struct ch_softc *)periph->softc; - crit_enter(); + cam_periph_lock(periph); + if (softc->flags & CH_FLAG_INVALID) { - crit_exit(); + cam_periph_unlock(periph); + cam_periph_release(periph); return(ENXIO); } - if ((error = cam_periph_lock(periph, PCATCH)) != 0) { - crit_exit(); - return (error); - } - - crit_exit(); - - if ((softc->flags & CH_FLAG_OPEN) == 0) { - if (cam_periph_acquire(periph) != CAM_REQ_CMP) - return(ENXIO); + if ((softc->flags & CH_FLAG_OPEN) == 0) softc->flags |= CH_FLAG_OPEN; + else + cam_periph_release(periph); + + if ((error = cam_periph_hold(periph, PCATCH)) != 0) { + cam_periph_unlock(periph); + cam_periph_release(periph); + return (error); } /* @@ -455,6 +429,7 @@ chopen(struct dev_open_args *ap) return(error); } + cam_periph_unhold(periph); cam_periph_unlock(periph); return(error); @@ -477,8 +452,7 @@ chclose(struct dev_close_args *ap) softc = (struct ch_softc *)periph->softc; - if ((error = cam_periph_lock(periph, 0)) != 0) - return(error); + cam_periph_lock(periph); softc->flags &= ~CH_FLAG_OPEN; @@ -498,7 +472,6 @@ chstart(struct cam_periph *periph, union ccb *start_ccb) switch (softc->state) { case CH_STATE_NORMAL: { - crit_enter(); if (periph->immediate_priority <= periph->pinfo.priority){ start_ccb->ccb_h.ccb_state = CH_CCB_WAITING; @@ -507,7 +480,6 @@ chstart(struct cam_periph *periph, union ccb *start_ccb) periph->immediate_priority = CAM_PRIORITY_NONE; wakeup(&periph->ccb_list); } - crit_exit(); break; } case CH_STATE_PROBE: @@ -523,7 +495,7 @@ chstart(struct cam_periph *periph, union ccb *start_ccb) sizeof(struct scsi_mode_blk_desc) + sizeof(struct page_element_address_assignment); - mode_buffer = kmalloc(mode_buffer_len, M_TEMP, M_INTWAIT | M_ZERO); + mode_buffer = kmalloc(mode_buffer_len, M_SCSICH, M_INTWAIT | M_ZERO); /* * Get the element address assignment page. */ @@ -648,13 +620,12 @@ chdone(struct cam_periph *periph, union ccb *done_ccb) == CAM_SCSI_STATUS_ERROR) scsi_sense_print(&done_ccb->csio); else { - xpt_print_path(periph->path); - kprintf("got CAM status %#x\n", - done_ccb->ccb_h.status); + xpt_print(periph->path, + "got CAM status %#x\n", + done_ccb->ccb_h.status); } - xpt_print_path(periph->path); - kprintf("fatal error, failed to attach to" - " device\n"); + xpt_print(periph->path, "fatal error, failed " + "to attach to device\n"); cam_periph_invalidate(periph); @@ -664,7 +635,7 @@ chdone(struct cam_periph *periph, union ccb *done_ccb) if (announce_buf[0] != '\0') xpt_announce_periph(periph, announce_buf); softc->state = CH_STATE_NORMAL; - kfree(mode_header, M_TEMP); + kfree(mode_header, M_SCSICH); /* * Since our peripheral may be invalidated by an error * above or an external event, we must release our CCB @@ -674,7 +645,7 @@ chdone(struct cam_periph *periph, union ccb *done_ccb) * operation. */ xpt_release_ccb(done_ccb); - cam_periph_unlock(periph); + cam_periph_unhold(periph); return; } case CH_CCB_WAITING: @@ -719,6 +690,7 @@ chioctl(struct dev_ioctl_args *ap) if (periph == NULL) return(ENXIO); + cam_periph_lock(periph); CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("entering chioctl\n")); softc = (struct ch_softc *)periph->softc; @@ -739,8 +711,10 @@ chioctl(struct dev_ioctl_args *ap) break; default: - if ((flag & FWRITE) == 0) + if ((flag & FWRITE) == 0) { + cam_periph_unlock(periph); return (EBADF); + } } switch (ap->a_cmd) { @@ -764,8 +738,10 @@ chioctl(struct dev_ioctl_args *ap) { int new_picker = *(int *)addr; - if (new_picker > (softc->sc_counts[CHET_MT] - 1)) - return (EINVAL); + if (new_picker > (softc->sc_counts[CHET_MT] - 1)) { + error = EINVAL; + break; + } softc->sc_picker = softc->sc_firsts[CHET_MT] + new_picker; break; } @@ -804,6 +780,7 @@ chioctl(struct dev_ioctl_args *ap) break; } + cam_periph_unlock(periph); return (error); } @@ -1101,8 +1078,10 @@ chgetelemstatus(struct cam_periph *periph, * we can allocate enough storage for all of them. We assume * that the first one can fit into 1k. */ + cam_periph_unlock(periph); data = (caddr_t)kmalloc(1024, M_DEVBUF, M_INTWAIT); + cam_periph_lock(periph); ccb = cam_periph_getccb(periph, /*priority*/ 1); scsi_read_element_status(&ccb->csio, @@ -1123,6 +1102,7 @@ chgetelemstatus(struct cam_periph *periph, if (error) goto done; + cam_periph_unlock(periph); st_hdr = (struct read_element_status_header *)data; pg_hdr = (struct read_element_status_page_header *)((uintptr_t)st_hdr + @@ -1140,6 +1120,7 @@ chgetelemstatus(struct cam_periph *periph, kfree(data, M_DEVBUF); data = (caddr_t)kmalloc(size, M_DEVBUF, M_INTWAIT); + cam_periph_lock(periph); scsi_read_element_status(&ccb->csio, /* retries */ 1, /* cbfcnp */ chdone, @@ -1159,6 +1140,7 @@ chgetelemstatus(struct cam_periph *periph, if (error) goto done; + cam_periph_unlock(periph); /* * Fill in the user status array. @@ -1169,8 +1151,8 @@ chgetelemstatus(struct cam_periph *periph, avail = scsi_2btoul(st_hdr->count); if (avail != cesr->cesr_element_count) { - xpt_print_path(periph->path); - kprintf("warning, READ ELEMENT STATUS avail != count\n"); + xpt_print(periph->path, + "warning, READ ELEMENT STATUS avail != count\n"); } user_data = (struct changer_element_status *) @@ -1196,6 +1178,7 @@ chgetelemstatus(struct cam_periph *periph, error = copyout(user_data, cesr->cesr_element_status, avail * sizeof(struct changer_element_status)); + cam_periph_lock(periph); done: xpt_release_ccb(ccb); @@ -1356,7 +1339,7 @@ chgetparams(struct cam_periph *periph) */ mode_buffer_len = sizeof(struct scsi_mode_sense_data); - mode_buffer = kmalloc(mode_buffer_len, M_TEMP, M_INTWAIT | M_ZERO); + mode_buffer = kmalloc(mode_buffer_len, M_SCSICH, M_INTWAIT | M_ZERO); if (softc->quirks & CH_Q_NO_DBD) dbd = FALSE; @@ -1403,11 +1386,11 @@ chgetparams(struct cam_periph *periph) } if (error) { - xpt_print_path(periph->path); - kprintf("chgetparams: error getting element " - "address page\n"); + xpt_print(periph->path, + "chgetparams: error getting element " + "address page\n"); xpt_release_ccb(ccb); - kfree(mode_buffer, M_TEMP); + kfree(mode_buffer, M_SCSICH); return(error); } } @@ -1466,11 +1449,11 @@ chgetparams(struct cam_periph *periph) } if (error) { - xpt_print_path(periph->path); - kprintf("chgetparams: error getting device " - "capabilities page\n"); + xpt_print(periph->path, + "chgetparams: error getting device " + "capabilities page\n"); xpt_release_ccb(ccb); - kfree(mode_buffer, M_TEMP); + kfree(mode_buffer, M_SCSICH); return(error); } } @@ -1489,7 +1472,7 @@ chgetparams(struct cam_periph *periph) softc->sc_exchangemask[from] = exchanges[from]; } - kfree(mode_buffer, M_TEMP); + kfree(mode_buffer, M_SCSICH); return(error); } diff --git a/sys/bus/cam/scsi/scsi_da.c b/sys/bus/cam/scsi/scsi_da.c index 252aa8f..4ecb789 100644 --- a/sys/bus/cam/scsi/scsi_da.c +++ b/sys/bus/cam/scsi/scsi_da.c @@ -42,27 +42,20 @@ #include #include #include -#endif /* _KERNEL */ - -#include +#include #include -#ifdef _KERNEL +#include #include #include #include #include #include #include -#endif #include -#ifdef _KERNEL #include -#endif - -#include +#endif /* _KERNEL */ #ifdef _KERNEL -#include #include #endif @@ -76,6 +69,7 @@ #include "../cam_extend.h" #include "../cam_periph.h" #include "../cam_xpt_periph.h" +#include "../cam_sim.h" #include "scsi_message.h" @@ -149,6 +143,7 @@ struct da_softc { struct task sysctl_task; struct sysctl_ctx_list sysctl_ctx; struct sysctl_oid *sysctl_tree; + struct callout sendordered_c; }; struct da_quirk_entry { @@ -654,9 +649,10 @@ static struct dev_ops da_ops = { .d_dump = dadump }; -static SLIST_HEAD(,da_softc) softc_list; static struct extend_array *daperiphs; +MALLOC_DEFINE(M_SCSIDA, "scsi_da", "scsi_da buffers"); + static int daopen(struct dev_open_args *ap) { @@ -668,38 +664,35 @@ daopen(struct dev_open_args *ap) int error; unit = dkunit(dev); - crit_enter(); periph = cam_extend_get(daperiphs, unit); if (periph == NULL) { - crit_exit(); return (ENXIO); } + if (cam_periph_acquire(periph) != CAM_REQ_CMP) { + return(ENXIO); + } + + cam_periph_lock(periph); + if ((error = cam_periph_hold(periph, PCATCH)) != 0) { + cam_periph_unlock(periph); + cam_periph_release(periph); + return (error); + } + + unit = periph->unit_number; softc = (struct da_softc *)periph->softc; + softc->flags |= DA_FLAG_OPEN; CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("daopen: dev=%s (unit %d)\n", devtoname(dev), unit)); - if ((error = cam_periph_lock(periph, PCATCH)) != 0) { - crit_exit(); - return (error); /* error code from tsleep */ - } - - if ((softc->flags & DA_FLAG_OPEN) == 0) { - if (cam_periph_acquire(periph) != CAM_REQ_CMP) { - crit_exit(); - return(ENXIO); - } - softc->flags |= DA_FLAG_OPEN; - } - if ((softc->flags & DA_FLAG_PACK_INVALID) != 0) { /* Invalidate our pack information. */ disk_invalidate(&softc->disk); softc->flags &= ~DA_FLAG_PACK_INVALID; } - crit_exit(); error = dagetcapacity(periph); @@ -709,7 +702,7 @@ daopen(struct dev_open_args *ap) struct scsi_read_capacity_data *rcap; union ccb *ccb; - rcap = kmalloc(sizeof(*rcap), M_TEMP, M_INTWAIT | M_ZERO); + rcap = kmalloc(sizeof(*rcap), M_SCSIDA, M_INTWAIT | M_ZERO); ccb = cam_periph_getccb(periph, /*priority*/1); scsi_read_capacity(&ccb->csio, @@ -732,7 +725,7 @@ daopen(struct dev_open_args *ap) dasetgeom(periph, rcap); } - kfree(rcap, M_TEMP); + kfree(rcap, M_SCSIDA); } #endif @@ -794,6 +787,7 @@ daopen(struct dev_open_args *ap) softc->flags &= ~DA_FLAG_OPEN; cam_periph_release(periph); } + cam_periph_unhold(periph); cam_periph_unlock(periph); return (error); } @@ -812,12 +806,15 @@ daclose(struct dev_close_args *ap) if (periph == NULL) return (ENXIO); - softc = (struct da_softc *)periph->softc; - - if ((error = cam_periph_lock(periph, 0)) != 0) { - return (error); /* error code from tsleep */ + cam_periph_lock(periph); + if ((error = cam_periph_hold(periph, 0)) != 0) { + cam_periph_unlock(periph); + cam_periph_release(periph); + return (error); } + softc = (struct da_softc *)periph->softc; + if ((softc->quirks & DA_Q_NO_SYNC_CACHE) == 0) { union ccb *ccb; @@ -849,11 +846,10 @@ daclose(struct dev_close_args *ap) if (sense_key != SSD_KEY_ILLEGAL_REQUEST) scsi_sense_print(&ccb->csio); } else { - xpt_print_path(periph->path); - kprintf("Synchronize cache failed, status " - "== 0x%x, scsi status == 0x%x\n", - ccb->csio.ccb_h.status, - ccb->csio.scsi_status); + xpt_print(periph->path, "Synchronize cache " + "failed, status == 0x%x, scsi status == " + "0x%x\n", ccb->csio.ccb_h.status, + ccb->csio.scsi_status); } } @@ -886,9 +882,10 @@ daclose(struct dev_close_args *ap) softc->flags &= ~DA_FLAG_OPEN; cam_periph_release(periph); } else { - xpt_print_path(periph->path); - kprintf("daclose() called on an already closed device!\n"); + xpt_print(periph->path, + "daclose() called on an already closed device!\n"); } + cam_periph_unhold(periph); cam_periph_unlock(periph); return (0); } @@ -917,6 +914,9 @@ dastrategy(struct dev_strategy_args *ap) goto bad; } softc = (struct da_softc *)periph->softc; + + cam_periph_lock(periph); + #if 0 /* * check it's not too big a transfer for our adapter @@ -929,13 +929,12 @@ dastrategy(struct dev_strategy_args *ap) * after we are in the queue. Otherwise, we might not properly * clean up one of the buffers. */ - crit_enter(); /* * If the device has been made invalid, error out */ if ((softc->flags & DA_FLAG_PACK_INVALID)) { - crit_exit(); + cam_periph_unlock(periph); bp->b_error = ENXIO; goto bad; } @@ -944,13 +943,12 @@ dastrategy(struct dev_strategy_args *ap) * Place it in the queue of disk activities for this disk */ bioqdisksort(&softc->bio_queue, bio); - - crit_exit(); /* * Schedule ourselves for performing the work. */ xpt_schedule(periph, /* XXX priority */1); + cam_periph_unlock(periph); return(0); bad: @@ -988,8 +986,11 @@ dadump(struct dev_dump_args *ap) } softc = (struct da_softc *)periph->softc; - if ((softc->flags & DA_FLAG_PACK_INVALID) != 0) + cam_periph_lock(periph); + if ((softc->flags & DA_FLAG_PACK_INVALID) != 0) { + cam_periph_unlock(periph); return (ENXIO); + } addr = 0; /* starting address */ blkcnt = howmany(PAGE_SIZE, ap->a_secsize); @@ -1008,6 +1009,7 @@ dadump(struct dev_dump_args *ap) va = pmap_kenter_temporary(trunc_page(0), i); } + periph->flags |= CAM_PERIPH_POLLED; xpt_setup_ccb(&csio.ccb_h, periph->path, /*priority*/1); csio.ccb_h.ccb_state = DA_CCB_DUMP; scsi_read_write(&csio, @@ -1033,6 +1035,7 @@ dadump(struct dev_dump_args *ap) else kprintf("status == 0x%x, scsi status == 0x%x\n", csio.ccb_h.status, csio.scsi_status); + periph->flags |= CAM_PERIPH_POLLED; return(EIO); } @@ -1075,13 +1078,15 @@ dadump(struct dev_dump_args *ap) if (sense_key != SSD_KEY_ILLEGAL_REQUEST) scsi_sense_print(&csio); } else { - xpt_print_path(periph->path); - kprintf("Synchronize cache failed, status " - "== 0x%x, scsi status == 0x%x\n", - csio.ccb_h.status, csio.scsi_status); + xpt_print(periph->path, "Synchronize cache " + "failed, status == 0x%x, scsi status == " + "0x%x\n", csio.ccb_h.status, + csio.scsi_status); } } } + periph->flags &= ~CAM_PERIPH_POLLED; + cam_periph_unlock(periph); return (0); } @@ -1089,13 +1094,11 @@ static void dainit(void) { cam_status status; - struct cam_path *path; /* * Create our extend array for storing the devices we attach to. */ daperiphs = cam_extend_new(); - SLIST_INIT(&softc_list); if (daperiphs == NULL) { kprintf("da: Failed to alloc extend array!\n"); return; @@ -1107,35 +1110,13 @@ dainit(void) * Install a global async callback. This callback will * receive async callbacks like "new device found". */ - status = xpt_create_path(&path, /*periph*/NULL, CAM_XPT_PATH_ID, - CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD); - - if (status == CAM_REQ_CMP) { - struct ccb_setasync csa; - - xpt_setup_ccb(&csa.ccb_h, path, /*priority*/5); - csa.ccb_h.func_code = XPT_SASYNC_CB; - csa.event_enable = AC_FOUND_DEVICE; - csa.callback = daasync; - csa.callback_arg = NULL; - xpt_action((union ccb *)&csa); - status = csa.ccb_h.status; - xpt_free_path(path); - } + status = xpt_register_async(AC_FOUND_DEVICE, daasync, NULL, NULL); if (status != CAM_REQ_CMP) { kprintf("da: Failed to attach master async callback " "due to status 0x%x!\n", status); } else if (da_send_ordered) { - /* - * Schedule a periodic event to occasionally send an - * ordered tag to a device. - */ - callout_reset(&dasendorderedtag_ch, - (DA_DEFAULT_TIMEOUT * hz) / DA_ORDEREDTAG_INTERVAL, - dasendorderedtag, NULL); - /* Register our shutdown event handler */ if ((EVENTHANDLER_REGISTER(shutdown_post_sync, dashutdown, NULL, SHUTDOWN_PRI_DEFAULT)) == NULL) @@ -1149,30 +1130,17 @@ daoninvalidate(struct cam_periph *periph) struct da_softc *softc; struct bio *q_bio; struct buf *q_bp; - struct ccb_setasync csa; softc = (struct da_softc *)periph->softc; /* * De-register any async callbacks. */ - xpt_setup_ccb(&csa.ccb_h, periph->path, - /* priority */ 5); - csa.ccb_h.func_code = XPT_SASYNC_CB; - csa.event_enable = 0; - csa.callback = daasync; - csa.callback_arg = periph; - xpt_action((union ccb *)&csa); + xpt_register_async(0, daasync, periph, periph->path); softc->flags |= DA_FLAG_PACK_INVALID; /* - * Use a critical section to keep the buffer queue from being - * modified while we traverse it. - */ - crit_enter(); - - /* * Return all queued I/O with ENXIO. * XXX Handle any transactions queued to the card * with XPT_ABORT_CCB. @@ -1185,12 +1153,7 @@ daoninvalidate(struct cam_periph *periph) q_bp->b_flags |= B_ERROR; biodone(q_bio); } - crit_exit(); - - SLIST_REMOVE(&softc_list, softc, da_softc, links); - - xpt_print_path(periph->path); - kprintf("lost device\n"); + xpt_print(periph->path, "lost device\n"); } static void @@ -1202,19 +1165,21 @@ dacleanup(struct cam_periph *periph) devstat_remove_entry(&softc->device_stats); cam_extend_release(daperiphs, periph->unit_number); - xpt_print_path(periph->path); - kprintf("removing device entry\n"); + xpt_print(periph->path, "removing device entry\n"); /* * If we can't free the sysctl tree, oh well... */ if ((softc->flags & DA_FLAG_SCTX_INIT) != 0 && sysctl_ctx_free(&softc->sysctl_ctx) != 0) { - xpt_print_path(periph->path); - kprintf("can't remove sysctl context\n"); + xpt_print(periph->path, "can't remove sysctl context\n"); } if (softc->disk.d_rawdev) { + cam_periph_unlock(periph); disk_destroy(&softc->disk); + cam_periph_lock(periph); } + + callout_stop(&softc->sendordered_c); kfree(softc, M_DEVBUF); } @@ -1229,6 +1194,7 @@ daasync(void *callback_arg, u_int32_t code, case AC_FOUND_DEVICE: { struct ccb_getdev *cgd; + struct cam_sim *sim; cam_status status; cgd = (struct ccb_getdev *)arg; @@ -1245,6 +1211,7 @@ daasync(void *callback_arg, u_int32_t code, * this device and start the probe * process. */ + sim = xpt_path_sim(cgd->ccb_h.path); status = cam_periph_alloc(daregister, daoninvalidate, dacleanup, dastart, "da", CAM_PERIPH_BIO, @@ -1264,7 +1231,6 @@ daasync(void *callback_arg, u_int32_t code, struct ccb_hdr *ccbh; softc = (struct da_softc *)periph->softc; - crit_enter(); /* * Don't fail on the expected unit attention * that will occur. @@ -1272,7 +1238,6 @@ daasync(void *callback_arg, u_int32_t code, softc->flags |= DA_FLAG_RETRY_UA; LIST_FOREACH(ccbh, &softc->pending_ccbs, periph_links.le) ccbh->ccb_state |= DA_CCB_RETRY_UA; - crit_exit(); /* FALLTHROUGH*/ } default: @@ -1289,8 +1254,10 @@ dasysctlinit(void *context, int pending) char tmpstr[80], tmpstr2[80]; periph = (struct cam_periph *)context; - softc = (struct da_softc *)periph->softc; + if (cam_periph_acquire(periph) != CAM_REQ_CMP) + return; + softc = (struct da_softc *)periph->softc; ksnprintf(tmpstr, sizeof(tmpstr), "CAM DA unit %d", periph->unit_number); ksnprintf(tmpstr2, sizeof(tmpstr2), "%d", periph->unit_number); @@ -1301,6 +1268,7 @@ dasysctlinit(void *context, int pending) CTLFLAG_RD, 0, tmpstr); if (softc->sysctl_tree == NULL) { kprintf("dasysctlinit: unable to allocate sysctl tree\n"); + cam_periph_release(periph); return; } @@ -1312,6 +1280,8 @@ dasysctlinit(void *context, int pending) OID_AUTO, "minimum_cmd_size", CTLTYPE_INT | CTLFLAG_RW, &softc->minimum_cmd_size, 0, dacmdsizesysctl, "I", "Minimum CDB size"); + + cam_periph_release(periph); } static int @@ -1350,7 +1320,6 @@ static cam_status daregister(struct cam_periph *periph, void *arg) { struct da_softc *softc; - struct ccb_setasync csa; struct ccb_pathinq cpi; struct ccb_getdev *cgd; char tmpstr[80]; @@ -1432,14 +1401,6 @@ daregister(struct cam_periph *periph, void *arg) softc->minimum_cmd_size = 16; /* - * Block our timeout handler while we - * add this softc to the dev list. - */ - crit_enter(); - SLIST_INSERT_HEAD(&softc_list, softc, links); - crit_exit(); - - /* * The DA driver supports a blocksize, but * we don't know the blocksize until we do * a read capacity. So, set a flag to @@ -1456,8 +1417,11 @@ daregister(struct cam_periph *periph, void *arg) /* * Register this media as a disk */ + + CAM_SIM_UNLOCK(periph->sim); disk_create(periph->unit_number, &softc->disk, &da_ops); softc->disk.d_rawdev->si_iosize_max = MAXPHYS; + CAM_SIM_LOCK(periph->sim); /* * Add async callbacks for bus reset and @@ -1467,19 +1431,26 @@ daregister(struct cam_periph *periph, void *arg) * them and the only alternative would be to * not attach the device on failure. */ - xpt_setup_ccb(&csa.ccb_h, periph->path, /*priority*/5); - csa.ccb_h.func_code = XPT_SASYNC_CB; - csa.event_enable = AC_SENT_BDR | AC_BUS_RESET | AC_LOST_DEVICE; - csa.callback = daasync; - csa.callback_arg = periph; - xpt_action((union ccb *)&csa); + xpt_register_async(AC_SENT_BDR | AC_BUS_RESET | AC_LOST_DEVICE, + daasync, periph, periph->path); + /* - * Lock this peripheral until we are setup. - * This first call can't block + * Take an exclusive refcount on the periph while dastart is called + * to finish the probe. The reference will be dropped in dadone at + * the end of probe. */ - cam_periph_lock(periph, 0); + cam_periph_hold(periph, 0); xpt_schedule(periph, /*priority*/5); + /* + * Schedule a periodic event to occasionally send an + * ordered tag to a device. + */ + callout_init(&softc->sendordered_c); + callout_reset(&softc->sendordered_c, + (DA_DEFAULT_TIMEOUT * hz) / DA_ORDEREDTAG_INTERVAL, + dasendorderedtag, softc); + return(CAM_REQ_CMP); } @@ -1490,7 +1461,6 @@ dastart(struct cam_periph *periph, union ccb *start_ccb) softc = (struct da_softc *)periph->softc; - switch (softc->state) { case DA_STATE_NORMAL: { @@ -1501,7 +1471,6 @@ dastart(struct cam_periph *periph, union ccb *start_ccb) /* * See if there is a buf with work for us to do.. */ - crit_enter(); bio = bioq_first(&softc->bio_queue); if (periph->immediate_priority <= periph->pinfo.priority) { CAM_DEBUG_PRINT(CAM_DEBUG_SUBTRACE, @@ -1510,10 +1479,8 @@ dastart(struct cam_periph *periph, union ccb *start_ccb) SLIST_INSERT_HEAD(&periph->ccb_list, &start_ccb->ccb_h, periph_links.sle); periph->immediate_priority = CAM_PRIORITY_NONE; - crit_exit(); wakeup(&periph->ccb_list); } else if (bio == NULL) { - crit_exit(); xpt_release_ccb(start_ccb); } else { u_int8_t tag_code; @@ -1565,7 +1532,6 @@ dastart(struct cam_periph *periph, union ccb *start_ccb) start_ccb->ccb_h.ccb_bio = bio; bio = bioq_first(&softc->bio_queue); - crit_exit(); xpt_action(start_ccb); } @@ -1581,7 +1547,7 @@ dastart(struct cam_periph *periph, union ccb *start_ccb) struct ccb_scsiio *csio; struct scsi_read_capacity_data *rcap; - rcap = kmalloc(sizeof(*rcap), M_TEMP, M_INTWAIT | M_ZERO); + rcap = kmalloc(sizeof(*rcap), M_SCSIDA, M_INTWAIT | M_ZERO); csio = &start_ccb->csio; scsi_read_capacity(csio, /*retries*/4, @@ -1601,7 +1567,7 @@ dastart(struct cam_periph *periph, union ccb *start_ccb) struct scsi_read_capacity_data_long *rcaplong; rcaplong = (struct scsi_read_capacity_data_long *) - kmalloc(sizeof(*rcaplong), M_TEMP, M_INTWAIT); + kmalloc(sizeof(*rcaplong), M_SCSIDA, M_INTWAIT | M_ZERO); if (rcaplong == NULL) { kprintf("dastart: Couldn't allocate read_capacity\n"); /* da_free_periph??? */ @@ -1642,9 +1608,8 @@ cmd6workaround(union ccb *ccb) (*cdb != READ_6 && *cdb != WRITE_6)) return 0; - xpt_print_path(ccb->ccb_h.path); - kprintf("READ(6)/WRITE(6) not supported, " - "increasing minimum_cmd_size to 10.\n"); + xpt_print(ccb->ccb_h.path, "READ(6)/WRITE(6) not supported, " + "increasing minimum_cmd_size to 10.\n"); softc = (struct da_softc *)xpt_path_periph(ccb->ccb_h.path)->softc; softc->minimum_cmd_size = 10; @@ -1709,18 +1674,17 @@ dadone(struct cam_periph *periph, union ccb *done_ccb) struct bio *q_bio; struct buf *q_bp; - crit_enter(); - if (error == ENXIO) { /* * Catastrophic error. Mark our pack as * invalid. */ - /* XXX See if this is really a media - * change first. + /* + * XXX See if this is really a media + * XXX change first? */ - xpt_print_path(periph->path); - kprintf("Invalidating pack\n"); + xpt_print(periph->path, + "Invalidating pack\n"); softc->flags |= DA_FLAG_PACK_INVALID; } @@ -1738,7 +1702,6 @@ dadone(struct cam_periph *periph, union ccb *done_ccb) q_bp->b_flags |= B_ERROR; biodone(q_bio); } - crit_exit(); bp->b_error = error; bp->b_resid = bp->b_bcount; bp->b_flags |= B_ERROR; @@ -1766,12 +1729,10 @@ dadone(struct cam_periph *periph, union ccb *done_ccb) * Block out any asyncronous callbacks * while we touch the pending ccb list. */ - crit_enter(); LIST_REMOVE(&done_ccb->ccb_h, periph_links.le); softc->outstanding_cmds--; if (softc->outstanding_cmds == 0) softc->flags |= DA_FLAG_WENT_IDLE; - crit_exit(); devstat_end_transaction_buf(&softc->device_stats, bp); biodone(bio); @@ -1811,7 +1772,7 @@ dadone(struct cam_periph *periph, union ccb *done_ccb) */ if (maxsector == 0xffffffff) { softc->state = DA_STATE_PROBE2; - kfree(rdcap, M_TEMP); + kfree(rdcap, M_SCSIDA); xpt_release_ccb(done_ccb); xpt_schedule(periph, /*priority*/5); return; @@ -1909,14 +1870,13 @@ dadone(struct cam_periph *periph, union ccb *done_ccb) scsi_sense_print( &done_ccb->csio); else { - xpt_print_path(periph->path); - kprintf("got CAM status %#x\n", - done_ccb->ccb_h.status); + xpt_print(periph->path, + "got CAM status %#x\n", + done_ccb->ccb_h.status); } - xpt_print_path(periph->path); - kprintf("fatal error, failed" - " to attach to device\n"); + xpt_print(periph->path, "fatal error, " + "failed to attach to device\n"); /* * Free up resources. @@ -1925,7 +1885,7 @@ dadone(struct cam_periph *periph, union ccb *done_ccb) } } } - kfree(csio->data_ptr, M_TEMP); + kfree(csio->data_ptr, M_SCSIDA); if (announce_buf[0] != '\0') { xpt_announce_periph(periph, announce_buf); /* @@ -1945,7 +1905,7 @@ dadone(struct cam_periph *periph, union ccb *done_ccb) * operation. */ xpt_release_ccb(done_ccb); - cam_periph_unlock(periph); + cam_periph_unhold(periph); return; } case DA_CCB_WAITING: @@ -2062,7 +2022,8 @@ dagetcapacity(struct cam_periph *periph) error = 0; /* Do a read capacity */ - rcap = (void *)kmalloc(sizeof(*rcaplong), M_TEMP, M_INTWAIT); + rcap = (struct scsi_read_capacity_data *)kmalloc(sizeof(*rcaplong), + M_SCSIDA, M_INTWAIT); ccb = cam_periph_getccb(periph, /*priority*/1); scsi_read_capacity(&ccb->csio, @@ -2133,7 +2094,7 @@ done: xpt_release_ccb(ccb); - kfree(rcap, M_TEMP); + kfree(rcap, M_SCSIDA); return (error); } @@ -2188,25 +2149,22 @@ dasetgeom(struct cam_periph *periph, uint32_t block_len, uint64_t maxsector) static void dasendorderedtag(void *arg) { - struct da_softc *softc; + struct da_softc *softc = arg; if (da_send_ordered) { - SLIST_FOREACH(softc, &softc_list, links) { - crit_enter(); - if ((softc->ordered_tag_count == 0) - && ((softc->flags & DA_FLAG_WENT_IDLE) == 0)) { - softc->flags |= DA_FLAG_NEED_OTAG; - } - if (softc->outstanding_cmds > 0) - softc->flags &= ~DA_FLAG_WENT_IDLE; - softc->ordered_tag_count = 0; - crit_exit(); + if ((softc->ordered_tag_count == 0) + && ((softc->flags & DA_FLAG_WENT_IDLE) == 0)) { + softc->flags |= DA_FLAG_NEED_OTAG; } - /* Queue us up again */ - callout_reset(&dasendorderedtag_ch, - (da_default_timeout * hz) / DA_ORDEREDTAG_INTERVAL, - dasendorderedtag, NULL); + if (softc->outstanding_cmds > 0) + softc->flags &= ~DA_FLAG_WENT_IDLE; + + softc->ordered_tag_count = 0; } + /* Queue us up again */ + callout_reset(&softc->sendordered_c, + (DA_DEFAULT_TIMEOUT * hz) / DA_ORDEREDTAG_INTERVAL, + dasendorderedtag, softc); } /* @@ -2222,6 +2180,7 @@ dashutdown(void * arg, int howto) TAILQ_FOREACH(periph, &dadriver.units, unit_links) { union ccb ccb; + cam_periph_lock(periph); softc = (struct da_softc *)periph->softc; /* @@ -2229,8 +2188,10 @@ dashutdown(void * arg, int howto) * if the drive is capable of it.. */ if (((softc->flags & DA_FLAG_OPEN) == 0) - || (softc->quirks & DA_Q_NO_SYNC_CACHE)) + || (softc->quirks & DA_Q_NO_SYNC_CACHE)) { + cam_periph_unlock(periph); continue; + } xpt_setup_ccb(&ccb.ccb_h, periph->path, /*priority*/1); @@ -2259,10 +2220,10 @@ dashutdown(void * arg, int howto) if (sense_key != SSD_KEY_ILLEGAL_REQUEST) scsi_sense_print(&ccb.csio); } else { - xpt_print_path(periph->path); - kprintf("Synchronize cache failed, status " - "== 0x%x, scsi status == 0x%x\n", - ccb.ccb_h.status, ccb.csio.scsi_status); + xpt_print(periph->path, "Synchronize " + "cache failed, status == 0x%x, scsi status " + "== 0x%x\n", ccb.ccb_h.status, + ccb.csio.scsi_status); } } @@ -2273,6 +2234,7 @@ dashutdown(void * arg, int howto) /*timeout*/0, /*getcount_only*/0); + cam_periph_unlock(periph); } } diff --git a/sys/bus/cam/scsi/scsi_low.c b/sys/bus/cam/scsi/scsi_low.c index 9249aff..5673e61 100644 --- a/sys/bus/cam/scsi/scsi_low.c +++ b/sys/bus/cam/scsi/scsi_low.c @@ -781,7 +781,7 @@ scsi_low_attach_cam(struct scsi_low_softc *slp) slp->sl_si.sim = cam_sim_alloc(scsi_low_scsi_action_cam, scsi_low_poll_cam, DEVPORT_DEVNAME(slp->sl_dev), slp, - DEVPORT_DEVUNIT(slp->sl_dev), + DEVPORT_DEVUNIT(slp->sl_dev), &sim_mplock, slp->sl_openings, tagged_openings, devq); cam_simq_release(devq); if (slp->sl_si.sim == NULL) { diff --git a/sys/bus/cam/scsi/scsi_pass.c b/sys/bus/cam/scsi/scsi_pass.c index 0e1bb81..8405961 100644 --- a/sys/bus/cam/scsi/scsi_pass.c +++ b/sys/bus/cam/scsi/scsi_pass.c @@ -49,6 +49,7 @@ #include "../cam_queue.h" #include "../cam_xpt_periph.h" #include "../cam_debug.h" +#include "../cam_sim.h" #include "scsi_all.h" #include "scsi_message.h" @@ -125,7 +126,6 @@ static void passinit(void) { cam_status status; - struct cam_path *path; /* * Create our extend array for storing the devices we attach to. @@ -140,21 +140,7 @@ passinit(void) * Install a global async callback. This callback will * receive async callbacks like "new device found". */ - status = xpt_create_path(&path, /*periph*/NULL, CAM_XPT_PATH_ID, - CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD); - - if (status == CAM_REQ_CMP) { - struct ccb_setasync csa; - - xpt_setup_ccb(&csa.ccb_h, path, /*priority*/5); - csa.ccb_h.func_code = XPT_SASYNC_CB; - csa.event_enable = AC_FOUND_DEVICE; - csa.callback = passasync; - csa.callback_arg = NULL; - xpt_action((union ccb *)&csa); - status = csa.ccb_h.status; - xpt_free_path(path); - } + status = xpt_register_async(AC_FOUND_DEVICE, passasync, NULL, NULL); if (status != CAM_REQ_CMP) { kprintf("pass: Failed to attach master async callback " @@ -167,26 +153,18 @@ static void passoninvalidate(struct cam_periph *periph) { struct pass_softc *softc; - struct ccb_setasync csa; softc = (struct pass_softc *)periph->softc; /* * De-register any async callbacks. */ - xpt_setup_ccb(&csa.ccb_h, periph->path, - /* priority */ 5); - csa.ccb_h.func_code = XPT_SASYNC_CB; - csa.event_enable = 0; - csa.callback = passasync; - csa.callback_arg = periph; - xpt_action((union ccb *)&csa); + xpt_register_async(0, passasync, periph, periph->path); softc->flags |= PASS_FLAG_INVALID; if (bootverbose) { - xpt_print_path(periph->path); - kprintf("lost device\n"); + xpt_print(periph->path, "lost device\n"); } } @@ -203,8 +181,7 @@ passcleanup(struct cam_periph *periph) cam_extend_release(passperiphs, periph->unit_number); if (bootverbose) { - xpt_print_path(periph->path); - kprintf("removing device entry\n"); + xpt_print(periph->path, "removing device entry\n"); } dev_ops_remove(&pass_ops, -1, periph->unit_number); kfree(softc, M_DEVBUF); @@ -215,6 +192,7 @@ passasync(void *callback_arg, u_int32_t code, struct cam_path *path, void *arg) { struct cam_periph *periph; + struct cam_sim *sim; periph = (struct cam_periph *)callback_arg; @@ -233,6 +211,7 @@ passasync(void *callback_arg, u_int32_t code, * this device and start the probe * process. */ + sim = xpt_path_sim(cgd->ccb_h.path); status = cam_periph_alloc(passregister, passoninvalidate, passcleanup, passstart, "pass", CAM_PERIPH_BIO, cgd->ccb_h.path, @@ -261,7 +240,6 @@ static cam_status passregister(struct cam_periph *periph, void *arg) { struct pass_softc *softc; - struct ccb_setasync csa; struct ccb_getdev *cgd; int no_tags; @@ -288,6 +266,7 @@ passregister(struct cam_periph *periph, void *arg) * know what the blocksize of this device is, if * it even has a blocksize. */ + CAM_SIM_UNLOCK(periph->sim); no_tags = (cgd->inq_data.flags & SID_CmdQue) == 0; devstat_add_entry(&softc->device_stats, "pass", periph->unit_number, 0, DEVSTAT_NO_BLOCKSIZE @@ -302,17 +281,12 @@ passregister(struct cam_periph *periph, void *arg) make_dev(&pass_ops, periph->unit_number, UID_ROOT, GID_OPERATOR, 0600, "%s%d", periph->periph_name, periph->unit_number); - + CAM_SIM_LOCK(periph->sim); /* * Add an async callback so that we get * notified if this device goes away. */ - xpt_setup_ccb(&csa.ccb_h, periph->path, /* priority */ 5); - csa.ccb_h.func_code = XPT_SASYNC_CB; - csa.event_enable = AC_LOST_DEVICE; - csa.callback = passasync; - csa.callback_arg = periph; - xpt_action((union ccb *)&csa); + xpt_register_async(AC_LOST_DEVICE, passasync, periph, periph->path); if (bootverbose) xpt_announce_periph(periph, NULL); @@ -336,14 +310,16 @@ passopen(struct dev_open_args *ap) periph = cam_extend_get(passperiphs, unit); - if (periph == NULL) + if (cam_periph_acquire(periph) != CAM_REQ_CMP) return (ENXIO); + cam_periph_lock(periph); + softc = (struct pass_softc *)periph->softc; - crit_enter(); if (softc->flags & PASS_FLAG_INVALID) { - crit_exit(); + cam_periph_unlock(periph); + cam_periph_release(periph); return(ENXIO); } @@ -351,7 +327,8 @@ passopen(struct dev_open_args *ap) * Don't allow access when we're running at a high securelevel. */ if (securelevel > 1) { - crit_exit(); + cam_periph_unlock(periph); + cam_periph_release(periph); return(EPERM); } @@ -359,7 +336,8 @@ passopen(struct dev_open_args *ap) * Only allow read-write access. */ if (((ap->a_oflags & FWRITE) == 0) || ((ap->a_oflags & FREAD) == 0)) { - crit_exit(); + cam_periph_unlock(periph); + cam_periph_release(periph); return(EPERM); } @@ -367,23 +345,17 @@ passopen(struct dev_open_args *ap) * We don't allow nonblocking access. */ if ((ap->a_oflags & O_NONBLOCK) != 0) { - xpt_print_path(periph->path); - kprintf("can't do nonblocking access\n"); - crit_exit(); + xpt_print(periph->path, "can't do nonblocking access\n"); + cam_periph_unlock(periph); + cam_periph_release(periph); return(EINVAL); } - if ((error = cam_periph_lock(periph, PCATCH)) != 0) { - crit_exit(); - return (error); - } - - crit_exit(); - if ((softc->flags & PASS_FLAG_OPEN) == 0) { - if (cam_periph_acquire(periph) != CAM_REQ_CMP) - return(ENXIO); softc->flags |= PASS_FLAG_OPEN; + } else { + /* Device closes aren't symmertical, so fix up the refcount */ + cam_periph_release(periph); } cam_periph_unlock(periph); @@ -397,7 +369,7 @@ passclose(struct dev_close_args *ap) cdev_t dev = ap->a_head.a_dev; struct cam_periph *periph; struct pass_softc *softc; - int unit, error; + int unit; /* unit = dkunit(dev); */ /* XXX KDM fix this */ @@ -407,11 +379,9 @@ passclose(struct dev_close_args *ap) if (periph == NULL) return (ENXIO); - softc = (struct pass_softc *)periph->softc; - - if ((error = cam_periph_lock(periph, 0)) != 0) - return (error); + cam_periph_lock(periph); + softc = (struct pass_softc *)periph->softc; softc->flags &= ~PASS_FLAG_OPEN; cam_periph_unlock(periph); @@ -429,12 +399,10 @@ passstart(struct cam_periph *periph, union ccb *start_ccb) switch (softc->state) { case PASS_STATE_NORMAL: - crit_enter(); start_ccb->ccb_h.ccb_type = PASS_CCB_WAITING; SLIST_INSERT_HEAD(&periph->ccb_list, &start_ccb->ccb_h, periph_links.sle); periph->immediate_priority = CAM_PRIORITY_NONE; - crit_exit(); wakeup(&periph->ccb_list); break; } @@ -477,6 +445,7 @@ passioctl(struct dev_ioctl_args *ap) if (periph == NULL) return(ENXIO); + cam_periph_lock(periph); softc = (struct pass_softc *)periph->softc; error = 0; @@ -496,9 +465,9 @@ passioctl(struct dev_ioctl_args *ap) * through the transport layer device. */ if (inccb->ccb_h.func_code & XPT_FC_XPT_ONLY) { - xpt_print_path(periph->path); - kprintf("CCB function code %#x is restricted to the " - "XPT device\n", inccb->ccb_h.func_code); + xpt_print(periph->path, "CCB function code %#x is " + "restricted to the XPT device\n", + inccb->ccb_h.func_code); error = ENODEV; break; } @@ -524,8 +493,7 @@ passioctl(struct dev_ioctl_args *ap) } if (ccb == NULL) { - xpt_print_path(periph->path); - kprintf("unable to allocate CCB\n"); + xpt_print(periph->path, "unable to allocate CCB\n"); error = ENOMEM; break; } @@ -544,6 +512,7 @@ passioctl(struct dev_ioctl_args *ap) break; } + cam_periph_unlock(periph); return(error); } @@ -592,7 +561,14 @@ passsendccb(struct cam_periph *periph, union ccb *ccb, union ccb *inccb) bzero(&mapinfo, sizeof(mapinfo)); + /* + * cam_periph_mapmem calls into proc and vm functions that can + * sleep as well as trigger I/O, so we can't hold the lock. + * Dropping it here is reasonably safe. + */ + cam_periph_unlock(periph); error = cam_periph_mapmem(ccb, &mapinfo); + cam_periph_lock(periph); /* * cam_periph_mapmem returned an error, we can't continue. diff --git a/sys/bus/cam/scsi/scsi_pt.c b/sys/bus/cam/scsi/scsi_pt.c index bcac1b3..44fcd50 100644 --- a/sys/bus/cam/scsi/scsi_pt.c +++ b/sys/bus/cam/scsi/scsi_pt.c @@ -144,38 +144,31 @@ ptopen(struct dev_open_args *ap) struct cam_periph *periph; struct pt_softc *softc; int unit; - int error; + int error = 0; unit = minor(dev); periph = cam_extend_get(ptperiphs, unit); - if (periph == NULL) + if (cam_periph_acquire(periph) != CAM_REQ_CMP) return (ENXIO); softc = (struct pt_softc *)periph->softc; - crit_enter(); + cam_periph_lock(periph); if (softc->flags & PT_FLAG_DEVICE_INVALID) { - crit_exit(); + cam_periph_unlock(periph); + cam_periph_release(periph); return(ENXIO); } - CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, - ("ptopen: dev=%s (unit %d)\n", devtoname(dev), unit)); - - if ((error = cam_periph_lock(periph, PCATCH)) != 0) { - crit_exit(); - return (error); /* error code from tsleep */ + if ((softc->flags & PT_FLAG_OPEN) == 0) + softc->flags |= PT_FLAG_OPEN; + else { + error = EBUSY; + cam_periph_release(periph); } - crit_exit(); - - if ((softc->flags & PT_FLAG_OPEN) == 0) { - if (cam_periph_acquire(periph) != CAM_REQ_CMP) - error = ENXIO; - else - softc->flags |= PT_FLAG_OPEN; - } else - error = EBUSY; + CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, + ("ptopen: dev=%s\n", devtoname(dev))); cam_periph_unlock(periph); return (error); @@ -188,7 +181,6 @@ ptclose(struct dev_close_args *ap) struct cam_periph *periph; struct pt_softc *softc; int unit; - int error; unit = minor(dev); periph = cam_extend_get(ptperiphs, unit); @@ -197,8 +189,7 @@ ptclose(struct dev_close_args *ap) softc = (struct pt_softc *)periph->softc; - if ((error = cam_periph_lock(periph, 0)) != 0) - return (error); /* error code from tsleep */ + cam_periph_lock(periph); softc->flags &= ~PT_FLAG_OPEN; cam_periph_unlock(periph); @@ -227,20 +218,14 @@ ptstrategy(struct dev_strategy_args *ap) bp->b_error = ENXIO; goto bad; } + cam_periph_lock(periph); softc = (struct pt_softc *)periph->softc; /* - * Mask interrupts so that the pack cannot be invalidated until - * after we are in the queue. Otherwise, we might not properly - * clean up one of the buffers. - */ - crit_enter(); - - /* * If the device has been made invalid, error out */ if ((softc->flags & PT_FLAG_DEVICE_INVALID)) { - crit_exit(); + cam_periph_unlock(periph); bp->b_error = ENXIO; goto bad; } @@ -249,13 +234,12 @@ ptstrategy(struct dev_strategy_args *ap) * Place it in the queue of disk activities for this disk */ bioq_insert_tail(&softc->bio_queue, bio); - - crit_exit(); /* * Schedule ourselves for performing the work. */ xpt_schedule(periph, /* XXX priority */1); + cam_periph_unlock(periph); return(0); bad: @@ -273,7 +257,6 @@ static void ptinit(void) { cam_status status; - struct cam_path *path; /* * Create our extend array for storing the devices we attach to. @@ -288,21 +271,7 @@ ptinit(void) * Install a global async callback. This callback will * receive async callbacks like "new device found". */ - status = xpt_create_path(&path, /*periph*/NULL, CAM_XPT_PATH_ID, - CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD); - - if (status == CAM_REQ_CMP) { - struct ccb_setasync csa; - - xpt_setup_ccb(&csa.ccb_h, path, /*priority*/5); - csa.ccb_h.func_code = XPT_SASYNC_CB; - csa.event_enable = AC_FOUND_DEVICE; - csa.callback = ptasync; - csa.callback_arg = NULL; - xpt_action((union ccb *)&csa); - status = csa.ccb_h.status; - xpt_free_path(path); - } + status = xpt_register_async(AC_FOUND_DEVICE, ptasync, NULL, NULL); if (status != CAM_REQ_CMP) { kprintf("pt: Failed to attach master async callback " @@ -314,7 +283,6 @@ static cam_status ptctor(struct cam_periph *periph, void *arg) { struct pt_softc *softc; - struct ccb_setasync csa; struct ccb_getdev *cgd; cgd = (struct ccb_getdev *)arg; @@ -337,6 +305,7 @@ ptctor(struct cam_periph *periph, void *arg) periph->softc = softc; + cam_periph_unlock(periph); cam_extend_set(ptperiphs, periph->unit_number, periph); devstat_add_entry(&softc->device_stats, "pt", @@ -349,6 +318,7 @@ ptctor(struct cam_periph *periph, void *arg) make_dev(&pt_ops, periph->unit_number, UID_ROOT, GID_OPERATOR, 0600, "%s%d", periph->periph_name, periph->unit_number); + cam_periph_lock(periph); /* * Add async callbacks for bus reset and * bus device reset calls. I don't bother @@ -357,12 +327,8 @@ ptctor(struct cam_periph *periph, void *arg) * them and the only alternative would be to * not attach the device on failure. */ - xpt_setup_ccb(&csa.ccb_h, periph->path, /*priority*/5); - csa.ccb_h.func_code = XPT_SASYNC_CB; - csa.event_enable = AC_SENT_BDR | AC_BUS_RESET | AC_LOST_DEVICE; - csa.callback = ptasync; - csa.callback_arg = periph; - xpt_action((union ccb *)&csa); + xpt_register_async(AC_SENT_BDR | AC_BUS_RESET | AC_LOST_DEVICE, + ptasync, periph, periph->path); /* Tell the user we've attached to the device */ xpt_announce_periph(periph, NULL); @@ -376,30 +342,17 @@ ptoninvalidate(struct cam_periph *periph) struct pt_softc *softc; struct bio *q_bio; struct buf *q_bp; - struct ccb_setasync csa; softc = (struct pt_softc *)periph->softc; /* * De-register any async callbacks. */ - xpt_setup_ccb(&csa.ccb_h, periph->path, - /* priority */ 5); - csa.ccb_h.func_code = XPT_SASYNC_CB; - csa.event_enable = 0; - csa.callback = ptasync; - csa.callback_arg = periph; - xpt_action((union ccb *)&csa); + xpt_register_async(0, ptasync, periph, periph->path); softc->flags |= PT_FLAG_DEVICE_INVALID; /* - * We need to be in a critical section here to keep the buffer - * queue from being modified while we traverse it. - */ - crit_enter(); - - /* * Return all queued I/O with ENXIO. * XXX Handle any transactions queued to the card * with XPT_ABORT_CCB. @@ -413,10 +366,7 @@ ptoninvalidate(struct cam_periph *periph) biodone(q_bio); } - crit_exit(); - - xpt_print_path(periph->path); - kprintf("lost device\n"); + xpt_print(periph->path, "lost device\n"); } static void @@ -429,8 +379,7 @@ ptdtor(struct cam_periph *periph) devstat_remove_entry(&softc->device_stats); cam_extend_release(ptperiphs, periph->unit_number); - xpt_print_path(periph->path); - kprintf("removing device entry\n"); + xpt_print(periph->path, "removing device entry\n"); dev_ops_remove(&pt_ops, -1, periph->unit_number); kfree(softc, M_DEVBUF); } @@ -477,16 +426,13 @@ ptasync(void *callback_arg, u_int32_t code, struct cam_path *path, void *arg) struct ccb_hdr *ccbh; softc = (struct pt_softc *)periph->softc; - crit_enter(); /* * Don't fail on the expected unit attention * that will occur. */ softc->flags |= PT_FLAG_RETRY_UA; - for (ccbh = LIST_FIRST(&softc->pending_ccbs); - ccbh != NULL; ccbh = LIST_NEXT(ccbh, periph_links.le)) + LIST_FOREACH(ccbh, &softc->pending_ccbs, periph_links.le) ccbh->ccb_state |= PT_CCB_RETRY_UA; - crit_exit(); /* FALLTHROUGH */ } default: @@ -507,7 +453,6 @@ ptstart(struct cam_periph *periph, union ccb *start_ccb) /* * See if there is a buf with work for us to do.. */ - crit_enter(); bio = bioq_first(&softc->bio_queue); if (periph->immediate_priority <= periph->pinfo.priority) { CAM_DEBUG_PRINT(CAM_DEBUG_SUBTRACE, @@ -516,10 +461,8 @@ ptstart(struct cam_periph *periph, union ccb *start_ccb) SLIST_INSERT_HEAD(&periph->ccb_list, &start_ccb->ccb_h, periph_links.sle); periph->immediate_priority = CAM_PRIORITY_NONE; - crit_exit(); wakeup(&periph->ccb_list); } else if (bio == NULL) { - crit_exit(); xpt_release_ccb(start_ccb); } else { bioq_remove(&softc->bio_queue, bio); @@ -549,7 +492,6 @@ ptstart(struct cam_periph *periph, union ccb *start_ccb) start_ccb->ccb_h.ccb_bio = bio; bio = bioq_first(&softc->bio_queue); - crit_exit(); xpt_action(start_ccb); @@ -599,15 +541,13 @@ ptdone(struct cam_periph *periph, union ccb *done_ccb) struct buf *q_bp; struct bio *q_bio; - crit_enter(); - if (error == ENXIO) { /* * Catastrophic error. Mark our device * as invalid. */ - xpt_print_path(periph->path); - kprintf("Invalidating device\n"); + xpt_print(periph->path, + "Invalidating device\n"); softc->flags |= PT_FLAG_DEVICE_INVALID; } @@ -625,7 +565,6 @@ ptdone(struct cam_periph *periph, union ccb *done_ccb) q_bp->b_flags |= B_ERROR; biodone(q_bio); } - crit_exit(); bp->b_error = error; bp->b_resid = bp->b_bcount; bp->b_flags |= B_ERROR; @@ -653,9 +592,7 @@ ptdone(struct cam_periph *periph, union ccb *done_ccb) * Block out any asyncronous callbacks * while we touch the pending ccb list. */ - crit_enter(); LIST_REMOVE(&done_ccb->ccb_h, periph_links.le); - crit_exit(); devstat_end_transaction_buf(&softc->device_stats, bp); biodone(bio); @@ -690,7 +627,7 @@ ptioctl(struct dev_ioctl_args *ap) struct cam_periph *periph; struct pt_softc *softc; int unit; - int error; + int error = 0; unit = minor(dev); periph = cam_extend_get(ptperiphs, unit); @@ -700,9 +637,7 @@ ptioctl(struct dev_ioctl_args *ap) softc = (struct pt_softc *)periph->softc; - if ((error = cam_periph_lock(periph, PCATCH)) != 0) { - return (error); /* error code from tsleep */ - } + cam_periph_lock(periph); switch(ap->a_cmd) { case PTIOCGETTIMEOUT: @@ -712,18 +647,14 @@ ptioctl(struct dev_ioctl_args *ap) *(int *)addr = 0; break; case PTIOCSETTIMEOUT: - { if (*(int *)addr < 1) { error = EINVAL; break; } - crit_enter(); softc->io_timeout = *(int *)addr * 1000; - crit_exit(); break; - } default: error = cam_periph_ioctl(periph, ap->a_cmd, addr, pterror); break; diff --git a/sys/bus/cam/scsi/scsi_sa.c b/sys/bus/cam/scsi/scsi_sa.c index fced040..efbdb55 100644 --- a/sys/bus/cam/scsi/scsi_sa.c +++ b/sys/bus/cam/scsi/scsi_sa.c @@ -452,33 +452,30 @@ saopen(struct dev_open_args *ap) unit = SAUNIT(dev); - crit_enter(); periph = cam_extend_get(saperiphs, unit); - if (periph == NULL) { - crit_exit(); - return (ENXIO); + if (cam_periph_acquire(periph) != CAM_REQ_CMP) { + return (ENXIO); } + + cam_periph_lock(periph); + softc = (struct sa_softc *)periph->softc; - if ((error = cam_periph_lock(periph, PCATCH)) != 0) { - crit_exit(); - return (error); - } - crit_exit(); CAM_DEBUG(periph->path, CAM_DEBUG_TRACE|CAM_DEBUG_INFO, ("saopen(%d): dev=0x%x softc=0x%x\n", unit, unit, softc->flags)); - if (cam_periph_acquire(periph) != CAM_REQ_CMP) { - cam_periph_unlock(periph); - return (ENXIO); - } - if (SA_IS_CTRL(dev)) { softc->ctrl_mode = 1; cam_periph_unlock(periph); return (0); } + if ((error = cam_periph_hold(periph, PCATCH)) != 0) { + cam_periph_unlock(periph); + cam_periph_release(periph); + return (error); + } + if (softc->flags & SA_FLAG_OPEN) { error = EBUSY; } else if (softc->flags & SA_FLAG_INVALID) { @@ -500,17 +497,23 @@ saopen(struct dev_open_args *ap) if (error && (ap->a_oflags & O_NONBLOCK)) { softc->flags |= SA_FLAG_OPEN; softc->open_pending_mount = 1; + cam_periph_unhold(periph); cam_periph_unlock(periph); return (0); } } if (error) { + cam_periph_unhold(periph); + cam_periph_unlock(periph); cam_periph_release(periph); - } else { - saprevent(periph, PR_PREVENT); - softc->flags |= SA_FLAG_OPEN; + return (error); } + + saprevent(periph, PR_PREVENT); + softc->flags |= SA_FLAG_OPEN; + + cam_periph_unhold(periph); cam_periph_unlock(periph); return (error); } @@ -530,32 +533,35 @@ saclose(struct dev_close_args *ap) if (periph == NULL) return (ENXIO); + cam_periph_lock(periph); + softc = (struct sa_softc *)periph->softc; CAM_DEBUG(periph->path, CAM_DEBUG_TRACE|CAM_DEBUG_INFO, ("saclose(%d): dev=0x%x softc=0x%x\n", unit, unit, softc->flags)); - if ((error = cam_periph_lock(periph, 0)) != 0) { - return (error); - } - softc->open_rdonly = 0; if (SA_IS_CTRL(dev)) { softc->ctrl_mode = 0; - cam_periph_release(periph); cam_periph_unlock(periph); + cam_periph_release(periph); return (0); } if (softc->open_pending_mount) { softc->flags &= ~SA_FLAG_OPEN; softc->open_pending_mount = 0; - cam_periph_release(periph); cam_periph_unlock(periph); + cam_periph_release(periph); return (0); } + if ((error = cam_periph_hold(periph, 0)) != 0) { + cam_periph_unlock(periph); + return (error); + } + /* * Were we writing the tape? */ @@ -568,8 +574,8 @@ saclose(struct dev_close_args *ap) */ error = sacheckeod(periph); if (error) { - xpt_print_path(periph->path); - kprintf("failed to write terminating filemark(s)\n"); + xpt_print(periph->path, + "failed to write terminating filemark(s)\n"); softc->flags |= SA_FLAG_TAPE_FROZEN; } @@ -624,19 +630,18 @@ saclose(struct dev_close_args *ap) if (error == 0 && writing && (softc->quirks & SA_QUIRK_2FM)) { tmp = saspace(periph, -1, SS_FILEMARKS); if (tmp) { - xpt_print_path(periph->path); - kprintf("unable to backspace over one of double" - " filemarks at end of tape\n"); - xpt_print_path(periph->path); - kprintf("it is possible that this device" - " needs a SA_QUIRK_1FM quirk set for it\n"); + xpt_print(periph->path, "unable to backspace " + "over one of double filemarks at end of " + "tape\n"); + xpt_print(periph->path, "it is possible that " + "this device needs a SA_QUIRK_1FM quirk set" + "for it\n"); softc->flags |= SA_FLAG_TAPE_FROZEN; } } break; default: - xpt_print_path(periph->path); - panic("unknown mode 0x%x in saclose", mode); + xpt_print(periph->path, "unknown mode 0x%x in saclose\n", mode); /* NOTREACHED */ break; } @@ -656,15 +661,15 @@ saclose(struct dev_close_args *ap) * Inform users if tape state if frozen.... */ if (softc->flags & SA_FLAG_TAPE_FROZEN) { - xpt_print_path(periph->path); - kprintf("tape is now frozen- use an OFFLINE, REWIND or MTEOM " - "command to clear this state.\n"); + xpt_print(periph->path, "tape is now frozen- use an OFFLINE, " + "REWIND or MTEOM command to clear this state.\n"); } /* release the device if it is no longer mounted */ if ((softc->flags & SA_FLAG_TAPE_MOUNTED) == 0) sareservereleaseunit(periph, FALSE); + cam_periph_unhold(periph); cam_periph_unlock(periph); cam_periph_release(periph); @@ -696,18 +701,18 @@ sastrategy(struct dev_strategy_args *ap) bp->b_error = ENXIO; goto bad; } - softc = (struct sa_softc *)periph->softc; + cam_periph_lock(periph); - crit_enter(); + softc = (struct sa_softc *)periph->softc; if (softc->flags & SA_FLAG_INVALID) { - crit_exit(); + cam_periph_unlock(periph); bp->b_error = ENXIO; goto bad; } if (softc->flags & SA_FLAG_TAPE_FROZEN) { - crit_exit(); + cam_periph_unlock(periph); bp->b_error = EPERM; goto bad; } @@ -718,16 +723,15 @@ sastrategy(struct dev_strategy_args *ap) * file descriptor. */ if (bp->b_cmd == BUF_CMD_WRITE && softc->open_rdonly) { - crit_exit(); + cam_periph_unlock(periph); bp->b_error = EBADF; goto bad; } - crit_exit(); - if (softc->open_pending_mount) { int error = samount(periph, 0, dev); if (error) { + cam_periph_unlock(periph); bp->b_error = ENXIO; goto bad; } @@ -738,8 +742,10 @@ sastrategy(struct dev_strategy_args *ap) /* * If it's a null transfer, return immediately */ - if (bp->b_bcount == 0) + if (bp->b_bcount == 0) { + cam_periph_unlock(periph); goto done; + } /* valid request? */ if (softc->flags & SA_FLAG_FIXED) { @@ -751,10 +757,10 @@ sastrategy(struct dev_strategy_args *ap) ((bp->b_bcount & softc->blk_mask) != 0)) || ((softc->blk_mask == ~0) && ((bp->b_bcount % softc->min_blk) != 0))) { - xpt_print_path(periph->path); - kprintf("Invalid request. Fixed block device " - "requests must be a multiple " - "of %d bytes\n", softc->media_blksize); + xpt_print(periph->path, "Invalid request. Fixed block " + "device requests must be a multiple of %d bytes\n", + softc->min_blk); + cam_periph_unlock(periph); bp->b_error = EINVAL; goto bad; } @@ -763,25 +769,19 @@ sastrategy(struct dev_strategy_args *ap) (bp->b_bcount & softc->blk_mask) != 0) { xpt_print_path(periph->path); - kprintf("Invalid request. Variable block device " - "requests must be "); + kprintf("Invalid request. Variable block " + "device requests must be "); if (softc->blk_mask != 0) { kprintf("a multiple of %d ", (0x1 << softc->blk_gran)); } kprintf("between %d and %d bytes\n", softc->min_blk, softc->max_blk); + cam_periph_unlock(periph); bp->b_error = EINVAL; goto bad; } /* - * Mask interrupts so that the device cannot be invalidated until - * after we are in the queue. Otherwise, we might not properly - * clean up one of the buffers. - */ - crit_enter(); - - /* * Place it at the end of the queue. */ bioq_insert_tail(&softc->bio_queue, bio); @@ -796,12 +796,12 @@ sastrategy(struct dev_strategy_args *ap) CAM_DEBUG(periph->path, CAM_DEBUG_INFO, ("sastrategy: queue count now %d\n", softc->queue_count)); } - crit_exit(); /* * Schedule ourselves for performing the work. */ xpt_schedule(periph, 1); + cam_periph_unlock(periph); return(0); bad: @@ -849,6 +849,7 @@ saioctl(struct dev_ioctl_args *ap) if (periph == NULL) return (ENXIO); + cam_periph_lock(periph); softc = (struct sa_softc *)periph->softc; /* @@ -874,16 +875,13 @@ saioctl(struct dev_ioctl_args *ap) * other thread that has this device open to do * an MTIOCERRSTAT that would clear latched status. */ - crit_enter(); if ((periph->flags & CAM_PERIPH_LOCKED) == 0) { - error = cam_periph_lock(periph, PCATCH); + error = cam_periph_hold(periph, PCATCH); if (error != 0) { - crit_exit(); return (error); } didlockperiph = 1; } - crit_exit(); break; case MTIOCTOP: @@ -914,14 +912,11 @@ saioctl(struct dev_ioctl_args *ap) * than at open time because we are sharing writable * access to data structures. */ - crit_enter(); - error = cam_periph_lock(periph, PCATCH); + error = cam_periph_hold(periph, PCATCH); if (error != 0) { - crit_exit(); return (error); } didlockperiph = 1; - crit_exit(); break; default: @@ -1086,8 +1081,8 @@ saioctl(struct dev_ioctl_args *ap) nmarks = softc->filemarks; error = sacheckeod(periph); if (error) { - xpt_print_path(periph->path); - kprintf("EOD check prior to spacing failed\n"); + xpt_print(periph->path, + "EOD check prior to spacing failed\n"); softc->flags |= SA_FLAG_EIO_PENDING; break; } @@ -1338,16 +1333,17 @@ saioctl(struct dev_ioctl_args *ap) softc->fileno = (daddr_t) -1; softc->blkno = (daddr_t) -1; softc->flags &= ~SA_FLAG_TAPE_FROZEN; - xpt_print_path(periph->path); - kprintf("tape state now unfrozen.\n"); + xpt_print(periph->path, + "tape state now unfrozen.\n"); break; default: break; } } if (didlockperiph) { - cam_periph_unlock(periph); + cam_periph_unhold(periph); } + cam_periph_unlock(periph); return (error); } @@ -1355,7 +1351,6 @@ static void sainit(void) { cam_status status; - struct cam_path *path; /* * Create our extend array for storing the devices we attach to. @@ -1369,24 +1364,7 @@ sainit(void) /* * Install a global async callback. */ - status = xpt_create_path(&path, NULL, CAM_XPT_PATH_ID, - CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD); - - if (status == CAM_REQ_CMP) { - /* Register the async callbacks of interrest */ - struct ccb_setasync csa; /* - * This is an immediate CCB, - * so using the stack is OK - */ - xpt_setup_ccb(&csa.ccb_h, path, 5); - csa.ccb_h.func_code = XPT_SASYNC_CB; - csa.event_enable = AC_FOUND_DEVICE; - csa.callback = saasync; - csa.callback_arg = NULL; - xpt_action((union ccb *)&csa); - status = csa.ccb_h.status; - xpt_free_path(path); - } + status = xpt_register_async(AC_FOUND_DEVICE, saasync, NULL, NULL); if (status != CAM_REQ_CMP) { kprintf("sa: Failed to attach master async callback " @@ -1400,30 +1378,17 @@ saoninvalidate(struct cam_periph *periph) struct sa_softc *softc; struct buf *q_bp; struct bio *q_bio; - struct ccb_setasync csa; softc = (struct sa_softc *)periph->softc; /* * De-register any async callbacks. */ - xpt_setup_ccb(&csa.ccb_h, periph->path, - /* priority */ 5); - csa.ccb_h.func_code = XPT_SASYNC_CB; - csa.event_enable = 0; - csa.callback = saasync; - csa.callback_arg = periph; - xpt_action((union ccb *)&csa); + xpt_register_async(0, saasync, periph, periph->path); softc->flags |= SA_FLAG_INVALID; /* - * We need to be in a critical section here to keep the buffer - * queue from being modified while we traverse it. - */ - crit_enter(); - - /* * Return all queued I/O with ENXIO. * XXX Handle any transactions queued to the card * with XPT_ABORT_CCB. @@ -1437,10 +1402,8 @@ saoninvalidate(struct cam_periph *periph) biodone(q_bio); } softc->queue_count = 0; - crit_exit(); - xpt_print_path(periph->path); - kprintf("lost device\n"); + xpt_print(periph->path, "lost device\n"); } @@ -1454,8 +1417,7 @@ sacleanup(struct cam_periph *periph) devstat_remove_entry(&softc->device_stats); cam_extend_release(saperiphs, periph->unit_number); - xpt_print_path(periph->path); - kprintf("removing device entry\n"); + xpt_print(periph->path, "removing device entry\n"); dev_ops_remove(&sa_ops, SA_UNITMASK, SA_UNIT(periph->unit_number)); kfree(softc, M_SCSISA); } @@ -1506,7 +1468,6 @@ static cam_status saregister(struct cam_periph *periph, void *arg) { struct sa_softc *softc; - struct ccb_setasync csa; struct ccb_getdev *cgd; caddr_t match; int i; @@ -1545,9 +1506,8 @@ saregister(struct cam_periph *periph, void *arg) softc->last_media_blksize = ((struct sa_quirk_entry *)match)->prefblk; #ifdef CAMDEBUG - xpt_print_path(periph->path); - kprintf("found quirk entry %d\n", (int) - (((struct sa_quirk_entry *) match) - sa_quirk_table)); + xpt_print(periph->path, "found quirk entry %d\n", + (int) (((struct sa_quirk_entry *) match) - sa_quirk_table)); #endif } else softc->quirks = SA_QUIRK_NONE; @@ -1557,6 +1517,7 @@ saregister(struct cam_periph *periph, void *arg) * blocksize until we media is inserted. So, set a flag to * indicate that the blocksize is unavailable right now. */ + cam_periph_unlock(periph); devstat_add_entry(&softc->device_stats, "sa", periph->unit_number, 0, DEVSTAT_BS_UNAVAILABLE, SID_TYPE(&cgd->inq_data) | DEVSTAT_TYPE_IF_SCSI, DEVSTAT_PRIORITY_TAPE); @@ -1596,17 +1557,13 @@ saregister(struct cam_periph *periph, void *arg) UID_ROOT, GID_OPERATOR, 0660, "e%s%d.%d", periph->periph_name, periph->unit_number, i); } + cam_periph_lock(periph); /* * Add an async callback so that we get * notified if this device goes away. */ - xpt_setup_ccb(&csa.ccb_h, periph->path, /* priority */ 5); - csa.ccb_h.func_code = XPT_SASYNC_CB; - csa.event_enable = AC_LOST_DEVICE; - csa.callback = saasync; - csa.callback_arg = periph; - xpt_action((union ccb *)&csa); + xpt_register_async(AC_LOST_DEVICE, saasync, periph, periph->path); xpt_announce_periph(periph, NULL); @@ -1633,7 +1590,6 @@ sastart(struct cam_periph *periph, union ccb *start_ccb) /* * See if there is a buf with work for us to do.. */ - crit_enter(); bio = bioq_first(&softc->bio_queue); if (periph->immediate_priority <= periph->pinfo.priority) { CAM_DEBUG_PRINT(CAM_DEBUG_SUBTRACE, @@ -1642,10 +1598,8 @@ sastart(struct cam_periph *periph, union ccb *start_ccb) SLIST_INSERT_HEAD(&periph->ccb_list, &start_ccb->ccb_h, periph_links.sle); periph->immediate_priority = CAM_PRIORITY_NONE; - crit_exit(); wakeup(&periph->ccb_list); } else if (bio == NULL) { - crit_exit(); xpt_release_ccb(start_ccb); } else if ((softc->flags & SA_FLAG_ERR_PENDING) != 0) { struct bio *done_bio; @@ -1689,7 +1643,6 @@ again: "%d more buffers queued up\n", (softc->flags & SA_FLAG_ERR_PENDING), (bio != NULL)? "not " : " ", softc->queue_count)); - crit_exit(); xpt_release_ccb(start_ccb); biodone(done_bio); } else { @@ -1708,10 +1661,8 @@ again: bp->b_bcount / softc->media_blksize; } else { bp->b_error = EIO; - xpt_print_path(periph->path); - kprintf("zero blocksize for " - "FIXED length writes?\n"); - crit_exit(); + xpt_print(periph->path, "zero blocksize" + " for FIXED length writes?\n"); biodone(bio); break; } @@ -1762,7 +1713,6 @@ again: Set_CCB_Type(start_ccb, SA_CCB_BUFFER_IO); start_ccb->ccb_h.ccb_bio = bio; bio = bioq_first(&softc->bio_queue); - crit_exit(); xpt_action(start_ccb); } @@ -1823,7 +1773,6 @@ sadone(struct cam_periph *periph, union ccb *done_ccb) * */ - crit_enter(); softc->flags |= SA_FLAG_TAPE_FROZEN; while ((q_bio = bioq_first(&softc->bio_queue)) != NULL) { bioq_remove(&softc->bio_queue, q_bio); @@ -1833,7 +1782,6 @@ sadone(struct cam_periph *periph, union ccb *done_ccb) q_bp->b_flags |= B_ERROR; biodone(q_bio); } - crit_exit(); } if (error != 0) { bp->b_resid = bp->b_bcount; @@ -1946,8 +1894,8 @@ samount(struct cam_periph *periph, int oflags, cdev_t dev) */ softc->flags &= ~SA_FLAG_TAPE_MOUNTED; if (CAM_DEBUGGED(periph->path, CAM_DEBUG_INFO)) { - xpt_print_path(periph->path); - kprintf("error %d on TUR in samount\n", error); + xpt_print(periph->path, + "error %d on TUR in samount\n", error); } } } else { @@ -2007,7 +1955,7 @@ samount(struct cam_periph *periph, int oflags, cdev_t dev) * blocksize on tape is and don't expect to really * read a full record. */ - rblim = kmalloc(8192, M_TEMP, M_INTWAIT); + rblim = kmalloc(8192, M_SCSISA, M_INTWAIT); if ((softc->quirks & SA_QUIRK_NODREAD) == 0) { scsi_sa_read_write(&ccb->csio, 0, sadone, @@ -2024,8 +1972,8 @@ samount(struct cam_periph *periph, int oflags, cdev_t dev) &softc->device_stats); QFRLS(ccb); if (error) { - xpt_print_path(periph->path); - kprintf("unable to rewind after test read\n"); + xpt_print(periph->path, + "unable to rewind after test read\n"); xpt_release_ccb(ccb); goto exit; } @@ -2189,8 +2137,8 @@ samount(struct cam_periph *periph, int oflags, cdev_t dev) if ((softc->max_blk < softc->media_blksize) || (softc->min_blk > softc->media_blksize && softc->media_blksize)) { - xpt_print_path(periph->path); - kprintf("BLOCK LIMITS (%d..%d) could not match current " + xpt_print(periph->path, + "BLOCK LIMITS (%d..%d) could not match current " "block settings (%d)- adjusting\n", softc->min_blk, softc->max_blk, softc->media_blksize); softc->max_blk = softc->min_blk = @@ -2224,9 +2172,9 @@ tryagain: error = sasetparams(periph, SA_PARAM_BLOCKSIZE, softc->media_blksize, 0, 0, SF_NO_PRINT); if (error) { - xpt_print_path(periph->path); - kprintf("unable to set fixed blocksize to %d\n", - softc->media_blksize); + xpt_print(periph->path, + "unable to set fixed blocksize to %d\n", + softc->media_blksize); goto exit; } } @@ -2251,8 +2199,8 @@ tryagain: softc->last_media_blksize = 512; goto tryagain; } - xpt_print_path(periph->path); - kprintf("unable to set variable blocksize\n"); + xpt_print(periph->path, + "unable to set variable blocksize\n"); goto exit; } } @@ -2309,8 +2257,8 @@ tryagain: if (error == 0) { softc->buffer_mode = SMH_SA_BUF_MODE_SIBUF; } else { - xpt_print_path(periph->path); - kprintf("unable to set buffered mode\n"); + xpt_print(periph->path, + "unable to set buffered mode\n"); } error = 0; /* not an error */ } @@ -2321,7 +2269,7 @@ tryagain: } exit: if (rblim != NULL) - kfree(rblim, M_TEMP); + kfree(rblim, M_SCSISA); if (error != 0) { softc->dsreg = MTIO_DSREG_NIL; @@ -2552,8 +2500,8 @@ saerror(union ccb *ccb, u_int32_t cflgs, u_int32_t sflgs) */ if (error == 0 && (sense->flags & SSD_ILI)) { if (info < 0) { - xpt_print_path(csio->ccb_h.path); - kprintf(toobig, csio->dxfer_len - info); + xpt_print(csio->ccb_h.path, toobig, + csio->dxfer_len - info); csio->resid = csio->dxfer_len; error = EIO; } else { @@ -2622,7 +2570,7 @@ retry: mode_buffer_len += sizeof (sa_comp_t); } - mode_buffer = kmalloc(mode_buffer_len, M_TEMP, M_INTWAIT | M_ZERO); + mode_buffer = kmalloc(mode_buffer_len, M_SCSISA, M_INTWAIT | M_ZERO); mode_hdr = (struct scsi_mode_header_6 *)mode_buffer; mode_blk = (struct scsi_mode_blk_desc *)&mode_hdr[1]; @@ -2651,7 +2599,7 @@ retry: goto retry; } softc->quirks |= SA_QUIRK_NOCOMP; - kfree(mode_buffer, M_TEMP); + kfree(mode_buffer, M_SCSISA); goto retry; } else if (status == CAM_SCSI_STATUS_ERROR) { /* Tell the user about the fatal error. */ @@ -2760,7 +2708,7 @@ retry: sagetparamsexit: xpt_release_ccb(ccb); - kfree(mode_buffer, M_TEMP); + kfree(mode_buffer, M_SCSISA); return (error); } @@ -2802,7 +2750,7 @@ sasetparams(struct cam_periph *periph, sa_params params_to_set, softc = (struct sa_softc *)periph->softc; - ccomp = kmalloc(sizeof (sa_comp_t), M_TEMP, M_INTWAIT); + ccomp = kmalloc(sizeof (sa_comp_t), M_SCSISA, M_INTWAIT); /* * Since it doesn't make sense to set the number of blocks, or @@ -2817,7 +2765,7 @@ sasetparams(struct cam_periph *periph, sa_params params_to_set, ¤t_calg, ccomp); if (error != 0) { - kfree(ccomp, M_TEMP); + kfree(ccomp, M_SCSISA); return (error); } @@ -2825,7 +2773,7 @@ sasetparams(struct cam_periph *periph, sa_params params_to_set, if (params_to_set & SA_PARAM_COMPRESSION) mode_buffer_len += sizeof (sa_comp_t); - mode_buffer = kmalloc(mode_buffer_len, M_TEMP, M_INTWAIT | M_ZERO); + mode_buffer = kmalloc(mode_buffer_len, M_SCSISA, M_INTWAIT | M_ZERO); mode_hdr = (struct scsi_mode_header_6 *)mode_buffer; mode_blk = (struct scsi_mode_blk_desc *)&mode_hdr[1]; @@ -2974,8 +2922,8 @@ retry: * so turn off the set compression bit. */ params_to_set &= ~SA_PARAM_COMPRESSION; - xpt_print_path(periph->path); - kprintf("device does not seem to support compression\n"); + xpt_print(periph->path, + "device does not seem to support compression\n"); /* * If that was the only thing the user wanted us to set, @@ -2983,7 +2931,7 @@ retry: * 'operation not supported'. */ if (params_to_set == SA_PARAM_NONE) { - kfree(mode_buffer, M_TEMP); + kfree(mode_buffer, M_SCSISA); xpt_release_ccb(ccb); return (ENODEV); } @@ -3068,7 +3016,7 @@ retry: xpt_release_ccb(ccb); if (ccomp != NULL) - kfree(ccomp, M_TEMP); + kfree(ccomp, M_SCSISA); if (params_to_set & SA_PARAM_COMPRESSION) { if (error) { @@ -3087,7 +3035,7 @@ retry: } } - kfree(mode_buffer, M_TEMP); + kfree(mode_buffer, M_SCSISA); return (error); } diff --git a/sys/bus/cam/scsi/scsi_ses.c b/sys/bus/cam/scsi/scsi_ses.c index 15338ad..1e0c55e 100644 --- a/sys/bus/cam/scsi/scsi_ses.c +++ b/sys/bus/cam/scsi/scsi_ses.c @@ -46,6 +46,7 @@ #include "../cam_periph.h" #include "../cam_xpt_periph.h" #include "../cam_debug.h" +#include "../cam_sim.h" #include "scsi_all.h" #include "scsi_message.h" @@ -191,7 +192,6 @@ static void sesinit(void) { cam_status status; - struct cam_path *path; /* * Create our extend array for storing the devices we attach to. @@ -206,21 +206,7 @@ sesinit(void) * Install a global async callback. This callback will * receive async callbacks like "new device found". */ - status = xpt_create_path(&path, NULL, CAM_XPT_PATH_ID, - CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD); - - if (status == CAM_REQ_CMP) { - struct ccb_setasync csa; - - xpt_setup_ccb(&csa.ccb_h, path, 5); - csa.ccb_h.func_code = XPT_SASYNC_CB; - csa.event_enable = AC_FOUND_DEVICE; - csa.callback = sesasync; - csa.callback_arg = NULL; - xpt_action((union ccb *)&csa); - status = csa.ccb_h.status; - xpt_free_path(path); - } + status = xpt_register_async(AC_FOUND_DEVICE, sesasync, NULL, NULL); if (status != CAM_REQ_CMP) { kprintf("ses: Failed to attach master async callback " @@ -232,24 +218,17 @@ static void sesoninvalidate(struct cam_periph *periph) { struct ses_softc *softc; - struct ccb_setasync csa; softc = (struct ses_softc *)periph->softc; /* * Unregister any async callbacks. */ - xpt_setup_ccb(&csa.ccb_h, periph->path, 5); - csa.ccb_h.func_code = XPT_SASYNC_CB; - csa.event_enable = 0; - csa.callback = sesasync; - csa.callback_arg = periph; - xpt_action((union ccb *)&csa); + xpt_register_async(0, sesasync, periph, periph->path); softc->ses_flags |= SES_FLAG_INVALID; - xpt_print_path(periph->path); - kprintf("lost device\n"); + xpt_print(periph->path, "lost device\n"); } static void @@ -260,8 +239,7 @@ sescleanup(struct cam_periph *periph) softc = (struct ses_softc *)periph->softc; cam_extend_release(sesperiphs, periph->unit_number); - xpt_print_path(periph->path); - kprintf("removing device entry\n"); + xpt_print(periph->path, "removing device entry\n"); dev_ops_remove(&ses_ops, -1, periph->unit_number); kfree(softc, M_SCSISES); } @@ -322,7 +300,6 @@ static cam_status sesregister(struct cam_periph *periph, void *arg) { struct ses_softc *softc; - struct ccb_setasync csa; struct ccb_getdev *cgd; char *tname; @@ -372,21 +349,18 @@ sesregister(struct cam_periph *periph, void *arg) cam_extend_set(sesperiphs, periph->unit_number, periph); + cam_periph_unlock(periph); dev_ops_add(&ses_ops, -1, periph->unit_number); make_dev(&ses_ops, periph->unit_number, UID_ROOT, GID_OPERATOR, 0600, "%s%d", periph->periph_name, periph->unit_number); + cam_periph_lock(periph); /* * Add an async callback so that we get * notified if this device goes away. */ - xpt_setup_ccb(&csa.ccb_h, periph->path, 5); - csa.ccb_h.func_code = XPT_SASYNC_CB; - csa.event_enable = AC_LOST_DEVICE; - csa.callback = sesasync; - csa.callback_arg = periph; - xpt_action((union ccb *)&csa); + xpt_register_async(AC_LOST_DEVICE, sesasync, periph, periph->path); switch (softc->ses_type) { default: @@ -419,25 +393,20 @@ sesopen(struct dev_open_args *ap) cdev_t dev = ap->a_head.a_dev; struct cam_periph *periph; struct ses_softc *softc; - int error; + int error = 0; - crit_enter(); periph = cam_extend_get(sesperiphs, SESUNIT(dev)); if (periph == NULL) { - crit_exit(); return (ENXIO); } - if ((error = cam_periph_lock(periph, PCATCH)) != 0) { - crit_exit(); - return (error); - } - crit_exit(); if (cam_periph_acquire(periph) != CAM_REQ_CMP) { cam_periph_unlock(periph); return (ENXIO); } + cam_periph_lock(periph); + softc = (struct ses_softc *)periph->softc; if (softc->ses_flags & SES_FLAG_INVALID) { @@ -463,10 +432,10 @@ sesopen(struct dev_open_args *ap) } out: + cam_periph_unlock(periph); if (error) { cam_periph_release(periph); } - cam_periph_unlock(periph); return (error); } @@ -485,11 +454,9 @@ sesclose(struct dev_close_args *ap) if (periph == NULL) return (ENXIO); - softc = (struct ses_softc *)periph->softc; - - if ((error = cam_periph_lock(periph, 0)) != 0) - return (error); + cam_periph_lock(periph); + softc = (struct ses_softc *)periph->softc; softc->ses_flags &= ~SES_FLAG_OPEN; cam_periph_unlock(periph); @@ -501,13 +468,11 @@ sesclose(struct dev_close_args *ap) static void sesstart(struct cam_periph *p, union ccb *sccb) { - crit_enter(); if (p->immediate_priority <= p->pinfo.priority) { SLIST_INSERT_HEAD(&p->ccb_list, &sccb->ccb_h, periph_links.sle); p->immediate_priority = CAM_PRIORITY_NONE; wakeup(&p->ccb_list); } - crit_exit(); } static void @@ -552,14 +517,17 @@ sesioctl(struct dev_ioctl_args *ap) CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("entering sesioctl\n")); + cam_periph_lock(periph); ssc = (struct ses_softc *)periph->softc; /* * Now check to see whether we're initialized or not. */ if ((ssc->ses_flags & SES_FLAG_INITIALIZED) == 0) { + cam_periph_unlock(periph); return (ENXIO); } + cam_periph_unlock(periph); error = 0; @@ -589,22 +557,34 @@ sesioctl(struct dev_ioctl_args *ap) break; case SESIOC_GETOBJMAP: + /* + * XXX Dropping the lock while copying multiple segments is + * bogus. + */ + cam_periph_lock(periph); for (uobj = addr, i = 0; i != ssc->ses_nobjects; i++, uobj++) { obj.obj_id = i; obj.subencid = ssc->ses_objmap[i].subenclosure; obj.object_type = ssc->ses_objmap[i].enctype; + cam_periph_unlock(periph); error = copyout(&obj, uobj, sizeof (ses_object)); + cam_periph_lock(periph); if (error) { break; } } + cam_periph_unlock(periph); break; case SESIOC_GETENCSTAT: + cam_periph_lock(periph); error = (*ssc->ses_vec.get_encstat)(ssc, 1); - if (error) + if (error) { + cam_periph_unlock(periph); break; + } tmp = ssc->ses_encstat & ~ENCI_SVALID; + cam_periph_unlock(periph); error = copyout(&tmp, addr, sizeof (ses_encstat)); ssc->ses_encstat = tmp; break; @@ -613,7 +593,9 @@ sesioctl(struct dev_ioctl_args *ap) error = copyin(addr, &tmp, sizeof (ses_encstat)); if (error) break; + cam_periph_lock(periph); error = (*ssc->ses_vec.set_encstat)(ssc, tmp, 1); + cam_periph_unlock(periph); break; case SESIOC_GETOBJSTAT: @@ -624,7 +606,9 @@ sesioctl(struct dev_ioctl_args *ap) error = EINVAL; break; } + cam_periph_lock(periph); error = (*ssc->ses_vec.get_objstat)(ssc, &objs, 1); + cam_periph_unlock(periph); if (error) break; error = copyout(&objs, addr, sizeof (ses_objstat)); @@ -643,7 +627,9 @@ sesioctl(struct dev_ioctl_args *ap) error = EINVAL; break; } + cam_periph_lock(periph); error = (*ssc->ses_vec.set_objstat)(ssc, &objs, 1); + cam_periph_unlock(periph); /* * Always (for now) invalidate entry. @@ -653,11 +639,15 @@ sesioctl(struct dev_ioctl_args *ap) case SESIOC_INIT: + cam_periph_lock(periph); error = (*ssc->ses_vec.init_enc)(ssc); + cam_periph_unlock(periph); break; default: + cam_periph_lock(periph); error = cam_periph_ioctl(periph, ap->a_cmd, ap->a_data, seserror); + cam_periph_unlock(periph); break; } return (error); diff --git a/sys/bus/cam/scsi/scsi_targ_bh.c b/sys/bus/cam/scsi/scsi_targ_bh.c index 5026177..795e014 100644 --- a/sys/bus/cam/scsi/scsi_targ_bh.c +++ b/sys/bus/cam/scsi/scsi_targ_bh.c @@ -47,6 +47,7 @@ #include "../cam_queue.h" #include "../cam_xpt_periph.h" #include "../cam_debug.h" +#include "../cam_sim.h" #include "scsi_all.h" #include "scsi_message.h" @@ -156,27 +157,13 @@ static void targbhinit(void) { cam_status status; - struct cam_path *path; /* * Install a global async callback. This callback will * receive async callbacks like "new path registered". */ - status = xpt_create_path(&path, /*periph*/NULL, CAM_XPT_PATH_ID, - CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD); - - if (status == CAM_REQ_CMP) { - struct ccb_setasync csa; - - xpt_setup_ccb(&csa.ccb_h, path, /*priority*/5); - csa.ccb_h.func_code = XPT_SASYNC_CB; - csa.event_enable = AC_PATH_REGISTERED | AC_PATH_DEREGISTERED; - csa.callback = targbhasync; - csa.callback_arg = NULL; - xpt_action((union ccb *)&csa); - status = csa.ccb_h.status; - xpt_free_path(path); - } + status = xpt_register_async(AC_PATH_REGISTERED | AC_PATH_DEREGISTERED, + targbhasync, NULL, NULL); if (status != CAM_REQ_CMP) { kprintf("targbh: Failed to attach master async callback " @@ -264,9 +251,9 @@ targbhenlun(struct cam_periph *periph) xpt_action(&immed_ccb); status = immed_ccb.ccb_h.status; if (status != CAM_REQ_CMP) { - xpt_print_path(periph->path); - kprintf("targbhenlun - Enable Lun Rejected with status 0x%x\n", - status); + xpt_print(periph->path, + "targbhenlun - Enable Lun Rejected with status 0x%x\n", + status); return (status); } @@ -299,9 +286,9 @@ targbhenlun(struct cam_periph *periph) } if (i == 0) { - xpt_print_path(periph->path); - kprintf("targbhenlun - Could not allocate accept tio CCBs: " - "status = 0x%x\n", status); + xpt_print(periph->path, + "targbhenlun - Could not allocate accept tio CCBs: status " + "= 0x%x\n", status); targbhdislun(periph); return (CAM_REQ_CMP_ERR); } @@ -329,9 +316,9 @@ targbhenlun(struct cam_periph *periph) } if (i == 0) { - xpt_print_path(periph->path); - kprintf("targbhenlun - Could not allocate immediate notify " - "CCBs: status = 0x%x\n", status); + xpt_print(periph->path, + "targbhenlun - Could not allocate immediate notify " + "CCBs: status = 0x%x\n", status); targbhdislun(periph); return (CAM_REQ_CMP_ERR); } @@ -424,7 +411,7 @@ targbhdtor(struct cam_periph *periph) /* FALLTHROUGH */ default: /* XXX Wait for callback of targbhdislun() */ - tsleep(softc, 0, "targbh", hz/2); + sim_lock_sleep(softc, 0, "targbh", hz/2, periph->sim->lock); kfree(softc, M_SCSIBH); break; } @@ -442,23 +429,19 @@ targbhstart(struct cam_periph *periph, union ccb *start_ccb) softc = (struct targbh_softc *)periph->softc; - crit_enter(); ccbh = TAILQ_FIRST(&softc->work_queue); if (periph->immediate_priority <= periph->pinfo.priority) { start_ccb->ccb_h.ccb_type = TARGBH_CCB_WAITING; SLIST_INSERT_HEAD(&periph->ccb_list, &start_ccb->ccb_h, periph_links.sle); periph->immediate_priority = CAM_PRIORITY_NONE; - crit_exit(); wakeup(&periph->ccb_list); } else if (ccbh == NULL) { - crit_exit(); xpt_release_ccb(start_ccb); } else { TAILQ_REMOVE(&softc->work_queue, ccbh, periph_links.tqe); TAILQ_INSERT_HEAD(&softc->pending_queue, ccbh, periph_links.tqe); - crit_exit(); atio = (struct ccb_accept_tio*)ccbh; desc = (struct targbh_cmd_desc *)atio->ccb_h.ccb_descr; @@ -519,9 +502,7 @@ targbhstart(struct cam_periph *periph, union ccb *start_ccb) /*getcount_only*/0); atio->ccb_h.status &= ~CAM_DEV_QFRZN; } - crit_enter(); ccbh = TAILQ_FIRST(&softc->work_queue); - crit_exit(); } if (ccbh != NULL) xpt_schedule(periph, /*priority*/1); diff --git a/sys/bus/cam/scsi/scsi_target.c b/sys/bus/cam/scsi/scsi_target.c index cc13c52..7f85772 100644 --- a/sys/bus/cam/scsi/scsi_target.c +++ b/sys/bus/cam/scsi/scsi_target.c @@ -45,6 +45,7 @@ #include "../cam_ccb.h" #include "../cam_periph.h" #include "../cam_xpt_periph.h" +#include "../cam_sim.h" #include "scsi_targetio.h" /* Transaction information attached to each CCB sent by the user */ @@ -155,7 +156,11 @@ PERIPHDRIVER_DECLARE(targ, targdriver); static MALLOC_DEFINE(M_TARG, "TARG", "TARG data"); -/* Create softc and initialize it. Only one proc can open each targ device. */ +/* + * Create softc and initialize it. Only one proc can open each targ device. + * There is no locking here because a periph doesn't get created until an + * ioctl is issued to do so, and that can't happen until this method returns. + */ static int targopen(struct dev_open_args *ap) { @@ -194,9 +199,24 @@ targclose(struct dev_close_args *ap) { cdev_t dev = ap->a_head.a_dev; struct targ_softc *softc; + struct cam_periph *periph; int error; softc = (struct targ_softc *)dev->si_drv1; + if ((softc->periph == NULL) || + (softc->state & TARG_STATE_LUN_ENABLED) == 0) { + destroy_dev(dev); + FREE(softc, M_TARG); + return (0); + } + + /* + * Acquire a hold on the periph so that it doesn't go away before + * we are ready at the end of the function. + */ + periph = softc->periph; + cam_periph_acquire(periph); + cam_periph_lock(periph); error = targdisable(softc); if (error == CAM_REQ_CMP) { dev->si_drv1 = 0; @@ -209,6 +229,9 @@ targclose(struct dev_close_args *ap) } else { release_dev(dev); } + cam_periph_unlock(periph); + cam_periph_release(periph); + return (error); } @@ -226,44 +249,56 @@ targioctl(struct dev_ioctl_args *ap) { struct ioc_enable_lun *new_lun; struct cam_path *path; + struct cam_sim *sim; new_lun = (struct ioc_enable_lun *)ap->a_data; - status = xpt_create_path(&path, /*periph*/NULL, - new_lun->path_id, - new_lun->target_id, - new_lun->lun_id); + status = xpt_create_path_unlocked(&path, /*periph*/NULL, + new_lun->path_id, + new_lun->target_id, + new_lun->lun_id); if (status != CAM_REQ_CMP) { kprintf("Couldn't create path, status %#x\n", status); break; } + sim = xpt_path_sim(path); + CAM_SIM_LOCK(sim); status = targenable(softc, path, new_lun->grp6_len, new_lun->grp7_len); xpt_free_path(path); + CAM_SIM_UNLOCK(sim); break; } case TARGIOCDISABLE: + if (softc->periph == NULL) { + status = CAM_DEV_NOT_THERE; + break; + } + cam_periph_lock(softc->periph); status = targdisable(softc); + cam_periph_unlock(softc->periph); break; case TARGIOCDEBUG: { #ifdef CAMDEBUG struct ccb_debug cdbg; + /* If no periph available, disallow debugging changes */ + if ((softc->state & TARG_STATE_LUN_ENABLED) == 0) { + status = CAM_DEV_NOT_THERE; + break; + } bzero(&cdbg, sizeof cdbg); if (*((int *)ap->a_data) != 0) cdbg.flags = CAM_DEBUG_PERIPH; else cdbg.flags = CAM_DEBUG_NONE; + cam_periph_lock(softc->periph); xpt_setup_ccb(&cdbg.ccb_h, softc->path, /*priority*/0); cdbg.ccb_h.func_code = XPT_DEBUG; cdbg.ccb_h.cbfcnp = targdone; - /* If no periph available, disallow debugging changes */ - if ((softc->state & TARG_STATE_LUN_ENABLED) == 0) { - status = CAM_DEV_NOT_THERE; - break; - } xpt_action((union ccb *)&cdbg); + cam_periph_unlock(softc->periph); status = cdbg.ccb_h.status & CAM_STATUS_MASK; #else status = CAM_FUNC_NOTAVAIL; @@ -290,16 +325,16 @@ targpoll(struct dev_poll_args *ap) /* Poll for write() is always ok. */ revents = ap->a_events & (POLLOUT | POLLWRNORM); if ((ap->a_events & (POLLIN | POLLRDNORM)) != 0) { - crit_enter(); /* Poll for read() depends on user and abort queues. */ + cam_periph_lock(softc->periph); if (!TAILQ_EMPTY(&softc->user_ccb_queue) || !TAILQ_EMPTY(&softc->abort_queue)) { revents |= ap->a_events & (POLLIN | POLLRDNORM); } + cam_periph_unlock(softc->periph); /* Only sleep if the user didn't poll for write. */ if (revents == 0) selrecord(curthread, &softc->read_select); - crit_exit(); } ap->a_events = revents; return (0); @@ -339,10 +374,10 @@ targreadfilt(struct knote *kn, long hint) int retval; softc = (struct targ_softc *)kn->kn_hook; - crit_enter(); + cam_periph_unlock(softc->periph); retval = !TAILQ_EMPTY(&softc->user_ccb_queue) || !TAILQ_EMPTY(&softc->abort_queue); - crit_exit(); + cam_periph_unlock(softc->periph); return (retval); } @@ -363,9 +398,8 @@ targendislun(struct cam_path *path, int enable, int grp6_len, int grp7_len) xpt_action((union ccb *)&en_ccb); status = en_ccb.ccb_h.status & CAM_STATUS_MASK; if (status != CAM_REQ_CMP) { - xpt_print_path(path); - kprintf("%sable lun CCB rejected, status %#x\n", - enable ? "en" : "dis", status); + xpt_print(path, "%sable lun CCB rejected, status %#x\n", + enable ? "en" : "dis", status); } return (status); } @@ -542,6 +576,7 @@ targwrite(struct dev_write_args *ap) switch (func_code) { case XPT_ACCEPT_TARGET_IO: case XPT_IMMED_NOTIFY: + cam_periph_lock(softc->periph); ccb = targgetccb(softc, func_code, priority); descr = (struct targ_cmd_descr *)ccb->ccb_h.targ_descr; descr->user_ccb = user_ccb; @@ -549,13 +584,13 @@ targwrite(struct dev_write_args *ap) CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH, ("Sent ATIO/INOT (%p)\n", user_ccb)); xpt_action(ccb); - crit_enter(); TAILQ_INSERT_TAIL(&softc->pending_ccb_queue, &ccb->ccb_h, periph_links.tqe); - crit_exit(); + cam_periph_unlock(softc->periph); break; default: + cam_periph_lock(softc->periph); if ((func_code & XPT_FC_QUEUED) != 0) { CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH, ("Sending queued ccb %#x (%p)\n", @@ -583,6 +618,7 @@ targwrite(struct dev_write_args *ap) targsendccb(softc, ccb, descr); targreturnccb(softc, ccb); } + cam_periph_unlock(softc->periph); break; } write_len += sizeof(user_ccb); @@ -627,8 +663,8 @@ targstart(struct cam_periph *periph, union ccb *start_ccb) if (error == 0) error = targsendccb(softc, start_ccb, descr); if (error != 0) { - xpt_print_path(periph->path); - kprintf("targsendccb failed, err %d\n", error); + xpt_print(periph->path, + "targsendccb failed, err %d\n", error); xpt_release_ccb(start_ccb); suword(&descr->user_ccb->ccb_h.status, CAM_REQ_CMP_ERR); @@ -828,24 +864,24 @@ targread(struct dev_read_args *ap) CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH, ("targread\n")); /* If no data is available, wait or return immediately */ - crit_enter(); + cam_periph_lock(softc->periph); ccb_h = TAILQ_FIRST(user_queue); user_descr = TAILQ_FIRST(abort_queue); while (ccb_h == NULL && user_descr == NULL) { if ((ap->a_ioflag & IO_NDELAY) == 0) { - error = tsleep(user_queue, PCATCH, "targrd", 0); + error = sim_lock_sleep(user_queue, PCATCH, "targrd", 0, + softc->periph->sim->lock); ccb_h = TAILQ_FIRST(user_queue); user_descr = TAILQ_FIRST(abort_queue); if (error != 0) { if (error == ERESTART) { continue; } else { - crit_exit(); goto read_fail; } } } else { - crit_exit(); + cam_periph_unlock(softc->periph); return (EAGAIN); } } @@ -857,7 +893,6 @@ targread(struct dev_read_args *ap) if (uio->uio_resid < sizeof(user_ccb)) break; TAILQ_REMOVE(user_queue, ccb_h, periph_links.tqe); - crit_exit(); descr = (struct targ_cmd_descr *)ccb_h->targ_descr; user_ccb = descr->user_ccb; CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH, @@ -865,12 +900,13 @@ targread(struct dev_read_args *ap) error = targreturnccb(softc, (union ccb *)ccb_h); if (error != 0) goto read_fail; + cam_periph_unlock(softc->periph); error = uiomove((caddr_t)&user_ccb, sizeof(user_ccb), uio); + cam_periph_lock(softc->periph); if (error != 0) goto read_fail; read_len += sizeof(user_ccb); - crit_enter(); ccb_h = TAILQ_FIRST(user_queue); } @@ -879,21 +915,20 @@ targread(struct dev_read_args *ap) if (uio->uio_resid < sizeof(user_ccb)) break; TAILQ_REMOVE(abort_queue, user_descr, tqe); - crit_exit(); user_ccb = user_descr->user_ccb; CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH, ("targread aborted descr %p (%p)\n", user_descr, user_ccb)); suword(&user_ccb->ccb_h.status, CAM_REQ_ABORTED); + cam_periph_unlock(softc->periph); error = uiomove((caddr_t)&user_ccb, sizeof(user_ccb), uio); + cam_periph_lock(softc->periph); if (error != 0) goto read_fail; read_len += sizeof(user_ccb); - crit_enter(); user_descr = TAILQ_FIRST(abort_queue); } - crit_exit(); /* * If we've successfully read some amount of data, don't report an @@ -904,6 +939,7 @@ targread(struct dev_read_args *ap) error = ENOSPC; read_fail: + cam_periph_unlock(softc->periph); return (error); } @@ -931,9 +967,8 @@ targreturnccb(struct targ_softc *softc, union ccb *ccb) cam_periph_unmapmem(ccb, &descr->mapinfo); error = copyout(&ccb->ccb_h + 1, u_ccbh + 1, ccb_len); if (error != 0) { - xpt_print_path(softc->path); - kprintf("targreturnccb - CCB copyout failed (%d)\n", - error); + xpt_print(softc->path, + "targreturnccb - CCB copyout failed (%d)\n", error); } /* Free CCB or send back to devq. */ targfreeccb(softc, ccb); @@ -1017,6 +1052,7 @@ abort_all_pending(struct targ_softc *softc) struct targ_cmd_descr *descr; struct ccb_abort cab; struct ccb_hdr *ccb_h; + struct cam_sim *sim; CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH, ("abort_all_pending\n")); @@ -1041,15 +1077,17 @@ abort_all_pending(struct targ_softc *softc) cab.abort_ccb = (union ccb *)ccb_h; xpt_action((union ccb *)&cab); if (cab.ccb_h.status != CAM_REQ_CMP) { - xpt_print_path(cab.ccb_h.path); - kprintf("Unable to abort CCB, status %#x\n", - cab.ccb_h.status); + xpt_print(cab.ccb_h.path, + "Unable to abort CCB, status %#x\n", + cab.ccb_h.status); } } /* If we aborted at least one pending CCB ok, wait for it. */ if (cab.ccb_h.status == CAM_REQ_CMP) { - tsleep(&softc->pending_ccb_queue, PCATCH, "tgabrt", 0); + sim = xpt_path_sim(softc->path); + sim_lock_sleep(&softc->pending_ccb_queue, PCATCH, "tgabrt", 0, + sim->lock); } /* If we aborted anything from the work queue, wakeup user. */ diff --git a/sys/dev/disk/advansys/advansys.c b/sys/dev/disk/advansys/advansys.c index d04226b..8bb23ba 100644 --- a/sys/dev/disk/advansys/advansys.c +++ b/sys/dev/disk/advansys/advansys.c @@ -1388,7 +1388,7 @@ adv_attach(struct adv_softc *adv) * Construct our SIM entry. */ adv->sim = cam_sim_alloc(adv_action, adv_poll, "adv", adv, adv->unit, - 1, adv->max_openings, NULL); + &sim_mplock, 1, adv->max_openings, NULL); if (adv->sim == NULL) return (ENOMEM); diff --git a/sys/dev/disk/advansys/adwcam.c b/sys/dev/disk/advansys/adwcam.c index e1e60da..ea91cf7 100644 --- a/sys/dev/disk/advansys/adwcam.c +++ b/sys/dev/disk/advansys/adwcam.c @@ -1171,7 +1171,7 @@ adw_attach(struct adw_softc *adw) * Construct our SIM entry. */ adw->sim = cam_sim_alloc(adw_action, adw_poll, "adw", adw, adw->unit, - 1, adw->max_acbs, NULL); + &sim_mplock, 1, adw->max_acbs, NULL); if (adw->sim == NULL) { error = ENOMEM; goto fail; diff --git a/sys/dev/disk/aha/aha.c b/sys/dev/disk/aha/aha.c index 2c0f6c0..3a8e8cf 100644 --- a/sys/dev/disk/aha/aha.c +++ b/sys/dev/disk/aha/aha.c @@ -648,7 +648,7 @@ aha_attach(struct aha_softc *aha) * Construct our SIM entry */ aha->sim = cam_sim_alloc(ahaaction, ahapoll, "aha", aha, device_get_unit(aha->dev), - 2, tagged_dev_openings, devq); + &sim_mplock, 2, tagged_dev_openings, devq); cam_simq_release(devq); if (aha->sim == NULL) { return (ENOMEM); diff --git a/sys/dev/disk/ahb/ahb.c b/sys/dev/disk/ahb/ahb.c index 1b0a273..02f3761 100644 --- a/sys/dev/disk/ahb/ahb.c +++ b/sys/dev/disk/ahb/ahb.c @@ -526,7 +526,7 @@ ahbxptattach(struct ahb_softc *ahb) * Construct our SIM entry */ ahb->sim = cam_sim_alloc(ahbaction, ahbpoll, "ahb", ahb, ahb->unit, - 2, ahb->num_ecbs, NULL); + &sim_mplock, 2, ahb->num_ecbs, NULL); if (ahb->sim == NULL) return (ENOMEM); diff --git a/sys/dev/disk/aic/aic.c b/sys/dev/disk/aic/aic.c index a02e7b5..33c5a29 100644 --- a/sys/dev/disk/aic/aic.c +++ b/sys/dev/disk/aic/aic.c @@ -1527,7 +1527,7 @@ aic_attach(struct aic_softc *aic) * Construct our SIM entry */ aic->sim = cam_sim_alloc(aic_action, aic_poll, "aic", aic, - aic->unit, 2, 256, NULL); + aic->unit, &sim_mplock, 2, 256, NULL); if (aic->sim == NULL) return (ENOMEM); diff --git a/sys/dev/disk/aic7xxx/ahc_eisa.c b/sys/dev/disk/aic7xxx/ahc_eisa.c index 40e5c67..0c142bb 100644 --- a/sys/dev/disk/aic7xxx/ahc_eisa.c +++ b/sys/dev/disk/aic7xxx/ahc_eisa.c @@ -119,7 +119,7 @@ aic7770_attach(device_t dev) * set it up for attachment by our * common detect routine. */ - name = kmalloc(strlen(device_get_nameunit(dev)) + 1, M_DEVBUF, M_WAITOK); + name = kmalloc(strlen(device_get_nameunit(dev)) + 1, M_DEVBUF, M_INTWAIT); strcpy(name, device_get_nameunit(dev)); ahc = ahc_alloc(dev, name); if (ahc == NULL) diff --git a/sys/dev/disk/aic7xxx/ahc_isa.c b/sys/dev/disk/aic7xxx/ahc_isa.c index f269762..9296ec1 100644 --- a/sys/dev/disk/aic7xxx/ahc_isa.c +++ b/sys/dev/disk/aic7xxx/ahc_isa.c @@ -242,7 +242,7 @@ ahc_isa_attach(device_t dev) * set it up for attachment by our * common detect routine. */ - name = kmalloc(strlen(device_get_nameunit(dev)) + 1, M_DEVBUF, M_WAITOK); + name = kmalloc(strlen(device_get_nameunit(dev)) + 1, M_DEVBUF, M_INTWAIT); strcpy(name, device_get_nameunit(dev)); ahc = ahc_alloc(dev, name); if (ahc == NULL) diff --git a/sys/dev/disk/aic7xxx/ahc_pci.c b/sys/dev/disk/aic7xxx/ahc_pci.c index e035094..3944420 100644 --- a/sys/dev/disk/aic7xxx/ahc_pci.c +++ b/sys/dev/disk/aic7xxx/ahc_pci.c @@ -88,7 +88,7 @@ ahc_pci_attach(device_t dev) * set it up for attachment by our * common detect routine. */ - name = kmalloc(strlen(device_get_nameunit(dev)) + 1, M_DEVBUF, M_WAITOK); + name = kmalloc(strlen(device_get_nameunit(dev)) + 1, M_DEVBUF, M_INTWAIT); strcpy(name, device_get_nameunit(dev)); ahc = ahc_alloc(dev, name); if (ahc == NULL) diff --git a/sys/dev/disk/aic7xxx/ahd_pci.c b/sys/dev/disk/aic7xxx/ahd_pci.c index 4fcf139..772f4d6 100644 --- a/sys/dev/disk/aic7xxx/ahd_pci.c +++ b/sys/dev/disk/aic7xxx/ahd_pci.c @@ -90,7 +90,7 @@ ahd_pci_attach(device_t dev) * set it up for attachment by our * common detect routine. */ - name = kmalloc(strlen(device_get_nameunit(dev)) + 1, M_DEVBUF, M_WAITOK); + name = kmalloc(strlen(device_get_nameunit(dev)) + 1, M_DEVBUF, M_INTWAIT); strcpy(name, device_get_nameunit(dev)); ahd = ahd_alloc(dev, name); if (ahd == NULL) diff --git a/sys/dev/disk/aic7xxx/aic79xx.c b/sys/dev/disk/aic7xxx/aic79xx.c index 84d1b25..e354144 100644 --- a/sys/dev/disk/aic7xxx/aic79xx.c +++ b/sys/dev/disk/aic7xxx/aic79xx.c @@ -6235,7 +6235,7 @@ ahd_init(struct ahd_softc *ahd) ahd->stack_size = ahd_probe_stack_size(ahd); ahd->saved_stack = kmalloc(ahd->stack_size * sizeof(uint16_t), - M_DEVBUF, M_WAITOK); + M_DEVBUF, M_INTWAIT); /* * Verify that the compiler hasn't over-agressively diff --git a/sys/dev/disk/aic7xxx/aic79xx_osm.c b/sys/dev/disk/aic7xxx/aic79xx_osm.c index f561bc3..75e7664 100644 --- a/sys/dev/disk/aic7xxx/aic79xx_osm.c +++ b/sys/dev/disk/aic7xxx/aic79xx_osm.c @@ -133,7 +133,7 @@ ahd_attach(struct ahd_softc *ahd) */ sim = cam_sim_alloc(ahd_action, ahd_poll, "ahd", ahd, device_get_unit(ahd->dev_softc), - 1, AHD_MAX_QUEUE, NULL); + &ahd->platform_data->lock, 1, AHD_MAX_QUEUE, NULL); if (sim == NULL) goto fail; diff --git a/sys/dev/disk/aic7xxx/aic7xxx.c b/sys/dev/disk/aic7xxx/aic7xxx.c index 8a277b3..28c9a17 100644 --- a/sys/dev/disk/aic7xxx/aic7xxx.c +++ b/sys/dev/disk/aic7xxx/aic7xxx.c @@ -3896,13 +3896,13 @@ ahc_alloc(void *platform_arg, char *name) int i; #if !defined(__DragonFly__) && !defined(__FreeBSD__) - ahc = kmalloc(sizeof(*ahc), M_DEVBUF, M_WAITOK); + ahc = kmalloc(sizeof(*ahc), M_DEVBUF, M_INTWAIT); #else ahc = device_get_softc((device_t)platform_arg); #endif memset(ahc, 0, sizeof(*ahc)); ahc->seep_config = kmalloc(sizeof(*ahc->seep_config), - M_DEVBUF, M_WAITOK); + M_DEVBUF, M_INTWAIT); LIST_INIT(&ahc->pending_scbs); LIST_INIT(&ahc->timedout_scbs); /* We don't know our unit number until the OSM sets it */ @@ -3945,7 +3945,7 @@ ahc_softc_init(struct ahc_softc *ahc) /* XXX The shared scb data stuff should be deprecated */ if (ahc->scb_data == NULL) { ahc->scb_data = kmalloc(sizeof(*ahc->scb_data), - M_DEVBUF, M_WAITOK | M_ZERO); + M_DEVBUF, M_INTWAIT | M_ZERO); } return (0); diff --git a/sys/dev/disk/aic7xxx/aic7xxx_osm.c b/sys/dev/disk/aic7xxx/aic7xxx_osm.c index 0aa9094..adeea83 100644 --- a/sys/dev/disk/aic7xxx/aic7xxx_osm.c +++ b/sys/dev/disk/aic7xxx/aic7xxx_osm.c @@ -187,7 +187,7 @@ ahc_attach(struct ahc_softc *ahc) */ sim = cam_sim_alloc(ahc_action, ahc_poll, "ahc", ahc, device_get_unit(ahc->dev_softc), - 1, AHC_MAX_QUEUE, NULL); + &ahc->platform_data->lock, 1, AHC_MAX_QUEUE, NULL); if (sim == NULL) goto fail; @@ -216,7 +216,8 @@ ahc_attach(struct ahc_softc *ahc) if (ahc->features & AHC_TWIN) { sim2 = cam_sim_alloc(ahc_action, ahc_poll, "ahc", - ahc, device_get_unit(ahc->dev_softc), 1, + ahc, device_get_unit(ahc->dev_softc), + &ahc->platform_data->lock, 1, AHC_MAX_QUEUE, NULL); if (sim2 == NULL) { diff --git a/sys/dev/disk/aic7xxx/aic_osm_lib.h b/sys/dev/disk/aic7xxx/aic_osm_lib.h index 2b24385..7971f32 100644 --- a/sys/dev/disk/aic7xxx/aic_osm_lib.h +++ b/sys/dev/disk/aic7xxx/aic_osm_lib.h @@ -189,9 +189,9 @@ aic_wakeup_recovery_thread(struct aic_softc *aic) /***************************** Timer Facilities *******************************/ #if __FreeBSD_version >= 500000 -#define aic_timer_init(timer) callout_init(timer, /*mpsafe*/0) +#define aic_timer_init(timer) callout_init(timer, /*mpsafe*/1) #else -#define aic_timer_init callout_init +#define aic_timer_init callout_init_mp #endif #define aic_timer_stop callout_stop diff --git a/sys/dev/disk/amd/amd.c b/sys/dev/disk/amd/amd.c index d4caeef..f058e01 100644 --- a/sys/dev/disk/amd/amd.c +++ b/sys/dev/disk/amd/amd.c @@ -2426,8 +2426,8 @@ amd_attach(device_t dev) } amd->psim = cam_sim_alloc(amd_action, amd_poll, "amd", - amd, amd->unit, 1, MAX_TAGS_CMD_QUEUE, - devq); + amd, amd->unit, &sim_mplock, 1, + MAX_TAGS_CMD_QUEUE, devq); cam_simq_release(devq); if (amd->psim == NULL) { if (bootverbose) diff --git a/sys/dev/disk/ata/atapi-cam.c b/sys/dev/disk/ata/atapi-cam.c index 05144cb..3864247 100644 --- a/sys/dev/disk/ata/atapi-cam.c +++ b/sys/dev/disk/ata/atapi-cam.c @@ -126,7 +126,7 @@ atapi_cam_attach_bus(struct ata_channel *ata_ch) devq = cam_simq_alloc(16); sim = cam_sim_alloc(atapi_action, atapi_poll, "ata", (void *)scp, - unit, 1, 1, devq); + unit, &sim_mplock, 1, 1, devq); cam_simq_release(devq); if (sim == NULL) goto error; diff --git a/sys/dev/disk/buslogic/bt.c b/sys/dev/disk/buslogic/bt.c index 9e2d3c4..15f25ef 100644 --- a/sys/dev/disk/buslogic/bt.c +++ b/sys/dev/disk/buslogic/bt.c @@ -831,7 +831,7 @@ bt_attach(device_t dev) * Construct our SIM entry */ bt->sim = cam_sim_alloc(btaction, btpoll, "bt", bt, bt->unit, - 2, tagged_dev_openings, devq); + &sim_mplock, 2, tagged_dev_openings, devq); cam_simq_release(devq); if (bt->sim == NULL) return (ENOMEM); diff --git a/sys/dev/disk/isp/isp_freebsd.c b/sys/dev/disk/isp/isp_freebsd.c index e9c6347..bd9ac51 100644 --- a/sys/dev/disk/isp/isp_freebsd.c +++ b/sys/dev/disk/isp/isp_freebsd.c @@ -84,7 +84,7 @@ isp_attach(struct ispsoftc *isp) */ ISPLOCK_2_CAMLOCK(isp); sim = cam_sim_alloc(isp_action, isp_poll, "isp", isp, - device_get_unit(isp->isp_dev), 1, isp->isp_maxcmds, devq); + device_get_unit(isp->isp_dev), &sim_mplock, 1, isp->isp_maxcmds, devq); cam_simq_release(devq); /* leaves 1 ref due to cam_sim_alloc */ if (sim == NULL) { CAMLOCK_2_ISPLOCK(isp); @@ -153,7 +153,7 @@ isp_attach(struct ispsoftc *isp) if (IS_DUALBUS(isp)) { ISPLOCK_2_CAMLOCK(isp); sim = cam_sim_alloc(isp_action, isp_poll, "isp", isp, - device_get_unit(isp->isp_dev), 1, isp->isp_maxcmds, devq); + device_get_unit(isp->isp_dev), &sim_mplock, 1, isp->isp_maxcmds, devq); if (sim == NULL) { xpt_bus_deregister(cam_sim_path(isp->isp_sim)); xpt_free_path(isp->isp_path); diff --git a/sys/dev/disk/mpt/mpt_freebsd.c b/sys/dev/disk/mpt/mpt_freebsd.c index 28612d3..e69f0d4 100644 --- a/sys/dev/disk/mpt/mpt_freebsd.c +++ b/sys/dev/disk/mpt/mpt_freebsd.c @@ -55,7 +55,7 @@ mpt_cam_attach(mpt_softc_t *mpt) * Construct our SIM entry. */ sim = cam_sim_alloc(mpt_action, mpt_poll, "mpt", mpt, - mpt->unit, 1, maxq, NULL); + mpt->unit, &sim_mplock, 1, maxq, NULL); if (sim == NULL) return; diff --git a/sys/dev/disk/nata/atapi-cam.c b/sys/dev/disk/nata/atapi-cam.c index ee52df7..251ee4a 100644 --- a/sys/dev/disk/nata/atapi-cam.c +++ b/sys/dev/disk/nata/atapi-cam.c @@ -208,7 +208,7 @@ atapi_cam_attach(device_t dev) } if ((sim = cam_sim_alloc(atapi_action, atapi_poll, "ata", - (void *)scp, unit, 1, 1, devq)) == NULL) { + (void *)scp, unit, &sim_mplock, 1, 1, devq)) == NULL) { error = ENOMEM; goto out; } diff --git a/sys/dev/disk/ncr/ncr.c b/sys/dev/disk/ncr/ncr.c index 5797e22..7e96674 100644 --- a/sys/dev/disk/ncr/ncr.c +++ b/sys/dev/disk/ncr/ncr.c @@ -3782,7 +3782,7 @@ ncr_attach (device_t dev) ** about our bus. */ np->sim = cam_sim_alloc(ncr_action, ncr_poll, "ncr", np, np->unit, - 1, MAX_TAGS, devq); + &sim_mplock, 1, MAX_TAGS, devq); cam_simq_release(devq); if (np->sim == NULL) return ENOMEM; diff --git a/sys/dev/disk/sbp/sbp.c b/sys/dev/disk/sbp/sbp.c index a71adb4..e079db1 100644 --- a/sys/dev/disk/sbp/sbp.c +++ b/sys/dev/disk/sbp/sbp.c @@ -1885,6 +1885,7 @@ END_DEBUG sbp->sim = cam_sim_alloc(sbp_action, sbp_poll, "sbp", sbp, device_get_unit(dev), + &sim_mplock, /*untagged*/ 1, /*tagged*/ SBP_QUEUE_LEN - 1, devq); diff --git a/sys/dev/disk/sym/sym_hipd.c b/sys/dev/disk/sym/sym_hipd.c index b3e6b81..2e00cbe 100644 --- a/sys/dev/disk/sym/sym_hipd.c +++ b/sys/dev/disk/sym/sym_hipd.c @@ -9500,7 +9500,7 @@ int sym_cam_attach(hcb_p np) * Construct our SIM entry. */ sim = cam_sim_alloc(sym_action, sym_poll, "sym", np, np->unit, - 1, SYM_SETUP_MAX_TAG, devq); + &sim_mplock, 1, SYM_SETUP_MAX_TAG, devq); cam_simq_release(devq); if (sim == NULL) goto fail; diff --git a/sys/dev/disk/trm/trm.c b/sys/dev/disk/trm/trm.c index 9561dc9..f3bd7fc 100644 --- a/sys/dev/disk/trm/trm.c +++ b/sys/dev/disk/trm/trm.c @@ -3613,6 +3613,7 @@ trm_attach(device_t dev) "trm", pACB, unit, + &sim_mplock, 1, TRM_MAX_TAGS_CMD_QUEUE, device_Q); diff --git a/sys/dev/disk/vpo/vpo.c b/sys/dev/disk/vpo/vpo.c index 1214aec..6025b0f 100644 --- a/sys/dev/disk/vpo/vpo.c +++ b/sys/dev/disk/vpo/vpo.c @@ -153,7 +153,7 @@ vpo_attach(device_t dev) return (ENXIO); vpo->sim = cam_sim_alloc(vpo_action, vpo_poll, "vpo", vpo, - device_get_unit(dev), + device_get_unit(dev), &sim_mplock, /*untagged*/1, /*tagged*/0, devq); cam_simq_release(devq); if (vpo->sim == NULL) { diff --git a/sys/dev/raid/aac/aac_cam.c b/sys/dev/raid/aac/aac_cam.c index b96b129..b5e0434 100644 --- a/sys/dev/raid/aac/aac_cam.c +++ b/sys/dev/raid/aac/aac_cam.c @@ -171,7 +171,7 @@ aac_cam_attach(device_t dev) return (EIO); sim = cam_sim_alloc(aac_cam_action, aac_cam_poll, "aacp", camsc, - device_get_unit(dev), 1, 1, devq); + device_get_unit(dev), &sim_mplock, 1, 1, devq); cam_simq_release(devq); if (sim == NULL) { return (EIO); diff --git a/sys/dev/raid/amr/amr_cam.c b/sys/dev/raid/amr/amr_cam.c index cd04f2c..07e133c 100644 --- a/sys/dev/raid/amr/amr_cam.c +++ b/sys/dev/raid/amr/amr_cam.c @@ -148,6 +148,7 @@ amr_cam_attach(struct amr_softc *sc) "amr", sc, device_get_unit(sc->amr_dev), + &sim_mplock, 1, AMR_MAX_SCSI_CMDS, devq)) == NULL) { diff --git a/sys/dev/raid/asr/asr.c b/sys/dev/raid/asr/asr.c index c6a2db9..8731cf6 100644 --- a/sys/dev/raid/asr/asr.c +++ b/sys/dev/raid/asr/asr.c @@ -2742,7 +2742,7 @@ asr_attach (ATTACH_ARGS) */ sc->ha_sim[bus] = cam_sim_alloc( asr_action, asr_poll, "asr", sc, - unit, 1, QueueSize, NULL); + unit, &sim_mplock, 1, QueueSize, NULL); if (sc->ha_sim[bus] == NULL) continue; diff --git a/sys/dev/raid/ciss/ciss.c b/sys/dev/raid/ciss/ciss.c index 49bf3dc..d656641 100644 --- a/sys/dev/raid/ciss/ciss.c +++ b/sys/dev/raid/ciss/ciss.c @@ -2070,8 +2070,8 @@ ciss_cam_init(struct ciss_softc *sc) */ if ((sc->ciss_cam_sim = cam_sim_alloc(ciss_cam_action, ciss_cam_poll, "ciss", sc, device_get_unit(sc->ciss_dev), + &sim_mplock, 1, sc->ciss_max_requests - 2, - 1, sc->ciss_cam_devq)) == NULL) { ciss_printf(sc, "can't allocate CAM SIM\n"); return(ENOMEM); diff --git a/sys/dev/raid/dpt/dpt_scsi.c b/sys/dev/raid/dpt/dpt_scsi.c index 102c1b2..e82064d 100644 --- a/sys/dev/raid/dpt/dpt_scsi.c +++ b/sys/dev/raid/dpt/dpt_scsi.c @@ -1485,7 +1485,8 @@ dpt_attach(dpt_softc_t *dpt) * Construct our SIM entry */ dpt->sims[i] = cam_sim_alloc(dpt_action, dpt_poll, "dpt", - dpt, dpt->unit, /*untagged*/2, + dpt, dpt->unit, &sim_mplock, + /*untagged*/2, /*tagged*/dpt->max_dccbs, devq); if (xpt_bus_register(dpt->sims[i], i) != CAM_SUCCESS) { cam_sim_free(dpt->sims[i]); diff --git a/sys/dev/raid/iir/iir.c b/sys/dev/raid/iir/iir.c index e9722e8..219f580 100644 --- a/sys/dev/raid/iir/iir.c +++ b/sys/dev/raid/iir/iir.c @@ -482,7 +482,8 @@ iir_attach(struct gdt_softc *gdt) * Construct our SIM entry */ gdt->sims[i] = cam_sim_alloc(iir_action, iir_poll, "iir", - gdt, gdt->sc_hanum, /*untagged*/2, + gdt, gdt->sc_hanum, &sim_mplock, + /*untagged*/2, /*tagged*/GDT_MAXCMDS, devq); if (xpt_bus_register(gdt->sims[i], i) != CAM_SUCCESS) { cam_sim_free(gdt->sims[i]); diff --git a/sys/dev/raid/mly/mly.c b/sys/dev/raid/mly/mly.c index 4dea7e5..dae6183 100644 --- a/sys/dev/raid/mly/mly.c +++ b/sys/dev/raid/mly/mly.c @@ -1933,6 +1933,7 @@ mly_cam_attach(struct mly_softc *sc) if ((sc->mly_cam_sim[chn] = cam_sim_alloc(mly_cam_action, mly_cam_poll, "mly", sc, device_get_unit(sc->mly_dev), + &sim_mplock, sc->mly_controllerinfo->maximum_parallel_commands, 1, devq)) == NULL) { return(ENOMEM); @@ -1952,6 +1953,7 @@ mly_cam_attach(struct mly_softc *sc) for (i = 0; i < sc->mly_controllerinfo->virtual_channels_present; i++, chn++) { if ((sc->mly_cam_sim[chn] = cam_sim_alloc(mly_cam_action, mly_cam_poll, "mly", sc, device_get_unit(sc->mly_dev), + &sim_mplock, sc->mly_controllerinfo->maximum_parallel_commands, 0, devq)) == NULL) { return(ENOMEM); diff --git a/sys/dev/raid/twa/twa_cam.c b/sys/dev/raid/twa/twa_cam.c index 49bd6fc..e82a440 100644 --- a/sys/dev/raid/twa/twa_cam.c +++ b/sys/dev/raid/twa/twa_cam.c @@ -87,6 +87,7 @@ twa_cam_setup(struct twa_softc *sc) twa_dbg_dprint(3, sc, "Calling cam_sim_alloc"); sc->twa_sim = cam_sim_alloc(twa_action, twa_poll, "twa", sc, device_get_unit(sc->twa_bus_dev), + &sim_mplock, TWA_Q_LENGTH - 1, 1, devq); cam_simq_release(devq); if (sc->twa_sim == NULL) { diff --git a/sys/dev/usbmisc/umass/umass.c b/sys/dev/usbmisc/umass/umass.c index 8e53c84..bbe92e4 100644 --- a/sys/dev/usbmisc/umass/umass.c +++ b/sys/dev/usbmisc/umass/umass.c @@ -2696,6 +2696,7 @@ umass_cam_attach_sim(struct umass_softc *sc) DEVNAME_SIM, sc /*priv*/, device_get_unit(sc->sc_dev) /*unit number*/, + &sim_mplock, 1 /*maximum device openings*/, 0 /*maximum tagged device openings*/, devq);