1898b0535SWarner Losh /*- 28b8a9b1dSJustin T. Gibbs * Implementation of the Common Access Method Transport (XPT) layer. 38b8a9b1dSJustin T. Gibbs * 4c8bead2aSJustin T. Gibbs * Copyright (c) 1997, 1998, 1999 Justin T. Gibbs. 559190eaaSKenneth D. Merry * Copyright (c) 1997, 1998, 1999 Kenneth D. Merry. 68b8a9b1dSJustin T. Gibbs * All rights reserved. 78b8a9b1dSJustin T. Gibbs * 88b8a9b1dSJustin T. Gibbs * Redistribution and use in source and binary forms, with or without 98b8a9b1dSJustin T. Gibbs * modification, are permitted provided that the following conditions 108b8a9b1dSJustin T. Gibbs * are met: 118b8a9b1dSJustin T. Gibbs * 1. Redistributions of source code must retain the above copyright 128b8a9b1dSJustin T. Gibbs * notice, this list of conditions, and the following disclaimer, 138b8a9b1dSJustin T. Gibbs * without modification, immediately at the beginning of the file. 148b8a9b1dSJustin T. Gibbs * 2. The name of the author may not be used to endorse or promote products 158b8a9b1dSJustin T. Gibbs * derived from this software without specific prior written permission. 168b8a9b1dSJustin T. Gibbs * 178b8a9b1dSJustin T. Gibbs * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 188b8a9b1dSJustin T. Gibbs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 198b8a9b1dSJustin T. Gibbs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 208b8a9b1dSJustin T. Gibbs * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 218b8a9b1dSJustin T. Gibbs * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 228b8a9b1dSJustin T. Gibbs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 238b8a9b1dSJustin T. Gibbs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 248b8a9b1dSJustin T. Gibbs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 258b8a9b1dSJustin T. Gibbs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 268b8a9b1dSJustin T. Gibbs * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 278b8a9b1dSJustin T. Gibbs * SUCH DAMAGE. 288b8a9b1dSJustin T. Gibbs */ 299c963d87SDavid E. O'Brien 30*2379d1d6SWarner Losh #include "opt_printf.h" 31*2379d1d6SWarner Losh 329c963d87SDavid E. O'Brien #include <sys/cdefs.h> 339c963d87SDavid E. O'Brien __FBSDID("$FreeBSD$"); 349c963d87SDavid E. O'Brien 358b8a9b1dSJustin T. Gibbs #include <sys/param.h> 368532d381SConrad Meyer #include <sys/bio.h> 379a94c9c5SJohn Baldwin #include <sys/bus.h> 388b8a9b1dSJustin T. Gibbs #include <sys/systm.h> 398b8a9b1dSJustin T. Gibbs #include <sys/types.h> 408b8a9b1dSJustin T. Gibbs #include <sys/malloc.h> 418b8a9b1dSJustin T. Gibbs #include <sys/kernel.h> 4287cfaf0eSJustin T. Gibbs #include <sys/time.h> 438b8a9b1dSJustin T. Gibbs #include <sys/conf.h> 448b8a9b1dSJustin T. Gibbs #include <sys/fcntl.h> 455d754af7SMatt Jacob #include <sys/interrupt.h> 46227d67aaSAlexander Motin #include <sys/proc.h> 473393f8daSKenneth D. Merry #include <sys/sbuf.h> 48227d67aaSAlexander Motin #include <sys/smp.h> 492b83592fSScott Long #include <sys/taskqueue.h> 508b8a9b1dSJustin T. Gibbs 51ef3cf714SScott Long #include <sys/lock.h> 52ef3cf714SScott Long #include <sys/mutex.h> 533b87a552SMatt Jacob #include <sys/sysctl.h> 549e6461a2SMatt Jacob #include <sys/kthread.h> 55ef3cf714SScott Long 568b8a9b1dSJustin T. Gibbs #include <cam/cam.h> 578b8a9b1dSJustin T. Gibbs #include <cam/cam_ccb.h> 588b8a9b1dSJustin T. Gibbs #include <cam/cam_periph.h> 5952c9ce25SScott Long #include <cam/cam_queue.h> 608b8a9b1dSJustin T. Gibbs #include <cam/cam_sim.h> 618b8a9b1dSJustin T. Gibbs #include <cam/cam_xpt.h> 628b8a9b1dSJustin T. Gibbs #include <cam/cam_xpt_sim.h> 638b8a9b1dSJustin T. Gibbs #include <cam/cam_xpt_periph.h> 6452c9ce25SScott Long #include <cam/cam_xpt_internal.h> 658b8a9b1dSJustin T. Gibbs #include <cam/cam_debug.h> 6625a2902cSScott Long #include <cam/cam_compat.h> 678b8a9b1dSJustin T. Gibbs 688b8a9b1dSJustin T. Gibbs #include <cam/scsi/scsi_all.h> 698b8a9b1dSJustin T. Gibbs #include <cam/scsi/scsi_message.h> 708b8a9b1dSJustin T. Gibbs #include <cam/scsi/scsi_pass.h> 71abef0e67SMarius Strobl 72abef0e67SMarius Strobl #include <machine/md_var.h> /* geometry translation */ 73f0d9af51SMatt Jacob #include <machine/stdarg.h> /* for xpt_print below */ 74abef0e67SMarius Strobl 758b8a9b1dSJustin T. Gibbs #include "opt_cam.h" 768b8a9b1dSJustin T. Gibbs 77*2379d1d6SWarner Losh /* Wild guess based on not wanting to grow the stack too much */ 78*2379d1d6SWarner Losh #define XPT_PRINT_MAXLEN 512 79*2379d1d6SWarner Losh #ifdef PRINTF_BUFR_SIZE 80*2379d1d6SWarner Losh #define XPT_PRINT_LEN PRINTF_BUFR_SIZE 81*2379d1d6SWarner Losh #else 82*2379d1d6SWarner Losh #define XPT_PRINT_LEN 128 83*2379d1d6SWarner Losh #endif 84*2379d1d6SWarner Losh _Static_assert(XPT_PRINT_LEN <= XPT_PRINT_MAXLEN, "XPT_PRINT_LEN is too large"); 85*2379d1d6SWarner Losh 8652c9ce25SScott Long /* 8752c9ce25SScott Long * This is the maximum number of high powered commands (e.g. start unit) 8852c9ce25SScott Long * that can be outstanding at a particular time. 8952c9ce25SScott Long */ 9052c9ce25SScott Long #ifndef CAM_MAX_HIGHPOWER 9152c9ce25SScott Long #define CAM_MAX_HIGHPOWER 4 9252c9ce25SScott Long #endif 9352c9ce25SScott Long 948b8a9b1dSJustin T. Gibbs /* Datastructures internal to the xpt layer */ 95362abc44STai-hwa Liang MALLOC_DEFINE(M_CAMXPT, "CAM XPT", "CAM XPT buffers"); 96596ee08fSAlexander Motin MALLOC_DEFINE(M_CAMDEV, "CAM DEV", "CAM devices"); 97596ee08fSAlexander Motin MALLOC_DEFINE(M_CAMCCB, "CAM CCB", "CAM CCBs"); 98596ee08fSAlexander Motin MALLOC_DEFINE(M_CAMPATH, "CAM path", "CAM paths"); 998b8a9b1dSJustin T. Gibbs 1002b83592fSScott Long /* Object for defering XPT actions to a taskqueue */ 1012b83592fSScott Long struct xpt_task { 1022b83592fSScott Long struct task task; 10384f82481SScott Long void *data1; 10484f82481SScott Long uintptr_t data2; 1052b83592fSScott Long }; 1062b83592fSScott Long 1078b8a9b1dSJustin T. Gibbs struct xpt_softc { 108636870ffSWill Andrews uint32_t xpt_generation; 109636870ffSWill Andrews 1102b83592fSScott Long /* number of high powered commands that can go through right now */ 111daa5487fSAlexander Motin struct mtx xpt_highpower_lock; 112ea541bfdSAlexander Motin STAILQ_HEAD(highpowerlist, cam_ed) highpowerq; 1132b83592fSScott Long int num_highpower; 1142b83592fSScott Long 1152b83592fSScott Long /* queue for handling async rescan requests. */ 1162b83592fSScott Long TAILQ_HEAD(, ccb_hdr) ccb_scanq; 11783c5d981SAlexander Motin int buses_to_config; 11883c5d981SAlexander Motin int buses_config_done; 1192b83592fSScott Long 120db4fcadfSConrad Meyer /* 121db4fcadfSConrad Meyer * Registered buses 122db4fcadfSConrad Meyer * 123db4fcadfSConrad Meyer * N.B., "busses" is an archaic spelling of "buses". In new code 124db4fcadfSConrad Meyer * "buses" is preferred. 125db4fcadfSConrad Meyer */ 1262b83592fSScott Long TAILQ_HEAD(,cam_eb) xpt_busses; 1272b83592fSScott Long u_int bus_generation; 1282b83592fSScott Long 1292b83592fSScott Long struct intr_config_hook *xpt_config_hook; 1302b83592fSScott Long 13183c5d981SAlexander Motin int boot_delay; 13283c5d981SAlexander Motin struct callout boot_callout; 13383c5d981SAlexander Motin 1342b83592fSScott Long struct mtx xpt_topo_lock; 1352b83592fSScott Long struct mtx xpt_lock; 136227d67aaSAlexander Motin struct taskqueue *xpt_taskq; 1378b8a9b1dSJustin T. Gibbs }; 1388b8a9b1dSJustin T. Gibbs 1398b8a9b1dSJustin T. Gibbs typedef enum { 1408b8a9b1dSJustin T. Gibbs DM_RET_COPY = 0x01, 1418b8a9b1dSJustin T. Gibbs DM_RET_FLAG_MASK = 0x0f, 1428b8a9b1dSJustin T. Gibbs DM_RET_NONE = 0x00, 1438b8a9b1dSJustin T. Gibbs DM_RET_STOP = 0x10, 1448b8a9b1dSJustin T. Gibbs DM_RET_DESCEND = 0x20, 1458b8a9b1dSJustin T. Gibbs DM_RET_ERROR = 0x30, 1468b8a9b1dSJustin T. Gibbs DM_RET_ACTION_MASK = 0xf0 1478b8a9b1dSJustin T. Gibbs } dev_match_ret; 1488b8a9b1dSJustin T. Gibbs 1498b8a9b1dSJustin T. Gibbs typedef enum { 1508b8a9b1dSJustin T. Gibbs XPT_DEPTH_BUS, 1518b8a9b1dSJustin T. Gibbs XPT_DEPTH_TARGET, 1528b8a9b1dSJustin T. Gibbs XPT_DEPTH_DEVICE, 1538b8a9b1dSJustin T. Gibbs XPT_DEPTH_PERIPH 1548b8a9b1dSJustin T. Gibbs } xpt_traverse_depth; 1558b8a9b1dSJustin T. Gibbs 1568b8a9b1dSJustin T. Gibbs struct xpt_traverse_config { 1578b8a9b1dSJustin T. Gibbs xpt_traverse_depth depth; 1588b8a9b1dSJustin T. Gibbs void *tr_func; 1598b8a9b1dSJustin T. Gibbs void *tr_arg; 1608b8a9b1dSJustin T. Gibbs }; 1618b8a9b1dSJustin T. Gibbs 1628b8a9b1dSJustin T. Gibbs typedef int xpt_busfunc_t (struct cam_eb *bus, void *arg); 1638b8a9b1dSJustin T. Gibbs typedef int xpt_targetfunc_t (struct cam_et *target, void *arg); 1648b8a9b1dSJustin T. Gibbs typedef int xpt_devicefunc_t (struct cam_ed *device, void *arg); 1658b8a9b1dSJustin T. Gibbs typedef int xpt_periphfunc_t (struct cam_periph *periph, void *arg); 1668b8a9b1dSJustin T. Gibbs typedef int xpt_pdrvfunc_t (struct periph_driver **pdrv, void *arg); 1678b8a9b1dSJustin T. Gibbs 1688b8a9b1dSJustin T. Gibbs /* Transport layer configuration information */ 1698b8a9b1dSJustin T. Gibbs static struct xpt_softc xsoftc; 1708b8a9b1dSJustin T. Gibbs 1715719711fSEdward Tomasz Napierala MTX_SYSINIT(xpt_topo_init, &xsoftc.xpt_topo_lock, "XPT topology lock", MTX_DEF); 1725719711fSEdward Tomasz Napierala 17383c5d981SAlexander Motin SYSCTL_INT(_kern_cam, OID_AUTO, boot_delay, CTLFLAG_RDTUN, 17483c5d981SAlexander Motin &xsoftc.boot_delay, 0, "Bus registration wait time"); 175636870ffSWill Andrews SYSCTL_UINT(_kern_cam, OID_AUTO, xpt_generation, CTLFLAG_RD, 176636870ffSWill Andrews &xsoftc.xpt_generation, 0, "CAM peripheral generation count"); 17783c5d981SAlexander Motin 178227d67aaSAlexander Motin struct cam_doneq { 179227d67aaSAlexander Motin struct mtx_padalign cam_doneq_mtx; 180227d67aaSAlexander Motin STAILQ_HEAD(, ccb_hdr) cam_doneq; 181227d67aaSAlexander Motin int cam_doneq_sleep; 182227d67aaSAlexander Motin }; 1838b8a9b1dSJustin T. Gibbs 184227d67aaSAlexander Motin static struct cam_doneq cam_doneqs[MAXCPU]; 185227d67aaSAlexander Motin static int cam_num_doneqs; 186227d67aaSAlexander Motin static struct proc *cam_proc; 187227d67aaSAlexander Motin 188227d67aaSAlexander Motin SYSCTL_INT(_kern_cam, OID_AUTO, num_doneqs, CTLFLAG_RDTUN, 189227d67aaSAlexander Motin &cam_num_doneqs, 0, "Number of completion queues/threads"); 1908b8a9b1dSJustin T. Gibbs 1919a1c8571SNick Hibma struct cam_periph *xpt_periph; 1929a1c8571SNick Hibma 1938b8a9b1dSJustin T. Gibbs static periph_init_t xpt_periph_init; 1948b8a9b1dSJustin T. Gibbs 1958b8a9b1dSJustin T. Gibbs static struct periph_driver xpt_driver = 1968b8a9b1dSJustin T. Gibbs { 1978b8a9b1dSJustin T. Gibbs xpt_periph_init, "xpt", 1981e637ba6SAlexander Motin TAILQ_HEAD_INITIALIZER(xpt_driver.units), /* generation */ 0, 1991e637ba6SAlexander Motin CAM_PERIPH_DRV_EARLY 2008b8a9b1dSJustin T. Gibbs }; 2018b8a9b1dSJustin T. Gibbs 2020b7c27b9SPeter Wemm PERIPHDRIVER_DECLARE(xpt, xpt_driver); 2038b8a9b1dSJustin T. Gibbs 2048b8a9b1dSJustin T. Gibbs static d_open_t xptopen; 2058b8a9b1dSJustin T. Gibbs static d_close_t xptclose; 2068b8a9b1dSJustin T. Gibbs static d_ioctl_t xptioctl; 20725a2902cSScott Long static d_ioctl_t xptdoioctl; 2088b8a9b1dSJustin T. Gibbs 2094e2f199eSPoul-Henning Kamp static struct cdevsw xpt_cdevsw = { 210dc08ffecSPoul-Henning Kamp .d_version = D_VERSION, 2112b83592fSScott Long .d_flags = 0, 2127ac40f5fSPoul-Henning Kamp .d_open = xptopen, 2137ac40f5fSPoul-Henning Kamp .d_close = xptclose, 2147ac40f5fSPoul-Henning Kamp .d_ioctl = xptioctl, 2157ac40f5fSPoul-Henning Kamp .d_name = "xpt", 2168b8a9b1dSJustin T. Gibbs }; 2178b8a9b1dSJustin T. Gibbs 2188b8a9b1dSJustin T. Gibbs /* Storage for debugging datastructures */ 2198b8a9b1dSJustin T. Gibbs struct cam_path *cam_dpath; 22082b361b1SMatt Jacob u_int32_t cam_dflags = CAM_DEBUG_FLAGS; 221af3b2549SHans Petter Selasky SYSCTL_UINT(_kern_cam, OID_AUTO, dflags, CTLFLAG_RWTUN, 222f0f25b9cSAlexander Motin &cam_dflags, 0, "Enabled debug flags"); 223f0f25b9cSAlexander Motin u_int32_t cam_debug_delay = CAM_DEBUG_DELAY; 224af3b2549SHans Petter Selasky SYSCTL_UINT(_kern_cam, OID_AUTO, debug_delay, CTLFLAG_RWTUN, 225f0f25b9cSAlexander Motin &cam_debug_delay, 0, "Delay in us after each debug message"); 2268b8a9b1dSJustin T. Gibbs 2276d2a8f1cSPeter Wemm /* Our boot-time initialization hook */ 22874bd1c10SNick Hibma static int cam_module_event_handler(module_t, int /*modeventtype_t*/, void *); 22974bd1c10SNick Hibma 23074bd1c10SNick Hibma static moduledata_t cam_moduledata = { 23174bd1c10SNick Hibma "cam", 23274bd1c10SNick Hibma cam_module_event_handler, 23374bd1c10SNick Hibma NULL 23474bd1c10SNick Hibma }; 23574bd1c10SNick Hibma 2362b83592fSScott Long static int xpt_init(void *); 23774bd1c10SNick Hibma 23874bd1c10SNick Hibma DECLARE_MODULE(cam, cam_moduledata, SI_SUB_CONFIGURE, SI_ORDER_SECOND); 23974bd1c10SNick Hibma MODULE_VERSION(cam, 1); 24074bd1c10SNick Hibma 2418b8a9b1dSJustin T. Gibbs 2428b8a9b1dSJustin T. Gibbs static void xpt_async_bcast(struct async_list *async_head, 2438b8a9b1dSJustin T. Gibbs u_int32_t async_code, 2448b8a9b1dSJustin T. Gibbs struct cam_path *path, 2458b8a9b1dSJustin T. Gibbs void *async_arg); 246434bbf6eSJustin T. Gibbs static path_id_t xptnextfreepathid(void); 247434bbf6eSJustin T. Gibbs static path_id_t xptpathid(const char *sim_name, int sim_unit, int sim_bus); 248227d67aaSAlexander Motin static union ccb *xpt_get_ccb(struct cam_periph *periph); 249227d67aaSAlexander Motin static union ccb *xpt_get_ccb_nowait(struct cam_periph *periph); 250227d67aaSAlexander Motin static void xpt_run_allocq(struct cam_periph *periph, int sleep); 251227d67aaSAlexander Motin static void xpt_run_allocq_task(void *context, int pending); 252cccf4220SAlexander Motin static void xpt_run_devq(struct cam_devq *devq); 2538b8a9b1dSJustin T. Gibbs static timeout_t xpt_release_devq_timeout; 2542b83592fSScott Long static void xpt_release_simq_timeout(void *arg) __unused; 255227d67aaSAlexander Motin static void xpt_acquire_bus(struct cam_eb *bus); 256a5479bc5SJustin T. Gibbs static void xpt_release_bus(struct cam_eb *bus); 257daa5487fSAlexander Motin static uint32_t xpt_freeze_devq_device(struct cam_ed *dev, u_int count); 258227d67aaSAlexander Motin static int xpt_release_devq_device(struct cam_ed *dev, u_int count, 259cccf4220SAlexander Motin int run_queue); 2608b8a9b1dSJustin T. Gibbs static struct cam_et* 2618b8a9b1dSJustin T. Gibbs xpt_alloc_target(struct cam_eb *bus, target_id_t target_id); 262227d67aaSAlexander Motin static void xpt_acquire_target(struct cam_et *target); 263f98d7a47SAlexander Motin static void xpt_release_target(struct cam_et *target); 2648b8a9b1dSJustin T. Gibbs static struct cam_eb* 2658b8a9b1dSJustin T. Gibbs xpt_find_bus(path_id_t path_id); 2668b8a9b1dSJustin T. Gibbs static struct cam_et* 2678b8a9b1dSJustin T. Gibbs xpt_find_target(struct cam_eb *bus, target_id_t target_id); 2688b8a9b1dSJustin T. Gibbs static struct cam_ed* 2698b8a9b1dSJustin T. Gibbs xpt_find_device(struct cam_et *target, lun_id_t lun_id); 2708b8a9b1dSJustin T. Gibbs static void xpt_config(void *arg); 271227d67aaSAlexander Motin static int xpt_schedule_dev(struct camq *queue, cam_pinfo *dev_pinfo, 272227d67aaSAlexander Motin u_int32_t new_priority); 2738b8a9b1dSJustin T. Gibbs static xpt_devicefunc_t xptpassannouncefunc; 2748b8a9b1dSJustin T. Gibbs static void xptaction(struct cam_sim *sim, union ccb *work_ccb); 275434bbf6eSJustin T. Gibbs static void xptpoll(struct cam_sim *sim); 276227d67aaSAlexander Motin static void camisr_runqueue(void); 277227d67aaSAlexander Motin static void xpt_done_process(struct ccb_hdr *ccb_h); 278227d67aaSAlexander Motin static void xpt_done_td(void *); 2798b8a9b1dSJustin T. Gibbs static dev_match_ret xptbusmatch(struct dev_match_pattern *patterns, 2803393f8daSKenneth D. Merry u_int num_patterns, struct cam_eb *bus); 2818b8a9b1dSJustin T. Gibbs static dev_match_ret xptdevicematch(struct dev_match_pattern *patterns, 2823393f8daSKenneth D. Merry u_int num_patterns, 2833393f8daSKenneth D. Merry struct cam_ed *device); 2848b8a9b1dSJustin T. Gibbs static dev_match_ret xptperiphmatch(struct dev_match_pattern *patterns, 2853393f8daSKenneth D. Merry u_int num_patterns, 2868b8a9b1dSJustin T. Gibbs struct cam_periph *periph); 2878b8a9b1dSJustin T. Gibbs static xpt_busfunc_t xptedtbusfunc; 2888b8a9b1dSJustin T. Gibbs static xpt_targetfunc_t xptedttargetfunc; 2898b8a9b1dSJustin T. Gibbs static xpt_devicefunc_t xptedtdevicefunc; 2908b8a9b1dSJustin T. Gibbs static xpt_periphfunc_t xptedtperiphfunc; 2918b8a9b1dSJustin T. Gibbs static xpt_pdrvfunc_t xptplistpdrvfunc; 2928b8a9b1dSJustin T. Gibbs static xpt_periphfunc_t xptplistperiphfunc; 2938b8a9b1dSJustin T. Gibbs static int xptedtmatch(struct ccb_dev_match *cdm); 2948b8a9b1dSJustin T. Gibbs static int xptperiphlistmatch(struct ccb_dev_match *cdm); 2958b8a9b1dSJustin T. Gibbs static int xptbustraverse(struct cam_eb *start_bus, 2968b8a9b1dSJustin T. Gibbs xpt_busfunc_t *tr_func, void *arg); 2978b8a9b1dSJustin T. Gibbs static int xpttargettraverse(struct cam_eb *bus, 2988b8a9b1dSJustin T. Gibbs struct cam_et *start_target, 2998b8a9b1dSJustin T. Gibbs xpt_targetfunc_t *tr_func, void *arg); 3008b8a9b1dSJustin T. Gibbs static int xptdevicetraverse(struct cam_et *target, 3018b8a9b1dSJustin T. Gibbs struct cam_ed *start_device, 3028b8a9b1dSJustin T. Gibbs xpt_devicefunc_t *tr_func, void *arg); 3038b8a9b1dSJustin T. Gibbs static int xptperiphtraverse(struct cam_ed *device, 3048b8a9b1dSJustin T. Gibbs struct cam_periph *start_periph, 3058b8a9b1dSJustin T. Gibbs xpt_periphfunc_t *tr_func, void *arg); 3068b8a9b1dSJustin T. Gibbs static int xptpdrvtraverse(struct periph_driver **start_pdrv, 3078b8a9b1dSJustin T. Gibbs xpt_pdrvfunc_t *tr_func, void *arg); 3088b8a9b1dSJustin T. Gibbs static int xptpdperiphtraverse(struct periph_driver **pdrv, 3098b8a9b1dSJustin T. Gibbs struct cam_periph *start_periph, 3108b8a9b1dSJustin T. Gibbs xpt_periphfunc_t *tr_func, 3118b8a9b1dSJustin T. Gibbs void *arg); 3128b8a9b1dSJustin T. Gibbs static xpt_busfunc_t xptdefbusfunc; 3138b8a9b1dSJustin T. Gibbs static xpt_targetfunc_t xptdeftargetfunc; 3148b8a9b1dSJustin T. Gibbs static xpt_devicefunc_t xptdefdevicefunc; 3158b8a9b1dSJustin T. Gibbs static xpt_periphfunc_t xptdefperiphfunc; 31683c5d981SAlexander Motin static void xpt_finishconfig_task(void *context, int pending); 31752c9ce25SScott Long static void xpt_dev_async_default(u_int32_t async_code, 31852c9ce25SScott Long struct cam_eb *bus, 31952c9ce25SScott Long struct cam_et *target, 32052c9ce25SScott Long struct cam_ed *device, 32152c9ce25SScott Long void *async_arg); 32252c9ce25SScott Long static struct cam_ed * xpt_alloc_device_default(struct cam_eb *bus, 32352c9ce25SScott Long struct cam_et *target, 32452c9ce25SScott Long lun_id_t lun_id); 3258b8a9b1dSJustin T. Gibbs static xpt_devicefunc_t xptsetasyncfunc; 3268b8a9b1dSJustin T. Gibbs static xpt_busfunc_t xptsetasyncbusfunc; 3278b8a9b1dSJustin T. Gibbs static cam_status xptregister(struct cam_periph *periph, 3288b8a9b1dSJustin T. Gibbs void *arg); 32969be012fSWarner Losh static const char * xpt_action_name(uint32_t action); 330cccf4220SAlexander Motin static __inline int device_is_queued(struct cam_ed *device); 3318b8a9b1dSJustin T. Gibbs 3328b8a9b1dSJustin T. Gibbs static __inline int 333cccf4220SAlexander Motin xpt_schedule_devq(struct cam_devq *devq, struct cam_ed *dev) 33430a4094fSAlexander Motin { 33530a4094fSAlexander Motin int retval; 33630a4094fSAlexander Motin 337227d67aaSAlexander Motin mtx_assert(&devq->send_mtx, MA_OWNED); 33883c5d981SAlexander Motin if ((dev->ccbq.queue.entries > 0) && 33983c5d981SAlexander Motin (dev->ccbq.dev_openings > 0) && 340cccf4220SAlexander Motin (dev->ccbq.queue.qfrozen_cnt == 0)) { 34130a4094fSAlexander Motin /* 34230a4094fSAlexander Motin * The priority of a device waiting for controller 3436bccea7cSRebecca Cran * resources is that of the highest priority CCB 34430a4094fSAlexander Motin * enqueued. 34530a4094fSAlexander Motin */ 34630a4094fSAlexander Motin retval = 347cccf4220SAlexander Motin xpt_schedule_dev(&devq->send_queue, 348227d67aaSAlexander Motin &dev->devq_entry, 34983c5d981SAlexander Motin CAMQ_GET_PRIO(&dev->ccbq.queue)); 35030a4094fSAlexander Motin } else { 35130a4094fSAlexander Motin retval = 0; 35230a4094fSAlexander Motin } 35330a4094fSAlexander Motin return (retval); 35430a4094fSAlexander Motin } 35530a4094fSAlexander Motin 35630a4094fSAlexander Motin static __inline int 357cccf4220SAlexander Motin device_is_queued(struct cam_ed *device) 3588b8a9b1dSJustin T. Gibbs { 359227d67aaSAlexander Motin return (device->devq_entry.index != CAM_UNQUEUED_INDEX); 3608b8a9b1dSJustin T. Gibbs } 3618b8a9b1dSJustin T. Gibbs 3628b8a9b1dSJustin T. Gibbs static void 3638b8a9b1dSJustin T. Gibbs xpt_periph_init() 3648b8a9b1dSJustin T. Gibbs { 36573d26919SKenneth D. Merry make_dev(&xpt_cdevsw, 0, UID_ROOT, GID_OPERATOR, 0600, "xpt0"); 3668b8a9b1dSJustin T. Gibbs } 3678b8a9b1dSJustin T. Gibbs 3688b8a9b1dSJustin T. Gibbs static int 36989c9c53dSPoul-Henning Kamp xptopen(struct cdev *dev, int flags, int fmt, struct thread *td) 3708b8a9b1dSJustin T. Gibbs { 3718b8a9b1dSJustin T. Gibbs 3728b8a9b1dSJustin T. Gibbs /* 37366a0780eSKenneth D. Merry * Only allow read-write access. 37466a0780eSKenneth D. Merry */ 37566a0780eSKenneth D. Merry if (((flags & FWRITE) == 0) || ((flags & FREAD) == 0)) 37666a0780eSKenneth D. Merry return(EPERM); 37766a0780eSKenneth D. Merry 37866a0780eSKenneth D. Merry /* 3798b8a9b1dSJustin T. Gibbs * We don't allow nonblocking access. 3808b8a9b1dSJustin T. Gibbs */ 3818b8a9b1dSJustin T. Gibbs if ((flags & O_NONBLOCK) != 0) { 3822b83592fSScott Long printf("%s: can't do nonblocking access\n", devtoname(dev)); 3838b8a9b1dSJustin T. Gibbs return(ENODEV); 3848b8a9b1dSJustin T. Gibbs } 3858b8a9b1dSJustin T. Gibbs 3868b8a9b1dSJustin T. Gibbs return(0); 3878b8a9b1dSJustin T. Gibbs } 3888b8a9b1dSJustin T. Gibbs 3898b8a9b1dSJustin T. Gibbs static int 39089c9c53dSPoul-Henning Kamp xptclose(struct cdev *dev, int flag, int fmt, struct thread *td) 3918b8a9b1dSJustin T. Gibbs { 3928b8a9b1dSJustin T. Gibbs 3938b8a9b1dSJustin T. Gibbs return(0); 3948b8a9b1dSJustin T. Gibbs } 3958b8a9b1dSJustin T. Gibbs 3962b83592fSScott Long /* 3972b83592fSScott Long * Don't automatically grab the xpt softc lock here even though this is going 3982b83592fSScott Long * through the xpt device. The xpt device is really just a back door for 3992b83592fSScott Long * accessing other devices and SIMs, so the right thing to do is to grab 4002b83592fSScott Long * the appropriate SIM lock once the bus/SIM is located. 4012b83592fSScott Long */ 4028b8a9b1dSJustin T. Gibbs static int 40389c9c53dSPoul-Henning Kamp xptioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, struct thread *td) 4048b8a9b1dSJustin T. Gibbs { 4052b83592fSScott Long int error; 4068b8a9b1dSJustin T. Gibbs 40725a2902cSScott Long if ((error = xptdoioctl(dev, cmd, addr, flag, td)) == ENOTTY) { 408f564de00SScott Long error = cam_compat_ioctl(dev, cmd, addr, flag, td, xptdoioctl); 40925a2902cSScott Long } 41025a2902cSScott Long return (error); 41125a2902cSScott Long } 41225a2902cSScott Long 41325a2902cSScott Long static int 41425a2902cSScott Long xptdoioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, struct thread *td) 41525a2902cSScott Long { 41625a2902cSScott Long int error; 41725a2902cSScott Long 4188b8a9b1dSJustin T. Gibbs error = 0; 4198b8a9b1dSJustin T. Gibbs 4208b8a9b1dSJustin T. Gibbs switch(cmd) { 4218b8a9b1dSJustin T. Gibbs /* 4228b8a9b1dSJustin T. Gibbs * For the transport layer CAMIOCOMMAND ioctl, we really only want 4238b8a9b1dSJustin T. Gibbs * to accept CCB types that don't quite make sense to send through a 4248c7a96c5SScott Long * passthrough driver. XPT_PATH_INQ is an exception to this, as stated 4258c7a96c5SScott Long * in the CAM spec. 4268b8a9b1dSJustin T. Gibbs */ 4278b8a9b1dSJustin T. Gibbs case CAMIOCOMMAND: { 4288b8a9b1dSJustin T. Gibbs union ccb *ccb; 4298b8a9b1dSJustin T. Gibbs union ccb *inccb; 4302b83592fSScott Long struct cam_eb *bus; 4318b8a9b1dSJustin T. Gibbs 4328b8a9b1dSJustin T. Gibbs inccb = (union ccb *)addr; 4338fc77fffSConrad Meyer #if defined(BUF_TRACKING) || defined(FULL_BUF_TRACKING) 4348fc77fffSConrad Meyer if (inccb->ccb_h.func_code == XPT_SCSI_IO) 4358fc77fffSConrad Meyer inccb->csio.bio = NULL; 4368fc77fffSConrad Meyer #endif 4378b8a9b1dSJustin T. Gibbs 4382b83592fSScott Long bus = xpt_find_bus(inccb->ccb_h.path_id); 4390e85f214SMatt Jacob if (bus == NULL) 4400e85f214SMatt Jacob return (EINVAL); 4410e85f214SMatt Jacob 4420e85f214SMatt Jacob switch (inccb->ccb_h.func_code) { 4430e85f214SMatt Jacob case XPT_SCAN_BUS: 4440e85f214SMatt Jacob case XPT_RESET_BUS: 4450e85f214SMatt Jacob if (inccb->ccb_h.target_id != CAM_TARGET_WILDCARD || 4460e85f214SMatt Jacob inccb->ccb_h.target_lun != CAM_LUN_WILDCARD) { 4470e85f214SMatt Jacob xpt_release_bus(bus); 4480e85f214SMatt Jacob return (EINVAL); 4490e85f214SMatt Jacob } 4500e85f214SMatt Jacob break; 4510e85f214SMatt Jacob case XPT_SCAN_TGT: 4520e85f214SMatt Jacob if (inccb->ccb_h.target_id == CAM_TARGET_WILDCARD || 4530e85f214SMatt Jacob inccb->ccb_h.target_lun != CAM_LUN_WILDCARD) { 4540e85f214SMatt Jacob xpt_release_bus(bus); 4550e85f214SMatt Jacob return (EINVAL); 4560e85f214SMatt Jacob } 4570e85f214SMatt Jacob break; 4580e85f214SMatt Jacob default: 4592b83592fSScott Long break; 4602b83592fSScott Long } 4612b83592fSScott Long 4628b8a9b1dSJustin T. Gibbs switch(inccb->ccb_h.func_code) { 4638b8a9b1dSJustin T. Gibbs case XPT_SCAN_BUS: 4648b8a9b1dSJustin T. Gibbs case XPT_RESET_BUS: 4658c7a96c5SScott Long case XPT_PATH_INQ: 4668fcf57f5SJustin T. Gibbs case XPT_ENG_INQ: 4678b8a9b1dSJustin T. Gibbs case XPT_SCAN_LUN: 4680e85f214SMatt Jacob case XPT_SCAN_TGT: 4698b8a9b1dSJustin T. Gibbs 4708008a935SScott Long ccb = xpt_alloc_ccb(); 4712b83592fSScott Long 4728b8a9b1dSJustin T. Gibbs /* 4738b8a9b1dSJustin T. Gibbs * Create a path using the bus, target, and lun the 4748b8a9b1dSJustin T. Gibbs * user passed in. 4758b8a9b1dSJustin T. Gibbs */ 476e5dfa058SAlexander Motin if (xpt_create_path(&ccb->ccb_h.path, NULL, 4778b8a9b1dSJustin T. Gibbs inccb->ccb_h.path_id, 4788b8a9b1dSJustin T. Gibbs inccb->ccb_h.target_id, 4798b8a9b1dSJustin T. Gibbs inccb->ccb_h.target_lun) != 4808b8a9b1dSJustin T. Gibbs CAM_REQ_CMP){ 4818b8a9b1dSJustin T. Gibbs error = EINVAL; 4828b8a9b1dSJustin T. Gibbs xpt_free_ccb(ccb); 4838b8a9b1dSJustin T. Gibbs break; 4848b8a9b1dSJustin T. Gibbs } 4858b8a9b1dSJustin T. Gibbs /* Ensure all of our fields are correct */ 4868b8a9b1dSJustin T. Gibbs xpt_setup_ccb(&ccb->ccb_h, ccb->ccb_h.path, 4878b8a9b1dSJustin T. Gibbs inccb->ccb_h.pinfo.priority); 4888b8a9b1dSJustin T. Gibbs xpt_merge_ccb(ccb, inccb); 489227d67aaSAlexander Motin xpt_path_lock(ccb->ccb_h.path); 4908b8a9b1dSJustin T. Gibbs cam_periph_runccb(ccb, NULL, 0, 0, NULL); 491227d67aaSAlexander Motin xpt_path_unlock(ccb->ccb_h.path); 4928b8a9b1dSJustin T. Gibbs bcopy(ccb, inccb, sizeof(union ccb)); 4938b8a9b1dSJustin T. Gibbs xpt_free_path(ccb->ccb_h.path); 4948b8a9b1dSJustin T. Gibbs xpt_free_ccb(ccb); 4958b8a9b1dSJustin T. Gibbs break; 4968b8a9b1dSJustin T. Gibbs 4978b8a9b1dSJustin T. Gibbs case XPT_DEBUG: { 4988b8a9b1dSJustin T. Gibbs union ccb ccb; 4998b8a9b1dSJustin T. Gibbs 5008b8a9b1dSJustin T. Gibbs /* 501aa872be6SMatt Jacob * This is an immediate CCB, so it's okay to 5028b8a9b1dSJustin T. Gibbs * allocate it on the stack. 5038b8a9b1dSJustin T. Gibbs */ 5048b8a9b1dSJustin T. Gibbs 5058b8a9b1dSJustin T. Gibbs /* 5068b8a9b1dSJustin T. Gibbs * Create a path using the bus, target, and lun the 5078b8a9b1dSJustin T. Gibbs * user passed in. 5088b8a9b1dSJustin T. Gibbs */ 509e5dfa058SAlexander Motin if (xpt_create_path(&ccb.ccb_h.path, NULL, 5108b8a9b1dSJustin T. Gibbs inccb->ccb_h.path_id, 5118b8a9b1dSJustin T. Gibbs inccb->ccb_h.target_id, 5128b8a9b1dSJustin T. Gibbs inccb->ccb_h.target_lun) != 5138b8a9b1dSJustin T. Gibbs CAM_REQ_CMP){ 5148b8a9b1dSJustin T. Gibbs error = EINVAL; 5158b8a9b1dSJustin T. Gibbs break; 5168b8a9b1dSJustin T. Gibbs } 5178b8a9b1dSJustin T. Gibbs /* Ensure all of our fields are correct */ 5188b8a9b1dSJustin T. Gibbs xpt_setup_ccb(&ccb.ccb_h, ccb.ccb_h.path, 5198b8a9b1dSJustin T. Gibbs inccb->ccb_h.pinfo.priority); 5208b8a9b1dSJustin T. Gibbs xpt_merge_ccb(&ccb, inccb); 5218b8a9b1dSJustin T. Gibbs xpt_action(&ccb); 5228b8a9b1dSJustin T. Gibbs bcopy(&ccb, inccb, sizeof(union ccb)); 5238b8a9b1dSJustin T. Gibbs xpt_free_path(ccb.ccb_h.path); 5248b8a9b1dSJustin T. Gibbs break; 5258b8a9b1dSJustin T. Gibbs 5268b8a9b1dSJustin T. Gibbs } 5278b8a9b1dSJustin T. Gibbs case XPT_DEV_MATCH: { 5288b8a9b1dSJustin T. Gibbs struct cam_periph_map_info mapinfo; 52959190eaaSKenneth D. Merry struct cam_path *old_path; 5308b8a9b1dSJustin T. Gibbs 5318b8a9b1dSJustin T. Gibbs /* 5328b8a9b1dSJustin T. Gibbs * We can't deal with physical addresses for this 5338b8a9b1dSJustin T. Gibbs * type of transaction. 5348b8a9b1dSJustin T. Gibbs */ 535dd0b4fb6SKonstantin Belousov if ((inccb->ccb_h.flags & CAM_DATA_MASK) != 536dd0b4fb6SKonstantin Belousov CAM_DATA_VADDR) { 5378b8a9b1dSJustin T. Gibbs error = EINVAL; 5388b8a9b1dSJustin T. Gibbs break; 5398b8a9b1dSJustin T. Gibbs } 54059190eaaSKenneth D. Merry 54159190eaaSKenneth D. Merry /* 54259190eaaSKenneth D. Merry * Save this in case the caller had it set to 54359190eaaSKenneth D. Merry * something in particular. 54459190eaaSKenneth D. Merry */ 54559190eaaSKenneth D. Merry old_path = inccb->ccb_h.path; 54659190eaaSKenneth D. Merry 54759190eaaSKenneth D. Merry /* 54859190eaaSKenneth D. Merry * We really don't need a path for the matching 54959190eaaSKenneth D. Merry * code. The path is needed because of the 55059190eaaSKenneth D. Merry * debugging statements in xpt_action(). They 55159190eaaSKenneth D. Merry * assume that the CCB has a valid path. 55259190eaaSKenneth D. Merry */ 55359190eaaSKenneth D. Merry inccb->ccb_h.path = xpt_periph->path; 55459190eaaSKenneth D. Merry 5558b8a9b1dSJustin T. Gibbs bzero(&mapinfo, sizeof(mapinfo)); 5568b8a9b1dSJustin T. Gibbs 5578b8a9b1dSJustin T. Gibbs /* 5588b8a9b1dSJustin T. Gibbs * Map the pattern and match buffers into kernel 5598b8a9b1dSJustin T. Gibbs * virtual address space. 5608b8a9b1dSJustin T. Gibbs */ 561de239312SAlexander Motin error = cam_periph_mapmem(inccb, &mapinfo, MAXPHYS); 5628b8a9b1dSJustin T. Gibbs 56359190eaaSKenneth D. Merry if (error) { 56459190eaaSKenneth D. Merry inccb->ccb_h.path = old_path; 5658b8a9b1dSJustin T. Gibbs break; 56659190eaaSKenneth D. Merry } 5678b8a9b1dSJustin T. Gibbs 5688b8a9b1dSJustin T. Gibbs /* 5698b8a9b1dSJustin T. Gibbs * This is an immediate CCB, we can send it on directly. 5708b8a9b1dSJustin T. Gibbs */ 5718b8a9b1dSJustin T. Gibbs xpt_action(inccb); 5728b8a9b1dSJustin T. Gibbs 5738b8a9b1dSJustin T. Gibbs /* 5748b8a9b1dSJustin T. Gibbs * Map the buffers back into user space. 5758b8a9b1dSJustin T. Gibbs */ 5768b8a9b1dSJustin T. Gibbs cam_periph_unmapmem(inccb, &mapinfo); 5778b8a9b1dSJustin T. Gibbs 57859190eaaSKenneth D. Merry inccb->ccb_h.path = old_path; 57959190eaaSKenneth D. Merry 5808b8a9b1dSJustin T. Gibbs error = 0; 5818b8a9b1dSJustin T. Gibbs break; 5828b8a9b1dSJustin T. Gibbs } 5838b8a9b1dSJustin T. Gibbs default: 5848fcf57f5SJustin T. Gibbs error = ENOTSUP; 5858b8a9b1dSJustin T. Gibbs break; 5868b8a9b1dSJustin T. Gibbs } 587daddc001SScott Long xpt_release_bus(bus); 5888b8a9b1dSJustin T. Gibbs break; 5898b8a9b1dSJustin T. Gibbs } 5908b8a9b1dSJustin T. Gibbs /* 5918b8a9b1dSJustin T. Gibbs * This is the getpassthru ioctl. It takes a XPT_GDEVLIST ccb as input, 5928b8a9b1dSJustin T. Gibbs * with the periphal driver name and unit name filled in. The other 5938b8a9b1dSJustin T. Gibbs * fields don't really matter as input. The passthrough driver name 5948b8a9b1dSJustin T. Gibbs * ("pass"), and unit number are passed back in the ccb. The current 5958b8a9b1dSJustin T. Gibbs * device generation number, and the index into the device peripheral 5968b8a9b1dSJustin T. Gibbs * driver list, and the status are also passed back. Note that 5978b8a9b1dSJustin T. Gibbs * since we do everything in one pass, unlike the XPT_GDEVLIST ccb, 5988b8a9b1dSJustin T. Gibbs * we never return a status of CAM_GDEVLIST_LIST_CHANGED. It is 5998b8a9b1dSJustin T. Gibbs * (or rather should be) impossible for the device peripheral driver 6008b8a9b1dSJustin T. Gibbs * list to change since we look at the whole thing in one pass, and 60177dc25ccSScott Long * we do it with lock protection. 6028b8a9b1dSJustin T. Gibbs * 6038b8a9b1dSJustin T. Gibbs */ 6048b8a9b1dSJustin T. Gibbs case CAMGETPASSTHRU: { 6058b8a9b1dSJustin T. Gibbs union ccb *ccb; 6068b8a9b1dSJustin T. Gibbs struct cam_periph *periph; 6078b8a9b1dSJustin T. Gibbs struct periph_driver **p_drv; 6088b8a9b1dSJustin T. Gibbs char *name; 6093393f8daSKenneth D. Merry u_int unit; 610621a60d4SKenneth D. Merry int base_periph_found; 6118b8a9b1dSJustin T. Gibbs 6128b8a9b1dSJustin T. Gibbs ccb = (union ccb *)addr; 6138b8a9b1dSJustin T. Gibbs unit = ccb->cgdl.unit_number; 6148b8a9b1dSJustin T. Gibbs name = ccb->cgdl.periph_name; 615621a60d4SKenneth D. Merry base_periph_found = 0; 6168fc77fffSConrad Meyer #if defined(BUF_TRACKING) || defined(FULL_BUF_TRACKING) 6178fc77fffSConrad Meyer if (ccb->ccb_h.func_code == XPT_SCSI_IO) 6188fc77fffSConrad Meyer ccb->csio.bio = NULL; 6198fc77fffSConrad Meyer #endif 620621a60d4SKenneth D. Merry 6218b8a9b1dSJustin T. Gibbs /* 6228b8a9b1dSJustin T. Gibbs * Sanity check -- make sure we don't get a null peripheral 6238b8a9b1dSJustin T. Gibbs * driver name. 6248b8a9b1dSJustin T. Gibbs */ 6258b8a9b1dSJustin T. Gibbs if (*ccb->cgdl.periph_name == '\0') { 6268b8a9b1dSJustin T. Gibbs error = EINVAL; 6278b8a9b1dSJustin T. Gibbs break; 6288b8a9b1dSJustin T. Gibbs } 6298b8a9b1dSJustin T. Gibbs 6308b8a9b1dSJustin T. Gibbs /* Keep the list from changing while we traverse it */ 6319a7c2696SAlexander Motin xpt_lock_buses(); 6328b8a9b1dSJustin T. Gibbs 6338b8a9b1dSJustin T. Gibbs /* first find our driver in the list of drivers */ 6340b7c27b9SPeter Wemm for (p_drv = periph_drivers; *p_drv != NULL; p_drv++) 6358b8a9b1dSJustin T. Gibbs if (strcmp((*p_drv)->driver_name, name) == 0) 6368b8a9b1dSJustin T. Gibbs break; 6378b8a9b1dSJustin T. Gibbs 6388b8a9b1dSJustin T. Gibbs if (*p_drv == NULL) { 6399a7c2696SAlexander Motin xpt_unlock_buses(); 6408b8a9b1dSJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_CMP_ERR; 6418b8a9b1dSJustin T. Gibbs ccb->cgdl.status = CAM_GDEVLIST_ERROR; 6428b8a9b1dSJustin T. Gibbs *ccb->cgdl.periph_name = '\0'; 6438b8a9b1dSJustin T. Gibbs ccb->cgdl.unit_number = 0; 6448b8a9b1dSJustin T. Gibbs error = ENOENT; 6458b8a9b1dSJustin T. Gibbs break; 6468b8a9b1dSJustin T. Gibbs } 6478b8a9b1dSJustin T. Gibbs 6488b8a9b1dSJustin T. Gibbs /* 6498b8a9b1dSJustin T. Gibbs * Run through every peripheral instance of this driver 6508b8a9b1dSJustin T. Gibbs * and check to see whether it matches the unit passed 6518b8a9b1dSJustin T. Gibbs * in by the user. If it does, get out of the loops and 6528b8a9b1dSJustin T. Gibbs * find the passthrough driver associated with that 6538b8a9b1dSJustin T. Gibbs * peripheral driver. 6548b8a9b1dSJustin T. Gibbs */ 6558b8a9b1dSJustin T. Gibbs for (periph = TAILQ_FIRST(&(*p_drv)->units); periph != NULL; 6568b8a9b1dSJustin T. Gibbs periph = TAILQ_NEXT(periph, unit_links)) { 6578b8a9b1dSJustin T. Gibbs 658a29779e8SAlexander Motin if (periph->unit_number == unit) 6598b8a9b1dSJustin T. Gibbs break; 6608b8a9b1dSJustin T. Gibbs } 6618b8a9b1dSJustin T. Gibbs /* 6628b8a9b1dSJustin T. Gibbs * If we found the peripheral driver that the user passed 6638b8a9b1dSJustin T. Gibbs * in, go through all of the peripheral drivers for that 6648b8a9b1dSJustin T. Gibbs * particular device and look for a passthrough driver. 6658b8a9b1dSJustin T. Gibbs */ 6668b8a9b1dSJustin T. Gibbs if (periph != NULL) { 6678b8a9b1dSJustin T. Gibbs struct cam_ed *device; 6688b8a9b1dSJustin T. Gibbs int i; 6698b8a9b1dSJustin T. Gibbs 670621a60d4SKenneth D. Merry base_periph_found = 1; 6718b8a9b1dSJustin T. Gibbs device = periph->path->device; 672fc2ffbe6SPoul-Henning Kamp for (i = 0, periph = SLIST_FIRST(&device->periphs); 6738b8a9b1dSJustin T. Gibbs periph != NULL; 674fc2ffbe6SPoul-Henning Kamp periph = SLIST_NEXT(periph, periph_links), i++) { 6758b8a9b1dSJustin T. Gibbs /* 6768b8a9b1dSJustin T. Gibbs * Check to see whether we have a 6778b8a9b1dSJustin T. Gibbs * passthrough device or not. 6788b8a9b1dSJustin T. Gibbs */ 6798b8a9b1dSJustin T. Gibbs if (strcmp(periph->periph_name, "pass") == 0) { 6808b8a9b1dSJustin T. Gibbs /* 6818b8a9b1dSJustin T. Gibbs * Fill in the getdevlist fields. 6828b8a9b1dSJustin T. Gibbs */ 6838b8a9b1dSJustin T. Gibbs strcpy(ccb->cgdl.periph_name, 6848b8a9b1dSJustin T. Gibbs periph->periph_name); 6858b8a9b1dSJustin T. Gibbs ccb->cgdl.unit_number = 6868b8a9b1dSJustin T. Gibbs periph->unit_number; 687fc2ffbe6SPoul-Henning Kamp if (SLIST_NEXT(periph, periph_links)) 6888b8a9b1dSJustin T. Gibbs ccb->cgdl.status = 6898b8a9b1dSJustin T. Gibbs CAM_GDEVLIST_MORE_DEVS; 6908b8a9b1dSJustin T. Gibbs else 6918b8a9b1dSJustin T. Gibbs ccb->cgdl.status = 6928b8a9b1dSJustin T. Gibbs CAM_GDEVLIST_LAST_DEVICE; 6938b8a9b1dSJustin T. Gibbs ccb->cgdl.generation = 6948b8a9b1dSJustin T. Gibbs device->generation; 6958b8a9b1dSJustin T. Gibbs ccb->cgdl.index = i; 6968b8a9b1dSJustin T. Gibbs /* 6978b8a9b1dSJustin T. Gibbs * Fill in some CCB header fields 6988b8a9b1dSJustin T. Gibbs * that the user may want. 6998b8a9b1dSJustin T. Gibbs */ 7008b8a9b1dSJustin T. Gibbs ccb->ccb_h.path_id = 7018b8a9b1dSJustin T. Gibbs periph->path->bus->path_id; 7028b8a9b1dSJustin T. Gibbs ccb->ccb_h.target_id = 7038b8a9b1dSJustin T. Gibbs periph->path->target->target_id; 7048b8a9b1dSJustin T. Gibbs ccb->ccb_h.target_lun = 7058b8a9b1dSJustin T. Gibbs periph->path->device->lun_id; 7068b8a9b1dSJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_CMP; 7078b8a9b1dSJustin T. Gibbs break; 7088b8a9b1dSJustin T. Gibbs } 7098b8a9b1dSJustin T. Gibbs } 7108b8a9b1dSJustin T. Gibbs } 7118b8a9b1dSJustin T. Gibbs 7128b8a9b1dSJustin T. Gibbs /* 7138b8a9b1dSJustin T. Gibbs * If the periph is null here, one of two things has 7148b8a9b1dSJustin T. Gibbs * happened. The first possibility is that we couldn't 7158b8a9b1dSJustin T. Gibbs * find the unit number of the particular peripheral driver 7168b8a9b1dSJustin T. Gibbs * that the user is asking about. e.g. the user asks for 7178b8a9b1dSJustin T. Gibbs * the passthrough driver for "da11". We find the list of 7188b8a9b1dSJustin T. Gibbs * "da" peripherals all right, but there is no unit 11. 7198b8a9b1dSJustin T. Gibbs * The other possibility is that we went through the list 7208b8a9b1dSJustin T. Gibbs * of peripheral drivers attached to the device structure, 7218b8a9b1dSJustin T. Gibbs * but didn't find one with the name "pass". Either way, 7228b8a9b1dSJustin T. Gibbs * we return ENOENT, since we couldn't find something. 7238b8a9b1dSJustin T. Gibbs */ 7248b8a9b1dSJustin T. Gibbs if (periph == NULL) { 7258b8a9b1dSJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_CMP_ERR; 7268b8a9b1dSJustin T. Gibbs ccb->cgdl.status = CAM_GDEVLIST_ERROR; 7278b8a9b1dSJustin T. Gibbs *ccb->cgdl.periph_name = '\0'; 7288b8a9b1dSJustin T. Gibbs ccb->cgdl.unit_number = 0; 7298b8a9b1dSJustin T. Gibbs error = ENOENT; 730621a60d4SKenneth D. Merry /* 731621a60d4SKenneth D. Merry * It is unfortunate that this is even necessary, 732621a60d4SKenneth D. Merry * but there are many, many clueless users out there. 733621a60d4SKenneth D. Merry * If this is true, the user is looking for the 734621a60d4SKenneth D. Merry * passthrough driver, but doesn't have one in his 735621a60d4SKenneth D. Merry * kernel. 736621a60d4SKenneth D. Merry */ 737621a60d4SKenneth D. Merry if (base_periph_found == 1) { 738621a60d4SKenneth D. Merry printf("xptioctl: pass driver is not in the " 739621a60d4SKenneth D. Merry "kernel\n"); 740935c968aSChristian Brueffer printf("xptioctl: put \"device pass\" in " 741621a60d4SKenneth D. Merry "your kernel config file\n"); 742621a60d4SKenneth D. Merry } 7438b8a9b1dSJustin T. Gibbs } 7449a7c2696SAlexander Motin xpt_unlock_buses(); 7458b8a9b1dSJustin T. Gibbs break; 7468b8a9b1dSJustin T. Gibbs } 7478b8a9b1dSJustin T. Gibbs default: 7488b8a9b1dSJustin T. Gibbs error = ENOTTY; 7498b8a9b1dSJustin T. Gibbs break; 7508b8a9b1dSJustin T. Gibbs } 7518b8a9b1dSJustin T. Gibbs 7528b8a9b1dSJustin T. Gibbs return(error); 7538b8a9b1dSJustin T. Gibbs } 7548b8a9b1dSJustin T. Gibbs 75574bd1c10SNick Hibma static int 75674bd1c10SNick Hibma cam_module_event_handler(module_t mod, int what, void *arg) 75774bd1c10SNick Hibma { 7582b83592fSScott Long int error; 7592b83592fSScott Long 7602b83592fSScott Long switch (what) { 7612b83592fSScott Long case MOD_LOAD: 7622b83592fSScott Long if ((error = xpt_init(NULL)) != 0) 7632b83592fSScott Long return (error); 7642b83592fSScott Long break; 7652b83592fSScott Long case MOD_UNLOAD: 76674bd1c10SNick Hibma return EBUSY; 7672b83592fSScott Long default: 7683e019deaSPoul-Henning Kamp return EOPNOTSUPP; 76974bd1c10SNick Hibma } 77074bd1c10SNick Hibma 77174bd1c10SNick Hibma return 0; 77274bd1c10SNick Hibma } 77374bd1c10SNick Hibma 77408f13879SWarner Losh static struct xpt_proto * 77508f13879SWarner Losh xpt_proto_find(cam_proto proto) 77608f13879SWarner Losh { 77708f13879SWarner Losh struct xpt_proto **pp; 77808f13879SWarner Losh 77908f13879SWarner Losh SET_FOREACH(pp, cam_xpt_proto_set) { 78008f13879SWarner Losh if ((*pp)->proto == proto) 78108f13879SWarner Losh return *pp; 78208f13879SWarner Losh } 78308f13879SWarner Losh 78408f13879SWarner Losh return NULL; 78508f13879SWarner Losh } 78608f13879SWarner Losh 78783c5d981SAlexander Motin static void 78883c5d981SAlexander Motin xpt_rescan_done(struct cam_periph *periph, union ccb *done_ccb) 78983c5d981SAlexander Motin { 79083c5d981SAlexander Motin 79183c5d981SAlexander Motin if (done_ccb->ccb_h.ppriv_ptr1 == NULL) { 79283c5d981SAlexander Motin xpt_free_path(done_ccb->ccb_h.path); 79383c5d981SAlexander Motin xpt_free_ccb(done_ccb); 79483c5d981SAlexander Motin } else { 79583c5d981SAlexander Motin done_ccb->ccb_h.cbfcnp = done_ccb->ccb_h.ppriv_ptr1; 79683c5d981SAlexander Motin (*done_ccb->ccb_h.cbfcnp)(periph, done_ccb); 79783c5d981SAlexander Motin } 79883c5d981SAlexander Motin xpt_release_boot(); 79983c5d981SAlexander Motin } 80083c5d981SAlexander Motin 8019e6461a2SMatt Jacob /* thread to handle bus rescans */ 8029e6461a2SMatt Jacob static void 8039e6461a2SMatt Jacob xpt_scanner_thread(void *dummy) 8049e6461a2SMatt Jacob { 8059e6461a2SMatt Jacob union ccb *ccb; 806227d67aaSAlexander Motin struct cam_path path; 8072b83592fSScott Long 8082b83592fSScott Long xpt_lock_buses(); 80983c5d981SAlexander Motin for (;;) { 8105a73cc12SKenneth D. Merry if (TAILQ_EMPTY(&xsoftc.ccb_scanq)) 8112b83592fSScott Long msleep(&xsoftc.ccb_scanq, &xsoftc.xpt_topo_lock, PRIBIO, 8123710ae64SAlexander Motin "-", 0); 81383c5d981SAlexander Motin if ((ccb = (union ccb *)TAILQ_FIRST(&xsoftc.ccb_scanq)) != NULL) { 81483c5d981SAlexander Motin TAILQ_REMOVE(&xsoftc.ccb_scanq, &ccb->ccb_h, sim_links.tqe); 8152b83592fSScott Long xpt_unlock_buses(); 8162b83592fSScott Long 817227d67aaSAlexander Motin /* 818227d67aaSAlexander Motin * Since lock can be dropped inside and path freed 819227d67aaSAlexander Motin * by completion callback even before return here, 820227d67aaSAlexander Motin * take our own path copy for reference. 821227d67aaSAlexander Motin */ 822227d67aaSAlexander Motin xpt_copy_path(&path, ccb->ccb_h.path); 823227d67aaSAlexander Motin xpt_path_lock(&path); 82483c5d981SAlexander Motin xpt_action(ccb); 825227d67aaSAlexander Motin xpt_path_unlock(&path); 826227d67aaSAlexander Motin xpt_release_path(&path); 82783c5d981SAlexander Motin 82883c5d981SAlexander Motin xpt_lock_buses(); 8299e6461a2SMatt Jacob } 8309e6461a2SMatt Jacob } 8319e6461a2SMatt Jacob } 8329e6461a2SMatt Jacob 8339e6461a2SMatt Jacob void 8349e6461a2SMatt Jacob xpt_rescan(union ccb *ccb) 8359e6461a2SMatt Jacob { 8369e6461a2SMatt Jacob struct ccb_hdr *hdr; 8372b83592fSScott Long 83883c5d981SAlexander Motin /* Prepare request */ 8390e85f214SMatt Jacob if (ccb->ccb_h.path->target->target_id == CAM_TARGET_WILDCARD && 840411cadaeSAlexander Motin ccb->ccb_h.path->device->lun_id == CAM_LUN_WILDCARD) 84183c5d981SAlexander Motin ccb->ccb_h.func_code = XPT_SCAN_BUS; 8420e85f214SMatt Jacob else if (ccb->ccb_h.path->target->target_id != CAM_TARGET_WILDCARD && 8430e85f214SMatt Jacob ccb->ccb_h.path->device->lun_id == CAM_LUN_WILDCARD) 8440e85f214SMatt Jacob ccb->ccb_h.func_code = XPT_SCAN_TGT; 8450e85f214SMatt Jacob else if (ccb->ccb_h.path->target->target_id != CAM_TARGET_WILDCARD && 8460e85f214SMatt Jacob ccb->ccb_h.path->device->lun_id != CAM_LUN_WILDCARD) 84783c5d981SAlexander Motin ccb->ccb_h.func_code = XPT_SCAN_LUN; 8480e85f214SMatt Jacob else { 8490e85f214SMatt Jacob xpt_print(ccb->ccb_h.path, "illegal scan path\n"); 8500e85f214SMatt Jacob xpt_free_path(ccb->ccb_h.path); 8510e85f214SMatt Jacob xpt_free_ccb(ccb); 8520e85f214SMatt Jacob return; 8530e85f214SMatt Jacob } 85469be012fSWarner Losh CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE, 85569be012fSWarner Losh ("xpt_rescan: func %#x %s\n", ccb->ccb_h.func_code, 85669be012fSWarner Losh xpt_action_name(ccb->ccb_h.func_code))); 85769be012fSWarner Losh 85883c5d981SAlexander Motin ccb->ccb_h.ppriv_ptr1 = ccb->ccb_h.cbfcnp; 85983c5d981SAlexander Motin ccb->ccb_h.cbfcnp = xpt_rescan_done; 86083c5d981SAlexander Motin xpt_setup_ccb(&ccb->ccb_h, ccb->ccb_h.path, CAM_PRIORITY_XPT); 86183c5d981SAlexander Motin /* Don't make duplicate entries for the same paths. */ 8622b83592fSScott Long xpt_lock_buses(); 86383c5d981SAlexander Motin if (ccb->ccb_h.ppriv_ptr1 == NULL) { 8642b83592fSScott Long TAILQ_FOREACH(hdr, &xsoftc.ccb_scanq, sim_links.tqe) { 8659e6461a2SMatt Jacob if (xpt_path_comp(hdr->path, ccb->ccb_h.path) == 0) { 8665a73cc12SKenneth D. Merry wakeup(&xsoftc.ccb_scanq); 8672b83592fSScott Long xpt_unlock_buses(); 8689e6461a2SMatt Jacob xpt_print(ccb->ccb_h.path, "rescan already queued\n"); 8699e6461a2SMatt Jacob xpt_free_path(ccb->ccb_h.path); 8709e6461a2SMatt Jacob xpt_free_ccb(ccb); 8719e6461a2SMatt Jacob return; 8729e6461a2SMatt Jacob } 8739e6461a2SMatt Jacob } 87483c5d981SAlexander Motin } 8752b83592fSScott Long TAILQ_INSERT_TAIL(&xsoftc.ccb_scanq, &ccb->ccb_h, sim_links.tqe); 87683c5d981SAlexander Motin xsoftc.buses_to_config++; 8772b83592fSScott Long wakeup(&xsoftc.ccb_scanq); 8782b83592fSScott Long xpt_unlock_buses(); 8799e6461a2SMatt Jacob } 8809e6461a2SMatt Jacob 8818b8a9b1dSJustin T. Gibbs /* Functions accessed by the peripheral drivers */ 8822b83592fSScott Long static int 8839e6461a2SMatt Jacob xpt_init(void *dummy) 8848b8a9b1dSJustin T. Gibbs { 8858b8a9b1dSJustin T. Gibbs struct cam_sim *xpt_sim; 8868b8a9b1dSJustin T. Gibbs struct cam_path *path; 887434bbf6eSJustin T. Gibbs struct cam_devq *devq; 8888b8a9b1dSJustin T. Gibbs cam_status status; 889227d67aaSAlexander Motin int error, i; 8908b8a9b1dSJustin T. Gibbs 8912b83592fSScott Long TAILQ_INIT(&xsoftc.xpt_busses); 8922b83592fSScott Long TAILQ_INIT(&xsoftc.ccb_scanq); 8932b83592fSScott Long STAILQ_INIT(&xsoftc.highpowerq); 8942b83592fSScott Long xsoftc.num_highpower = CAM_MAX_HIGHPOWER; 8958b8a9b1dSJustin T. Gibbs 8962b83592fSScott Long mtx_init(&xsoftc.xpt_lock, "XPT lock", NULL, MTX_DEF); 897daa5487fSAlexander Motin mtx_init(&xsoftc.xpt_highpower_lock, "XPT highpower lock", NULL, MTX_DEF); 898227d67aaSAlexander Motin xsoftc.xpt_taskq = taskqueue_create("CAM XPT task", M_WAITOK, 899227d67aaSAlexander Motin taskqueue_thread_enqueue, /*context*/&xsoftc.xpt_taskq); 900ef3cf714SScott Long 9016b156f61SSean Bruno #ifdef CAM_BOOT_DELAY 9026b156f61SSean Bruno /* 9036b156f61SSean Bruno * Override this value at compile time to assist our users 9046b156f61SSean Bruno * who don't use loader to boot a kernel. 9056b156f61SSean Bruno */ 9066b156f61SSean Bruno xsoftc.boot_delay = CAM_BOOT_DELAY; 9076b156f61SSean Bruno #endif 9088b8a9b1dSJustin T. Gibbs /* 9091ffe5851SPedro F. Giffuni * The xpt layer is, itself, the equivalent of a SIM. 9108b8a9b1dSJustin T. Gibbs * Allow 16 ccbs in the ccb pool for it. This should 911db4fcadfSConrad Meyer * give decent parallelism when we probe buses and 9128b8a9b1dSJustin T. Gibbs * perform other XPT functions. 9138b8a9b1dSJustin T. Gibbs */ 914434bbf6eSJustin T. Gibbs devq = cam_simq_alloc(16); 915434bbf6eSJustin T. Gibbs xpt_sim = cam_sim_alloc(xptaction, 916434bbf6eSJustin T. Gibbs xptpoll, 917434bbf6eSJustin T. Gibbs "xpt", 918434bbf6eSJustin T. Gibbs /*softc*/NULL, 919434bbf6eSJustin T. Gibbs /*unit*/0, 9202b83592fSScott Long /*mtx*/&xsoftc.xpt_lock, 921434bbf6eSJustin T. Gibbs /*max_dev_transactions*/0, 922434bbf6eSJustin T. Gibbs /*max_tagged_dev_transactions*/0, 923434bbf6eSJustin T. Gibbs devq); 9242b83592fSScott Long if (xpt_sim == NULL) 9252b83592fSScott Long return (ENOMEM); 9268b8a9b1dSJustin T. Gibbs 9272b83592fSScott Long mtx_lock(&xsoftc.xpt_lock); 928b50569b7SScott Long if ((status = xpt_bus_register(xpt_sim, NULL, 0)) != CAM_SUCCESS) { 92983c5d981SAlexander Motin mtx_unlock(&xsoftc.xpt_lock); 930a2821e04SMatt Jacob printf("xpt_init: xpt_bus_register failed with status %#x," 931df826980SMatt Jacob " failing attach\n", status); 9322b83592fSScott Long return (EINVAL); 933df826980SMatt Jacob } 934daa5487fSAlexander Motin mtx_unlock(&xsoftc.xpt_lock); 9358b8a9b1dSJustin T. Gibbs 9368b8a9b1dSJustin T. Gibbs /* 9378b8a9b1dSJustin T. Gibbs * Looking at the XPT from the SIM layer, the XPT is 9381ffe5851SPedro F. Giffuni * the equivalent of a peripheral driver. Allocate 9398b8a9b1dSJustin T. Gibbs * a peripheral driver entry for us. 9408b8a9b1dSJustin T. Gibbs */ 9418b8a9b1dSJustin T. Gibbs if ((status = xpt_create_path(&path, NULL, CAM_XPT_PATH_ID, 9428b8a9b1dSJustin T. Gibbs CAM_TARGET_WILDCARD, 9438b8a9b1dSJustin T. Gibbs CAM_LUN_WILDCARD)) != CAM_REQ_CMP) { 9448b8a9b1dSJustin T. Gibbs printf("xpt_init: xpt_create_path failed with status %#x," 9458b8a9b1dSJustin T. Gibbs " failing attach\n", status); 9462b83592fSScott Long return (EINVAL); 9478b8a9b1dSJustin T. Gibbs } 948daa5487fSAlexander Motin xpt_path_lock(path); 949ee9c90c7SKenneth D. Merry cam_periph_alloc(xptregister, NULL, NULL, NULL, "xpt", CAM_PERIPH_BIO, 9502b83592fSScott Long path, NULL, 0, xpt_sim); 951daa5487fSAlexander Motin xpt_path_unlock(path); 9528b8a9b1dSJustin T. Gibbs xpt_free_path(path); 953daa5487fSAlexander Motin 954227d67aaSAlexander Motin if (cam_num_doneqs < 1) 955227d67aaSAlexander Motin cam_num_doneqs = 1 + mp_ncpus / 6; 956227d67aaSAlexander Motin else if (cam_num_doneqs > MAXCPU) 957227d67aaSAlexander Motin cam_num_doneqs = MAXCPU; 958227d67aaSAlexander Motin for (i = 0; i < cam_num_doneqs; i++) { 959227d67aaSAlexander Motin mtx_init(&cam_doneqs[i].cam_doneq_mtx, "CAM doneq", NULL, 960227d67aaSAlexander Motin MTX_DEF); 961227d67aaSAlexander Motin STAILQ_INIT(&cam_doneqs[i].cam_doneq); 962227d67aaSAlexander Motin error = kproc_kthread_add(xpt_done_td, &cam_doneqs[i], 963227d67aaSAlexander Motin &cam_proc, NULL, 0, 0, "cam", "doneq%d", i); 964227d67aaSAlexander Motin if (error != 0) { 965227d67aaSAlexander Motin cam_num_doneqs = i; 966227d67aaSAlexander Motin break; 967227d67aaSAlexander Motin } 968227d67aaSAlexander Motin } 969227d67aaSAlexander Motin if (cam_num_doneqs < 1) { 970227d67aaSAlexander Motin printf("xpt_init: Cannot init completion queues " 971227d67aaSAlexander Motin "- failing attach\n"); 972227d67aaSAlexander Motin return (ENOMEM); 973227d67aaSAlexander Motin } 9748b8a9b1dSJustin T. Gibbs /* 9758b8a9b1dSJustin T. Gibbs * Register a callback for when interrupts are enabled. 9768b8a9b1dSJustin T. Gibbs */ 9772b83592fSScott Long xsoftc.xpt_config_hook = 9788b8a9b1dSJustin T. Gibbs (struct intr_config_hook *)malloc(sizeof(struct intr_config_hook), 9790dd50e9bSScott Long M_CAMXPT, M_NOWAIT | M_ZERO); 9802b83592fSScott Long if (xsoftc.xpt_config_hook == NULL) { 9818b8a9b1dSJustin T. Gibbs printf("xpt_init: Cannot malloc config hook " 9828b8a9b1dSJustin T. Gibbs "- failing attach\n"); 9832b83592fSScott Long return (ENOMEM); 9848b8a9b1dSJustin T. Gibbs } 9852b83592fSScott Long xsoftc.xpt_config_hook->ich_func = xpt_config; 9862b83592fSScott Long if (config_intrhook_establish(xsoftc.xpt_config_hook) != 0) { 9870dd50e9bSScott Long free (xsoftc.xpt_config_hook, M_CAMXPT); 9888b8a9b1dSJustin T. Gibbs printf("xpt_init: config_intrhook_establish failed " 9898b8a9b1dSJustin T. Gibbs "- failing attach\n"); 9908b8a9b1dSJustin T. Gibbs } 9918b8a9b1dSJustin T. Gibbs 9922b83592fSScott Long return (0); 9938b8a9b1dSJustin T. Gibbs } 9948b8a9b1dSJustin T. Gibbs 9958b8a9b1dSJustin T. Gibbs static cam_status 9968b8a9b1dSJustin T. Gibbs xptregister(struct cam_periph *periph, void *arg) 9978b8a9b1dSJustin T. Gibbs { 9982b83592fSScott Long struct cam_sim *xpt_sim; 9992b83592fSScott Long 10008b8a9b1dSJustin T. Gibbs if (periph == NULL) { 10018b8a9b1dSJustin T. Gibbs printf("xptregister: periph was NULL!!\n"); 10028b8a9b1dSJustin T. Gibbs return(CAM_REQ_CMP_ERR); 10038b8a9b1dSJustin T. Gibbs } 10048b8a9b1dSJustin T. Gibbs 10052b83592fSScott Long xpt_sim = (struct cam_sim *)arg; 10062b83592fSScott Long xpt_sim->softc = periph; 10078b8a9b1dSJustin T. Gibbs xpt_periph = periph; 10082b83592fSScott Long periph->softc = NULL; 10098b8a9b1dSJustin T. Gibbs 10108b8a9b1dSJustin T. Gibbs return(CAM_REQ_CMP); 10118b8a9b1dSJustin T. Gibbs } 10128b8a9b1dSJustin T. Gibbs 10138b8a9b1dSJustin T. Gibbs int32_t 10148b8a9b1dSJustin T. Gibbs xpt_add_periph(struct cam_periph *periph) 10158b8a9b1dSJustin T. Gibbs { 10168b8a9b1dSJustin T. Gibbs struct cam_ed *device; 10178b8a9b1dSJustin T. Gibbs int32_t status; 10188b8a9b1dSJustin T. Gibbs 1019227d67aaSAlexander Motin TASK_INIT(&periph->periph_run_task, 0, xpt_run_allocq_task, periph); 10208b8a9b1dSJustin T. Gibbs device = periph->path->device; 10218b8a9b1dSJustin T. Gibbs status = CAM_REQ_CMP; 10228b8a9b1dSJustin T. Gibbs if (device != NULL) { 1023227d67aaSAlexander Motin mtx_lock(&device->target->bus->eb_mtx); 10248b8a9b1dSJustin T. Gibbs device->generation++; 1025227d67aaSAlexander Motin SLIST_INSERT_HEAD(&device->periphs, periph, periph_links); 1026227d67aaSAlexander Motin mtx_unlock(&device->target->bus->eb_mtx); 1027636870ffSWill Andrews atomic_add_32(&xsoftc.xpt_generation, 1); 10288b8a9b1dSJustin T. Gibbs } 10298b8a9b1dSJustin T. Gibbs 10308b8a9b1dSJustin T. Gibbs return (status); 10318b8a9b1dSJustin T. Gibbs } 10328b8a9b1dSJustin T. Gibbs 10338b8a9b1dSJustin T. Gibbs void 1034a29779e8SAlexander Motin xpt_remove_periph(struct cam_periph *periph) 10358b8a9b1dSJustin T. Gibbs { 10368b8a9b1dSJustin T. Gibbs struct cam_ed *device; 10378b8a9b1dSJustin T. Gibbs 10388b8a9b1dSJustin T. Gibbs device = periph->path->device; 10398b8a9b1dSJustin T. Gibbs if (device != NULL) { 1040227d67aaSAlexander Motin mtx_lock(&device->target->bus->eb_mtx); 10418b8a9b1dSJustin T. Gibbs device->generation++; 1042227d67aaSAlexander Motin SLIST_REMOVE(&device->periphs, periph, cam_periph, periph_links); 1043227d67aaSAlexander Motin mtx_unlock(&device->target->bus->eb_mtx); 1044636870ffSWill Andrews atomic_add_32(&xsoftc.xpt_generation, 1); 10458b8a9b1dSJustin T. Gibbs } 10468b8a9b1dSJustin T. Gibbs } 10478b8a9b1dSJustin T. Gibbs 10483393f8daSKenneth D. Merry 10493393f8daSKenneth D. Merry void 10503393f8daSKenneth D. Merry xpt_announce_periph(struct cam_periph *periph, char *announce_string) 10513393f8daSKenneth D. Merry { 105257079b17SAlexander Motin struct cam_path *path = periph->path; 105308f13879SWarner Losh struct xpt_proto *proto; 10543393f8daSKenneth D. Merry 1055227d67aaSAlexander Motin cam_periph_assert(periph, MA_OWNED); 10568d36a71bSAlexander Motin periph->flags |= CAM_PERIPH_ANNOUNCED; 105768153f43SScott Long 1058abe83505SNathan Whitehorn printf("%s%d at %s%d bus %d scbus%d target %d lun %jx\n", 10593393f8daSKenneth D. Merry periph->periph_name, periph->unit_number, 10603393f8daSKenneth D. Merry path->bus->sim->sim_name, 10613393f8daSKenneth D. Merry path->bus->sim->unit_number, 10623393f8daSKenneth D. Merry path->bus->sim->bus_id, 1063ad413009SAlexander Motin path->bus->path_id, 10643393f8daSKenneth D. Merry path->target->target_id, 1065abe83505SNathan Whitehorn (uintmax_t)path->device->lun_id); 10663393f8daSKenneth D. Merry printf("%s%d: ", periph->periph_name, periph->unit_number); 106708f13879SWarner Losh proto = xpt_proto_find(path->device->protocol); 106808f13879SWarner Losh if (proto) 106908f13879SWarner Losh proto->ops->announce(path->device); 107052c9ce25SScott Long else 107108f13879SWarner Losh printf("%s%d: Unknown protocol device %d\n", 107208f13879SWarner Losh periph->periph_name, periph->unit_number, 107308f13879SWarner Losh path->device->protocol); 1074aa93041dSAlexander Motin if (path->device->serial_num_len > 0) { 10753393f8daSKenneth D. Merry /* Don't wrap the screen - print only the first 60 chars */ 10763393f8daSKenneth D. Merry printf("%s%d: Serial Number %.60s\n", periph->periph_name, 10773393f8daSKenneth D. Merry periph->unit_number, path->device->serial_num); 10783393f8daSKenneth D. Merry } 107957079b17SAlexander Motin /* Announce transport details. */ 108008f13879SWarner Losh path->bus->xport->ops->announce(periph); 108157079b17SAlexander Motin /* Announce command queueing. */ 10823393f8daSKenneth D. Merry if (path->device->inq_flags & SID_CmdQue 10833393f8daSKenneth D. Merry || path->device->flags & CAM_DEV_TAG_AFTER_COUNT) { 10840aacc535SAlexander Motin printf("%s%d: Command Queueing enabled\n", 10853393f8daSKenneth D. Merry periph->periph_name, periph->unit_number); 10863393f8daSKenneth D. Merry } 108757079b17SAlexander Motin /* Announce caller's details if they've passed in. */ 10883393f8daSKenneth D. Merry if (announce_string != NULL) 10893393f8daSKenneth D. Merry printf("%s%d: %s\n", periph->periph_name, 10903393f8daSKenneth D. Merry periph->unit_number, announce_string); 10913393f8daSKenneth D. Merry } 10928b8a9b1dSJustin T. Gibbs 10936fb5c84eSSteven Hartland void 10946fb5c84eSSteven Hartland xpt_announce_quirks(struct cam_periph *periph, int quirks, char *bit_string) 10956fb5c84eSSteven Hartland { 10966fb5c84eSSteven Hartland if (quirks != 0) { 10976fb5c84eSSteven Hartland printf("%s%d: quirks=0x%b\n", periph->periph_name, 10986fb5c84eSSteven Hartland periph->unit_number, quirks, bit_string); 10996fb5c84eSSteven Hartland } 11006fb5c84eSSteven Hartland } 11016fb5c84eSSteven Hartland 11028d36a71bSAlexander Motin void 11038d36a71bSAlexander Motin xpt_denounce_periph(struct cam_periph *periph) 11048d36a71bSAlexander Motin { 11058d36a71bSAlexander Motin struct cam_path *path = periph->path; 110608f13879SWarner Losh struct xpt_proto *proto; 11078d36a71bSAlexander Motin 1108227d67aaSAlexander Motin cam_periph_assert(periph, MA_OWNED); 1109abe83505SNathan Whitehorn printf("%s%d at %s%d bus %d scbus%d target %d lun %jx\n", 11108d36a71bSAlexander Motin periph->periph_name, periph->unit_number, 11118d36a71bSAlexander Motin path->bus->sim->sim_name, 11128d36a71bSAlexander Motin path->bus->sim->unit_number, 11138d36a71bSAlexander Motin path->bus->sim->bus_id, 11148d36a71bSAlexander Motin path->bus->path_id, 11158d36a71bSAlexander Motin path->target->target_id, 1116abe83505SNathan Whitehorn (uintmax_t)path->device->lun_id); 11178d36a71bSAlexander Motin printf("%s%d: ", periph->periph_name, periph->unit_number); 111808f13879SWarner Losh proto = xpt_proto_find(path->device->protocol); 111908f13879SWarner Losh if (proto) 112008f13879SWarner Losh proto->ops->denounce(path->device); 11218d36a71bSAlexander Motin else 112208f13879SWarner Losh printf("%s%d: Unknown protocol device %d\n", 112308f13879SWarner Losh periph->periph_name, periph->unit_number, 112408f13879SWarner Losh path->device->protocol); 11258d36a71bSAlexander Motin if (path->device->serial_num_len > 0) 11268d36a71bSAlexander Motin printf(" s/n %.60s", path->device->serial_num); 11278d36a71bSAlexander Motin printf(" detached\n"); 11288d36a71bSAlexander Motin } 11298d36a71bSAlexander Motin 11308d36a71bSAlexander Motin 11313501942bSJustin T. Gibbs int 11323501942bSJustin T. Gibbs xpt_getattr(char *buf, size_t len, const char *attr, struct cam_path *path) 11333501942bSJustin T. Gibbs { 113400d72d57SAlexander Motin int ret = -1, l, o; 11353501942bSJustin T. Gibbs struct ccb_dev_advinfo cdai; 1136ccba7102SAlexander Motin struct scsi_vpd_id_descriptor *idd; 11373501942bSJustin T. Gibbs 1138227d67aaSAlexander Motin xpt_path_assert(path, MA_OWNED); 11396884b662SAlexander Motin 11403501942bSJustin T. Gibbs memset(&cdai, 0, sizeof(cdai)); 11413501942bSJustin T. Gibbs xpt_setup_ccb(&cdai.ccb_h, path, CAM_PRIORITY_NORMAL); 11423501942bSJustin T. Gibbs cdai.ccb_h.func_code = XPT_DEV_ADVINFO; 1143ab4327bbSAlexander Motin cdai.flags = CDAI_FLAG_NONE; 11443501942bSJustin T. Gibbs cdai.bufsiz = len; 11453501942bSJustin T. Gibbs 11463501942bSJustin T. Gibbs if (!strcmp(attr, "GEOM::ident")) 11473501942bSJustin T. Gibbs cdai.buftype = CDAI_TYPE_SERIAL_NUM; 11483501942bSJustin T. Gibbs else if (!strcmp(attr, "GEOM::physpath")) 11493501942bSJustin T. Gibbs cdai.buftype = CDAI_TYPE_PHYS_PATH; 115040f27d7cSAlexander Motin else if (strcmp(attr, "GEOM::lunid") == 0 || 115140f27d7cSAlexander Motin strcmp(attr, "GEOM::lunname") == 0) { 1152ccba7102SAlexander Motin cdai.buftype = CDAI_TYPE_SCSI_DEVID; 1153ccba7102SAlexander Motin cdai.bufsiz = CAM_SCSI_DEVID_MAXLEN; 1154ccba7102SAlexander Motin } else 11553501942bSJustin T. Gibbs goto out; 11563501942bSJustin T. Gibbs 11573501942bSJustin T. Gibbs cdai.buf = malloc(cdai.bufsiz, M_CAMXPT, M_NOWAIT|M_ZERO); 11583501942bSJustin T. Gibbs if (cdai.buf == NULL) { 11593501942bSJustin T. Gibbs ret = ENOMEM; 11603501942bSJustin T. Gibbs goto out; 11613501942bSJustin T. Gibbs } 11623501942bSJustin T. Gibbs xpt_action((union ccb *)&cdai); /* can only be synchronous */ 11633501942bSJustin T. Gibbs if ((cdai.ccb_h.status & CAM_DEV_QFRZN) != 0) 11643501942bSJustin T. Gibbs cam_release_devq(cdai.ccb_h.path, 0, 0, 0, FALSE); 11653501942bSJustin T. Gibbs if (cdai.provsiz == 0) 11663501942bSJustin T. Gibbs goto out; 1167ccba7102SAlexander Motin if (cdai.buftype == CDAI_TYPE_SCSI_DEVID) { 116840f27d7cSAlexander Motin if (strcmp(attr, "GEOM::lunid") == 0) { 1169ccba7102SAlexander Motin idd = scsi_get_devid((struct scsi_vpd_device_id *)cdai.buf, 1170ccba7102SAlexander Motin cdai.provsiz, scsi_devid_is_lun_naa); 1171ccba7102SAlexander Motin if (idd == NULL) 1172ccba7102SAlexander Motin idd = scsi_get_devid((struct scsi_vpd_device_id *)cdai.buf, 1173ccba7102SAlexander Motin cdai.provsiz, scsi_devid_is_lun_eui64); 117400d72d57SAlexander Motin if (idd == NULL) 117500d72d57SAlexander Motin idd = scsi_get_devid((struct scsi_vpd_device_id *)cdai.buf, 117600d72d57SAlexander Motin cdai.provsiz, scsi_devid_is_lun_uuid); 117700d72d57SAlexander Motin if (idd == NULL) 117800d72d57SAlexander Motin idd = scsi_get_devid((struct scsi_vpd_device_id *)cdai.buf, 117900d72d57SAlexander Motin cdai.provsiz, scsi_devid_is_lun_md5); 118040f27d7cSAlexander Motin } else 118140f27d7cSAlexander Motin idd = NULL; 1182ccba7102SAlexander Motin if (idd == NULL) 1183ccba7102SAlexander Motin idd = scsi_get_devid((struct scsi_vpd_device_id *)cdai.buf, 1184ccba7102SAlexander Motin cdai.provsiz, scsi_devid_is_lun_t10); 1185ccba7102SAlexander Motin if (idd == NULL) 1186ccba7102SAlexander Motin idd = scsi_get_devid((struct scsi_vpd_device_id *)cdai.buf, 1187ccba7102SAlexander Motin cdai.provsiz, scsi_devid_is_lun_name); 1188ccba7102SAlexander Motin if (idd == NULL) 1189ccba7102SAlexander Motin goto out; 1190ccba7102SAlexander Motin ret = 0; 1191fa91cabfSAlexander Motin if ((idd->proto_codeset & SVPD_ID_CODESET_MASK) == SVPD_ID_CODESET_ASCII) { 1192fa91cabfSAlexander Motin if (idd->length < len) { 1193fa91cabfSAlexander Motin for (l = 0; l < idd->length; l++) 1194fa91cabfSAlexander Motin buf[l] = idd->identifier[l] ? 1195fa91cabfSAlexander Motin idd->identifier[l] : ' '; 1196fa91cabfSAlexander Motin buf[l] = 0; 1197fa91cabfSAlexander Motin } else 1198fa91cabfSAlexander Motin ret = EFAULT; 1199fa91cabfSAlexander Motin } else if ((idd->proto_codeset & SVPD_ID_CODESET_MASK) == SVPD_ID_CODESET_UTF8) { 1200ccba7102SAlexander Motin l = strnlen(idd->identifier, idd->length); 1201ccba7102SAlexander Motin if (l < len) { 1202ccba7102SAlexander Motin bcopy(idd->identifier, buf, l); 1203ccba7102SAlexander Motin buf[l] = 0; 1204ccba7102SAlexander Motin } else 1205ccba7102SAlexander Motin ret = EFAULT; 120600d72d57SAlexander Motin } else if ((idd->id_type & SVPD_ID_TYPE_MASK) == SVPD_ID_TYPE_UUID 120700d72d57SAlexander Motin && idd->identifier[0] == 0x10) { 120800d72d57SAlexander Motin if ((idd->length - 2) * 2 + 4 < len) { 120900d72d57SAlexander Motin for (l = 2, o = 0; l < idd->length; l++) { 12103157c368SAlexander Motin if (l == 6 || l == 8 || l == 10 || l == 12) 12113157c368SAlexander Motin o += sprintf(buf + o, "-"); 121200d72d57SAlexander Motin o += sprintf(buf + o, "%02x", 121300d72d57SAlexander Motin idd->identifier[l]); 121400d72d57SAlexander Motin } 121500d72d57SAlexander Motin } else 121600d72d57SAlexander Motin ret = EFAULT; 1217ccba7102SAlexander Motin } else { 1218ccba7102SAlexander Motin if (idd->length * 2 < len) { 1219ccba7102SAlexander Motin for (l = 0; l < idd->length; l++) 1220ccba7102SAlexander Motin sprintf(buf + l * 2, "%02x", 1221ccba7102SAlexander Motin idd->identifier[l]); 1222ccba7102SAlexander Motin } else 1223ccba7102SAlexander Motin ret = EFAULT; 1224ccba7102SAlexander Motin } 1225ccba7102SAlexander Motin } else { 12263501942bSJustin T. Gibbs ret = 0; 12273501942bSJustin T. Gibbs if (strlcpy(buf, cdai.buf, len) >= len) 12283501942bSJustin T. Gibbs ret = EFAULT; 1229ccba7102SAlexander Motin } 12303501942bSJustin T. Gibbs 12313501942bSJustin T. Gibbs out: 12323501942bSJustin T. Gibbs if (cdai.buf != NULL) 12333501942bSJustin T. Gibbs free(cdai.buf, M_CAMXPT); 12343501942bSJustin T. Gibbs return ret; 12353501942bSJustin T. Gibbs } 12363501942bSJustin T. Gibbs 12378b8a9b1dSJustin T. Gibbs static dev_match_ret 12383393f8daSKenneth D. Merry xptbusmatch(struct dev_match_pattern *patterns, u_int num_patterns, 12398b8a9b1dSJustin T. Gibbs struct cam_eb *bus) 12408b8a9b1dSJustin T. Gibbs { 12418b8a9b1dSJustin T. Gibbs dev_match_ret retval; 1242167e63e3SPedro F. Giffuni u_int i; 12438b8a9b1dSJustin T. Gibbs 12448b8a9b1dSJustin T. Gibbs retval = DM_RET_NONE; 12458b8a9b1dSJustin T. Gibbs 12468b8a9b1dSJustin T. Gibbs /* 12478b8a9b1dSJustin T. Gibbs * If we aren't given something to match against, that's an error. 12488b8a9b1dSJustin T. Gibbs */ 12498b8a9b1dSJustin T. Gibbs if (bus == NULL) 12508b8a9b1dSJustin T. Gibbs return(DM_RET_ERROR); 12518b8a9b1dSJustin T. Gibbs 12528b8a9b1dSJustin T. Gibbs /* 12538b8a9b1dSJustin T. Gibbs * If there are no match entries, then this bus matches no 12548b8a9b1dSJustin T. Gibbs * matter what. 12558b8a9b1dSJustin T. Gibbs */ 12568b8a9b1dSJustin T. Gibbs if ((patterns == NULL) || (num_patterns == 0)) 12578b8a9b1dSJustin T. Gibbs return(DM_RET_DESCEND | DM_RET_COPY); 12588b8a9b1dSJustin T. Gibbs 12598b8a9b1dSJustin T. Gibbs for (i = 0; i < num_patterns; i++) { 12608b8a9b1dSJustin T. Gibbs struct bus_match_pattern *cur_pattern; 12618b8a9b1dSJustin T. Gibbs 12628b8a9b1dSJustin T. Gibbs /* 12638b8a9b1dSJustin T. Gibbs * If the pattern in question isn't for a bus node, we 12648b8a9b1dSJustin T. Gibbs * aren't interested. However, we do indicate to the 12658b8a9b1dSJustin T. Gibbs * calling routine that we should continue descending the 12668b8a9b1dSJustin T. Gibbs * tree, since the user wants to match against lower-level 12678b8a9b1dSJustin T. Gibbs * EDT elements. 12688b8a9b1dSJustin T. Gibbs */ 12698b8a9b1dSJustin T. Gibbs if (patterns[i].type != DEV_MATCH_BUS) { 12708b8a9b1dSJustin T. Gibbs if ((retval & DM_RET_ACTION_MASK) == DM_RET_NONE) 12718b8a9b1dSJustin T. Gibbs retval |= DM_RET_DESCEND; 12728b8a9b1dSJustin T. Gibbs continue; 12738b8a9b1dSJustin T. Gibbs } 12748b8a9b1dSJustin T. Gibbs 12758b8a9b1dSJustin T. Gibbs cur_pattern = &patterns[i].pattern.bus_pattern; 12768b8a9b1dSJustin T. Gibbs 12778b8a9b1dSJustin T. Gibbs /* 12788b8a9b1dSJustin T. Gibbs * If they want to match any bus node, we give them any 12798b8a9b1dSJustin T. Gibbs * device node. 12808b8a9b1dSJustin T. Gibbs */ 12818b8a9b1dSJustin T. Gibbs if (cur_pattern->flags == BUS_MATCH_ANY) { 12828b8a9b1dSJustin T. Gibbs /* set the copy flag */ 12838b8a9b1dSJustin T. Gibbs retval |= DM_RET_COPY; 12848b8a9b1dSJustin T. Gibbs 12858b8a9b1dSJustin T. Gibbs /* 12868b8a9b1dSJustin T. Gibbs * If we've already decided on an action, go ahead 12878b8a9b1dSJustin T. Gibbs * and return. 12888b8a9b1dSJustin T. Gibbs */ 12898b8a9b1dSJustin T. Gibbs if ((retval & DM_RET_ACTION_MASK) != DM_RET_NONE) 12908b8a9b1dSJustin T. Gibbs return(retval); 12918b8a9b1dSJustin T. Gibbs } 12928b8a9b1dSJustin T. Gibbs 12938b8a9b1dSJustin T. Gibbs /* 12948b8a9b1dSJustin T. Gibbs * Not sure why someone would do this... 12958b8a9b1dSJustin T. Gibbs */ 12968b8a9b1dSJustin T. Gibbs if (cur_pattern->flags == BUS_MATCH_NONE) 12978b8a9b1dSJustin T. Gibbs continue; 12988b8a9b1dSJustin T. Gibbs 12998b8a9b1dSJustin T. Gibbs if (((cur_pattern->flags & BUS_MATCH_PATH) != 0) 13008b8a9b1dSJustin T. Gibbs && (cur_pattern->path_id != bus->path_id)) 13018b8a9b1dSJustin T. Gibbs continue; 13028b8a9b1dSJustin T. Gibbs 13038b8a9b1dSJustin T. Gibbs if (((cur_pattern->flags & BUS_MATCH_BUS_ID) != 0) 13048b8a9b1dSJustin T. Gibbs && (cur_pattern->bus_id != bus->sim->bus_id)) 13058b8a9b1dSJustin T. Gibbs continue; 13068b8a9b1dSJustin T. Gibbs 13078b8a9b1dSJustin T. Gibbs if (((cur_pattern->flags & BUS_MATCH_UNIT) != 0) 13088b8a9b1dSJustin T. Gibbs && (cur_pattern->unit_number != bus->sim->unit_number)) 13098b8a9b1dSJustin T. Gibbs continue; 13108b8a9b1dSJustin T. Gibbs 13118b8a9b1dSJustin T. Gibbs if (((cur_pattern->flags & BUS_MATCH_NAME) != 0) 13128b8a9b1dSJustin T. Gibbs && (strncmp(cur_pattern->dev_name, bus->sim->sim_name, 13138b8a9b1dSJustin T. Gibbs DEV_IDLEN) != 0)) 13148b8a9b1dSJustin T. Gibbs continue; 13158b8a9b1dSJustin T. Gibbs 13168b8a9b1dSJustin T. Gibbs /* 13178b8a9b1dSJustin T. Gibbs * If we get to this point, the user definitely wants 13188b8a9b1dSJustin T. Gibbs * information on this bus. So tell the caller to copy the 13198b8a9b1dSJustin T. Gibbs * data out. 13208b8a9b1dSJustin T. Gibbs */ 13218b8a9b1dSJustin T. Gibbs retval |= DM_RET_COPY; 13228b8a9b1dSJustin T. Gibbs 13238b8a9b1dSJustin T. Gibbs /* 13248b8a9b1dSJustin T. Gibbs * If the return action has been set to descend, then we 13258b8a9b1dSJustin T. Gibbs * know that we've already seen a non-bus matching 13268b8a9b1dSJustin T. Gibbs * expression, therefore we need to further descend the tree. 13278b8a9b1dSJustin T. Gibbs * This won't change by continuing around the loop, so we 13288b8a9b1dSJustin T. Gibbs * go ahead and return. If we haven't seen a non-bus 13298b8a9b1dSJustin T. Gibbs * matching expression, we keep going around the loop until 13308b8a9b1dSJustin T. Gibbs * we exhaust the matching expressions. We'll set the stop 13318b8a9b1dSJustin T. Gibbs * flag once we fall out of the loop. 13328b8a9b1dSJustin T. Gibbs */ 13338b8a9b1dSJustin T. Gibbs if ((retval & DM_RET_ACTION_MASK) == DM_RET_DESCEND) 13348b8a9b1dSJustin T. Gibbs return(retval); 13358b8a9b1dSJustin T. Gibbs } 13368b8a9b1dSJustin T. Gibbs 13378b8a9b1dSJustin T. Gibbs /* 13388b8a9b1dSJustin T. Gibbs * If the return action hasn't been set to descend yet, that means 13398b8a9b1dSJustin T. Gibbs * we haven't seen anything other than bus matching patterns. So 13408b8a9b1dSJustin T. Gibbs * tell the caller to stop descending the tree -- the user doesn't 13418b8a9b1dSJustin T. Gibbs * want to match against lower level tree elements. 13428b8a9b1dSJustin T. Gibbs */ 13438b8a9b1dSJustin T. Gibbs if ((retval & DM_RET_ACTION_MASK) == DM_RET_NONE) 13448b8a9b1dSJustin T. Gibbs retval |= DM_RET_STOP; 13458b8a9b1dSJustin T. Gibbs 13468b8a9b1dSJustin T. Gibbs return(retval); 13478b8a9b1dSJustin T. Gibbs } 13488b8a9b1dSJustin T. Gibbs 13498b8a9b1dSJustin T. Gibbs static dev_match_ret 13503393f8daSKenneth D. Merry xptdevicematch(struct dev_match_pattern *patterns, u_int num_patterns, 13518b8a9b1dSJustin T. Gibbs struct cam_ed *device) 13528b8a9b1dSJustin T. Gibbs { 13538b8a9b1dSJustin T. Gibbs dev_match_ret retval; 1354167e63e3SPedro F. Giffuni u_int i; 13558b8a9b1dSJustin T. Gibbs 13568b8a9b1dSJustin T. Gibbs retval = DM_RET_NONE; 13578b8a9b1dSJustin T. Gibbs 13588b8a9b1dSJustin T. Gibbs /* 13598b8a9b1dSJustin T. Gibbs * If we aren't given something to match against, that's an error. 13608b8a9b1dSJustin T. Gibbs */ 13618b8a9b1dSJustin T. Gibbs if (device == NULL) 13628b8a9b1dSJustin T. Gibbs return(DM_RET_ERROR); 13638b8a9b1dSJustin T. Gibbs 13648b8a9b1dSJustin T. Gibbs /* 13658b8a9b1dSJustin T. Gibbs * If there are no match entries, then this device matches no 13668b8a9b1dSJustin T. Gibbs * matter what. 13678b8a9b1dSJustin T. Gibbs */ 136859e75884SColin Percival if ((patterns == NULL) || (num_patterns == 0)) 13698b8a9b1dSJustin T. Gibbs return(DM_RET_DESCEND | DM_RET_COPY); 13708b8a9b1dSJustin T. Gibbs 13718b8a9b1dSJustin T. Gibbs for (i = 0; i < num_patterns; i++) { 13728b8a9b1dSJustin T. Gibbs struct device_match_pattern *cur_pattern; 13733501942bSJustin T. Gibbs struct scsi_vpd_device_id *device_id_page; 13748b8a9b1dSJustin T. Gibbs 13758b8a9b1dSJustin T. Gibbs /* 13768b8a9b1dSJustin T. Gibbs * If the pattern in question isn't for a device node, we 13778b8a9b1dSJustin T. Gibbs * aren't interested. 13788b8a9b1dSJustin T. Gibbs */ 13798b8a9b1dSJustin T. Gibbs if (patterns[i].type != DEV_MATCH_DEVICE) { 13808b8a9b1dSJustin T. Gibbs if ((patterns[i].type == DEV_MATCH_PERIPH) 13818b8a9b1dSJustin T. Gibbs && ((retval & DM_RET_ACTION_MASK) == DM_RET_NONE)) 13828b8a9b1dSJustin T. Gibbs retval |= DM_RET_DESCEND; 13838b8a9b1dSJustin T. Gibbs continue; 13848b8a9b1dSJustin T. Gibbs } 13858b8a9b1dSJustin T. Gibbs 13868b8a9b1dSJustin T. Gibbs cur_pattern = &patterns[i].pattern.device_pattern; 13878b8a9b1dSJustin T. Gibbs 13883501942bSJustin T. Gibbs /* Error out if mutually exclusive options are specified. */ 13893501942bSJustin T. Gibbs if ((cur_pattern->flags & (DEV_MATCH_INQUIRY|DEV_MATCH_DEVID)) 13903501942bSJustin T. Gibbs == (DEV_MATCH_INQUIRY|DEV_MATCH_DEVID)) 13913501942bSJustin T. Gibbs return(DM_RET_ERROR); 13923501942bSJustin T. Gibbs 13938b8a9b1dSJustin T. Gibbs /* 13948b8a9b1dSJustin T. Gibbs * If they want to match any device node, we give them any 13958b8a9b1dSJustin T. Gibbs * device node. 13968b8a9b1dSJustin T. Gibbs */ 13973501942bSJustin T. Gibbs if (cur_pattern->flags == DEV_MATCH_ANY) 13983501942bSJustin T. Gibbs goto copy_dev_node; 13998b8a9b1dSJustin T. Gibbs 14008b8a9b1dSJustin T. Gibbs /* 14018b8a9b1dSJustin T. Gibbs * Not sure why someone would do this... 14028b8a9b1dSJustin T. Gibbs */ 14038b8a9b1dSJustin T. Gibbs if (cur_pattern->flags == DEV_MATCH_NONE) 14048b8a9b1dSJustin T. Gibbs continue; 14058b8a9b1dSJustin T. Gibbs 14068b8a9b1dSJustin T. Gibbs if (((cur_pattern->flags & DEV_MATCH_PATH) != 0) 14078b8a9b1dSJustin T. Gibbs && (cur_pattern->path_id != device->target->bus->path_id)) 14088b8a9b1dSJustin T. Gibbs continue; 14098b8a9b1dSJustin T. Gibbs 14108b8a9b1dSJustin T. Gibbs if (((cur_pattern->flags & DEV_MATCH_TARGET) != 0) 14118b8a9b1dSJustin T. Gibbs && (cur_pattern->target_id != device->target->target_id)) 14128b8a9b1dSJustin T. Gibbs continue; 14138b8a9b1dSJustin T. Gibbs 14148b8a9b1dSJustin T. Gibbs if (((cur_pattern->flags & DEV_MATCH_LUN) != 0) 14158b8a9b1dSJustin T. Gibbs && (cur_pattern->target_lun != device->lun_id)) 14168b8a9b1dSJustin T. Gibbs continue; 14178b8a9b1dSJustin T. Gibbs 14188b8a9b1dSJustin T. Gibbs if (((cur_pattern->flags & DEV_MATCH_INQUIRY) != 0) 14198b8a9b1dSJustin T. Gibbs && (cam_quirkmatch((caddr_t)&device->inq_data, 14203501942bSJustin T. Gibbs (caddr_t)&cur_pattern->data.inq_pat, 14213501942bSJustin T. Gibbs 1, sizeof(cur_pattern->data.inq_pat), 14228b8a9b1dSJustin T. Gibbs scsi_static_inquiry_match) == NULL)) 14238b8a9b1dSJustin T. Gibbs continue; 14248b8a9b1dSJustin T. Gibbs 14253501942bSJustin T. Gibbs device_id_page = (struct scsi_vpd_device_id *)device->device_id; 14263501942bSJustin T. Gibbs if (((cur_pattern->flags & DEV_MATCH_DEVID) != 0) 14273501942bSJustin T. Gibbs && (device->device_id_len < SVPD_DEVICE_ID_HDR_LEN 14283501942bSJustin T. Gibbs || scsi_devid_match((uint8_t *)device_id_page->desc_list, 14293501942bSJustin T. Gibbs device->device_id_len 14303501942bSJustin T. Gibbs - SVPD_DEVICE_ID_HDR_LEN, 14313501942bSJustin T. Gibbs cur_pattern->data.devid_pat.id, 14323501942bSJustin T. Gibbs cur_pattern->data.devid_pat.id_len) != 0)) 14333501942bSJustin T. Gibbs continue; 14343501942bSJustin T. Gibbs 14353501942bSJustin T. Gibbs copy_dev_node: 14368b8a9b1dSJustin T. Gibbs /* 14378b8a9b1dSJustin T. Gibbs * If we get to this point, the user definitely wants 14388b8a9b1dSJustin T. Gibbs * information on this device. So tell the caller to copy 14398b8a9b1dSJustin T. Gibbs * the data out. 14408b8a9b1dSJustin T. Gibbs */ 14418b8a9b1dSJustin T. Gibbs retval |= DM_RET_COPY; 14428b8a9b1dSJustin T. Gibbs 14438b8a9b1dSJustin T. Gibbs /* 14448b8a9b1dSJustin T. Gibbs * If the return action has been set to descend, then we 14458b8a9b1dSJustin T. Gibbs * know that we've already seen a peripheral matching 14468b8a9b1dSJustin T. Gibbs * expression, therefore we need to further descend the tree. 14478b8a9b1dSJustin T. Gibbs * This won't change by continuing around the loop, so we 14488b8a9b1dSJustin T. Gibbs * go ahead and return. If we haven't seen a peripheral 14498b8a9b1dSJustin T. Gibbs * matching expression, we keep going around the loop until 14508b8a9b1dSJustin T. Gibbs * we exhaust the matching expressions. We'll set the stop 14518b8a9b1dSJustin T. Gibbs * flag once we fall out of the loop. 14528b8a9b1dSJustin T. Gibbs */ 14538b8a9b1dSJustin T. Gibbs if ((retval & DM_RET_ACTION_MASK) == DM_RET_DESCEND) 14548b8a9b1dSJustin T. Gibbs return(retval); 14558b8a9b1dSJustin T. Gibbs } 14568b8a9b1dSJustin T. Gibbs 14578b8a9b1dSJustin T. Gibbs /* 14588b8a9b1dSJustin T. Gibbs * If the return action hasn't been set to descend yet, that means 14598b8a9b1dSJustin T. Gibbs * we haven't seen any peripheral matching patterns. So tell the 14608b8a9b1dSJustin T. Gibbs * caller to stop descending the tree -- the user doesn't want to 14618b8a9b1dSJustin T. Gibbs * match against lower level tree elements. 14628b8a9b1dSJustin T. Gibbs */ 14638b8a9b1dSJustin T. Gibbs if ((retval & DM_RET_ACTION_MASK) == DM_RET_NONE) 14648b8a9b1dSJustin T. Gibbs retval |= DM_RET_STOP; 14658b8a9b1dSJustin T. Gibbs 14668b8a9b1dSJustin T. Gibbs return(retval); 14678b8a9b1dSJustin T. Gibbs } 14688b8a9b1dSJustin T. Gibbs 14698b8a9b1dSJustin T. Gibbs /* 14708b8a9b1dSJustin T. Gibbs * Match a single peripheral against any number of match patterns. 14718b8a9b1dSJustin T. Gibbs */ 14728b8a9b1dSJustin T. Gibbs static dev_match_ret 14733393f8daSKenneth D. Merry xptperiphmatch(struct dev_match_pattern *patterns, u_int num_patterns, 14748b8a9b1dSJustin T. Gibbs struct cam_periph *periph) 14758b8a9b1dSJustin T. Gibbs { 14768b8a9b1dSJustin T. Gibbs dev_match_ret retval; 1477167e63e3SPedro F. Giffuni u_int i; 14788b8a9b1dSJustin T. Gibbs 14798b8a9b1dSJustin T. Gibbs /* 14808b8a9b1dSJustin T. Gibbs * If we aren't given something to match against, that's an error. 14818b8a9b1dSJustin T. Gibbs */ 14828b8a9b1dSJustin T. Gibbs if (periph == NULL) 14838b8a9b1dSJustin T. Gibbs return(DM_RET_ERROR); 14848b8a9b1dSJustin T. Gibbs 14858b8a9b1dSJustin T. Gibbs /* 14868b8a9b1dSJustin T. Gibbs * If there are no match entries, then this peripheral matches no 14878b8a9b1dSJustin T. Gibbs * matter what. 14888b8a9b1dSJustin T. Gibbs */ 14898b8a9b1dSJustin T. Gibbs if ((patterns == NULL) || (num_patterns == 0)) 14908b8a9b1dSJustin T. Gibbs return(DM_RET_STOP | DM_RET_COPY); 14918b8a9b1dSJustin T. Gibbs 14928b8a9b1dSJustin T. Gibbs /* 14938b8a9b1dSJustin T. Gibbs * There aren't any nodes below a peripheral node, so there's no 14948b8a9b1dSJustin T. Gibbs * reason to descend the tree any further. 14958b8a9b1dSJustin T. Gibbs */ 14968b8a9b1dSJustin T. Gibbs retval = DM_RET_STOP; 14978b8a9b1dSJustin T. Gibbs 14988b8a9b1dSJustin T. Gibbs for (i = 0; i < num_patterns; i++) { 14998b8a9b1dSJustin T. Gibbs struct periph_match_pattern *cur_pattern; 15008b8a9b1dSJustin T. Gibbs 15018b8a9b1dSJustin T. Gibbs /* 15028b8a9b1dSJustin T. Gibbs * If the pattern in question isn't for a peripheral, we 15038b8a9b1dSJustin T. Gibbs * aren't interested. 15048b8a9b1dSJustin T. Gibbs */ 15058b8a9b1dSJustin T. Gibbs if (patterns[i].type != DEV_MATCH_PERIPH) 15068b8a9b1dSJustin T. Gibbs continue; 15078b8a9b1dSJustin T. Gibbs 15088b8a9b1dSJustin T. Gibbs cur_pattern = &patterns[i].pattern.periph_pattern; 15098b8a9b1dSJustin T. Gibbs 15108b8a9b1dSJustin T. Gibbs /* 15118b8a9b1dSJustin T. Gibbs * If they want to match on anything, then we will do so. 15128b8a9b1dSJustin T. Gibbs */ 15138b8a9b1dSJustin T. Gibbs if (cur_pattern->flags == PERIPH_MATCH_ANY) { 15148b8a9b1dSJustin T. Gibbs /* set the copy flag */ 15158b8a9b1dSJustin T. Gibbs retval |= DM_RET_COPY; 15168b8a9b1dSJustin T. Gibbs 15178b8a9b1dSJustin T. Gibbs /* 15188b8a9b1dSJustin T. Gibbs * We've already set the return action to stop, 15198b8a9b1dSJustin T. Gibbs * since there are no nodes below peripherals in 15208b8a9b1dSJustin T. Gibbs * the tree. 15218b8a9b1dSJustin T. Gibbs */ 15228b8a9b1dSJustin T. Gibbs return(retval); 15238b8a9b1dSJustin T. Gibbs } 15248b8a9b1dSJustin T. Gibbs 15258b8a9b1dSJustin T. Gibbs /* 15268b8a9b1dSJustin T. Gibbs * Not sure why someone would do this... 15278b8a9b1dSJustin T. Gibbs */ 15288b8a9b1dSJustin T. Gibbs if (cur_pattern->flags == PERIPH_MATCH_NONE) 15298b8a9b1dSJustin T. Gibbs continue; 15308b8a9b1dSJustin T. Gibbs 15318b8a9b1dSJustin T. Gibbs if (((cur_pattern->flags & PERIPH_MATCH_PATH) != 0) 15328b8a9b1dSJustin T. Gibbs && (cur_pattern->path_id != periph->path->bus->path_id)) 15338b8a9b1dSJustin T. Gibbs continue; 15348b8a9b1dSJustin T. Gibbs 15358b8a9b1dSJustin T. Gibbs /* 15368b8a9b1dSJustin T. Gibbs * For the target and lun id's, we have to make sure the 15378b8a9b1dSJustin T. Gibbs * target and lun pointers aren't NULL. The xpt peripheral 15388b8a9b1dSJustin T. Gibbs * has a wildcard target and device. 15398b8a9b1dSJustin T. Gibbs */ 15408b8a9b1dSJustin T. Gibbs if (((cur_pattern->flags & PERIPH_MATCH_TARGET) != 0) 15418b8a9b1dSJustin T. Gibbs && ((periph->path->target == NULL) 15428b8a9b1dSJustin T. Gibbs ||(cur_pattern->target_id != periph->path->target->target_id))) 15438b8a9b1dSJustin T. Gibbs continue; 15448b8a9b1dSJustin T. Gibbs 15458b8a9b1dSJustin T. Gibbs if (((cur_pattern->flags & PERIPH_MATCH_LUN) != 0) 15468b8a9b1dSJustin T. Gibbs && ((periph->path->device == NULL) 15478b8a9b1dSJustin T. Gibbs || (cur_pattern->target_lun != periph->path->device->lun_id))) 15488b8a9b1dSJustin T. Gibbs continue; 15498b8a9b1dSJustin T. Gibbs 15508b8a9b1dSJustin T. Gibbs if (((cur_pattern->flags & PERIPH_MATCH_UNIT) != 0) 15518b8a9b1dSJustin T. Gibbs && (cur_pattern->unit_number != periph->unit_number)) 15528b8a9b1dSJustin T. Gibbs continue; 15538b8a9b1dSJustin T. Gibbs 15548b8a9b1dSJustin T. Gibbs if (((cur_pattern->flags & PERIPH_MATCH_NAME) != 0) 15558b8a9b1dSJustin T. Gibbs && (strncmp(cur_pattern->periph_name, periph->periph_name, 15568b8a9b1dSJustin T. Gibbs DEV_IDLEN) != 0)) 15578b8a9b1dSJustin T. Gibbs continue; 15588b8a9b1dSJustin T. Gibbs 15598b8a9b1dSJustin T. Gibbs /* 15608b8a9b1dSJustin T. Gibbs * If we get to this point, the user definitely wants 15618b8a9b1dSJustin T. Gibbs * information on this peripheral. So tell the caller to 15628b8a9b1dSJustin T. Gibbs * copy the data out. 15638b8a9b1dSJustin T. Gibbs */ 15648b8a9b1dSJustin T. Gibbs retval |= DM_RET_COPY; 15658b8a9b1dSJustin T. Gibbs 15668b8a9b1dSJustin T. Gibbs /* 15678b8a9b1dSJustin T. Gibbs * The return action has already been set to stop, since 15688b8a9b1dSJustin T. Gibbs * peripherals don't have any nodes below them in the EDT. 15698b8a9b1dSJustin T. Gibbs */ 15708b8a9b1dSJustin T. Gibbs return(retval); 15718b8a9b1dSJustin T. Gibbs } 15728b8a9b1dSJustin T. Gibbs 15738b8a9b1dSJustin T. Gibbs /* 15748b8a9b1dSJustin T. Gibbs * If we get to this point, the peripheral that was passed in 15758b8a9b1dSJustin T. Gibbs * doesn't match any of the patterns. 15768b8a9b1dSJustin T. Gibbs */ 15778b8a9b1dSJustin T. Gibbs return(retval); 15788b8a9b1dSJustin T. Gibbs } 15798b8a9b1dSJustin T. Gibbs 15808b8a9b1dSJustin T. Gibbs static int 15818b8a9b1dSJustin T. Gibbs xptedtbusfunc(struct cam_eb *bus, void *arg) 15828b8a9b1dSJustin T. Gibbs { 15838b8a9b1dSJustin T. Gibbs struct ccb_dev_match *cdm; 1584227d67aaSAlexander Motin struct cam_et *target; 15858b8a9b1dSJustin T. Gibbs dev_match_ret retval; 15868b8a9b1dSJustin T. Gibbs 15878b8a9b1dSJustin T. Gibbs cdm = (struct ccb_dev_match *)arg; 15888b8a9b1dSJustin T. Gibbs 15898b8a9b1dSJustin T. Gibbs /* 15908b8a9b1dSJustin T. Gibbs * If our position is for something deeper in the tree, that means 15918b8a9b1dSJustin T. Gibbs * that we've already seen this node. So, we keep going down. 15928b8a9b1dSJustin T. Gibbs */ 15938b8a9b1dSJustin T. Gibbs if ((cdm->pos.position_type & CAM_DEV_POS_BUS) 15948b8a9b1dSJustin T. Gibbs && (cdm->pos.cookie.bus == bus) 15958b8a9b1dSJustin T. Gibbs && (cdm->pos.position_type & CAM_DEV_POS_TARGET) 15968b8a9b1dSJustin T. Gibbs && (cdm->pos.cookie.target != NULL)) 15978b8a9b1dSJustin T. Gibbs retval = DM_RET_DESCEND; 15988b8a9b1dSJustin T. Gibbs else 15998b8a9b1dSJustin T. Gibbs retval = xptbusmatch(cdm->patterns, cdm->num_patterns, bus); 16008b8a9b1dSJustin T. Gibbs 16018b8a9b1dSJustin T. Gibbs /* 16028b8a9b1dSJustin T. Gibbs * If we got an error, bail out of the search. 16038b8a9b1dSJustin T. Gibbs */ 16048b8a9b1dSJustin T. Gibbs if ((retval & DM_RET_ACTION_MASK) == DM_RET_ERROR) { 16058b8a9b1dSJustin T. Gibbs cdm->status = CAM_DEV_MATCH_ERROR; 16068b8a9b1dSJustin T. Gibbs return(0); 16078b8a9b1dSJustin T. Gibbs } 16088b8a9b1dSJustin T. Gibbs 16098b8a9b1dSJustin T. Gibbs /* 16108b8a9b1dSJustin T. Gibbs * If the copy flag is set, copy this bus out. 16118b8a9b1dSJustin T. Gibbs */ 16128b8a9b1dSJustin T. Gibbs if (retval & DM_RET_COPY) { 16138b8a9b1dSJustin T. Gibbs int spaceleft, j; 16148b8a9b1dSJustin T. Gibbs 16158b8a9b1dSJustin T. Gibbs spaceleft = cdm->match_buf_len - (cdm->num_matches * 16168b8a9b1dSJustin T. Gibbs sizeof(struct dev_match_result)); 16178b8a9b1dSJustin T. Gibbs 16188b8a9b1dSJustin T. Gibbs /* 16198b8a9b1dSJustin T. Gibbs * If we don't have enough space to put in another 16208b8a9b1dSJustin T. Gibbs * match result, save our position and tell the 16218b8a9b1dSJustin T. Gibbs * user there are more devices to check. 16228b8a9b1dSJustin T. Gibbs */ 16238b8a9b1dSJustin T. Gibbs if (spaceleft < sizeof(struct dev_match_result)) { 16248b8a9b1dSJustin T. Gibbs bzero(&cdm->pos, sizeof(cdm->pos)); 16258b8a9b1dSJustin T. Gibbs cdm->pos.position_type = 16268b8a9b1dSJustin T. Gibbs CAM_DEV_POS_EDT | CAM_DEV_POS_BUS; 16278b8a9b1dSJustin T. Gibbs 16288b8a9b1dSJustin T. Gibbs cdm->pos.cookie.bus = bus; 16298b8a9b1dSJustin T. Gibbs cdm->pos.generations[CAM_BUS_GENERATION]= 16302b83592fSScott Long xsoftc.bus_generation; 16318b8a9b1dSJustin T. Gibbs cdm->status = CAM_DEV_MATCH_MORE; 16328b8a9b1dSJustin T. Gibbs return(0); 16338b8a9b1dSJustin T. Gibbs } 16348b8a9b1dSJustin T. Gibbs j = cdm->num_matches; 16358b8a9b1dSJustin T. Gibbs cdm->num_matches++; 16368b8a9b1dSJustin T. Gibbs cdm->matches[j].type = DEV_MATCH_BUS; 16378b8a9b1dSJustin T. Gibbs cdm->matches[j].result.bus_result.path_id = bus->path_id; 16388b8a9b1dSJustin T. Gibbs cdm->matches[j].result.bus_result.bus_id = bus->sim->bus_id; 16398b8a9b1dSJustin T. Gibbs cdm->matches[j].result.bus_result.unit_number = 16408b8a9b1dSJustin T. Gibbs bus->sim->unit_number; 16418b8a9b1dSJustin T. Gibbs strncpy(cdm->matches[j].result.bus_result.dev_name, 16428b8a9b1dSJustin T. Gibbs bus->sim->sim_name, DEV_IDLEN); 16438b8a9b1dSJustin T. Gibbs } 16448b8a9b1dSJustin T. Gibbs 16458b8a9b1dSJustin T. Gibbs /* 1646db4fcadfSConrad Meyer * If the user is only interested in buses, there's no 16478b8a9b1dSJustin T. Gibbs * reason to descend to the next level in the tree. 16488b8a9b1dSJustin T. Gibbs */ 16498b8a9b1dSJustin T. Gibbs if ((retval & DM_RET_ACTION_MASK) == DM_RET_STOP) 16508b8a9b1dSJustin T. Gibbs return(1); 16518b8a9b1dSJustin T. Gibbs 16528b8a9b1dSJustin T. Gibbs /* 16538b8a9b1dSJustin T. Gibbs * If there is a target generation recorded, check it to 16548b8a9b1dSJustin T. Gibbs * make sure the target list hasn't changed. 16558b8a9b1dSJustin T. Gibbs */ 1656227d67aaSAlexander Motin mtx_lock(&bus->eb_mtx); 16578b8a9b1dSJustin T. Gibbs if ((cdm->pos.position_type & CAM_DEV_POS_BUS) 16588b8a9b1dSJustin T. Gibbs && (cdm->pos.cookie.bus == bus) 16598b8a9b1dSJustin T. Gibbs && (cdm->pos.position_type & CAM_DEV_POS_TARGET) 1660227d67aaSAlexander Motin && (cdm->pos.cookie.target != NULL)) { 1661227d67aaSAlexander Motin if ((cdm->pos.generations[CAM_TARGET_GENERATION] != 1662227d67aaSAlexander Motin bus->generation)) { 1663227d67aaSAlexander Motin mtx_unlock(&bus->eb_mtx); 1664227d67aaSAlexander Motin cdm->status = CAM_DEV_MATCH_LIST_CHANGED; 1665227d67aaSAlexander Motin return (0); 1666227d67aaSAlexander Motin } 1667227d67aaSAlexander Motin target = (struct cam_et *)cdm->pos.cookie.target; 1668227d67aaSAlexander Motin target->refcount++; 1669227d67aaSAlexander Motin } else 1670227d67aaSAlexander Motin target = NULL; 1671227d67aaSAlexander Motin mtx_unlock(&bus->eb_mtx); 1672227d67aaSAlexander Motin 1673227d67aaSAlexander Motin return (xpttargettraverse(bus, target, xptedttargetfunc, arg)); 16748b8a9b1dSJustin T. Gibbs } 16758b8a9b1dSJustin T. Gibbs 16768b8a9b1dSJustin T. Gibbs static int 16778b8a9b1dSJustin T. Gibbs xptedttargetfunc(struct cam_et *target, void *arg) 16788b8a9b1dSJustin T. Gibbs { 16798b8a9b1dSJustin T. Gibbs struct ccb_dev_match *cdm; 1680227d67aaSAlexander Motin struct cam_eb *bus; 1681227d67aaSAlexander Motin struct cam_ed *device; 16828b8a9b1dSJustin T. Gibbs 16838b8a9b1dSJustin T. Gibbs cdm = (struct ccb_dev_match *)arg; 1684227d67aaSAlexander Motin bus = target->bus; 16858b8a9b1dSJustin T. Gibbs 16868b8a9b1dSJustin T. Gibbs /* 16878b8a9b1dSJustin T. Gibbs * If there is a device list generation recorded, check it to 16888b8a9b1dSJustin T. Gibbs * make sure the device list hasn't changed. 16898b8a9b1dSJustin T. Gibbs */ 1690227d67aaSAlexander Motin mtx_lock(&bus->eb_mtx); 16918b8a9b1dSJustin T. Gibbs if ((cdm->pos.position_type & CAM_DEV_POS_BUS) 1692227d67aaSAlexander Motin && (cdm->pos.cookie.bus == bus) 16938b8a9b1dSJustin T. Gibbs && (cdm->pos.position_type & CAM_DEV_POS_TARGET) 16948b8a9b1dSJustin T. Gibbs && (cdm->pos.cookie.target == target) 16958b8a9b1dSJustin T. Gibbs && (cdm->pos.position_type & CAM_DEV_POS_DEVICE) 1696227d67aaSAlexander Motin && (cdm->pos.cookie.device != NULL)) { 1697227d67aaSAlexander Motin if (cdm->pos.generations[CAM_DEV_GENERATION] != 1698227d67aaSAlexander Motin target->generation) { 1699227d67aaSAlexander Motin mtx_unlock(&bus->eb_mtx); 17008b8a9b1dSJustin T. Gibbs cdm->status = CAM_DEV_MATCH_LIST_CHANGED; 17018b8a9b1dSJustin T. Gibbs return(0); 17028b8a9b1dSJustin T. Gibbs } 1703227d67aaSAlexander Motin device = (struct cam_ed *)cdm->pos.cookie.device; 1704227d67aaSAlexander Motin device->refcount++; 1705227d67aaSAlexander Motin } else 1706227d67aaSAlexander Motin device = NULL; 1707227d67aaSAlexander Motin mtx_unlock(&bus->eb_mtx); 17088b8a9b1dSJustin T. Gibbs 1709227d67aaSAlexander Motin return (xptdevicetraverse(target, device, xptedtdevicefunc, arg)); 17108b8a9b1dSJustin T. Gibbs } 17118b8a9b1dSJustin T. Gibbs 17128b8a9b1dSJustin T. Gibbs static int 17138b8a9b1dSJustin T. Gibbs xptedtdevicefunc(struct cam_ed *device, void *arg) 17148b8a9b1dSJustin T. Gibbs { 1715227d67aaSAlexander Motin struct cam_eb *bus; 1716227d67aaSAlexander Motin struct cam_periph *periph; 17178b8a9b1dSJustin T. Gibbs struct ccb_dev_match *cdm; 17188b8a9b1dSJustin T. Gibbs dev_match_ret retval; 17198b8a9b1dSJustin T. Gibbs 17208b8a9b1dSJustin T. Gibbs cdm = (struct ccb_dev_match *)arg; 1721227d67aaSAlexander Motin bus = device->target->bus; 17228b8a9b1dSJustin T. Gibbs 17238b8a9b1dSJustin T. Gibbs /* 17248b8a9b1dSJustin T. Gibbs * If our position is for something deeper in the tree, that means 17258b8a9b1dSJustin T. Gibbs * that we've already seen this node. So, we keep going down. 17268b8a9b1dSJustin T. Gibbs */ 17278b8a9b1dSJustin T. Gibbs if ((cdm->pos.position_type & CAM_DEV_POS_DEVICE) 17288b8a9b1dSJustin T. Gibbs && (cdm->pos.cookie.device == device) 17298b8a9b1dSJustin T. Gibbs && (cdm->pos.position_type & CAM_DEV_POS_PERIPH) 17308b8a9b1dSJustin T. Gibbs && (cdm->pos.cookie.periph != NULL)) 17318b8a9b1dSJustin T. Gibbs retval = DM_RET_DESCEND; 17328b8a9b1dSJustin T. Gibbs else 17338b8a9b1dSJustin T. Gibbs retval = xptdevicematch(cdm->patterns, cdm->num_patterns, 17348b8a9b1dSJustin T. Gibbs device); 17358b8a9b1dSJustin T. Gibbs 17368b8a9b1dSJustin T. Gibbs if ((retval & DM_RET_ACTION_MASK) == DM_RET_ERROR) { 17378b8a9b1dSJustin T. Gibbs cdm->status = CAM_DEV_MATCH_ERROR; 17388b8a9b1dSJustin T. Gibbs return(0); 17398b8a9b1dSJustin T. Gibbs } 17408b8a9b1dSJustin T. Gibbs 17418b8a9b1dSJustin T. Gibbs /* 17428b8a9b1dSJustin T. Gibbs * If the copy flag is set, copy this device out. 17438b8a9b1dSJustin T. Gibbs */ 17448b8a9b1dSJustin T. Gibbs if (retval & DM_RET_COPY) { 17458b8a9b1dSJustin T. Gibbs int spaceleft, j; 17468b8a9b1dSJustin T. Gibbs 17478b8a9b1dSJustin T. Gibbs spaceleft = cdm->match_buf_len - (cdm->num_matches * 17488b8a9b1dSJustin T. Gibbs sizeof(struct dev_match_result)); 17498b8a9b1dSJustin T. Gibbs 17508b8a9b1dSJustin T. Gibbs /* 17518b8a9b1dSJustin T. Gibbs * If we don't have enough space to put in another 17528b8a9b1dSJustin T. Gibbs * match result, save our position and tell the 17538b8a9b1dSJustin T. Gibbs * user there are more devices to check. 17548b8a9b1dSJustin T. Gibbs */ 17558b8a9b1dSJustin T. Gibbs if (spaceleft < sizeof(struct dev_match_result)) { 17568b8a9b1dSJustin T. Gibbs bzero(&cdm->pos, sizeof(cdm->pos)); 17578b8a9b1dSJustin T. Gibbs cdm->pos.position_type = 17588b8a9b1dSJustin T. Gibbs CAM_DEV_POS_EDT | CAM_DEV_POS_BUS | 17598b8a9b1dSJustin T. Gibbs CAM_DEV_POS_TARGET | CAM_DEV_POS_DEVICE; 17608b8a9b1dSJustin T. Gibbs 17618b8a9b1dSJustin T. Gibbs cdm->pos.cookie.bus = device->target->bus; 17628b8a9b1dSJustin T. Gibbs cdm->pos.generations[CAM_BUS_GENERATION]= 17632b83592fSScott Long xsoftc.bus_generation; 17648b8a9b1dSJustin T. Gibbs cdm->pos.cookie.target = device->target; 17658b8a9b1dSJustin T. Gibbs cdm->pos.generations[CAM_TARGET_GENERATION] = 17668b8a9b1dSJustin T. Gibbs device->target->bus->generation; 17678b8a9b1dSJustin T. Gibbs cdm->pos.cookie.device = device; 17688b8a9b1dSJustin T. Gibbs cdm->pos.generations[CAM_DEV_GENERATION] = 17698b8a9b1dSJustin T. Gibbs device->target->generation; 17708b8a9b1dSJustin T. Gibbs cdm->status = CAM_DEV_MATCH_MORE; 17718b8a9b1dSJustin T. Gibbs return(0); 17728b8a9b1dSJustin T. Gibbs } 17738b8a9b1dSJustin T. Gibbs j = cdm->num_matches; 17748b8a9b1dSJustin T. Gibbs cdm->num_matches++; 17758b8a9b1dSJustin T. Gibbs cdm->matches[j].type = DEV_MATCH_DEVICE; 17768b8a9b1dSJustin T. Gibbs cdm->matches[j].result.device_result.path_id = 17778b8a9b1dSJustin T. Gibbs device->target->bus->path_id; 17788b8a9b1dSJustin T. Gibbs cdm->matches[j].result.device_result.target_id = 17798b8a9b1dSJustin T. Gibbs device->target->target_id; 17808b8a9b1dSJustin T. Gibbs cdm->matches[j].result.device_result.target_lun = 17818b8a9b1dSJustin T. Gibbs device->lun_id; 178252c9ce25SScott Long cdm->matches[j].result.device_result.protocol = 178352c9ce25SScott Long device->protocol; 17848b8a9b1dSJustin T. Gibbs bcopy(&device->inq_data, 17858b8a9b1dSJustin T. Gibbs &cdm->matches[j].result.device_result.inq_data, 17868b8a9b1dSJustin T. Gibbs sizeof(struct scsi_inquiry_data)); 178752c9ce25SScott Long bcopy(&device->ident_data, 178852c9ce25SScott Long &cdm->matches[j].result.device_result.ident_data, 178952c9ce25SScott Long sizeof(struct ata_params)); 17909deea857SKenneth D. Merry 17919deea857SKenneth D. Merry /* Let the user know whether this device is unconfigured */ 17929deea857SKenneth D. Merry if (device->flags & CAM_DEV_UNCONFIGURED) 17939deea857SKenneth D. Merry cdm->matches[j].result.device_result.flags = 17949deea857SKenneth D. Merry DEV_RESULT_UNCONFIGURED; 17959deea857SKenneth D. Merry else 17969deea857SKenneth D. Merry cdm->matches[j].result.device_result.flags = 17979deea857SKenneth D. Merry DEV_RESULT_NOFLAG; 17988b8a9b1dSJustin T. Gibbs } 17998b8a9b1dSJustin T. Gibbs 18008b8a9b1dSJustin T. Gibbs /* 18018b8a9b1dSJustin T. Gibbs * If the user isn't interested in peripherals, don't descend 18028b8a9b1dSJustin T. Gibbs * the tree any further. 18038b8a9b1dSJustin T. Gibbs */ 18048b8a9b1dSJustin T. Gibbs if ((retval & DM_RET_ACTION_MASK) == DM_RET_STOP) 18058b8a9b1dSJustin T. Gibbs return(1); 18068b8a9b1dSJustin T. Gibbs 18078b8a9b1dSJustin T. Gibbs /* 18088b8a9b1dSJustin T. Gibbs * If there is a peripheral list generation recorded, make sure 18098b8a9b1dSJustin T. Gibbs * it hasn't changed. 18108b8a9b1dSJustin T. Gibbs */ 1811227d67aaSAlexander Motin xpt_lock_buses(); 1812227d67aaSAlexander Motin mtx_lock(&bus->eb_mtx); 18138b8a9b1dSJustin T. Gibbs if ((cdm->pos.position_type & CAM_DEV_POS_BUS) 1814227d67aaSAlexander Motin && (cdm->pos.cookie.bus == bus) 18158b8a9b1dSJustin T. Gibbs && (cdm->pos.position_type & CAM_DEV_POS_TARGET) 18168b8a9b1dSJustin T. Gibbs && (cdm->pos.cookie.target == device->target) 18178b8a9b1dSJustin T. Gibbs && (cdm->pos.position_type & CAM_DEV_POS_DEVICE) 18188b8a9b1dSJustin T. Gibbs && (cdm->pos.cookie.device == device) 18198b8a9b1dSJustin T. Gibbs && (cdm->pos.position_type & CAM_DEV_POS_PERIPH) 1820227d67aaSAlexander Motin && (cdm->pos.cookie.periph != NULL)) { 1821227d67aaSAlexander Motin if (cdm->pos.generations[CAM_PERIPH_GENERATION] != 1822227d67aaSAlexander Motin device->generation) { 1823227d67aaSAlexander Motin mtx_unlock(&bus->eb_mtx); 1824227d67aaSAlexander Motin xpt_unlock_buses(); 1825227d67aaSAlexander Motin cdm->status = CAM_DEV_MATCH_LIST_CHANGED; 1826227d67aaSAlexander Motin return(0); 1827227d67aaSAlexander Motin } 1828227d67aaSAlexander Motin periph = (struct cam_periph *)cdm->pos.cookie.periph; 1829227d67aaSAlexander Motin periph->refcount++; 1830227d67aaSAlexander Motin } else 1831227d67aaSAlexander Motin periph = NULL; 1832227d67aaSAlexander Motin mtx_unlock(&bus->eb_mtx); 1833227d67aaSAlexander Motin xpt_unlock_buses(); 1834227d67aaSAlexander Motin 1835227d67aaSAlexander Motin return (xptperiphtraverse(device, periph, xptedtperiphfunc, arg)); 18368b8a9b1dSJustin T. Gibbs } 18378b8a9b1dSJustin T. Gibbs 18388b8a9b1dSJustin T. Gibbs static int 18398b8a9b1dSJustin T. Gibbs xptedtperiphfunc(struct cam_periph *periph, void *arg) 18408b8a9b1dSJustin T. Gibbs { 18418b8a9b1dSJustin T. Gibbs struct ccb_dev_match *cdm; 18428b8a9b1dSJustin T. Gibbs dev_match_ret retval; 18438b8a9b1dSJustin T. Gibbs 18448b8a9b1dSJustin T. Gibbs cdm = (struct ccb_dev_match *)arg; 18458b8a9b1dSJustin T. Gibbs 18468b8a9b1dSJustin T. Gibbs retval = xptperiphmatch(cdm->patterns, cdm->num_patterns, periph); 18478b8a9b1dSJustin T. Gibbs 18488b8a9b1dSJustin T. Gibbs if ((retval & DM_RET_ACTION_MASK) == DM_RET_ERROR) { 18498b8a9b1dSJustin T. Gibbs cdm->status = CAM_DEV_MATCH_ERROR; 18508b8a9b1dSJustin T. Gibbs return(0); 18518b8a9b1dSJustin T. Gibbs } 18528b8a9b1dSJustin T. Gibbs 18538b8a9b1dSJustin T. Gibbs /* 18548b8a9b1dSJustin T. Gibbs * If the copy flag is set, copy this peripheral out. 18558b8a9b1dSJustin T. Gibbs */ 18568b8a9b1dSJustin T. Gibbs if (retval & DM_RET_COPY) { 18578b8a9b1dSJustin T. Gibbs int spaceleft, j; 18588b8a9b1dSJustin T. Gibbs 18598b8a9b1dSJustin T. Gibbs spaceleft = cdm->match_buf_len - (cdm->num_matches * 18608b8a9b1dSJustin T. Gibbs sizeof(struct dev_match_result)); 18618b8a9b1dSJustin T. Gibbs 18628b8a9b1dSJustin T. Gibbs /* 18638b8a9b1dSJustin T. Gibbs * If we don't have enough space to put in another 18648b8a9b1dSJustin T. Gibbs * match result, save our position and tell the 18658b8a9b1dSJustin T. Gibbs * user there are more devices to check. 18668b8a9b1dSJustin T. Gibbs */ 18678b8a9b1dSJustin T. Gibbs if (spaceleft < sizeof(struct dev_match_result)) { 18688b8a9b1dSJustin T. Gibbs bzero(&cdm->pos, sizeof(cdm->pos)); 18698b8a9b1dSJustin T. Gibbs cdm->pos.position_type = 18708b8a9b1dSJustin T. Gibbs CAM_DEV_POS_EDT | CAM_DEV_POS_BUS | 18718b8a9b1dSJustin T. Gibbs CAM_DEV_POS_TARGET | CAM_DEV_POS_DEVICE | 18728b8a9b1dSJustin T. Gibbs CAM_DEV_POS_PERIPH; 18738b8a9b1dSJustin T. Gibbs 18748b8a9b1dSJustin T. Gibbs cdm->pos.cookie.bus = periph->path->bus; 18758b8a9b1dSJustin T. Gibbs cdm->pos.generations[CAM_BUS_GENERATION]= 18762b83592fSScott Long xsoftc.bus_generation; 18778b8a9b1dSJustin T. Gibbs cdm->pos.cookie.target = periph->path->target; 18788b8a9b1dSJustin T. Gibbs cdm->pos.generations[CAM_TARGET_GENERATION] = 18798b8a9b1dSJustin T. Gibbs periph->path->bus->generation; 18808b8a9b1dSJustin T. Gibbs cdm->pos.cookie.device = periph->path->device; 18818b8a9b1dSJustin T. Gibbs cdm->pos.generations[CAM_DEV_GENERATION] = 18828b8a9b1dSJustin T. Gibbs periph->path->target->generation; 18838b8a9b1dSJustin T. Gibbs cdm->pos.cookie.periph = periph; 18848b8a9b1dSJustin T. Gibbs cdm->pos.generations[CAM_PERIPH_GENERATION] = 18858b8a9b1dSJustin T. Gibbs periph->path->device->generation; 18868b8a9b1dSJustin T. Gibbs cdm->status = CAM_DEV_MATCH_MORE; 18878b8a9b1dSJustin T. Gibbs return(0); 18888b8a9b1dSJustin T. Gibbs } 18898b8a9b1dSJustin T. Gibbs 18908b8a9b1dSJustin T. Gibbs j = cdm->num_matches; 18918b8a9b1dSJustin T. Gibbs cdm->num_matches++; 18928b8a9b1dSJustin T. Gibbs cdm->matches[j].type = DEV_MATCH_PERIPH; 18938b8a9b1dSJustin T. Gibbs cdm->matches[j].result.periph_result.path_id = 18948b8a9b1dSJustin T. Gibbs periph->path->bus->path_id; 18958b8a9b1dSJustin T. Gibbs cdm->matches[j].result.periph_result.target_id = 18968b8a9b1dSJustin T. Gibbs periph->path->target->target_id; 18978b8a9b1dSJustin T. Gibbs cdm->matches[j].result.periph_result.target_lun = 18988b8a9b1dSJustin T. Gibbs periph->path->device->lun_id; 18998b8a9b1dSJustin T. Gibbs cdm->matches[j].result.periph_result.unit_number = 19008b8a9b1dSJustin T. Gibbs periph->unit_number; 19018b8a9b1dSJustin T. Gibbs strncpy(cdm->matches[j].result.periph_result.periph_name, 19028b8a9b1dSJustin T. Gibbs periph->periph_name, DEV_IDLEN); 19038b8a9b1dSJustin T. Gibbs } 19048b8a9b1dSJustin T. Gibbs 19058b8a9b1dSJustin T. Gibbs return(1); 19068b8a9b1dSJustin T. Gibbs } 19078b8a9b1dSJustin T. Gibbs 19088b8a9b1dSJustin T. Gibbs static int 19098b8a9b1dSJustin T. Gibbs xptedtmatch(struct ccb_dev_match *cdm) 19108b8a9b1dSJustin T. Gibbs { 1911227d67aaSAlexander Motin struct cam_eb *bus; 19128b8a9b1dSJustin T. Gibbs int ret; 19138b8a9b1dSJustin T. Gibbs 19148b8a9b1dSJustin T. Gibbs cdm->num_matches = 0; 19158b8a9b1dSJustin T. Gibbs 19168b8a9b1dSJustin T. Gibbs /* 19178b8a9b1dSJustin T. Gibbs * Check the bus list generation. If it has changed, the user 19188b8a9b1dSJustin T. Gibbs * needs to reset everything and start over. 19198b8a9b1dSJustin T. Gibbs */ 1920227d67aaSAlexander Motin xpt_lock_buses(); 19218b8a9b1dSJustin T. Gibbs if ((cdm->pos.position_type & CAM_DEV_POS_BUS) 1922227d67aaSAlexander Motin && (cdm->pos.cookie.bus != NULL)) { 1923227d67aaSAlexander Motin if (cdm->pos.generations[CAM_BUS_GENERATION] != 1924227d67aaSAlexander Motin xsoftc.bus_generation) { 1925227d67aaSAlexander Motin xpt_unlock_buses(); 19268b8a9b1dSJustin T. Gibbs cdm->status = CAM_DEV_MATCH_LIST_CHANGED; 19278b8a9b1dSJustin T. Gibbs return(0); 19288b8a9b1dSJustin T. Gibbs } 1929227d67aaSAlexander Motin bus = (struct cam_eb *)cdm->pos.cookie.bus; 1930227d67aaSAlexander Motin bus->refcount++; 1931227d67aaSAlexander Motin } else 1932227d67aaSAlexander Motin bus = NULL; 1933227d67aaSAlexander Motin xpt_unlock_buses(); 19348b8a9b1dSJustin T. Gibbs 1935227d67aaSAlexander Motin ret = xptbustraverse(bus, xptedtbusfunc, cdm); 19368b8a9b1dSJustin T. Gibbs 19378b8a9b1dSJustin T. Gibbs /* 19388b8a9b1dSJustin T. Gibbs * If we get back 0, that means that we had to stop before fully 19398b8a9b1dSJustin T. Gibbs * traversing the EDT. It also means that one of the subroutines 19408b8a9b1dSJustin T. Gibbs * has set the status field to the proper value. If we get back 1, 19418b8a9b1dSJustin T. Gibbs * we've fully traversed the EDT and copied out any matching entries. 19428b8a9b1dSJustin T. Gibbs */ 19438b8a9b1dSJustin T. Gibbs if (ret == 1) 19448b8a9b1dSJustin T. Gibbs cdm->status = CAM_DEV_MATCH_LAST; 19458b8a9b1dSJustin T. Gibbs 19468b8a9b1dSJustin T. Gibbs return(ret); 19478b8a9b1dSJustin T. Gibbs } 19488b8a9b1dSJustin T. Gibbs 19498b8a9b1dSJustin T. Gibbs static int 19508b8a9b1dSJustin T. Gibbs xptplistpdrvfunc(struct periph_driver **pdrv, void *arg) 19518b8a9b1dSJustin T. Gibbs { 1952227d67aaSAlexander Motin struct cam_periph *periph; 19538b8a9b1dSJustin T. Gibbs struct ccb_dev_match *cdm; 19548b8a9b1dSJustin T. Gibbs 19558b8a9b1dSJustin T. Gibbs cdm = (struct ccb_dev_match *)arg; 19568b8a9b1dSJustin T. Gibbs 1957227d67aaSAlexander Motin xpt_lock_buses(); 19588b8a9b1dSJustin T. Gibbs if ((cdm->pos.position_type & CAM_DEV_POS_PDPTR) 19598b8a9b1dSJustin T. Gibbs && (cdm->pos.cookie.pdrv == pdrv) 19608b8a9b1dSJustin T. Gibbs && (cdm->pos.position_type & CAM_DEV_POS_PERIPH) 1961227d67aaSAlexander Motin && (cdm->pos.cookie.periph != NULL)) { 1962227d67aaSAlexander Motin if (cdm->pos.generations[CAM_PERIPH_GENERATION] != 1963227d67aaSAlexander Motin (*pdrv)->generation) { 1964227d67aaSAlexander Motin xpt_unlock_buses(); 19658b8a9b1dSJustin T. Gibbs cdm->status = CAM_DEV_MATCH_LIST_CHANGED; 19668b8a9b1dSJustin T. Gibbs return(0); 19678b8a9b1dSJustin T. Gibbs } 1968227d67aaSAlexander Motin periph = (struct cam_periph *)cdm->pos.cookie.periph; 1969227d67aaSAlexander Motin periph->refcount++; 1970227d67aaSAlexander Motin } else 1971227d67aaSAlexander Motin periph = NULL; 1972227d67aaSAlexander Motin xpt_unlock_buses(); 19738b8a9b1dSJustin T. Gibbs 1974227d67aaSAlexander Motin return (xptpdperiphtraverse(pdrv, periph, xptplistperiphfunc, arg)); 19758b8a9b1dSJustin T. Gibbs } 19768b8a9b1dSJustin T. Gibbs 19778b8a9b1dSJustin T. Gibbs static int 19788b8a9b1dSJustin T. Gibbs xptplistperiphfunc(struct cam_periph *periph, void *arg) 19798b8a9b1dSJustin T. Gibbs { 19808b8a9b1dSJustin T. Gibbs struct ccb_dev_match *cdm; 19818b8a9b1dSJustin T. Gibbs dev_match_ret retval; 19828b8a9b1dSJustin T. Gibbs 19838b8a9b1dSJustin T. Gibbs cdm = (struct ccb_dev_match *)arg; 19848b8a9b1dSJustin T. Gibbs 19858b8a9b1dSJustin T. Gibbs retval = xptperiphmatch(cdm->patterns, cdm->num_patterns, periph); 19868b8a9b1dSJustin T. Gibbs 19878b8a9b1dSJustin T. Gibbs if ((retval & DM_RET_ACTION_MASK) == DM_RET_ERROR) { 19888b8a9b1dSJustin T. Gibbs cdm->status = CAM_DEV_MATCH_ERROR; 19898b8a9b1dSJustin T. Gibbs return(0); 19908b8a9b1dSJustin T. Gibbs } 19918b8a9b1dSJustin T. Gibbs 19928b8a9b1dSJustin T. Gibbs /* 19938b8a9b1dSJustin T. Gibbs * If the copy flag is set, copy this peripheral out. 19948b8a9b1dSJustin T. Gibbs */ 19958b8a9b1dSJustin T. Gibbs if (retval & DM_RET_COPY) { 19968b8a9b1dSJustin T. Gibbs int spaceleft, j; 19978b8a9b1dSJustin T. Gibbs 19988b8a9b1dSJustin T. Gibbs spaceleft = cdm->match_buf_len - (cdm->num_matches * 19998b8a9b1dSJustin T. Gibbs sizeof(struct dev_match_result)); 20008b8a9b1dSJustin T. Gibbs 20018b8a9b1dSJustin T. Gibbs /* 20028b8a9b1dSJustin T. Gibbs * If we don't have enough space to put in another 20038b8a9b1dSJustin T. Gibbs * match result, save our position and tell the 20048b8a9b1dSJustin T. Gibbs * user there are more devices to check. 20058b8a9b1dSJustin T. Gibbs */ 20068b8a9b1dSJustin T. Gibbs if (spaceleft < sizeof(struct dev_match_result)) { 20078b8a9b1dSJustin T. Gibbs struct periph_driver **pdrv; 20088b8a9b1dSJustin T. Gibbs 20098b8a9b1dSJustin T. Gibbs pdrv = NULL; 20108b8a9b1dSJustin T. Gibbs bzero(&cdm->pos, sizeof(cdm->pos)); 20118b8a9b1dSJustin T. Gibbs cdm->pos.position_type = 20128b8a9b1dSJustin T. Gibbs CAM_DEV_POS_PDRV | CAM_DEV_POS_PDPTR | 20138b8a9b1dSJustin T. Gibbs CAM_DEV_POS_PERIPH; 20148b8a9b1dSJustin T. Gibbs 20158b8a9b1dSJustin T. Gibbs /* 20168b8a9b1dSJustin T. Gibbs * This may look a bit non-sensical, but it is 20178b8a9b1dSJustin T. Gibbs * actually quite logical. There are very few 20188b8a9b1dSJustin T. Gibbs * peripheral drivers, and bloating every peripheral 20198b8a9b1dSJustin T. Gibbs * structure with a pointer back to its parent 20208b8a9b1dSJustin T. Gibbs * peripheral driver linker set entry would cost 20218b8a9b1dSJustin T. Gibbs * more in the long run than doing this quick lookup. 20228b8a9b1dSJustin T. Gibbs */ 20230b7c27b9SPeter Wemm for (pdrv = periph_drivers; *pdrv != NULL; pdrv++) { 20248b8a9b1dSJustin T. Gibbs if (strcmp((*pdrv)->driver_name, 20258b8a9b1dSJustin T. Gibbs periph->periph_name) == 0) 20268b8a9b1dSJustin T. Gibbs break; 20278b8a9b1dSJustin T. Gibbs } 20288b8a9b1dSJustin T. Gibbs 202901910babSScott Long if (*pdrv == NULL) { 20308b8a9b1dSJustin T. Gibbs cdm->status = CAM_DEV_MATCH_ERROR; 20318b8a9b1dSJustin T. Gibbs return(0); 20328b8a9b1dSJustin T. Gibbs } 20338b8a9b1dSJustin T. Gibbs 20348b8a9b1dSJustin T. Gibbs cdm->pos.cookie.pdrv = pdrv; 20358b8a9b1dSJustin T. Gibbs /* 20368b8a9b1dSJustin T. Gibbs * The periph generation slot does double duty, as 20378b8a9b1dSJustin T. Gibbs * does the periph pointer slot. They are used for 20388b8a9b1dSJustin T. Gibbs * both edt and pdrv lookups and positioning. 20398b8a9b1dSJustin T. Gibbs */ 20408b8a9b1dSJustin T. Gibbs cdm->pos.cookie.periph = periph; 20418b8a9b1dSJustin T. Gibbs cdm->pos.generations[CAM_PERIPH_GENERATION] = 20428b8a9b1dSJustin T. Gibbs (*pdrv)->generation; 20438b8a9b1dSJustin T. Gibbs cdm->status = CAM_DEV_MATCH_MORE; 20448b8a9b1dSJustin T. Gibbs return(0); 20458b8a9b1dSJustin T. Gibbs } 20468b8a9b1dSJustin T. Gibbs 20478b8a9b1dSJustin T. Gibbs j = cdm->num_matches; 20488b8a9b1dSJustin T. Gibbs cdm->num_matches++; 20498b8a9b1dSJustin T. Gibbs cdm->matches[j].type = DEV_MATCH_PERIPH; 20508b8a9b1dSJustin T. Gibbs cdm->matches[j].result.periph_result.path_id = 20518b8a9b1dSJustin T. Gibbs periph->path->bus->path_id; 20528b8a9b1dSJustin T. Gibbs 20538b8a9b1dSJustin T. Gibbs /* 20548b8a9b1dSJustin T. Gibbs * The transport layer peripheral doesn't have a target or 20558b8a9b1dSJustin T. Gibbs * lun. 20568b8a9b1dSJustin T. Gibbs */ 20578b8a9b1dSJustin T. Gibbs if (periph->path->target) 20588b8a9b1dSJustin T. Gibbs cdm->matches[j].result.periph_result.target_id = 20598b8a9b1dSJustin T. Gibbs periph->path->target->target_id; 20608b8a9b1dSJustin T. Gibbs else 2061431d3a5bSAlexander Motin cdm->matches[j].result.periph_result.target_id = 2062431d3a5bSAlexander Motin CAM_TARGET_WILDCARD; 20638b8a9b1dSJustin T. Gibbs 20648b8a9b1dSJustin T. Gibbs if (periph->path->device) 20658b8a9b1dSJustin T. Gibbs cdm->matches[j].result.periph_result.target_lun = 20668b8a9b1dSJustin T. Gibbs periph->path->device->lun_id; 20678b8a9b1dSJustin T. Gibbs else 2068431d3a5bSAlexander Motin cdm->matches[j].result.periph_result.target_lun = 2069431d3a5bSAlexander Motin CAM_LUN_WILDCARD; 20708b8a9b1dSJustin T. Gibbs 20718b8a9b1dSJustin T. Gibbs cdm->matches[j].result.periph_result.unit_number = 20728b8a9b1dSJustin T. Gibbs periph->unit_number; 20738b8a9b1dSJustin T. Gibbs strncpy(cdm->matches[j].result.periph_result.periph_name, 20748b8a9b1dSJustin T. Gibbs periph->periph_name, DEV_IDLEN); 20758b8a9b1dSJustin T. Gibbs } 20768b8a9b1dSJustin T. Gibbs 20778b8a9b1dSJustin T. Gibbs return(1); 20788b8a9b1dSJustin T. Gibbs } 20798b8a9b1dSJustin T. Gibbs 20808b8a9b1dSJustin T. Gibbs static int 20818b8a9b1dSJustin T. Gibbs xptperiphlistmatch(struct ccb_dev_match *cdm) 20828b8a9b1dSJustin T. Gibbs { 20838b8a9b1dSJustin T. Gibbs int ret; 20848b8a9b1dSJustin T. Gibbs 20858b8a9b1dSJustin T. Gibbs cdm->num_matches = 0; 20868b8a9b1dSJustin T. Gibbs 20878b8a9b1dSJustin T. Gibbs /* 20888b8a9b1dSJustin T. Gibbs * At this point in the edt traversal function, we check the bus 2089db4fcadfSConrad Meyer * list generation to make sure that no buses have been added or 20908b8a9b1dSJustin T. Gibbs * removed since the user last sent a XPT_DEV_MATCH ccb through. 20918b8a9b1dSJustin T. Gibbs * For the peripheral driver list traversal function, however, we 20928b8a9b1dSJustin T. Gibbs * don't have to worry about new peripheral driver types coming or 20938b8a9b1dSJustin T. Gibbs * going; they're in a linker set, and therefore can't change 20948b8a9b1dSJustin T. Gibbs * without a recompile. 20958b8a9b1dSJustin T. Gibbs */ 20968b8a9b1dSJustin T. Gibbs 20978b8a9b1dSJustin T. Gibbs if ((cdm->pos.position_type & CAM_DEV_POS_PDPTR) 20988b8a9b1dSJustin T. Gibbs && (cdm->pos.cookie.pdrv != NULL)) 20998b8a9b1dSJustin T. Gibbs ret = xptpdrvtraverse( 21008b8a9b1dSJustin T. Gibbs (struct periph_driver **)cdm->pos.cookie.pdrv, 21018b8a9b1dSJustin T. Gibbs xptplistpdrvfunc, cdm); 21028b8a9b1dSJustin T. Gibbs else 21038b8a9b1dSJustin T. Gibbs ret = xptpdrvtraverse(NULL, xptplistpdrvfunc, cdm); 21048b8a9b1dSJustin T. Gibbs 21058b8a9b1dSJustin T. Gibbs /* 21068b8a9b1dSJustin T. Gibbs * If we get back 0, that means that we had to stop before fully 21078b8a9b1dSJustin T. Gibbs * traversing the peripheral driver tree. It also means that one of 21088b8a9b1dSJustin T. Gibbs * the subroutines has set the status field to the proper value. If 21098b8a9b1dSJustin T. Gibbs * we get back 1, we've fully traversed the EDT and copied out any 21108b8a9b1dSJustin T. Gibbs * matching entries. 21118b8a9b1dSJustin T. Gibbs */ 21128b8a9b1dSJustin T. Gibbs if (ret == 1) 21138b8a9b1dSJustin T. Gibbs cdm->status = CAM_DEV_MATCH_LAST; 21148b8a9b1dSJustin T. Gibbs 21158b8a9b1dSJustin T. Gibbs return(ret); 21168b8a9b1dSJustin T. Gibbs } 21178b8a9b1dSJustin T. Gibbs 21188b8a9b1dSJustin T. Gibbs static int 21198b8a9b1dSJustin T. Gibbs xptbustraverse(struct cam_eb *start_bus, xpt_busfunc_t *tr_func, void *arg) 21208b8a9b1dSJustin T. Gibbs { 21218b8a9b1dSJustin T. Gibbs struct cam_eb *bus, *next_bus; 21228b8a9b1dSJustin T. Gibbs int retval; 21238b8a9b1dSJustin T. Gibbs 21248b8a9b1dSJustin T. Gibbs retval = 1; 2125227d67aaSAlexander Motin if (start_bus) 2126227d67aaSAlexander Motin bus = start_bus; 2127227d67aaSAlexander Motin else { 21289a7c2696SAlexander Motin xpt_lock_buses(); 2129227d67aaSAlexander Motin bus = TAILQ_FIRST(&xsoftc.xpt_busses); 2130227d67aaSAlexander Motin if (bus == NULL) { 21319a7c2696SAlexander Motin xpt_unlock_buses(); 2132227d67aaSAlexander Motin return (retval); 2133227d67aaSAlexander Motin } 2134227d67aaSAlexander Motin bus->refcount++; 2135227d67aaSAlexander Motin xpt_unlock_buses(); 2136227d67aaSAlexander Motin } 2137227d67aaSAlexander Motin for (; bus != NULL; bus = next_bus) { 21388b8a9b1dSJustin T. Gibbs retval = tr_func(bus, arg); 2139227d67aaSAlexander Motin if (retval == 0) { 2140227d67aaSAlexander Motin xpt_release_bus(bus); 2141227d67aaSAlexander Motin break; 2142227d67aaSAlexander Motin } 21439a7c2696SAlexander Motin xpt_lock_buses(); 21448900f4b8SKenneth D. Merry next_bus = TAILQ_NEXT(bus, links); 2145227d67aaSAlexander Motin if (next_bus) 2146227d67aaSAlexander Motin next_bus->refcount++; 21479a7c2696SAlexander Motin xpt_unlock_buses(); 21488900f4b8SKenneth D. Merry xpt_release_bus(bus); 21498b8a9b1dSJustin T. Gibbs } 21508b8a9b1dSJustin T. Gibbs return(retval); 21518b8a9b1dSJustin T. Gibbs } 21528b8a9b1dSJustin T. Gibbs 21538b8a9b1dSJustin T. Gibbs static int 21548b8a9b1dSJustin T. Gibbs xpttargettraverse(struct cam_eb *bus, struct cam_et *start_target, 21558b8a9b1dSJustin T. Gibbs xpt_targetfunc_t *tr_func, void *arg) 21568b8a9b1dSJustin T. Gibbs { 21578b8a9b1dSJustin T. Gibbs struct cam_et *target, *next_target; 21588b8a9b1dSJustin T. Gibbs int retval; 21598b8a9b1dSJustin T. Gibbs 21608b8a9b1dSJustin T. Gibbs retval = 1; 2161227d67aaSAlexander Motin if (start_target) 2162227d67aaSAlexander Motin target = start_target; 2163227d67aaSAlexander Motin else { 2164227d67aaSAlexander Motin mtx_lock(&bus->eb_mtx); 2165227d67aaSAlexander Motin target = TAILQ_FIRST(&bus->et_entries); 2166227d67aaSAlexander Motin if (target == NULL) { 2167227d67aaSAlexander Motin mtx_unlock(&bus->eb_mtx); 21688b8a9b1dSJustin T. Gibbs return (retval); 21698b8a9b1dSJustin T. Gibbs } 2170227d67aaSAlexander Motin target->refcount++; 2171227d67aaSAlexander Motin mtx_unlock(&bus->eb_mtx); 2172227d67aaSAlexander Motin } 2173227d67aaSAlexander Motin for (; target != NULL; target = next_target) { 2174227d67aaSAlexander Motin retval = tr_func(target, arg); 2175227d67aaSAlexander Motin if (retval == 0) { 2176227d67aaSAlexander Motin xpt_release_target(target); 2177227d67aaSAlexander Motin break; 2178227d67aaSAlexander Motin } 2179227d67aaSAlexander Motin mtx_lock(&bus->eb_mtx); 2180227d67aaSAlexander Motin next_target = TAILQ_NEXT(target, links); 2181227d67aaSAlexander Motin if (next_target) 2182227d67aaSAlexander Motin next_target->refcount++; 2183227d67aaSAlexander Motin mtx_unlock(&bus->eb_mtx); 2184227d67aaSAlexander Motin xpt_release_target(target); 2185227d67aaSAlexander Motin } 21868b8a9b1dSJustin T. Gibbs return(retval); 21878b8a9b1dSJustin T. Gibbs } 21888b8a9b1dSJustin T. Gibbs 21898b8a9b1dSJustin T. Gibbs static int 21908b8a9b1dSJustin T. Gibbs xptdevicetraverse(struct cam_et *target, struct cam_ed *start_device, 21918b8a9b1dSJustin T. Gibbs xpt_devicefunc_t *tr_func, void *arg) 21928b8a9b1dSJustin T. Gibbs { 2193227d67aaSAlexander Motin struct cam_eb *bus; 21948b8a9b1dSJustin T. Gibbs struct cam_ed *device, *next_device; 21958b8a9b1dSJustin T. Gibbs int retval; 21968b8a9b1dSJustin T. Gibbs 21978b8a9b1dSJustin T. Gibbs retval = 1; 2198227d67aaSAlexander Motin bus = target->bus; 2199227d67aaSAlexander Motin if (start_device) 2200227d67aaSAlexander Motin device = start_device; 2201227d67aaSAlexander Motin else { 2202227d67aaSAlexander Motin mtx_lock(&bus->eb_mtx); 2203227d67aaSAlexander Motin device = TAILQ_FIRST(&target->ed_entries); 2204227d67aaSAlexander Motin if (device == NULL) { 2205227d67aaSAlexander Motin mtx_unlock(&bus->eb_mtx); 22068b8a9b1dSJustin T. Gibbs return (retval); 22078b8a9b1dSJustin T. Gibbs } 2208227d67aaSAlexander Motin device->refcount++; 2209227d67aaSAlexander Motin mtx_unlock(&bus->eb_mtx); 2210227d67aaSAlexander Motin } 2211227d67aaSAlexander Motin for (; device != NULL; device = next_device) { 2212227d67aaSAlexander Motin mtx_lock(&device->device_mtx); 2213227d67aaSAlexander Motin retval = tr_func(device, arg); 2214227d67aaSAlexander Motin mtx_unlock(&device->device_mtx); 2215227d67aaSAlexander Motin if (retval == 0) { 2216227d67aaSAlexander Motin xpt_release_device(device); 2217227d67aaSAlexander Motin break; 2218227d67aaSAlexander Motin } 2219227d67aaSAlexander Motin mtx_lock(&bus->eb_mtx); 2220227d67aaSAlexander Motin next_device = TAILQ_NEXT(device, links); 2221227d67aaSAlexander Motin if (next_device) 2222227d67aaSAlexander Motin next_device->refcount++; 2223227d67aaSAlexander Motin mtx_unlock(&bus->eb_mtx); 2224227d67aaSAlexander Motin xpt_release_device(device); 2225227d67aaSAlexander Motin } 22268b8a9b1dSJustin T. Gibbs return(retval); 22278b8a9b1dSJustin T. Gibbs } 22288b8a9b1dSJustin T. Gibbs 22298b8a9b1dSJustin T. Gibbs static int 22308b8a9b1dSJustin T. Gibbs xptperiphtraverse(struct cam_ed *device, struct cam_periph *start_periph, 22318b8a9b1dSJustin T. Gibbs xpt_periphfunc_t *tr_func, void *arg) 22328b8a9b1dSJustin T. Gibbs { 2233227d67aaSAlexander Motin struct cam_eb *bus; 22348b8a9b1dSJustin T. Gibbs struct cam_periph *periph, *next_periph; 22358b8a9b1dSJustin T. Gibbs int retval; 22368b8a9b1dSJustin T. Gibbs 22378b8a9b1dSJustin T. Gibbs retval = 1; 22388b8a9b1dSJustin T. Gibbs 2239227d67aaSAlexander Motin bus = device->target->bus; 2240227d67aaSAlexander Motin if (start_periph) 2241227d67aaSAlexander Motin periph = start_periph; 2242227d67aaSAlexander Motin else { 22438900f4b8SKenneth D. Merry xpt_lock_buses(); 2244227d67aaSAlexander Motin mtx_lock(&bus->eb_mtx); 2245227d67aaSAlexander Motin periph = SLIST_FIRST(&device->periphs); 2246227d67aaSAlexander Motin while (periph != NULL && (periph->flags & CAM_PERIPH_FREE) != 0) 2247227d67aaSAlexander Motin periph = SLIST_NEXT(periph, periph_links); 2248227d67aaSAlexander Motin if (periph == NULL) { 2249227d67aaSAlexander Motin mtx_unlock(&bus->eb_mtx); 22508900f4b8SKenneth D. Merry xpt_unlock_buses(); 2251227d67aaSAlexander Motin return (retval); 2252227d67aaSAlexander Motin } 2253227d67aaSAlexander Motin periph->refcount++; 2254227d67aaSAlexander Motin mtx_unlock(&bus->eb_mtx); 2255227d67aaSAlexander Motin xpt_unlock_buses(); 2256227d67aaSAlexander Motin } 2257227d67aaSAlexander Motin for (; periph != NULL; periph = next_periph) { 2258227d67aaSAlexander Motin retval = tr_func(periph, arg); 2259227d67aaSAlexander Motin if (retval == 0) { 22609813c936SAlexander Motin cam_periph_release_locked(periph); 2261227d67aaSAlexander Motin break; 2262227d67aaSAlexander Motin } 2263227d67aaSAlexander Motin xpt_lock_buses(); 2264227d67aaSAlexander Motin mtx_lock(&bus->eb_mtx); 2265227d67aaSAlexander Motin next_periph = SLIST_NEXT(periph, periph_links); 2266227d67aaSAlexander Motin while (next_periph != NULL && 2267227d67aaSAlexander Motin (next_periph->flags & CAM_PERIPH_FREE) != 0) 2268840a5dd4SAlexander Motin next_periph = SLIST_NEXT(next_periph, periph_links); 2269227d67aaSAlexander Motin if (next_periph) 2270227d67aaSAlexander Motin next_periph->refcount++; 2271227d67aaSAlexander Motin mtx_unlock(&bus->eb_mtx); 2272227d67aaSAlexander Motin xpt_unlock_buses(); 2273227d67aaSAlexander Motin cam_periph_release_locked(periph); 2274227d67aaSAlexander Motin } 22758b8a9b1dSJustin T. Gibbs return(retval); 22768b8a9b1dSJustin T. Gibbs } 22778b8a9b1dSJustin T. Gibbs 22788b8a9b1dSJustin T. Gibbs static int 22798b8a9b1dSJustin T. Gibbs xptpdrvtraverse(struct periph_driver **start_pdrv, 22808b8a9b1dSJustin T. Gibbs xpt_pdrvfunc_t *tr_func, void *arg) 22818b8a9b1dSJustin T. Gibbs { 22828b8a9b1dSJustin T. Gibbs struct periph_driver **pdrv; 22838b8a9b1dSJustin T. Gibbs int retval; 22848b8a9b1dSJustin T. Gibbs 22858b8a9b1dSJustin T. Gibbs retval = 1; 22868b8a9b1dSJustin T. Gibbs 22878b8a9b1dSJustin T. Gibbs /* 22888b8a9b1dSJustin T. Gibbs * We don't traverse the peripheral driver list like we do the 22898b8a9b1dSJustin T. Gibbs * other lists, because it is a linker set, and therefore cannot be 22908b8a9b1dSJustin T. Gibbs * changed during runtime. If the peripheral driver list is ever 22918b8a9b1dSJustin T. Gibbs * re-done to be something other than a linker set (i.e. it can 22928b8a9b1dSJustin T. Gibbs * change while the system is running), the list traversal should 22938b8a9b1dSJustin T. Gibbs * be modified to work like the other traversal functions. 22948b8a9b1dSJustin T. Gibbs */ 22950b7c27b9SPeter Wemm for (pdrv = (start_pdrv ? start_pdrv : periph_drivers); 22968b8a9b1dSJustin T. Gibbs *pdrv != NULL; pdrv++) { 22978b8a9b1dSJustin T. Gibbs retval = tr_func(pdrv, arg); 22988b8a9b1dSJustin T. Gibbs 22998b8a9b1dSJustin T. Gibbs if (retval == 0) 23008b8a9b1dSJustin T. Gibbs return(retval); 23018b8a9b1dSJustin T. Gibbs } 23028b8a9b1dSJustin T. Gibbs 23038b8a9b1dSJustin T. Gibbs return(retval); 23048b8a9b1dSJustin T. Gibbs } 23058b8a9b1dSJustin T. Gibbs 23068b8a9b1dSJustin T. Gibbs static int 23078b8a9b1dSJustin T. Gibbs xptpdperiphtraverse(struct periph_driver **pdrv, 23088b8a9b1dSJustin T. Gibbs struct cam_periph *start_periph, 23098b8a9b1dSJustin T. Gibbs xpt_periphfunc_t *tr_func, void *arg) 23108b8a9b1dSJustin T. Gibbs { 23118b8a9b1dSJustin T. Gibbs struct cam_periph *periph, *next_periph; 23128b8a9b1dSJustin T. Gibbs int retval; 23138b8a9b1dSJustin T. Gibbs 23148b8a9b1dSJustin T. Gibbs retval = 1; 23158b8a9b1dSJustin T. Gibbs 2316227d67aaSAlexander Motin if (start_periph) 2317227d67aaSAlexander Motin periph = start_periph; 2318227d67aaSAlexander Motin else { 2319f1e2546aSMatt Jacob xpt_lock_buses(); 2320227d67aaSAlexander Motin periph = TAILQ_FIRST(&(*pdrv)->units); 2321227d67aaSAlexander Motin while (periph != NULL && (periph->flags & CAM_PERIPH_FREE) != 0) 2322227d67aaSAlexander Motin periph = TAILQ_NEXT(periph, unit_links); 2323227d67aaSAlexander Motin if (periph == NULL) { 2324227d67aaSAlexander Motin xpt_unlock_buses(); 2325227d67aaSAlexander Motin return (retval); 23268900f4b8SKenneth D. Merry } 23278900f4b8SKenneth D. Merry periph->refcount++; 2328dcdf6e74SAlexander Motin xpt_unlock_buses(); 23298b8a9b1dSJustin T. Gibbs } 2330227d67aaSAlexander Motin for (; periph != NULL; periph = next_periph) { 2331227d67aaSAlexander Motin cam_periph_lock(periph); 2332227d67aaSAlexander Motin retval = tr_func(periph, arg); 2333227d67aaSAlexander Motin cam_periph_unlock(periph); 2334227d67aaSAlexander Motin if (retval == 0) { 2335227d67aaSAlexander Motin cam_periph_release(periph); 2336227d67aaSAlexander Motin break; 2337227d67aaSAlexander Motin } 2338227d67aaSAlexander Motin xpt_lock_buses(); 2339227d67aaSAlexander Motin next_periph = TAILQ_NEXT(periph, unit_links); 2340227d67aaSAlexander Motin while (next_periph != NULL && 2341227d67aaSAlexander Motin (next_periph->flags & CAM_PERIPH_FREE) != 0) 2342840a5dd4SAlexander Motin next_periph = TAILQ_NEXT(next_periph, unit_links); 2343227d67aaSAlexander Motin if (next_periph) 2344227d67aaSAlexander Motin next_periph->refcount++; 2345f1e2546aSMatt Jacob xpt_unlock_buses(); 2346227d67aaSAlexander Motin cam_periph_release(periph); 2347227d67aaSAlexander Motin } 23488b8a9b1dSJustin T. Gibbs return(retval); 23498b8a9b1dSJustin T. Gibbs } 23508b8a9b1dSJustin T. Gibbs 23518b8a9b1dSJustin T. Gibbs static int 23528b8a9b1dSJustin T. Gibbs xptdefbusfunc(struct cam_eb *bus, void *arg) 23538b8a9b1dSJustin T. Gibbs { 23548b8a9b1dSJustin T. Gibbs struct xpt_traverse_config *tr_config; 23558b8a9b1dSJustin T. Gibbs 23568b8a9b1dSJustin T. Gibbs tr_config = (struct xpt_traverse_config *)arg; 23578b8a9b1dSJustin T. Gibbs 23588b8a9b1dSJustin T. Gibbs if (tr_config->depth == XPT_DEPTH_BUS) { 23598b8a9b1dSJustin T. Gibbs xpt_busfunc_t *tr_func; 23608b8a9b1dSJustin T. Gibbs 23618b8a9b1dSJustin T. Gibbs tr_func = (xpt_busfunc_t *)tr_config->tr_func; 23628b8a9b1dSJustin T. Gibbs 23638b8a9b1dSJustin T. Gibbs return(tr_func(bus, tr_config->tr_arg)); 23648b8a9b1dSJustin T. Gibbs } else 23658b8a9b1dSJustin T. Gibbs return(xpttargettraverse(bus, NULL, xptdeftargetfunc, arg)); 23668b8a9b1dSJustin T. Gibbs } 23678b8a9b1dSJustin T. Gibbs 23688b8a9b1dSJustin T. Gibbs static int 23698b8a9b1dSJustin T. Gibbs xptdeftargetfunc(struct cam_et *target, void *arg) 23708b8a9b1dSJustin T. Gibbs { 23718b8a9b1dSJustin T. Gibbs struct xpt_traverse_config *tr_config; 23728b8a9b1dSJustin T. Gibbs 23738b8a9b1dSJustin T. Gibbs tr_config = (struct xpt_traverse_config *)arg; 23748b8a9b1dSJustin T. Gibbs 23758b8a9b1dSJustin T. Gibbs if (tr_config->depth == XPT_DEPTH_TARGET) { 23768b8a9b1dSJustin T. Gibbs xpt_targetfunc_t *tr_func; 23778b8a9b1dSJustin T. Gibbs 23788b8a9b1dSJustin T. Gibbs tr_func = (xpt_targetfunc_t *)tr_config->tr_func; 23798b8a9b1dSJustin T. Gibbs 23808b8a9b1dSJustin T. Gibbs return(tr_func(target, tr_config->tr_arg)); 23818b8a9b1dSJustin T. Gibbs } else 23828b8a9b1dSJustin T. Gibbs return(xptdevicetraverse(target, NULL, xptdefdevicefunc, arg)); 23838b8a9b1dSJustin T. Gibbs } 23848b8a9b1dSJustin T. Gibbs 23858b8a9b1dSJustin T. Gibbs static int 23868b8a9b1dSJustin T. Gibbs xptdefdevicefunc(struct cam_ed *device, void *arg) 23878b8a9b1dSJustin T. Gibbs { 23888b8a9b1dSJustin T. Gibbs struct xpt_traverse_config *tr_config; 23898b8a9b1dSJustin T. Gibbs 23908b8a9b1dSJustin T. Gibbs tr_config = (struct xpt_traverse_config *)arg; 23918b8a9b1dSJustin T. Gibbs 23928b8a9b1dSJustin T. Gibbs if (tr_config->depth == XPT_DEPTH_DEVICE) { 23938b8a9b1dSJustin T. Gibbs xpt_devicefunc_t *tr_func; 23948b8a9b1dSJustin T. Gibbs 23958b8a9b1dSJustin T. Gibbs tr_func = (xpt_devicefunc_t *)tr_config->tr_func; 23968b8a9b1dSJustin T. Gibbs 23978b8a9b1dSJustin T. Gibbs return(tr_func(device, tr_config->tr_arg)); 23988b8a9b1dSJustin T. Gibbs } else 23998b8a9b1dSJustin T. Gibbs return(xptperiphtraverse(device, NULL, xptdefperiphfunc, arg)); 24008b8a9b1dSJustin T. Gibbs } 24018b8a9b1dSJustin T. Gibbs 24028b8a9b1dSJustin T. Gibbs static int 24038b8a9b1dSJustin T. Gibbs xptdefperiphfunc(struct cam_periph *periph, void *arg) 24048b8a9b1dSJustin T. Gibbs { 24058b8a9b1dSJustin T. Gibbs struct xpt_traverse_config *tr_config; 24068b8a9b1dSJustin T. Gibbs xpt_periphfunc_t *tr_func; 24078b8a9b1dSJustin T. Gibbs 24088b8a9b1dSJustin T. Gibbs tr_config = (struct xpt_traverse_config *)arg; 24098b8a9b1dSJustin T. Gibbs 24108b8a9b1dSJustin T. Gibbs tr_func = (xpt_periphfunc_t *)tr_config->tr_func; 24118b8a9b1dSJustin T. Gibbs 24128b8a9b1dSJustin T. Gibbs /* 24138b8a9b1dSJustin T. Gibbs * Unlike the other default functions, we don't check for depth 24148b8a9b1dSJustin T. Gibbs * here. The peripheral driver level is the last level in the EDT, 24158b8a9b1dSJustin T. Gibbs * so if we're here, we should execute the function in question. 24168b8a9b1dSJustin T. Gibbs */ 24178b8a9b1dSJustin T. Gibbs return(tr_func(periph, tr_config->tr_arg)); 24188b8a9b1dSJustin T. Gibbs } 24198b8a9b1dSJustin T. Gibbs 24208b8a9b1dSJustin T. Gibbs /* 24218b8a9b1dSJustin T. Gibbs * Execute the given function for every bus in the EDT. 24228b8a9b1dSJustin T. Gibbs */ 24238b8a9b1dSJustin T. Gibbs static int 24248b8a9b1dSJustin T. Gibbs xpt_for_all_busses(xpt_busfunc_t *tr_func, void *arg) 24258b8a9b1dSJustin T. Gibbs { 24268b8a9b1dSJustin T. Gibbs struct xpt_traverse_config tr_config; 24278b8a9b1dSJustin T. Gibbs 24288b8a9b1dSJustin T. Gibbs tr_config.depth = XPT_DEPTH_BUS; 24298b8a9b1dSJustin T. Gibbs tr_config.tr_func = tr_func; 24308b8a9b1dSJustin T. Gibbs tr_config.tr_arg = arg; 24318b8a9b1dSJustin T. Gibbs 24328b8a9b1dSJustin T. Gibbs return(xptbustraverse(NULL, xptdefbusfunc, &tr_config)); 24338b8a9b1dSJustin T. Gibbs } 24348b8a9b1dSJustin T. Gibbs 24358b8a9b1dSJustin T. Gibbs /* 24368b8a9b1dSJustin T. Gibbs * Execute the given function for every device in the EDT. 24378b8a9b1dSJustin T. Gibbs */ 24388b8a9b1dSJustin T. Gibbs static int 24398b8a9b1dSJustin T. Gibbs xpt_for_all_devices(xpt_devicefunc_t *tr_func, void *arg) 24408b8a9b1dSJustin T. Gibbs { 24418b8a9b1dSJustin T. Gibbs struct xpt_traverse_config tr_config; 24428b8a9b1dSJustin T. Gibbs 24438b8a9b1dSJustin T. Gibbs tr_config.depth = XPT_DEPTH_DEVICE; 24448b8a9b1dSJustin T. Gibbs tr_config.tr_func = tr_func; 24458b8a9b1dSJustin T. Gibbs tr_config.tr_arg = arg; 24468b8a9b1dSJustin T. Gibbs 24478b8a9b1dSJustin T. Gibbs return(xptbustraverse(NULL, xptdefbusfunc, &tr_config)); 24488b8a9b1dSJustin T. Gibbs } 24498b8a9b1dSJustin T. Gibbs 24508b8a9b1dSJustin T. Gibbs static int 24518b8a9b1dSJustin T. Gibbs xptsetasyncfunc(struct cam_ed *device, void *arg) 24528b8a9b1dSJustin T. Gibbs { 24538b8a9b1dSJustin T. Gibbs struct cam_path path; 24548b8a9b1dSJustin T. Gibbs struct ccb_getdev cgd; 24557685edecSAlexander Motin struct ccb_setasync *csa = (struct ccb_setasync *)arg; 24568b8a9b1dSJustin T. Gibbs 2457c8bead2aSJustin T. Gibbs /* 2458c8bead2aSJustin T. Gibbs * Don't report unconfigured devices (Wildcard devs, 2459c8bead2aSJustin T. Gibbs * devices only for target mode, device instances 2460c8bead2aSJustin T. Gibbs * that have been invalidated but are waiting for 2461c8bead2aSJustin T. Gibbs * their last reference count to be released). 2462c8bead2aSJustin T. Gibbs */ 2463c8bead2aSJustin T. Gibbs if ((device->flags & CAM_DEV_UNCONFIGURED) != 0) 2464c8bead2aSJustin T. Gibbs return (1); 2465c8bead2aSJustin T. Gibbs 24668b8a9b1dSJustin T. Gibbs xpt_compile_path(&path, 24678b8a9b1dSJustin T. Gibbs NULL, 24688b8a9b1dSJustin T. Gibbs device->target->bus->path_id, 24698b8a9b1dSJustin T. Gibbs device->target->target_id, 24708b8a9b1dSJustin T. Gibbs device->lun_id); 2471bbfa4aa1SAlexander Motin xpt_setup_ccb(&cgd.ccb_h, &path, CAM_PRIORITY_NORMAL); 24728b8a9b1dSJustin T. Gibbs cgd.ccb_h.func_code = XPT_GDEV_TYPE; 24738b8a9b1dSJustin T. Gibbs xpt_action((union ccb *)&cgd); 24747685edecSAlexander Motin csa->callback(csa->callback_arg, 24758b8a9b1dSJustin T. Gibbs AC_FOUND_DEVICE, 24768b8a9b1dSJustin T. Gibbs &path, &cgd); 24778b8a9b1dSJustin T. Gibbs xpt_release_path(&path); 24788b8a9b1dSJustin T. Gibbs 24798b8a9b1dSJustin T. Gibbs return(1); 24808b8a9b1dSJustin T. Gibbs } 2481c8bead2aSJustin T. Gibbs 24828b8a9b1dSJustin T. Gibbs static int 24838b8a9b1dSJustin T. Gibbs xptsetasyncbusfunc(struct cam_eb *bus, void *arg) 24848b8a9b1dSJustin T. Gibbs { 24858b8a9b1dSJustin T. Gibbs struct cam_path path; 24868b8a9b1dSJustin T. Gibbs struct ccb_pathinq cpi; 24877685edecSAlexander Motin struct ccb_setasync *csa = (struct ccb_setasync *)arg; 24888b8a9b1dSJustin T. Gibbs 24898b8a9b1dSJustin T. Gibbs xpt_compile_path(&path, /*periph*/NULL, 24906dfc67e3SAlexander Motin bus->path_id, 24918b8a9b1dSJustin T. Gibbs CAM_TARGET_WILDCARD, 24928b8a9b1dSJustin T. Gibbs CAM_LUN_WILDCARD); 2493227d67aaSAlexander Motin xpt_path_lock(&path); 2494bbfa4aa1SAlexander Motin xpt_setup_ccb(&cpi.ccb_h, &path, CAM_PRIORITY_NORMAL); 24958b8a9b1dSJustin T. Gibbs cpi.ccb_h.func_code = XPT_PATH_INQ; 24968b8a9b1dSJustin T. Gibbs xpt_action((union ccb *)&cpi); 24977685edecSAlexander Motin csa->callback(csa->callback_arg, 24988b8a9b1dSJustin T. Gibbs AC_PATH_REGISTERED, 24998b8a9b1dSJustin T. Gibbs &path, &cpi); 2500227d67aaSAlexander Motin xpt_path_unlock(&path); 25018b8a9b1dSJustin T. Gibbs xpt_release_path(&path); 25028b8a9b1dSJustin T. Gibbs 25038b8a9b1dSJustin T. Gibbs return(1); 25048b8a9b1dSJustin T. Gibbs } 25058b8a9b1dSJustin T. Gibbs 25068b8a9b1dSJustin T. Gibbs void 25078b8a9b1dSJustin T. Gibbs xpt_action(union ccb *start_ccb) 25088b8a9b1dSJustin T. Gibbs { 25099911ecf9SJustin T. Gibbs 251082727824SWarner Losh CAM_DEBUG(start_ccb->ccb_h.path, CAM_DEBUG_TRACE, 251169be012fSWarner Losh ("xpt_action: func %#x %s\n", start_ccb->ccb_h.func_code, 251269be012fSWarner Losh xpt_action_name(start_ccb->ccb_h.func_code))); 25138b8a9b1dSJustin T. Gibbs 25148b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.status = CAM_REQ_INPROG; 2515ded2b706SWarner Losh (*(start_ccb->ccb_h.path->bus->xport->ops->action))(start_ccb); 251652c9ce25SScott Long } 251752c9ce25SScott Long 251852c9ce25SScott Long void 251952c9ce25SScott Long xpt_action_default(union ccb *start_ccb) 252052c9ce25SScott Long { 2521da396db2SAlexander Motin struct cam_path *path; 2522227d67aaSAlexander Motin struct cam_sim *sim; 2523227d67aaSAlexander Motin int lock; 252452c9ce25SScott Long 2525da396db2SAlexander Motin path = start_ccb->ccb_h.path; 252682727824SWarner Losh CAM_DEBUG(path, CAM_DEBUG_TRACE, 252769be012fSWarner Losh ("xpt_action_default: func %#x %s\n", start_ccb->ccb_h.func_code, 252869be012fSWarner Losh xpt_action_name(start_ccb->ccb_h.func_code))); 252952c9ce25SScott Long 25308b8a9b1dSJustin T. Gibbs switch (start_ccb->ccb_h.func_code) { 25318b8a9b1dSJustin T. Gibbs case XPT_SCSI_IO: 2532d05caa00SKenneth D. Merry { 25333393f8daSKenneth D. Merry struct cam_ed *device; 2534d05caa00SKenneth D. Merry 25358b8a9b1dSJustin T. Gibbs /* 25368b8a9b1dSJustin T. Gibbs * For the sake of compatibility with SCSI-1 25378b8a9b1dSJustin T. Gibbs * devices that may not understand the identify 25388b8a9b1dSJustin T. Gibbs * message, we include lun information in the 25398b8a9b1dSJustin T. Gibbs * second byte of all commands. SCSI-1 specifies 25408b8a9b1dSJustin T. Gibbs * that luns are a 3 bit value and reserves only 3 25418b8a9b1dSJustin T. Gibbs * bits for lun information in the CDB. Later 25428b8a9b1dSJustin T. Gibbs * revisions of the SCSI spec allow for more than 8 25438b8a9b1dSJustin T. Gibbs * luns, but have deprecated lun information in the 25448b8a9b1dSJustin T. Gibbs * CDB. So, if the lun won't fit, we must omit. 25458b8a9b1dSJustin T. Gibbs * 25468b8a9b1dSJustin T. Gibbs * Also be aware that during initial probing for devices, 25478b8a9b1dSJustin T. Gibbs * the inquiry information is unknown but initialized to 0. 25488b8a9b1dSJustin T. Gibbs * This means that this code will be exercised while probing 25498b8a9b1dSJustin T. Gibbs * devices with an ANSI revision greater than 2. 25508b8a9b1dSJustin T. Gibbs */ 2551da396db2SAlexander Motin device = path->device; 25523393f8daSKenneth D. Merry if (device->protocol_version <= SCSI_REV_2 25538b8a9b1dSJustin T. Gibbs && start_ccb->ccb_h.target_lun < 8 25548b8a9b1dSJustin T. Gibbs && (start_ccb->ccb_h.flags & CAM_CDB_POINTER) == 0) { 25558b8a9b1dSJustin T. Gibbs 25568b8a9b1dSJustin T. Gibbs start_ccb->csio.cdb_io.cdb_bytes[1] |= 25578b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.target_lun << 5; 25588b8a9b1dSJustin T. Gibbs } 25598b8a9b1dSJustin T. Gibbs start_ccb->csio.scsi_status = SCSI_STATUS_OK; 2560d05caa00SKenneth D. Merry } 256107c6eac9SPoul-Henning Kamp /* FALLTHROUGH */ 25628b8a9b1dSJustin T. Gibbs case XPT_TARGET_IO: 25638b8a9b1dSJustin T. Gibbs case XPT_CONT_TARGET_IO: 25642cefde5fSJustin T. Gibbs start_ccb->csio.sense_resid = 0; 25652cefde5fSJustin T. Gibbs start_ccb->csio.resid = 0; 25662cefde5fSJustin T. Gibbs /* FALLTHROUGH */ 256752c9ce25SScott Long case XPT_ATA_IO: 2568de9ebb68SAlexander Motin if (start_ccb->ccb_h.func_code == XPT_ATA_IO) 256952c9ce25SScott Long start_ccb->ataio.resid = 0; 2570b882a6d3SMatt Jacob /* FALLTHROUGH */ 2571b24ced67SWarner Losh case XPT_NVME_IO: 2572b24ced67SWarner Losh if (start_ccb->ccb_h.func_code == XPT_NVME_IO) 2573b24ced67SWarner Losh start_ccb->nvmeio.resid = 0; 2574b24ced67SWarner Losh /* FALLTHROUGH */ 257510e1cf63SKenneth D. Merry case XPT_RESET_DEV: 25768b8a9b1dSJustin T. Gibbs case XPT_ENG_EXEC: 257706e79492SKenneth D. Merry case XPT_SMP_IO: 25782cefde5fSJustin T. Gibbs { 2579227d67aaSAlexander Motin struct cam_devq *devq; 25802cefde5fSJustin T. Gibbs 2581227d67aaSAlexander Motin devq = path->bus->sim->devq; 2582227d67aaSAlexander Motin mtx_lock(&devq->send_mtx); 2583227d67aaSAlexander Motin cam_ccbq_insert_ccb(&path->device->ccbq, start_ccb); 2584227d67aaSAlexander Motin if (xpt_schedule_devq(devq, path->device) != 0) 2585227d67aaSAlexander Motin xpt_run_devq(devq); 2586227d67aaSAlexander Motin mtx_unlock(&devq->send_mtx); 2587227d67aaSAlexander Motin break; 2588227d67aaSAlexander Motin } 2589227d67aaSAlexander Motin case XPT_CALC_GEOMETRY: 25908b8a9b1dSJustin T. Gibbs /* Filter out garbage */ 25918b8a9b1dSJustin T. Gibbs if (start_ccb->ccg.block_size == 0 25928b8a9b1dSJustin T. Gibbs || start_ccb->ccg.volume_size == 0) { 25938b8a9b1dSJustin T. Gibbs start_ccb->ccg.cylinders = 0; 25948b8a9b1dSJustin T. Gibbs start_ccb->ccg.heads = 0; 25958b8a9b1dSJustin T. Gibbs start_ccb->ccg.secs_per_track = 0; 25968b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.status = CAM_REQ_CMP; 25978b8a9b1dSJustin T. Gibbs break; 25988b8a9b1dSJustin T. Gibbs } 25992b375b4eSYoshihiro Takahashi #if defined(__sparc64__) 26008b8a9b1dSJustin T. Gibbs /* 2601abef0e67SMarius Strobl * For sparc64, we may need adjust the geometry of large 2602abef0e67SMarius Strobl * disks in order to fit the limitations of the 16-bit 2603abef0e67SMarius Strobl * fields of the VTOC8 disk label. 26048b8a9b1dSJustin T. Gibbs */ 26058b8a9b1dSJustin T. Gibbs if (scsi_da_bios_params(&start_ccb->ccg) != 0) { 26068b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.status = CAM_REQ_CMP; 26078b8a9b1dSJustin T. Gibbs break; 26088b8a9b1dSJustin T. Gibbs } 26098b8a9b1dSJustin T. Gibbs #endif 2610227d67aaSAlexander Motin goto call_sim; 2611bb6087e5SJustin T. Gibbs case XPT_ABORT: 26122cefde5fSJustin T. Gibbs { 26132cefde5fSJustin T. Gibbs union ccb* abort_ccb; 26142cefde5fSJustin T. Gibbs 26152cefde5fSJustin T. Gibbs abort_ccb = start_ccb->cab.abort_ccb; 26162cefde5fSJustin T. Gibbs if (XPT_FC_IS_DEV_QUEUED(abort_ccb)) { 261783c5d981SAlexander Motin struct cam_ed *device; 2618dda945f5SMark Johnston struct cam_devq *devq; 26192cefde5fSJustin T. Gibbs 262083c5d981SAlexander Motin device = abort_ccb->ccb_h.path->device; 2621dda945f5SMark Johnston devq = device->sim->devq; 2622dda945f5SMark Johnston 2623dda945f5SMark Johnston mtx_lock(&devq->send_mtx); 2624dda945f5SMark Johnston if (abort_ccb->ccb_h.pinfo.index > 0) { 2625dda945f5SMark Johnston cam_ccbq_remove_ccb(&device->ccbq, abort_ccb); 26262cefde5fSJustin T. Gibbs abort_ccb->ccb_h.status = 26272cefde5fSJustin T. Gibbs CAM_REQ_ABORTED|CAM_DEV_QFRZN; 2628dda945f5SMark Johnston xpt_freeze_devq_device(device, 1); 2629dda945f5SMark Johnston mtx_unlock(&devq->send_mtx); 26302cefde5fSJustin T. Gibbs xpt_done(abort_ccb); 26312cefde5fSJustin T. Gibbs start_ccb->ccb_h.status = CAM_REQ_CMP; 26322cefde5fSJustin T. Gibbs break; 26332cefde5fSJustin T. Gibbs } 2634dda945f5SMark Johnston mtx_unlock(&devq->send_mtx); 2635dda945f5SMark Johnston 26362cefde5fSJustin T. Gibbs if (abort_ccb->ccb_h.pinfo.index == CAM_UNQUEUED_INDEX 26372cefde5fSJustin T. Gibbs && (abort_ccb->ccb_h.status & CAM_SIM_QUEUED) == 0) { 26382cefde5fSJustin T. Gibbs /* 26392cefde5fSJustin T. Gibbs * We've caught this ccb en route to 26402cefde5fSJustin T. Gibbs * the SIM. Flag it for abort and the 26412cefde5fSJustin T. Gibbs * SIM will do so just before starting 26422cefde5fSJustin T. Gibbs * real work on the CCB. 26432cefde5fSJustin T. Gibbs */ 26442cefde5fSJustin T. Gibbs abort_ccb->ccb_h.status = 26452cefde5fSJustin T. Gibbs CAM_REQ_ABORTED|CAM_DEV_QFRZN; 26462cefde5fSJustin T. Gibbs xpt_freeze_devq(abort_ccb->ccb_h.path, 1); 26472cefde5fSJustin T. Gibbs start_ccb->ccb_h.status = CAM_REQ_CMP; 26482cefde5fSJustin T. Gibbs break; 26492cefde5fSJustin T. Gibbs } 26502cefde5fSJustin T. Gibbs } 26512cefde5fSJustin T. Gibbs if (XPT_FC_IS_QUEUED(abort_ccb) 26522cefde5fSJustin T. Gibbs && (abort_ccb->ccb_h.pinfo.index == CAM_DONEQ_INDEX)) { 26532cefde5fSJustin T. Gibbs /* 26542cefde5fSJustin T. Gibbs * It's already completed but waiting 26552cefde5fSJustin T. Gibbs * for our SWI to get to it. 26562cefde5fSJustin T. Gibbs */ 26572cefde5fSJustin T. Gibbs start_ccb->ccb_h.status = CAM_UA_ABORT; 26582cefde5fSJustin T. Gibbs break; 26592cefde5fSJustin T. Gibbs } 26602cefde5fSJustin T. Gibbs /* 26612cefde5fSJustin T. Gibbs * If we weren't able to take care of the abort request 26622cefde5fSJustin T. Gibbs * in the XPT, pass the request down to the SIM for processing. 26632cefde5fSJustin T. Gibbs */ 26642cefde5fSJustin T. Gibbs } 266507c6eac9SPoul-Henning Kamp /* FALLTHROUGH */ 26668b8a9b1dSJustin T. Gibbs case XPT_ACCEPT_TARGET_IO: 26678b8a9b1dSJustin T. Gibbs case XPT_EN_LUN: 26688b8a9b1dSJustin T. Gibbs case XPT_IMMED_NOTIFY: 26698b8a9b1dSJustin T. Gibbs case XPT_NOTIFY_ACK: 26708b8a9b1dSJustin T. Gibbs case XPT_RESET_BUS: 26712df76c16SMatt Jacob case XPT_IMMEDIATE_NOTIFY: 26722df76c16SMatt Jacob case XPT_NOTIFY_ACKNOWLEDGE: 2673a2531862SWarner Losh case XPT_GET_SIM_KNOB_OLD: 26742df76c16SMatt Jacob case XPT_GET_SIM_KNOB: 26752df76c16SMatt Jacob case XPT_SET_SIM_KNOB: 2676227d67aaSAlexander Motin case XPT_GET_TRAN_SETTINGS: 2677227d67aaSAlexander Motin case XPT_SET_TRAN_SETTINGS: 267887cfaf0eSJustin T. Gibbs case XPT_PATH_INQ: 2679227d67aaSAlexander Motin call_sim: 2680da396db2SAlexander Motin sim = path->bus->sim; 2681227d67aaSAlexander Motin lock = (mtx_owned(sim->mtx) == 0); 2682227d67aaSAlexander Motin if (lock) 2683227d67aaSAlexander Motin CAM_SIM_LOCK(sim); 268482727824SWarner Losh CAM_DEBUG(path, CAM_DEBUG_TRACE, 268582727824SWarner Losh ("sim->sim_action: func=%#x\n", start_ccb->ccb_h.func_code)); 268687cfaf0eSJustin T. Gibbs (*(sim->sim_action))(sim, start_ccb); 268782727824SWarner Losh CAM_DEBUG(path, CAM_DEBUG_TRACE, 268882727824SWarner Losh ("sim->sim_action: status=%#x\n", start_ccb->ccb_h.status)); 2689227d67aaSAlexander Motin if (lock) 2690227d67aaSAlexander Motin CAM_SIM_UNLOCK(sim); 269187cfaf0eSJustin T. Gibbs break; 269287cfaf0eSJustin T. Gibbs case XPT_PATH_STATS: 2693da396db2SAlexander Motin start_ccb->cpis.last_reset = path->bus->last_reset; 269487cfaf0eSJustin T. Gibbs start_ccb->ccb_h.status = CAM_REQ_CMP; 269587cfaf0eSJustin T. Gibbs break; 26968b8a9b1dSJustin T. Gibbs case XPT_GDEV_TYPE: 2697a5479bc5SJustin T. Gibbs { 269887cfaf0eSJustin T. Gibbs struct cam_ed *dev; 2699a5479bc5SJustin T. Gibbs 2700da396db2SAlexander Motin dev = path->device; 270187cfaf0eSJustin T. Gibbs if ((dev->flags & CAM_DEV_UNCONFIGURED) != 0) { 27028b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.status = CAM_DEV_NOT_THERE; 27038b8a9b1dSJustin T. Gibbs } else { 27048b8a9b1dSJustin T. Gibbs struct ccb_getdev *cgd; 27058b8a9b1dSJustin T. Gibbs 27068b8a9b1dSJustin T. Gibbs cgd = &start_ccb->cgd; 270752c9ce25SScott Long cgd->protocol = dev->protocol; 27088b8a9b1dSJustin T. Gibbs cgd->inq_data = dev->inq_data; 270952c9ce25SScott Long cgd->ident_data = dev->ident_data; 271030a4094fSAlexander Motin cgd->inq_flags = dev->inq_flags; 2711b24ced67SWarner Losh cgd->nvme_data = dev->nvme_data; 2712b24ced67SWarner Losh cgd->nvme_cdata = dev->nvme_cdata; 27138b8a9b1dSJustin T. Gibbs cgd->ccb_h.status = CAM_REQ_CMP; 27148b8a9b1dSJustin T. Gibbs cgd->serial_num_len = dev->serial_num_len; 27158b8a9b1dSJustin T. Gibbs if ((dev->serial_num_len > 0) 27168b8a9b1dSJustin T. Gibbs && (dev->serial_num != NULL)) 27178b8a9b1dSJustin T. Gibbs bcopy(dev->serial_num, cgd->serial_num, 27188b8a9b1dSJustin T. Gibbs dev->serial_num_len); 27198b8a9b1dSJustin T. Gibbs } 27208b8a9b1dSJustin T. Gibbs break; 2721a5479bc5SJustin T. Gibbs } 272287cfaf0eSJustin T. Gibbs case XPT_GDEV_STATS: 272387cfaf0eSJustin T. Gibbs { 272487cfaf0eSJustin T. Gibbs struct cam_ed *dev; 272587cfaf0eSJustin T. Gibbs 2726da396db2SAlexander Motin dev = path->device; 272787cfaf0eSJustin T. Gibbs if ((dev->flags & CAM_DEV_UNCONFIGURED) != 0) { 272887cfaf0eSJustin T. Gibbs start_ccb->ccb_h.status = CAM_DEV_NOT_THERE; 272987cfaf0eSJustin T. Gibbs } else { 273087cfaf0eSJustin T. Gibbs struct ccb_getdevstats *cgds; 273187cfaf0eSJustin T. Gibbs struct cam_eb *bus; 273287cfaf0eSJustin T. Gibbs struct cam_et *tar; 2733959ec258SAlexander Motin struct cam_devq *devq; 273487cfaf0eSJustin T. Gibbs 273587cfaf0eSJustin T. Gibbs cgds = &start_ccb->cgds; 2736da396db2SAlexander Motin bus = path->bus; 2737da396db2SAlexander Motin tar = path->target; 2738959ec258SAlexander Motin devq = bus->sim->devq; 2739959ec258SAlexander Motin mtx_lock(&devq->send_mtx); 274087cfaf0eSJustin T. Gibbs cgds->dev_openings = dev->ccbq.dev_openings; 274187cfaf0eSJustin T. Gibbs cgds->dev_active = dev->ccbq.dev_active; 2742959ec258SAlexander Motin cgds->allocated = dev->ccbq.allocated; 2743959ec258SAlexander Motin cgds->queued = cam_ccbq_pending_ccb_count(&dev->ccbq); 2744959ec258SAlexander Motin cgds->held = cgds->allocated - cgds->dev_active - 2745959ec258SAlexander Motin cgds->queued; 274687cfaf0eSJustin T. Gibbs cgds->last_reset = tar->last_reset; 274752c9ce25SScott Long cgds->maxtags = dev->maxtags; 274852c9ce25SScott Long cgds->mintags = dev->mintags; 274987cfaf0eSJustin T. Gibbs if (timevalcmp(&tar->last_reset, &bus->last_reset, <)) 275087cfaf0eSJustin T. Gibbs cgds->last_reset = bus->last_reset; 2751959ec258SAlexander Motin mtx_unlock(&devq->send_mtx); 275287cfaf0eSJustin T. Gibbs cgds->ccb_h.status = CAM_REQ_CMP; 275387cfaf0eSJustin T. Gibbs } 275487cfaf0eSJustin T. Gibbs break; 275587cfaf0eSJustin T. Gibbs } 27568b8a9b1dSJustin T. Gibbs case XPT_GDEVLIST: 27578b8a9b1dSJustin T. Gibbs { 27588b8a9b1dSJustin T. Gibbs struct cam_periph *nperiph; 27598b8a9b1dSJustin T. Gibbs struct periph_list *periph_head; 27608b8a9b1dSJustin T. Gibbs struct ccb_getdevlist *cgdl; 27613393f8daSKenneth D. Merry u_int i; 27628b8a9b1dSJustin T. Gibbs struct cam_ed *device; 27638b8a9b1dSJustin T. Gibbs int found; 27648b8a9b1dSJustin T. Gibbs 27658b8a9b1dSJustin T. Gibbs 27668b8a9b1dSJustin T. Gibbs found = 0; 27678b8a9b1dSJustin T. Gibbs 27688b8a9b1dSJustin T. Gibbs /* 27698b8a9b1dSJustin T. Gibbs * Don't want anyone mucking with our data. 27708b8a9b1dSJustin T. Gibbs */ 2771da396db2SAlexander Motin device = path->device; 27728b8a9b1dSJustin T. Gibbs periph_head = &device->periphs; 27738b8a9b1dSJustin T. Gibbs cgdl = &start_ccb->cgdl; 27748b8a9b1dSJustin T. Gibbs 27758b8a9b1dSJustin T. Gibbs /* 27768b8a9b1dSJustin T. Gibbs * Check and see if the list has changed since the user 27778b8a9b1dSJustin T. Gibbs * last requested a list member. If so, tell them that the 27788b8a9b1dSJustin T. Gibbs * list has changed, and therefore they need to start over 27798b8a9b1dSJustin T. Gibbs * from the beginning. 27808b8a9b1dSJustin T. Gibbs */ 27818b8a9b1dSJustin T. Gibbs if ((cgdl->index != 0) && 27828b8a9b1dSJustin T. Gibbs (cgdl->generation != device->generation)) { 27838b8a9b1dSJustin T. Gibbs cgdl->status = CAM_GDEVLIST_LIST_CHANGED; 27848b8a9b1dSJustin T. Gibbs break; 27858b8a9b1dSJustin T. Gibbs } 27868b8a9b1dSJustin T. Gibbs 27878b8a9b1dSJustin T. Gibbs /* 27888b8a9b1dSJustin T. Gibbs * Traverse the list of peripherals and attempt to find 27898b8a9b1dSJustin T. Gibbs * the requested peripheral. 27908b8a9b1dSJustin T. Gibbs */ 2791fc2ffbe6SPoul-Henning Kamp for (nperiph = SLIST_FIRST(periph_head), i = 0; 27928b8a9b1dSJustin T. Gibbs (nperiph != NULL) && (i <= cgdl->index); 2793fc2ffbe6SPoul-Henning Kamp nperiph = SLIST_NEXT(nperiph, periph_links), i++) { 27948b8a9b1dSJustin T. Gibbs if (i == cgdl->index) { 27958b8a9b1dSJustin T. Gibbs strncpy(cgdl->periph_name, 27968b8a9b1dSJustin T. Gibbs nperiph->periph_name, 27978b8a9b1dSJustin T. Gibbs DEV_IDLEN); 27988b8a9b1dSJustin T. Gibbs cgdl->unit_number = nperiph->unit_number; 27998b8a9b1dSJustin T. Gibbs found = 1; 28008b8a9b1dSJustin T. Gibbs } 28018b8a9b1dSJustin T. Gibbs } 28028b8a9b1dSJustin T. Gibbs if (found == 0) { 28038b8a9b1dSJustin T. Gibbs cgdl->status = CAM_GDEVLIST_ERROR; 28048b8a9b1dSJustin T. Gibbs break; 28058b8a9b1dSJustin T. Gibbs } 28068b8a9b1dSJustin T. Gibbs 28078b8a9b1dSJustin T. Gibbs if (nperiph == NULL) 28088b8a9b1dSJustin T. Gibbs cgdl->status = CAM_GDEVLIST_LAST_DEVICE; 28098b8a9b1dSJustin T. Gibbs else 28108b8a9b1dSJustin T. Gibbs cgdl->status = CAM_GDEVLIST_MORE_DEVS; 28118b8a9b1dSJustin T. Gibbs 28128b8a9b1dSJustin T. Gibbs cgdl->index++; 28138b8a9b1dSJustin T. Gibbs cgdl->generation = device->generation; 28148b8a9b1dSJustin T. Gibbs 28158b8a9b1dSJustin T. Gibbs cgdl->ccb_h.status = CAM_REQ_CMP; 28168b8a9b1dSJustin T. Gibbs break; 28178b8a9b1dSJustin T. Gibbs } 28188b8a9b1dSJustin T. Gibbs case XPT_DEV_MATCH: 28198b8a9b1dSJustin T. Gibbs { 28208b8a9b1dSJustin T. Gibbs dev_pos_type position_type; 28218b8a9b1dSJustin T. Gibbs struct ccb_dev_match *cdm; 28228b8a9b1dSJustin T. Gibbs 28238b8a9b1dSJustin T. Gibbs cdm = &start_ccb->cdm; 28248b8a9b1dSJustin T. Gibbs 28258b8a9b1dSJustin T. Gibbs /* 28268b8a9b1dSJustin T. Gibbs * There are two ways of getting at information in the EDT. 28278b8a9b1dSJustin T. Gibbs * The first way is via the primary EDT tree. It starts 2828db4fcadfSConrad Meyer * with a list of buses, then a list of targets on a bus, 28298b8a9b1dSJustin T. Gibbs * then devices/luns on a target, and then peripherals on a 28308b8a9b1dSJustin T. Gibbs * device/lun. The "other" way is by the peripheral driver 28318b8a9b1dSJustin T. Gibbs * lists. The peripheral driver lists are organized by 28328b8a9b1dSJustin T. Gibbs * peripheral driver. (obviously) So it makes sense to 28338b8a9b1dSJustin T. Gibbs * use the peripheral driver list if the user is looking 28348b8a9b1dSJustin T. Gibbs * for something like "da1", or all "da" devices. If the 28358b8a9b1dSJustin T. Gibbs * user is looking for something on a particular bus/target 28368b8a9b1dSJustin T. Gibbs * or lun, it's generally better to go through the EDT tree. 28378b8a9b1dSJustin T. Gibbs */ 28388b8a9b1dSJustin T. Gibbs 28398b8a9b1dSJustin T. Gibbs if (cdm->pos.position_type != CAM_DEV_POS_NONE) 28408b8a9b1dSJustin T. Gibbs position_type = cdm->pos.position_type; 28418b8a9b1dSJustin T. Gibbs else { 28423393f8daSKenneth D. Merry u_int i; 28438b8a9b1dSJustin T. Gibbs 28448b8a9b1dSJustin T. Gibbs position_type = CAM_DEV_POS_NONE; 28458b8a9b1dSJustin T. Gibbs 28468b8a9b1dSJustin T. Gibbs for (i = 0; i < cdm->num_patterns; i++) { 28478b8a9b1dSJustin T. Gibbs if ((cdm->patterns[i].type == DEV_MATCH_BUS) 28488b8a9b1dSJustin T. Gibbs ||(cdm->patterns[i].type == DEV_MATCH_DEVICE)){ 28498b8a9b1dSJustin T. Gibbs position_type = CAM_DEV_POS_EDT; 28508b8a9b1dSJustin T. Gibbs break; 28518b8a9b1dSJustin T. Gibbs } 28528b8a9b1dSJustin T. Gibbs } 28538b8a9b1dSJustin T. Gibbs 28548b8a9b1dSJustin T. Gibbs if (cdm->num_patterns == 0) 28558b8a9b1dSJustin T. Gibbs position_type = CAM_DEV_POS_EDT; 28568b8a9b1dSJustin T. Gibbs else if (position_type == CAM_DEV_POS_NONE) 28578b8a9b1dSJustin T. Gibbs position_type = CAM_DEV_POS_PDRV; 28588b8a9b1dSJustin T. Gibbs } 28598b8a9b1dSJustin T. Gibbs 28608b8a9b1dSJustin T. Gibbs switch(position_type & CAM_DEV_POS_TYPEMASK) { 28618b8a9b1dSJustin T. Gibbs case CAM_DEV_POS_EDT: 286207c6eac9SPoul-Henning Kamp xptedtmatch(cdm); 28638b8a9b1dSJustin T. Gibbs break; 28648b8a9b1dSJustin T. Gibbs case CAM_DEV_POS_PDRV: 286507c6eac9SPoul-Henning Kamp xptperiphlistmatch(cdm); 28668b8a9b1dSJustin T. Gibbs break; 28678b8a9b1dSJustin T. Gibbs default: 28688b8a9b1dSJustin T. Gibbs cdm->status = CAM_DEV_MATCH_ERROR; 28698b8a9b1dSJustin T. Gibbs break; 28708b8a9b1dSJustin T. Gibbs } 28718b8a9b1dSJustin T. Gibbs 28728b8a9b1dSJustin T. Gibbs if (cdm->status == CAM_DEV_MATCH_ERROR) 28738b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.status = CAM_REQ_CMP_ERR; 28748b8a9b1dSJustin T. Gibbs else 28758b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.status = CAM_REQ_CMP; 28768b8a9b1dSJustin T. Gibbs 28778b8a9b1dSJustin T. Gibbs break; 28788b8a9b1dSJustin T. Gibbs } 28798b8a9b1dSJustin T. Gibbs case XPT_SASYNC_CB: 28808b8a9b1dSJustin T. Gibbs { 288184f82481SScott Long struct ccb_setasync *csa; 288284f82481SScott Long struct async_node *cur_entry; 288384f82481SScott Long struct async_list *async_head; 288484f82481SScott Long u_int32_t added; 288584f82481SScott Long 288684f82481SScott Long csa = &start_ccb->csa; 288784f82481SScott Long added = csa->event_enable; 2888da396db2SAlexander Motin async_head = &path->device->asyncs; 288984f82481SScott Long 289084f82481SScott Long /* 289184f82481SScott Long * If there is already an entry for us, simply 289284f82481SScott Long * update it. 289384f82481SScott Long */ 289484f82481SScott Long cur_entry = SLIST_FIRST(async_head); 289584f82481SScott Long while (cur_entry != NULL) { 289684f82481SScott Long if ((cur_entry->callback_arg == csa->callback_arg) 289784f82481SScott Long && (cur_entry->callback == csa->callback)) 289884f82481SScott Long break; 289984f82481SScott Long cur_entry = SLIST_NEXT(cur_entry, links); 290084f82481SScott Long } 290184f82481SScott Long 290284f82481SScott Long if (cur_entry != NULL) { 290384f82481SScott Long /* 290484f82481SScott Long * If the request has no flags set, 290584f82481SScott Long * remove the entry. 290684f82481SScott Long */ 290784f82481SScott Long added &= ~cur_entry->event_enable; 290884f82481SScott Long if (csa->event_enable == 0) { 290984f82481SScott Long SLIST_REMOVE(async_head, cur_entry, 291084f82481SScott Long async_node, links); 2911da396db2SAlexander Motin xpt_release_device(path->device); 291284f82481SScott Long free(cur_entry, M_CAMXPT); 291384f82481SScott Long } else { 291484f82481SScott Long cur_entry->event_enable = csa->event_enable; 291584f82481SScott Long } 29167685edecSAlexander Motin csa->event_enable = added; 291784f82481SScott Long } else { 291884f82481SScott Long cur_entry = malloc(sizeof(*cur_entry), M_CAMXPT, 291984f82481SScott Long M_NOWAIT); 292084f82481SScott Long if (cur_entry == NULL) { 292184f82481SScott Long csa->ccb_h.status = CAM_RESRC_UNAVAIL; 292284f82481SScott Long break; 292384f82481SScott Long } 292484f82481SScott Long cur_entry->event_enable = csa->event_enable; 2925227d67aaSAlexander Motin cur_entry->event_lock = 2926227d67aaSAlexander Motin mtx_owned(path->bus->sim->mtx) ? 1 : 0; 292784f82481SScott Long cur_entry->callback_arg = csa->callback_arg; 292884f82481SScott Long cur_entry->callback = csa->callback; 292984f82481SScott Long SLIST_INSERT_HEAD(async_head, cur_entry, links); 2930da396db2SAlexander Motin xpt_acquire_device(path->device); 293184f82481SScott Long } 29328b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.status = CAM_REQ_CMP; 29338b8a9b1dSJustin T. Gibbs break; 29348b8a9b1dSJustin T. Gibbs } 29358b8a9b1dSJustin T. Gibbs case XPT_REL_SIMQ: 29368b8a9b1dSJustin T. Gibbs { 29378b8a9b1dSJustin T. Gibbs struct ccb_relsim *crs; 29388b8a9b1dSJustin T. Gibbs struct cam_ed *dev; 29398b8a9b1dSJustin T. Gibbs 29408b8a9b1dSJustin T. Gibbs crs = &start_ccb->crs; 2941da396db2SAlexander Motin dev = path->device; 29428b8a9b1dSJustin T. Gibbs if (dev == NULL) { 29438b8a9b1dSJustin T. Gibbs 29448b8a9b1dSJustin T. Gibbs crs->ccb_h.status = CAM_DEV_NOT_THERE; 29458b8a9b1dSJustin T. Gibbs break; 29468b8a9b1dSJustin T. Gibbs } 29478b8a9b1dSJustin T. Gibbs 29488b8a9b1dSJustin T. Gibbs if ((crs->release_flags & RELSIM_ADJUST_OPENINGS) != 0) { 29498b8a9b1dSJustin T. Gibbs 29508b8a9b1dSJustin T. Gibbs /* Don't ever go below one opening */ 29518b8a9b1dSJustin T. Gibbs if (crs->openings > 0) { 29527dc3213dSAlexander Motin xpt_dev_ccbq_resize(path, crs->openings); 295379ccc199SJordan K. Hubbard if (bootverbose) { 2954da396db2SAlexander Motin xpt_print(path, 29557dc3213dSAlexander Motin "number of openings is now %d\n", 29568b8a9b1dSJustin T. Gibbs crs->openings); 29578b8a9b1dSJustin T. Gibbs } 29588b8a9b1dSJustin T. Gibbs } 29598b8a9b1dSJustin T. Gibbs } 29608b8a9b1dSJustin T. Gibbs 2961227d67aaSAlexander Motin mtx_lock(&dev->sim->devq->send_mtx); 29628b8a9b1dSJustin T. Gibbs if ((crs->release_flags & RELSIM_RELEASE_AFTER_TIMEOUT) != 0) { 29638b8a9b1dSJustin T. Gibbs 29648b8a9b1dSJustin T. Gibbs if ((dev->flags & CAM_DEV_REL_TIMEOUT_PENDING) != 0) { 29658b8a9b1dSJustin T. Gibbs 29668b8a9b1dSJustin T. Gibbs /* 29678b8a9b1dSJustin T. Gibbs * Just extend the old timeout and decrement 29688b8a9b1dSJustin T. Gibbs * the freeze count so that a single timeout 29698b8a9b1dSJustin T. Gibbs * is sufficient for releasing the queue. 29708b8a9b1dSJustin T. Gibbs */ 29718b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.flags &= ~CAM_DEV_QFREEZE; 29722b83592fSScott Long callout_stop(&dev->callout); 29738b8a9b1dSJustin T. Gibbs } else { 29748b8a9b1dSJustin T. Gibbs 29758b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.flags |= CAM_DEV_QFREEZE; 29768b8a9b1dSJustin T. Gibbs } 29778b8a9b1dSJustin T. Gibbs 297885c9dd9dSSteven Hartland callout_reset_sbt(&dev->callout, 297985c9dd9dSSteven Hartland SBT_1MS * crs->release_timeout, 0, 298085c9dd9dSSteven Hartland xpt_release_devq_timeout, dev, 0); 29818b8a9b1dSJustin T. Gibbs 29828b8a9b1dSJustin T. Gibbs dev->flags |= CAM_DEV_REL_TIMEOUT_PENDING; 29838b8a9b1dSJustin T. Gibbs 29848b8a9b1dSJustin T. Gibbs } 29858b8a9b1dSJustin T. Gibbs 29868b8a9b1dSJustin T. Gibbs if ((crs->release_flags & RELSIM_RELEASE_AFTER_CMDCMPLT) != 0) { 29878b8a9b1dSJustin T. Gibbs 29888b8a9b1dSJustin T. Gibbs if ((dev->flags & CAM_DEV_REL_ON_COMPLETE) != 0) { 29898b8a9b1dSJustin T. Gibbs /* 29908b8a9b1dSJustin T. Gibbs * Decrement the freeze count so that a single 29918b8a9b1dSJustin T. Gibbs * completion is still sufficient to unfreeze 29928b8a9b1dSJustin T. Gibbs * the queue. 29938b8a9b1dSJustin T. Gibbs */ 29948b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.flags &= ~CAM_DEV_QFREEZE; 29958b8a9b1dSJustin T. Gibbs } else { 29968b8a9b1dSJustin T. Gibbs 29978b8a9b1dSJustin T. Gibbs dev->flags |= CAM_DEV_REL_ON_COMPLETE; 29988b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.flags |= CAM_DEV_QFREEZE; 29998b8a9b1dSJustin T. Gibbs } 30008b8a9b1dSJustin T. Gibbs } 30018b8a9b1dSJustin T. Gibbs 30028b8a9b1dSJustin T. Gibbs if ((crs->release_flags & RELSIM_RELEASE_AFTER_QEMPTY) != 0) { 30038b8a9b1dSJustin T. Gibbs 30048b8a9b1dSJustin T. Gibbs if ((dev->flags & CAM_DEV_REL_ON_QUEUE_EMPTY) != 0 30058b8a9b1dSJustin T. Gibbs || (dev->ccbq.dev_active == 0)) { 30068b8a9b1dSJustin T. Gibbs 30078b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.flags &= ~CAM_DEV_QFREEZE; 30088b8a9b1dSJustin T. Gibbs } else { 30098b8a9b1dSJustin T. Gibbs 30108b8a9b1dSJustin T. Gibbs dev->flags |= CAM_DEV_REL_ON_QUEUE_EMPTY; 30118b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.flags |= CAM_DEV_QFREEZE; 30128b8a9b1dSJustin T. Gibbs } 30138b8a9b1dSJustin T. Gibbs } 3014227d67aaSAlexander Motin mtx_unlock(&dev->sim->devq->send_mtx); 30158b8a9b1dSJustin T. Gibbs 3016cccf4220SAlexander Motin if ((start_ccb->ccb_h.flags & CAM_DEV_QFREEZE) == 0) 3017cccf4220SAlexander Motin xpt_release_devq(path, /*count*/1, /*run_queue*/TRUE); 3018cccf4220SAlexander Motin start_ccb->crs.qfrozen_cnt = dev->ccbq.queue.qfrozen_cnt; 30198b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.status = CAM_REQ_CMP; 30208b8a9b1dSJustin T. Gibbs break; 30218b8a9b1dSJustin T. Gibbs } 30228b8a9b1dSJustin T. Gibbs case XPT_DEBUG: { 302380d6987cSAlexander Motin struct cam_path *oldpath; 302480d6987cSAlexander Motin 3025f0f25b9cSAlexander Motin /* Check that all request bits are supported. */ 302622c7d606SAlexander Motin if (start_ccb->cdbg.flags & ~(CAM_DEBUG_COMPILE)) { 3027f0f25b9cSAlexander Motin start_ccb->ccb_h.status = CAM_FUNC_NOTAVAIL; 3028f0f25b9cSAlexander Motin break; 3029f0f25b9cSAlexander Motin } 3030f0f25b9cSAlexander Motin 303180d6987cSAlexander Motin cam_dflags = CAM_DEBUG_NONE; 30328b8a9b1dSJustin T. Gibbs if (cam_dpath != NULL) { 303380d6987cSAlexander Motin oldpath = cam_dpath; 30348b8a9b1dSJustin T. Gibbs cam_dpath = NULL; 303580d6987cSAlexander Motin xpt_free_path(oldpath); 30368b8a9b1dSJustin T. Gibbs } 303780d6987cSAlexander Motin if (start_ccb->cdbg.flags != CAM_DEBUG_NONE) { 3038e5dfa058SAlexander Motin if (xpt_create_path(&cam_dpath, NULL, 30398b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.path_id, 30408b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.target_id, 30418b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.target_lun) != 30428b8a9b1dSJustin T. Gibbs CAM_REQ_CMP) { 30438b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.status = CAM_RESRC_UNAVAIL; 3044aa872be6SMatt Jacob } else { 304580d6987cSAlexander Motin cam_dflags = start_ccb->cdbg.flags; 30468b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.status = CAM_REQ_CMP; 3047f0d9af51SMatt Jacob xpt_print(cam_dpath, "debugging flags now %x\n", 3048f0d9af51SMatt Jacob cam_dflags); 3049aa872be6SMatt Jacob } 305080d6987cSAlexander Motin } else 30518b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.status = CAM_REQ_CMP; 30528b8a9b1dSJustin T. Gibbs break; 30538b8a9b1dSJustin T. Gibbs } 30548b8a9b1dSJustin T. Gibbs case XPT_NOOP: 305587cfaf0eSJustin T. Gibbs if ((start_ccb->ccb_h.flags & CAM_DEV_QFREEZE) != 0) 3056da396db2SAlexander Motin xpt_freeze_devq(path, 1); 30578b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.status = CAM_REQ_CMP; 30588b8a9b1dSJustin T. Gibbs break; 3059d68fae58SEdward Tomasz Napierala case XPT_REPROBE_LUN: 3060d68fae58SEdward Tomasz Napierala xpt_async(AC_INQ_CHANGED, path, NULL); 3061d68fae58SEdward Tomasz Napierala start_ccb->ccb_h.status = CAM_REQ_CMP; 3062d68fae58SEdward Tomasz Napierala xpt_done(start_ccb); 3063d68fae58SEdward Tomasz Napierala break; 30648b8a9b1dSJustin T. Gibbs default: 30658b8a9b1dSJustin T. Gibbs case XPT_SDEV_TYPE: 30668b8a9b1dSJustin T. Gibbs case XPT_TERM_IO: 30678b8a9b1dSJustin T. Gibbs case XPT_ENG_INQ: 30688b8a9b1dSJustin T. Gibbs /* XXX Implement */ 3069bf1a8895SScott Long xpt_print(start_ccb->ccb_h.path, 3070bf1a8895SScott Long "%s: CCB type %#x %s not supported\n", __func__, 3071b24ced67SWarner Losh start_ccb->ccb_h.func_code, 3072b24ced67SWarner Losh xpt_action_name(start_ccb->ccb_h.func_code)); 30738b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.status = CAM_PROVIDE_FAIL; 3074b882a6d3SMatt Jacob if (start_ccb->ccb_h.func_code & XPT_FC_DEV_QUEUED) { 3075b882a6d3SMatt Jacob xpt_done(start_ccb); 3076b882a6d3SMatt Jacob } 30778b8a9b1dSJustin T. Gibbs break; 30788b8a9b1dSJustin T. Gibbs } 307969be012fSWarner Losh CAM_DEBUG(path, CAM_DEBUG_TRACE, 308069be012fSWarner Losh ("xpt_action_default: func= %#x %s status %#x\n", 308169be012fSWarner Losh start_ccb->ccb_h.func_code, 308269be012fSWarner Losh xpt_action_name(start_ccb->ccb_h.func_code), 308369be012fSWarner Losh start_ccb->ccb_h.status)); 30848b8a9b1dSJustin T. Gibbs } 30858b8a9b1dSJustin T. Gibbs 30868b8a9b1dSJustin T. Gibbs void 30878b8a9b1dSJustin T. Gibbs xpt_polled_action(union ccb *start_ccb) 30888b8a9b1dSJustin T. Gibbs { 30898b8a9b1dSJustin T. Gibbs u_int32_t timeout; 30908b8a9b1dSJustin T. Gibbs struct cam_sim *sim; 30918b8a9b1dSJustin T. Gibbs struct cam_devq *devq; 30928b8a9b1dSJustin T. Gibbs struct cam_ed *dev; 30938b8a9b1dSJustin T. Gibbs 30940069293bSAlexander Motin timeout = start_ccb->ccb_h.timeout * 10; 30958b8a9b1dSJustin T. Gibbs sim = start_ccb->ccb_h.path->bus->sim; 30968b8a9b1dSJustin T. Gibbs devq = sim->devq; 30978b8a9b1dSJustin T. Gibbs dev = start_ccb->ccb_h.path->device; 30988b8a9b1dSJustin T. Gibbs 3099227d67aaSAlexander Motin mtx_unlock(&dev->device_mtx); 31004a612489SAlexander Motin 31018b8a9b1dSJustin T. Gibbs /* 31028b8a9b1dSJustin T. Gibbs * Steal an opening so that no other queued requests 31038b8a9b1dSJustin T. Gibbs * can get it before us while we simulate interrupts. 31048b8a9b1dSJustin T. Gibbs */ 3105227d67aaSAlexander Motin mtx_lock(&devq->send_mtx); 31068b8a9b1dSJustin T. Gibbs dev->ccbq.dev_openings--; 3107227d67aaSAlexander Motin while((devq->send_openings <= 0 || dev->ccbq.dev_openings < 0) && 3108227d67aaSAlexander Motin (--timeout > 0)) { 3109227d67aaSAlexander Motin mtx_unlock(&devq->send_mtx); 31100069293bSAlexander Motin DELAY(100); 3111227d67aaSAlexander Motin CAM_SIM_LOCK(sim); 31128b8a9b1dSJustin T. Gibbs (*(sim->sim_poll))(sim); 3113227d67aaSAlexander Motin CAM_SIM_UNLOCK(sim); 3114227d67aaSAlexander Motin camisr_runqueue(); 3115227d67aaSAlexander Motin mtx_lock(&devq->send_mtx); 31168b8a9b1dSJustin T. Gibbs } 31178b8a9b1dSJustin T. Gibbs dev->ccbq.dev_openings++; 3118227d67aaSAlexander Motin mtx_unlock(&devq->send_mtx); 31198b8a9b1dSJustin T. Gibbs 31208b8a9b1dSJustin T. Gibbs if (timeout != 0) { 31218b8a9b1dSJustin T. Gibbs xpt_action(start_ccb); 31228b8a9b1dSJustin T. Gibbs while(--timeout > 0) { 3123227d67aaSAlexander Motin CAM_SIM_LOCK(sim); 31248b8a9b1dSJustin T. Gibbs (*(sim->sim_poll))(sim); 3125227d67aaSAlexander Motin CAM_SIM_UNLOCK(sim); 3126227d67aaSAlexander Motin camisr_runqueue(); 31278b8a9b1dSJustin T. Gibbs if ((start_ccb->ccb_h.status & CAM_STATUS_MASK) 31288b8a9b1dSJustin T. Gibbs != CAM_REQ_INPROG) 31298b8a9b1dSJustin T. Gibbs break; 31300069293bSAlexander Motin DELAY(100); 31318b8a9b1dSJustin T. Gibbs } 31328b8a9b1dSJustin T. Gibbs if (timeout == 0) { 31338b8a9b1dSJustin T. Gibbs /* 31348b8a9b1dSJustin T. Gibbs * XXX Is it worth adding a sim_timeout entry 31358b8a9b1dSJustin T. Gibbs * point so we can attempt recovery? If 31368b8a9b1dSJustin T. Gibbs * this is only used for dumps, I don't think 31378b8a9b1dSJustin T. Gibbs * it is. 31388b8a9b1dSJustin T. Gibbs */ 31398b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.status = CAM_CMD_TIMEOUT; 31408b8a9b1dSJustin T. Gibbs } 31418b8a9b1dSJustin T. Gibbs } else { 31428b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.status = CAM_RESRC_UNAVAIL; 31438b8a9b1dSJustin T. Gibbs } 31444a612489SAlexander Motin 3145227d67aaSAlexander Motin mtx_lock(&dev->device_mtx); 31468b8a9b1dSJustin T. Gibbs } 31478b8a9b1dSJustin T. Gibbs 31488b8a9b1dSJustin T. Gibbs /* 314921cffce5SBryan Drewery * Schedule a peripheral driver to receive a ccb when its 31508b8a9b1dSJustin T. Gibbs * target device has space for more transactions. 31518b8a9b1dSJustin T. Gibbs */ 31528b8a9b1dSJustin T. Gibbs void 3153227d67aaSAlexander Motin xpt_schedule(struct cam_periph *periph, u_int32_t new_priority) 31548b8a9b1dSJustin T. Gibbs { 31558b8a9b1dSJustin T. Gibbs 3156227d67aaSAlexander Motin CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("xpt_schedule\n")); 3157227d67aaSAlexander Motin cam_periph_assert(periph, MA_OWNED); 3158227d67aaSAlexander Motin if (new_priority < periph->scheduled_priority) { 3159227d67aaSAlexander Motin periph->scheduled_priority = new_priority; 3160227d67aaSAlexander Motin xpt_run_allocq(periph, 0); 31618b8a9b1dSJustin T. Gibbs } 31628b8a9b1dSJustin T. Gibbs } 31638b8a9b1dSJustin T. Gibbs 31648b8a9b1dSJustin T. Gibbs 31658b8a9b1dSJustin T. Gibbs /* 31668b8a9b1dSJustin T. Gibbs * Schedule a device to run on a given queue. 31678b8a9b1dSJustin T. Gibbs * If the device was inserted as a new entry on the queue, 31688b8a9b1dSJustin T. Gibbs * return 1 meaning the device queue should be run. If we 31698b8a9b1dSJustin T. Gibbs * were already queued, implying someone else has already 31708b8a9b1dSJustin T. Gibbs * started the queue, return 0 so the caller doesn't attempt 317177dc25ccSScott Long * to run the queue. 31728b8a9b1dSJustin T. Gibbs */ 3173227d67aaSAlexander Motin static int 31748b8a9b1dSJustin T. Gibbs xpt_schedule_dev(struct camq *queue, cam_pinfo *pinfo, 31758b8a9b1dSJustin T. Gibbs u_int32_t new_priority) 31768b8a9b1dSJustin T. Gibbs { 31778b8a9b1dSJustin T. Gibbs int retval; 31788b8a9b1dSJustin T. Gibbs u_int32_t old_priority; 31798b8a9b1dSJustin T. Gibbs 3180aa872be6SMatt Jacob CAM_DEBUG_PRINT(CAM_DEBUG_XPT, ("xpt_schedule_dev\n")); 31818b8a9b1dSJustin T. Gibbs 31828b8a9b1dSJustin T. Gibbs old_priority = pinfo->priority; 31838b8a9b1dSJustin T. Gibbs 31848b8a9b1dSJustin T. Gibbs /* 31858b8a9b1dSJustin T. Gibbs * Are we already queued? 31868b8a9b1dSJustin T. Gibbs */ 31878b8a9b1dSJustin T. Gibbs if (pinfo->index != CAM_UNQUEUED_INDEX) { 31888b8a9b1dSJustin T. Gibbs /* Simply reorder based on new priority */ 31898b8a9b1dSJustin T. Gibbs if (new_priority < old_priority) { 31908b8a9b1dSJustin T. Gibbs camq_change_priority(queue, pinfo->index, 31918b8a9b1dSJustin T. Gibbs new_priority); 3192aa872be6SMatt Jacob CAM_DEBUG_PRINT(CAM_DEBUG_XPT, 31938b8a9b1dSJustin T. Gibbs ("changed priority to %d\n", 31948b8a9b1dSJustin T. Gibbs new_priority)); 319583c5d981SAlexander Motin retval = 1; 319683c5d981SAlexander Motin } else 31978b8a9b1dSJustin T. Gibbs retval = 0; 31988b8a9b1dSJustin T. Gibbs } else { 31998b8a9b1dSJustin T. Gibbs /* New entry on the queue */ 32008b8a9b1dSJustin T. Gibbs if (new_priority < old_priority) 32018b8a9b1dSJustin T. Gibbs pinfo->priority = new_priority; 32028b8a9b1dSJustin T. Gibbs 3203aa872be6SMatt Jacob CAM_DEBUG_PRINT(CAM_DEBUG_XPT, 32048b8a9b1dSJustin T. Gibbs ("Inserting onto queue\n")); 32058bad620dSJustin T. Gibbs pinfo->generation = ++queue->generation; 32068b8a9b1dSJustin T. Gibbs camq_insert(queue, pinfo); 32078b8a9b1dSJustin T. Gibbs retval = 1; 32088b8a9b1dSJustin T. Gibbs } 32098b8a9b1dSJustin T. Gibbs return (retval); 32108b8a9b1dSJustin T. Gibbs } 32118b8a9b1dSJustin T. Gibbs 32128b8a9b1dSJustin T. Gibbs static void 3213227d67aaSAlexander Motin xpt_run_allocq_task(void *context, int pending) 32148b8a9b1dSJustin T. Gibbs { 3215227d67aaSAlexander Motin struct cam_periph *periph = context; 32168b8a9b1dSJustin T. Gibbs 3217227d67aaSAlexander Motin cam_periph_lock(periph); 3218227d67aaSAlexander Motin periph->flags &= ~CAM_PERIPH_RUN_TASK; 3219227d67aaSAlexander Motin xpt_run_allocq(periph, 1); 3220227d67aaSAlexander Motin cam_periph_unlock(periph); 3221227d67aaSAlexander Motin cam_periph_release(periph); 3222227d67aaSAlexander Motin } 3223227d67aaSAlexander Motin 3224227d67aaSAlexander Motin static void 3225227d67aaSAlexander Motin xpt_run_allocq(struct cam_periph *periph, int sleep) 3226227d67aaSAlexander Motin { 3227227d67aaSAlexander Motin struct cam_ed *device; 3228227d67aaSAlexander Motin union ccb *ccb; 3229227d67aaSAlexander Motin uint32_t prio; 3230227d67aaSAlexander Motin 3231227d67aaSAlexander Motin cam_periph_assert(periph, MA_OWNED); 3232227d67aaSAlexander Motin if (periph->periph_allocating) 3233cccf4220SAlexander Motin return; 3234227d67aaSAlexander Motin periph->periph_allocating = 1; 3235227d67aaSAlexander Motin CAM_DEBUG_PRINT(CAM_DEBUG_XPT, ("xpt_run_allocq(%p)\n", periph)); 3236227d67aaSAlexander Motin device = periph->path->device; 3237227d67aaSAlexander Motin ccb = NULL; 3238227d67aaSAlexander Motin restart: 3239227d67aaSAlexander Motin while ((prio = min(periph->scheduled_priority, 3240227d67aaSAlexander Motin periph->immediate_priority)) != CAM_PRIORITY_NONE && 3241227d67aaSAlexander Motin (periph->periph_allocated - (ccb != NULL ? 1 : 0) < 3242227d67aaSAlexander Motin device->ccbq.total_openings || prio <= CAM_PRIORITY_OOB)) { 3243cccf4220SAlexander Motin 3244227d67aaSAlexander Motin if (ccb == NULL && 3245227d67aaSAlexander Motin (ccb = xpt_get_ccb_nowait(periph)) == NULL) { 3246227d67aaSAlexander Motin if (sleep) { 3247227d67aaSAlexander Motin ccb = xpt_get_ccb(periph); 3248227d67aaSAlexander Motin goto restart; 3249227d67aaSAlexander Motin } 32508ec5ab3fSAlexander Motin if (periph->flags & CAM_PERIPH_RUN_TASK) 32518b8a9b1dSJustin T. Gibbs break; 3252c33e4029SAlexander Motin cam_periph_doacquire(periph); 3253227d67aaSAlexander Motin periph->flags |= CAM_PERIPH_RUN_TASK; 3254227d67aaSAlexander Motin taskqueue_enqueue(xsoftc.xpt_taskq, 3255227d67aaSAlexander Motin &periph->periph_run_task); 3256227d67aaSAlexander Motin break; 32578b8a9b1dSJustin T. Gibbs } 3258227d67aaSAlexander Motin xpt_setup_ccb(&ccb->ccb_h, periph->path, prio); 3259227d67aaSAlexander Motin if (prio == periph->immediate_priority) { 3260227d67aaSAlexander Motin periph->immediate_priority = CAM_PRIORITY_NONE; 3261227d67aaSAlexander Motin CAM_DEBUG_PRINT(CAM_DEBUG_XPT, 3262227d67aaSAlexander Motin ("waking cam_periph_getccb()\n")); 3263227d67aaSAlexander Motin SLIST_INSERT_HEAD(&periph->ccb_list, &ccb->ccb_h, 3264227d67aaSAlexander Motin periph_links.sle); 3265227d67aaSAlexander Motin wakeup(&periph->ccb_list); 3266227d67aaSAlexander Motin } else { 3267227d67aaSAlexander Motin periph->scheduled_priority = CAM_PRIORITY_NONE; 3268227d67aaSAlexander Motin CAM_DEBUG_PRINT(CAM_DEBUG_XPT, 3269227d67aaSAlexander Motin ("calling periph_start()\n")); 3270227d67aaSAlexander Motin periph->periph_start(periph, ccb); 3271227d67aaSAlexander Motin } 3272227d67aaSAlexander Motin ccb = NULL; 3273227d67aaSAlexander Motin } 3274227d67aaSAlexander Motin if (ccb != NULL) 3275227d67aaSAlexander Motin xpt_release_ccb(ccb); 3276227d67aaSAlexander Motin periph->periph_allocating = 0; 32778b8a9b1dSJustin T. Gibbs } 32788b8a9b1dSJustin T. Gibbs 327983c5d981SAlexander Motin static void 3280cccf4220SAlexander Motin xpt_run_devq(struct cam_devq *devq) 32818b8a9b1dSJustin T. Gibbs { 3282227d67aaSAlexander Motin int lock; 32838b8a9b1dSJustin T. Gibbs 3284cccf4220SAlexander Motin CAM_DEBUG_PRINT(CAM_DEBUG_XPT, ("xpt_run_devq\n")); 32858b8a9b1dSJustin T. Gibbs 3286cccf4220SAlexander Motin devq->send_queue.qfrozen_cnt++; 32878b8a9b1dSJustin T. Gibbs while ((devq->send_queue.entries > 0) 3288ec700f26SAlexander Motin && (devq->send_openings > 0) 3289cccf4220SAlexander Motin && (devq->send_queue.qfrozen_cnt <= 1)) { 32908b8a9b1dSJustin T. Gibbs struct cam_ed *device; 32918b8a9b1dSJustin T. Gibbs union ccb *work_ccb; 32928b8a9b1dSJustin T. Gibbs struct cam_sim *sim; 329308f13879SWarner Losh struct xpt_proto *proto; 32948b8a9b1dSJustin T. Gibbs 3295227d67aaSAlexander Motin device = (struct cam_ed *)camq_remove(&devq->send_queue, 32965a526431SJustin T. Gibbs CAMQ_HEAD); 3297aa872be6SMatt Jacob CAM_DEBUG_PRINT(CAM_DEBUG_XPT, 329850642f18SKenneth D. Merry ("running device %p\n", device)); 32998b8a9b1dSJustin T. Gibbs 33005a526431SJustin T. Gibbs work_ccb = cam_ccbq_peek_ccb(&device->ccbq, CAMQ_HEAD); 33018b8a9b1dSJustin T. Gibbs if (work_ccb == NULL) { 330257b89bbcSNate Lawson printf("device on run queue with no ccbs???\n"); 33038b8a9b1dSJustin T. Gibbs continue; 33048b8a9b1dSJustin T. Gibbs } 33058b8a9b1dSJustin T. Gibbs 33068b8a9b1dSJustin T. Gibbs if ((work_ccb->ccb_h.flags & CAM_HIGH_POWER) != 0) { 33078b8a9b1dSJustin T. Gibbs 3308daa5487fSAlexander Motin mtx_lock(&xsoftc.xpt_highpower_lock); 33092b83592fSScott Long if (xsoftc.num_highpower <= 0) { 33108b8a9b1dSJustin T. Gibbs /* 33118b8a9b1dSJustin T. Gibbs * We got a high power command, but we 33128b8a9b1dSJustin T. Gibbs * don't have any available slots. Freeze 33138b8a9b1dSJustin T. Gibbs * the device queue until we have a slot 33148b8a9b1dSJustin T. Gibbs * available. 33158b8a9b1dSJustin T. Gibbs */ 3316daa5487fSAlexander Motin xpt_freeze_devq_device(device, 1); 3317227d67aaSAlexander Motin STAILQ_INSERT_TAIL(&xsoftc.highpowerq, device, 3318ea541bfdSAlexander Motin highpowerq_entry); 33198b8a9b1dSJustin T. Gibbs 3320daa5487fSAlexander Motin mtx_unlock(&xsoftc.xpt_highpower_lock); 33218b8a9b1dSJustin T. Gibbs continue; 33228b8a9b1dSJustin T. Gibbs } else { 33238b8a9b1dSJustin T. Gibbs /* 33248b8a9b1dSJustin T. Gibbs * Consume a high power slot while 33258b8a9b1dSJustin T. Gibbs * this ccb runs. 33268b8a9b1dSJustin T. Gibbs */ 33272b83592fSScott Long xsoftc.num_highpower--; 33288b8a9b1dSJustin T. Gibbs } 3329daa5487fSAlexander Motin mtx_unlock(&xsoftc.xpt_highpower_lock); 33308b8a9b1dSJustin T. Gibbs } 33318b8a9b1dSJustin T. Gibbs cam_ccbq_remove_ccb(&device->ccbq, work_ccb); 33328b8a9b1dSJustin T. Gibbs cam_ccbq_send_ccb(&device->ccbq, work_ccb); 33338b8a9b1dSJustin T. Gibbs devq->send_openings--; 33348b8a9b1dSJustin T. Gibbs devq->send_active++; 3335cccf4220SAlexander Motin xpt_schedule_devq(devq, device); 3336227d67aaSAlexander Motin mtx_unlock(&devq->send_mtx); 33378b8a9b1dSJustin T. Gibbs 3338cccf4220SAlexander Motin if ((work_ccb->ccb_h.flags & CAM_DEV_QFREEZE) != 0) { 33398b8a9b1dSJustin T. Gibbs /* 33408b8a9b1dSJustin T. Gibbs * The client wants to freeze the queue 33418b8a9b1dSJustin T. Gibbs * after this CCB is sent. 33428b8a9b1dSJustin T. Gibbs */ 334383c5d981SAlexander Motin xpt_freeze_devq(work_ccb->ccb_h.path, 1); 33448b8a9b1dSJustin T. Gibbs } 33458b8a9b1dSJustin T. Gibbs 3346a4eb4f16SMatt Jacob /* In Target mode, the peripheral driver knows best... */ 3347a4eb4f16SMatt Jacob if (work_ccb->ccb_h.func_code == XPT_SCSI_IO) { 3348a4eb4f16SMatt Jacob if ((device->inq_flags & SID_CmdQue) != 0 3349a4eb4f16SMatt Jacob && work_ccb->csio.tag_action != CAM_TAG_ACTION_NONE) 33508b8a9b1dSJustin T. Gibbs work_ccb->ccb_h.flags |= CAM_TAG_ACTION_VALID; 33518b8a9b1dSJustin T. Gibbs else 33528b8a9b1dSJustin T. Gibbs /* 3353a4eb4f16SMatt Jacob * Clear this in case of a retried CCB that 3354a4eb4f16SMatt Jacob * failed due to a rejected tag. 33558b8a9b1dSJustin T. Gibbs */ 33568b8a9b1dSJustin T. Gibbs work_ccb->ccb_h.flags &= ~CAM_TAG_ACTION_VALID; 3357a4eb4f16SMatt Jacob } 33588b8a9b1dSJustin T. Gibbs 335908f13879SWarner Losh KASSERT(device == work_ccb->ccb_h.path->device, 336008f13879SWarner Losh ("device (%p) / path->device (%p) mismatch", 336108f13879SWarner Losh device, work_ccb->ccb_h.path->device)); 336208f13879SWarner Losh proto = xpt_proto_find(device->protocol); 336308f13879SWarner Losh if (proto && proto->ops->debug_out) 336408f13879SWarner Losh proto->ops->debug_out(work_ccb); 3365de9ebb68SAlexander Motin 33668b8a9b1dSJustin T. Gibbs /* 3367227d67aaSAlexander Motin * Device queues can be shared among multiple SIM instances 3368db4fcadfSConrad Meyer * that reside on different buses. Use the SIM from the 3369227d67aaSAlexander Motin * queued device, rather than the one from the calling bus. 33708b8a9b1dSJustin T. Gibbs */ 3371227d67aaSAlexander Motin sim = device->sim; 3372227d67aaSAlexander Motin lock = (mtx_owned(sim->mtx) == 0); 3373227d67aaSAlexander Motin if (lock) 3374227d67aaSAlexander Motin CAM_SIM_LOCK(sim); 3375a6e0c5daSWarner Losh work_ccb->ccb_h.qos.sim_data = sbinuptime(); // xxx uintprt_t too small 32bit platforms 33768b8a9b1dSJustin T. Gibbs (*(sim->sim_action))(sim, work_ccb); 3377227d67aaSAlexander Motin if (lock) 3378227d67aaSAlexander Motin CAM_SIM_UNLOCK(sim); 3379227d67aaSAlexander Motin mtx_lock(&devq->send_mtx); 33808b8a9b1dSJustin T. Gibbs } 3381cccf4220SAlexander Motin devq->send_queue.qfrozen_cnt--; 33828b8a9b1dSJustin T. Gibbs } 33838b8a9b1dSJustin T. Gibbs 33848b8a9b1dSJustin T. Gibbs /* 33858b8a9b1dSJustin T. Gibbs * This function merges stuff from the slave ccb into the master ccb, while 33868b8a9b1dSJustin T. Gibbs * keeping important fields in the master ccb constant. 33878b8a9b1dSJustin T. Gibbs */ 33888b8a9b1dSJustin T. Gibbs void 33898b8a9b1dSJustin T. Gibbs xpt_merge_ccb(union ccb *master_ccb, union ccb *slave_ccb) 33908b8a9b1dSJustin T. Gibbs { 339168153f43SScott Long 33928b8a9b1dSJustin T. Gibbs /* 33938b8a9b1dSJustin T. Gibbs * Pull fields that are valid for peripheral drivers to set 33948b8a9b1dSJustin T. Gibbs * into the master CCB along with the CCB "payload". 33958b8a9b1dSJustin T. Gibbs */ 33968b8a9b1dSJustin T. Gibbs master_ccb->ccb_h.retry_count = slave_ccb->ccb_h.retry_count; 33978b8a9b1dSJustin T. Gibbs master_ccb->ccb_h.func_code = slave_ccb->ccb_h.func_code; 33988b8a9b1dSJustin T. Gibbs master_ccb->ccb_h.timeout = slave_ccb->ccb_h.timeout; 33998b8a9b1dSJustin T. Gibbs master_ccb->ccb_h.flags = slave_ccb->ccb_h.flags; 34008b8a9b1dSJustin T. Gibbs bcopy(&(&slave_ccb->ccb_h)[1], &(&master_ccb->ccb_h)[1], 34018b8a9b1dSJustin T. Gibbs sizeof(union ccb) - sizeof(struct ccb_hdr)); 34028b8a9b1dSJustin T. Gibbs } 34038b8a9b1dSJustin T. Gibbs 34048b8a9b1dSJustin T. Gibbs void 3405a9934668SKenneth D. Merry xpt_setup_ccb_flags(struct ccb_hdr *ccb_h, struct cam_path *path, 3406a9934668SKenneth D. Merry u_int32_t priority, u_int32_t flags) 34078b8a9b1dSJustin T. Gibbs { 340868153f43SScott Long 34098b8a9b1dSJustin T. Gibbs CAM_DEBUG(path, CAM_DEBUG_TRACE, ("xpt_setup_ccb\n")); 34108b8a9b1dSJustin T. Gibbs ccb_h->pinfo.priority = priority; 34118b8a9b1dSJustin T. Gibbs ccb_h->path = path; 34128b8a9b1dSJustin T. Gibbs ccb_h->path_id = path->bus->path_id; 34138b8a9b1dSJustin T. Gibbs if (path->target) 34148b8a9b1dSJustin T. Gibbs ccb_h->target_id = path->target->target_id; 34158b8a9b1dSJustin T. Gibbs else 34168b8a9b1dSJustin T. Gibbs ccb_h->target_id = CAM_TARGET_WILDCARD; 34178b8a9b1dSJustin T. Gibbs if (path->device) { 34188b8a9b1dSJustin T. Gibbs ccb_h->target_lun = path->device->lun_id; 34198bad620dSJustin T. Gibbs ccb_h->pinfo.generation = ++path->device->ccbq.queue.generation; 34208b8a9b1dSJustin T. Gibbs } else { 34218b8a9b1dSJustin T. Gibbs ccb_h->target_lun = CAM_TARGET_WILDCARD; 34228b8a9b1dSJustin T. Gibbs } 34238b8a9b1dSJustin T. Gibbs ccb_h->pinfo.index = CAM_UNQUEUED_INDEX; 3424a9934668SKenneth D. Merry ccb_h->flags = flags; 3425b5595753SNathan Whitehorn ccb_h->xflags = 0; 34268b8a9b1dSJustin T. Gibbs } 34278b8a9b1dSJustin T. Gibbs 3428a9934668SKenneth D. Merry void 3429a9934668SKenneth D. Merry xpt_setup_ccb(struct ccb_hdr *ccb_h, struct cam_path *path, u_int32_t priority) 3430a9934668SKenneth D. Merry { 3431a9934668SKenneth D. Merry xpt_setup_ccb_flags(ccb_h, path, priority, /*flags*/ 0); 3432a9934668SKenneth D. Merry } 3433a9934668SKenneth D. Merry 34348b8a9b1dSJustin T. Gibbs /* Path manipulation functions */ 34358b8a9b1dSJustin T. Gibbs cam_status 34368b8a9b1dSJustin T. Gibbs xpt_create_path(struct cam_path **new_path_ptr, struct cam_periph *perph, 34378b8a9b1dSJustin T. Gibbs path_id_t path_id, target_id_t target_id, lun_id_t lun_id) 34388b8a9b1dSJustin T. Gibbs { 34398b8a9b1dSJustin T. Gibbs struct cam_path *path; 34408b8a9b1dSJustin T. Gibbs cam_status status; 34418b8a9b1dSJustin T. Gibbs 3442596ee08fSAlexander Motin path = (struct cam_path *)malloc(sizeof(*path), M_CAMPATH, M_NOWAIT); 34438b8a9b1dSJustin T. Gibbs 34448b8a9b1dSJustin T. Gibbs if (path == NULL) { 34458b8a9b1dSJustin T. Gibbs status = CAM_RESRC_UNAVAIL; 34468b8a9b1dSJustin T. Gibbs return(status); 34478b8a9b1dSJustin T. Gibbs } 34488b8a9b1dSJustin T. Gibbs status = xpt_compile_path(path, perph, path_id, target_id, lun_id); 34498b8a9b1dSJustin T. Gibbs if (status != CAM_REQ_CMP) { 3450596ee08fSAlexander Motin free(path, M_CAMPATH); 34518b8a9b1dSJustin T. Gibbs path = NULL; 34528b8a9b1dSJustin T. Gibbs } 34538b8a9b1dSJustin T. Gibbs *new_path_ptr = path; 34548b8a9b1dSJustin T. Gibbs return (status); 34558b8a9b1dSJustin T. Gibbs } 34568b8a9b1dSJustin T. Gibbs 34572b83592fSScott Long cam_status 34582b83592fSScott Long xpt_create_path_unlocked(struct cam_path **new_path_ptr, 34592b83592fSScott Long struct cam_periph *periph, path_id_t path_id, 34602b83592fSScott Long target_id_t target_id, lun_id_t lun_id) 34612b83592fSScott Long { 34622b83592fSScott Long 3463227d67aaSAlexander Motin return (xpt_create_path(new_path_ptr, periph, path_id, target_id, 3464227d67aaSAlexander Motin lun_id)); 34652b83592fSScott Long } 34662b83592fSScott Long 346752c9ce25SScott Long cam_status 34688b8a9b1dSJustin T. Gibbs xpt_compile_path(struct cam_path *new_path, struct cam_periph *perph, 34698b8a9b1dSJustin T. Gibbs path_id_t path_id, target_id_t target_id, lun_id_t lun_id) 34708b8a9b1dSJustin T. Gibbs { 34718b8a9b1dSJustin T. Gibbs struct cam_eb *bus; 34728b8a9b1dSJustin T. Gibbs struct cam_et *target; 34738b8a9b1dSJustin T. Gibbs struct cam_ed *device; 34748b8a9b1dSJustin T. Gibbs cam_status status; 34758b8a9b1dSJustin T. Gibbs 34768b8a9b1dSJustin T. Gibbs status = CAM_REQ_CMP; /* Completed without error */ 34778b8a9b1dSJustin T. Gibbs target = NULL; /* Wildcarded */ 34788b8a9b1dSJustin T. Gibbs device = NULL; /* Wildcarded */ 3479a5479bc5SJustin T. Gibbs 3480a5479bc5SJustin T. Gibbs /* 3481a5479bc5SJustin T. Gibbs * We will potentially modify the EDT, so block interrupts 3482a5479bc5SJustin T. Gibbs * that may attempt to create cam paths. 3483a5479bc5SJustin T. Gibbs */ 34848b8a9b1dSJustin T. Gibbs bus = xpt_find_bus(path_id); 34858b8a9b1dSJustin T. Gibbs if (bus == NULL) { 34868b8a9b1dSJustin T. Gibbs status = CAM_PATH_INVALID; 3487c8bead2aSJustin T. Gibbs } else { 3488227d67aaSAlexander Motin xpt_lock_buses(); 3489227d67aaSAlexander Motin mtx_lock(&bus->eb_mtx); 34908b8a9b1dSJustin T. Gibbs target = xpt_find_target(bus, target_id); 34918b8a9b1dSJustin T. Gibbs if (target == NULL) { 34928b8a9b1dSJustin T. Gibbs /* Create one */ 34938b8a9b1dSJustin T. Gibbs struct cam_et *new_target; 34948b8a9b1dSJustin T. Gibbs 34958b8a9b1dSJustin T. Gibbs new_target = xpt_alloc_target(bus, target_id); 34968b8a9b1dSJustin T. Gibbs if (new_target == NULL) { 34978b8a9b1dSJustin T. Gibbs status = CAM_RESRC_UNAVAIL; 34988b8a9b1dSJustin T. Gibbs } else { 34998b8a9b1dSJustin T. Gibbs target = new_target; 35008b8a9b1dSJustin T. Gibbs } 35018b8a9b1dSJustin T. Gibbs } 3502227d67aaSAlexander Motin xpt_unlock_buses(); 3503c8bead2aSJustin T. Gibbs if (target != NULL) { 35048b8a9b1dSJustin T. Gibbs device = xpt_find_device(target, lun_id); 35058b8a9b1dSJustin T. Gibbs if (device == NULL) { 35068b8a9b1dSJustin T. Gibbs /* Create one */ 35078b8a9b1dSJustin T. Gibbs struct cam_ed *new_device; 35088b8a9b1dSJustin T. Gibbs 350952c9ce25SScott Long new_device = 3510ded2b706SWarner Losh (*(bus->xport->ops->alloc_device))(bus, 35118b8a9b1dSJustin T. Gibbs target, 35128b8a9b1dSJustin T. Gibbs lun_id); 35138b8a9b1dSJustin T. Gibbs if (new_device == NULL) { 35148b8a9b1dSJustin T. Gibbs status = CAM_RESRC_UNAVAIL; 35158b8a9b1dSJustin T. Gibbs } else { 35168b8a9b1dSJustin T. Gibbs device = new_device; 35178b8a9b1dSJustin T. Gibbs } 35188b8a9b1dSJustin T. Gibbs } 35198b8a9b1dSJustin T. Gibbs } 3520227d67aaSAlexander Motin mtx_unlock(&bus->eb_mtx); 35218b8a9b1dSJustin T. Gibbs } 35228b8a9b1dSJustin T. Gibbs 35238b8a9b1dSJustin T. Gibbs /* 35248b8a9b1dSJustin T. Gibbs * Only touch the user's data if we are successful. 35258b8a9b1dSJustin T. Gibbs */ 35268b8a9b1dSJustin T. Gibbs if (status == CAM_REQ_CMP) { 35278b8a9b1dSJustin T. Gibbs new_path->periph = perph; 35288b8a9b1dSJustin T. Gibbs new_path->bus = bus; 35298b8a9b1dSJustin T. Gibbs new_path->target = target; 35308b8a9b1dSJustin T. Gibbs new_path->device = device; 35318b8a9b1dSJustin T. Gibbs CAM_DEBUG(new_path, CAM_DEBUG_TRACE, ("xpt_compile_path\n")); 35328b8a9b1dSJustin T. Gibbs } else { 35338b8a9b1dSJustin T. Gibbs if (device != NULL) 3534f98d7a47SAlexander Motin xpt_release_device(device); 35358b8a9b1dSJustin T. Gibbs if (target != NULL) 3536f98d7a47SAlexander Motin xpt_release_target(target); 3537a5479bc5SJustin T. Gibbs if (bus != NULL) 3538a5479bc5SJustin T. Gibbs xpt_release_bus(bus); 35398b8a9b1dSJustin T. Gibbs } 35408b8a9b1dSJustin T. Gibbs return (status); 35418b8a9b1dSJustin T. Gibbs } 35428b8a9b1dSJustin T. Gibbs 3543227d67aaSAlexander Motin cam_status 3544227d67aaSAlexander Motin xpt_clone_path(struct cam_path **new_path_ptr, struct cam_path *path) 3545227d67aaSAlexander Motin { 3546227d67aaSAlexander Motin struct cam_path *new_path; 3547227d67aaSAlexander Motin 3548227d67aaSAlexander Motin new_path = (struct cam_path *)malloc(sizeof(*path), M_CAMPATH, M_NOWAIT); 3549227d67aaSAlexander Motin if (new_path == NULL) 3550227d67aaSAlexander Motin return(CAM_RESRC_UNAVAIL); 3551227d67aaSAlexander Motin xpt_copy_path(new_path, path); 3552227d67aaSAlexander Motin *new_path_ptr = new_path; 3553227d67aaSAlexander Motin return (CAM_REQ_CMP); 3554227d67aaSAlexander Motin } 3555227d67aaSAlexander Motin 3556227d67aaSAlexander Motin void 3557227d67aaSAlexander Motin xpt_copy_path(struct cam_path *new_path, struct cam_path *path) 3558227d67aaSAlexander Motin { 3559227d67aaSAlexander Motin 3560227d67aaSAlexander Motin *new_path = *path; 3561227d67aaSAlexander Motin if (path->bus != NULL) 3562227d67aaSAlexander Motin xpt_acquire_bus(path->bus); 3563227d67aaSAlexander Motin if (path->target != NULL) 3564227d67aaSAlexander Motin xpt_acquire_target(path->target); 3565227d67aaSAlexander Motin if (path->device != NULL) 3566227d67aaSAlexander Motin xpt_acquire_device(path->device); 3567227d67aaSAlexander Motin } 3568227d67aaSAlexander Motin 356952c9ce25SScott Long void 35708b8a9b1dSJustin T. Gibbs xpt_release_path(struct cam_path *path) 35718b8a9b1dSJustin T. Gibbs { 35728b8a9b1dSJustin T. Gibbs CAM_DEBUG(path, CAM_DEBUG_TRACE, ("xpt_release_path\n")); 35739dd03ecfSJustin T. Gibbs if (path->device != NULL) { 3574f98d7a47SAlexander Motin xpt_release_device(path->device); 35759dd03ecfSJustin T. Gibbs path->device = NULL; 35769dd03ecfSJustin T. Gibbs } 35779dd03ecfSJustin T. Gibbs if (path->target != NULL) { 3578f98d7a47SAlexander Motin xpt_release_target(path->target); 35799dd03ecfSJustin T. Gibbs path->target = NULL; 35809dd03ecfSJustin T. Gibbs } 35819dd03ecfSJustin T. Gibbs if (path->bus != NULL) { 35829dd03ecfSJustin T. Gibbs xpt_release_bus(path->bus); 35839dd03ecfSJustin T. Gibbs path->bus = NULL; 35849dd03ecfSJustin T. Gibbs } 35858b8a9b1dSJustin T. Gibbs } 35868b8a9b1dSJustin T. Gibbs 35878b8a9b1dSJustin T. Gibbs void 35888b8a9b1dSJustin T. Gibbs xpt_free_path(struct cam_path *path) 35898b8a9b1dSJustin T. Gibbs { 359068153f43SScott Long 35918b8a9b1dSJustin T. Gibbs CAM_DEBUG(path, CAM_DEBUG_TRACE, ("xpt_free_path\n")); 35928b8a9b1dSJustin T. Gibbs xpt_release_path(path); 3593596ee08fSAlexander Motin free(path, M_CAMPATH); 35948b8a9b1dSJustin T. Gibbs } 35958b8a9b1dSJustin T. Gibbs 359615975b7bSMatt Jacob void 359715975b7bSMatt Jacob xpt_path_counts(struct cam_path *path, uint32_t *bus_ref, 359815975b7bSMatt Jacob uint32_t *periph_ref, uint32_t *target_ref, uint32_t *device_ref) 359915975b7bSMatt Jacob { 360015975b7bSMatt Jacob 36019a7c2696SAlexander Motin xpt_lock_buses(); 360215975b7bSMatt Jacob if (bus_ref) { 360315975b7bSMatt Jacob if (path->bus) 360415975b7bSMatt Jacob *bus_ref = path->bus->refcount; 360515975b7bSMatt Jacob else 360615975b7bSMatt Jacob *bus_ref = 0; 360715975b7bSMatt Jacob } 360815975b7bSMatt Jacob if (periph_ref) { 360915975b7bSMatt Jacob if (path->periph) 361015975b7bSMatt Jacob *periph_ref = path->periph->refcount; 361115975b7bSMatt Jacob else 361215975b7bSMatt Jacob *periph_ref = 0; 361315975b7bSMatt Jacob } 3614dcdf6e74SAlexander Motin xpt_unlock_buses(); 361515975b7bSMatt Jacob if (target_ref) { 361615975b7bSMatt Jacob if (path->target) 361715975b7bSMatt Jacob *target_ref = path->target->refcount; 361815975b7bSMatt Jacob else 361915975b7bSMatt Jacob *target_ref = 0; 362015975b7bSMatt Jacob } 362115975b7bSMatt Jacob if (device_ref) { 362215975b7bSMatt Jacob if (path->device) 362315975b7bSMatt Jacob *device_ref = path->device->refcount; 362415975b7bSMatt Jacob else 362515975b7bSMatt Jacob *device_ref = 0; 362615975b7bSMatt Jacob } 362715975b7bSMatt Jacob } 36288b8a9b1dSJustin T. Gibbs 36298b8a9b1dSJustin T. Gibbs /* 36302cefde5fSJustin T. Gibbs * Return -1 for failure, 0 for exact match, 1 for match with wildcards 36312cefde5fSJustin T. Gibbs * in path1, 2 for match with wildcards in path2. 36328b8a9b1dSJustin T. Gibbs */ 36338b8a9b1dSJustin T. Gibbs int 36348b8a9b1dSJustin T. Gibbs xpt_path_comp(struct cam_path *path1, struct cam_path *path2) 36358b8a9b1dSJustin T. Gibbs { 36368b8a9b1dSJustin T. Gibbs int retval = 0; 36378b8a9b1dSJustin T. Gibbs 36388b8a9b1dSJustin T. Gibbs if (path1->bus != path2->bus) { 36392cefde5fSJustin T. Gibbs if (path1->bus->path_id == CAM_BUS_WILDCARD) 36408b8a9b1dSJustin T. Gibbs retval = 1; 36412cefde5fSJustin T. Gibbs else if (path2->bus->path_id == CAM_BUS_WILDCARD) 36422cefde5fSJustin T. Gibbs retval = 2; 36438b8a9b1dSJustin T. Gibbs else 36448b8a9b1dSJustin T. Gibbs return (-1); 36458b8a9b1dSJustin T. Gibbs } 36468b8a9b1dSJustin T. Gibbs if (path1->target != path2->target) { 36472cefde5fSJustin T. Gibbs if (path1->target->target_id == CAM_TARGET_WILDCARD) { 36482cefde5fSJustin T. Gibbs if (retval == 0) 36498b8a9b1dSJustin T. Gibbs retval = 1; 36502cefde5fSJustin T. Gibbs } else if (path2->target->target_id == CAM_TARGET_WILDCARD) 36512cefde5fSJustin T. Gibbs retval = 2; 36528b8a9b1dSJustin T. Gibbs else 36538b8a9b1dSJustin T. Gibbs return (-1); 36548b8a9b1dSJustin T. Gibbs } 36558b8a9b1dSJustin T. Gibbs if (path1->device != path2->device) { 36562cefde5fSJustin T. Gibbs if (path1->device->lun_id == CAM_LUN_WILDCARD) { 36572cefde5fSJustin T. Gibbs if (retval == 0) 36588b8a9b1dSJustin T. Gibbs retval = 1; 36592cefde5fSJustin T. Gibbs } else if (path2->device->lun_id == CAM_LUN_WILDCARD) 36602cefde5fSJustin T. Gibbs retval = 2; 36618b8a9b1dSJustin T. Gibbs else 36628b8a9b1dSJustin T. Gibbs return (-1); 36638b8a9b1dSJustin T. Gibbs } 36648b8a9b1dSJustin T. Gibbs return (retval); 36658b8a9b1dSJustin T. Gibbs } 36668b8a9b1dSJustin T. Gibbs 36670d4f3c31SAlexander Motin int 36680d4f3c31SAlexander Motin xpt_path_comp_dev(struct cam_path *path, struct cam_ed *dev) 36690d4f3c31SAlexander Motin { 36700d4f3c31SAlexander Motin int retval = 0; 36710d4f3c31SAlexander Motin 36720d4f3c31SAlexander Motin if (path->bus != dev->target->bus) { 36730d4f3c31SAlexander Motin if (path->bus->path_id == CAM_BUS_WILDCARD) 36740d4f3c31SAlexander Motin retval = 1; 36750d4f3c31SAlexander Motin else if (dev->target->bus->path_id == CAM_BUS_WILDCARD) 36760d4f3c31SAlexander Motin retval = 2; 36770d4f3c31SAlexander Motin else 36780d4f3c31SAlexander Motin return (-1); 36790d4f3c31SAlexander Motin } 36800d4f3c31SAlexander Motin if (path->target != dev->target) { 36810d4f3c31SAlexander Motin if (path->target->target_id == CAM_TARGET_WILDCARD) { 36820d4f3c31SAlexander Motin if (retval == 0) 36830d4f3c31SAlexander Motin retval = 1; 36840d4f3c31SAlexander Motin } else if (dev->target->target_id == CAM_TARGET_WILDCARD) 36850d4f3c31SAlexander Motin retval = 2; 36860d4f3c31SAlexander Motin else 36870d4f3c31SAlexander Motin return (-1); 36880d4f3c31SAlexander Motin } 36890d4f3c31SAlexander Motin if (path->device != dev) { 36900d4f3c31SAlexander Motin if (path->device->lun_id == CAM_LUN_WILDCARD) { 36910d4f3c31SAlexander Motin if (retval == 0) 36920d4f3c31SAlexander Motin retval = 1; 36930d4f3c31SAlexander Motin } else if (dev->lun_id == CAM_LUN_WILDCARD) 36940d4f3c31SAlexander Motin retval = 2; 36950d4f3c31SAlexander Motin else 36960d4f3c31SAlexander Motin return (-1); 36970d4f3c31SAlexander Motin } 36980d4f3c31SAlexander Motin return (retval); 36990d4f3c31SAlexander Motin } 37000d4f3c31SAlexander Motin 37018b8a9b1dSJustin T. Gibbs void 37028b8a9b1dSJustin T. Gibbs xpt_print_path(struct cam_path *path) 37038b8a9b1dSJustin T. Gibbs { 3704ab3e89f1SScott Long struct sbuf sb; 3705ab3e89f1SScott Long char buffer[XPT_PRINT_LEN]; 370668153f43SScott Long 3707ab3e89f1SScott Long sbuf_new(&sb, buffer, XPT_PRINT_LEN, SBUF_FIXEDLEN); 3708ab3e89f1SScott Long xpt_path_sbuf(path, &sb); 3709ab3e89f1SScott Long sbuf_finish(&sb); 3710ab3e89f1SScott Long printf("%s", sbuf_data(&sb)); 3711ab3e89f1SScott Long sbuf_delete(&sb); 37128b8a9b1dSJustin T. Gibbs } 37138b8a9b1dSJustin T. Gibbs 3714f0d9af51SMatt Jacob void 37150d4f3c31SAlexander Motin xpt_print_device(struct cam_ed *device) 37160d4f3c31SAlexander Motin { 37170d4f3c31SAlexander Motin 37180d4f3c31SAlexander Motin if (device == NULL) 37190d4f3c31SAlexander Motin printf("(nopath): "); 37200d4f3c31SAlexander Motin else { 3721abe83505SNathan Whitehorn printf("(noperiph:%s%d:%d:%d:%jx): ", device->sim->sim_name, 37220d4f3c31SAlexander Motin device->sim->unit_number, 37230d4f3c31SAlexander Motin device->sim->bus_id, 37240d4f3c31SAlexander Motin device->target->target_id, 3725abe83505SNathan Whitehorn (uintmax_t)device->lun_id); 37260d4f3c31SAlexander Motin } 37270d4f3c31SAlexander Motin } 37280d4f3c31SAlexander Motin 37290d4f3c31SAlexander Motin void 3730f0d9af51SMatt Jacob xpt_print(struct cam_path *path, const char *fmt, ...) 3731f0d9af51SMatt Jacob { 3732f0d9af51SMatt Jacob va_list ap; 3733ab3e89f1SScott Long struct sbuf sb; 3734a136ca54SScott Long char buffer[XPT_PRINT_LEN]; 3735ab3e89f1SScott Long 3736a136ca54SScott Long sbuf_new(&sb, buffer, XPT_PRINT_LEN, SBUF_FIXEDLEN); 3737ab3e89f1SScott Long 3738ab3e89f1SScott Long xpt_path_sbuf(path, &sb); 3739f0d9af51SMatt Jacob va_start(ap, fmt); 3740ab3e89f1SScott Long sbuf_vprintf(&sb, fmt, ap); 3741f0d9af51SMatt Jacob va_end(ap); 3742ab3e89f1SScott Long 3743ab3e89f1SScott Long sbuf_finish(&sb); 3744ab3e89f1SScott Long printf("%s", sbuf_data(&sb)); 3745ab3e89f1SScott Long sbuf_delete(&sb); 3746f0d9af51SMatt Jacob } 3747f0d9af51SMatt Jacob 37483393f8daSKenneth D. Merry int 37493393f8daSKenneth D. Merry xpt_path_string(struct cam_path *path, char *str, size_t str_len) 37503393f8daSKenneth D. Merry { 37513393f8daSKenneth D. Merry struct sbuf sb; 3752ab3e89f1SScott Long int len; 37533393f8daSKenneth D. Merry 37543393f8daSKenneth D. Merry sbuf_new(&sb, str, str_len, 0); 3755ab3e89f1SScott Long len = xpt_path_sbuf(path, &sb); 3756ab3e89f1SScott Long sbuf_finish(&sb); 3757ab3e89f1SScott Long return (len); 3758ab3e89f1SScott Long } 3759ab3e89f1SScott Long 3760ab3e89f1SScott Long int 3761ab3e89f1SScott Long xpt_path_sbuf(struct cam_path *path, struct sbuf *sb) 3762ab3e89f1SScott Long { 37633393f8daSKenneth D. Merry 37643393f8daSKenneth D. Merry if (path == NULL) 3765ab3e89f1SScott Long sbuf_printf(sb, "(nopath): "); 37663393f8daSKenneth D. Merry else { 37673393f8daSKenneth D. Merry if (path->periph != NULL) 3768ab3e89f1SScott Long sbuf_printf(sb, "(%s%d:", path->periph->periph_name, 37693393f8daSKenneth D. Merry path->periph->unit_number); 37703393f8daSKenneth D. Merry else 3771ab3e89f1SScott Long sbuf_printf(sb, "(noperiph:"); 37723393f8daSKenneth D. Merry 37733393f8daSKenneth D. Merry if (path->bus != NULL) 3774ab3e89f1SScott Long sbuf_printf(sb, "%s%d:%d:", path->bus->sim->sim_name, 37753393f8daSKenneth D. Merry path->bus->sim->unit_number, 37763393f8daSKenneth D. Merry path->bus->sim->bus_id); 37773393f8daSKenneth D. Merry else 3778ab3e89f1SScott Long sbuf_printf(sb, "nobus:"); 37793393f8daSKenneth D. Merry 37803393f8daSKenneth D. Merry if (path->target != NULL) 3781ab3e89f1SScott Long sbuf_printf(sb, "%d:", path->target->target_id); 37823393f8daSKenneth D. Merry else 3783ab3e89f1SScott Long sbuf_printf(sb, "X:"); 37843393f8daSKenneth D. Merry 37853393f8daSKenneth D. Merry if (path->device != NULL) 3786ab3e89f1SScott Long sbuf_printf(sb, "%jx): ", 3787abe83505SNathan Whitehorn (uintmax_t)path->device->lun_id); 37883393f8daSKenneth D. Merry else 3789ab3e89f1SScott Long sbuf_printf(sb, "X): "); 37903393f8daSKenneth D. Merry } 37913393f8daSKenneth D. Merry 3792ab3e89f1SScott Long return(sbuf_len(sb)); 37933393f8daSKenneth D. Merry } 37943393f8daSKenneth D. Merry 37958b8a9b1dSJustin T. Gibbs path_id_t 37968b8a9b1dSJustin T. Gibbs xpt_path_path_id(struct cam_path *path) 37978b8a9b1dSJustin T. Gibbs { 37988b8a9b1dSJustin T. Gibbs return(path->bus->path_id); 37998b8a9b1dSJustin T. Gibbs } 38008b8a9b1dSJustin T. Gibbs 38018b8a9b1dSJustin T. Gibbs target_id_t 38028b8a9b1dSJustin T. Gibbs xpt_path_target_id(struct cam_path *path) 38038b8a9b1dSJustin T. Gibbs { 38048b8a9b1dSJustin T. Gibbs if (path->target != NULL) 38058b8a9b1dSJustin T. Gibbs return (path->target->target_id); 38068b8a9b1dSJustin T. Gibbs else 38078b8a9b1dSJustin T. Gibbs return (CAM_TARGET_WILDCARD); 38088b8a9b1dSJustin T. Gibbs } 38098b8a9b1dSJustin T. Gibbs 38108b8a9b1dSJustin T. Gibbs lun_id_t 38118b8a9b1dSJustin T. Gibbs xpt_path_lun_id(struct cam_path *path) 38128b8a9b1dSJustin T. Gibbs { 38138b8a9b1dSJustin T. Gibbs if (path->device != NULL) 38148b8a9b1dSJustin T. Gibbs return (path->device->lun_id); 38158b8a9b1dSJustin T. Gibbs else 38168b8a9b1dSJustin T. Gibbs return (CAM_LUN_WILDCARD); 38178b8a9b1dSJustin T. Gibbs } 38188b8a9b1dSJustin T. Gibbs 38198b8a9b1dSJustin T. Gibbs struct cam_sim * 38208b8a9b1dSJustin T. Gibbs xpt_path_sim(struct cam_path *path) 38218b8a9b1dSJustin T. Gibbs { 382268153f43SScott Long 38238b8a9b1dSJustin T. Gibbs return (path->bus->sim); 38248b8a9b1dSJustin T. Gibbs } 38258b8a9b1dSJustin T. Gibbs 38268b8a9b1dSJustin T. Gibbs struct cam_periph* 38278b8a9b1dSJustin T. Gibbs xpt_path_periph(struct cam_path *path) 38288b8a9b1dSJustin T. Gibbs { 382968153f43SScott Long 38308b8a9b1dSJustin T. Gibbs return (path->periph); 38318b8a9b1dSJustin T. Gibbs } 38328b8a9b1dSJustin T. Gibbs 38338b8a9b1dSJustin T. Gibbs /* 38348b8a9b1dSJustin T. Gibbs * Release a CAM control block for the caller. Remit the cost of the structure 38358b8a9b1dSJustin T. Gibbs * to the device referenced by the path. If the this device had no 'credits' 38368b8a9b1dSJustin T. Gibbs * and peripheral drivers have registered async callbacks for this notification 38378b8a9b1dSJustin T. Gibbs * call them now. 38388b8a9b1dSJustin T. Gibbs */ 38398b8a9b1dSJustin T. Gibbs void 38408b8a9b1dSJustin T. Gibbs xpt_release_ccb(union ccb *free_ccb) 38418b8a9b1dSJustin T. Gibbs { 38428b8a9b1dSJustin T. Gibbs struct cam_ed *device; 3843227d67aaSAlexander Motin struct cam_periph *periph; 384468153f43SScott Long 3845aa872be6SMatt Jacob CAM_DEBUG_PRINT(CAM_DEBUG_XPT, ("xpt_release_ccb\n")); 3846227d67aaSAlexander Motin xpt_path_assert(free_ccb->ccb_h.path, MA_OWNED); 3847227d67aaSAlexander Motin device = free_ccb->ccb_h.path->device; 3848227d67aaSAlexander Motin periph = free_ccb->ccb_h.path->periph; 38492b83592fSScott Long 38508b8a9b1dSJustin T. Gibbs xpt_free_ccb(free_ccb); 3851227d67aaSAlexander Motin periph->periph_allocated--; 3852227d67aaSAlexander Motin cam_ccbq_release_opening(&device->ccbq); 3853227d67aaSAlexander Motin xpt_run_allocq(periph, 0); 38548b8a9b1dSJustin T. Gibbs } 38558b8a9b1dSJustin T. Gibbs 38568b8a9b1dSJustin T. Gibbs /* Functions accessed by SIM drivers */ 38578b8a9b1dSJustin T. Gibbs 3858ded2b706SWarner Losh static struct xpt_xport_ops xport_default_ops = { 385952c9ce25SScott Long .alloc_device = xpt_alloc_device_default, 386052c9ce25SScott Long .action = xpt_action_default, 386152c9ce25SScott Long .async = xpt_dev_async_default, 386252c9ce25SScott Long }; 3863ded2b706SWarner Losh static struct xpt_xport xport_default = { 3864ded2b706SWarner Losh .xport = XPORT_UNKNOWN, 3865ded2b706SWarner Losh .name = "unknown", 3866ded2b706SWarner Losh .ops = &xport_default_ops, 3867ded2b706SWarner Losh }; 3868ded2b706SWarner Losh 3869ded2b706SWarner Losh CAM_XPT_XPORT(xport_default); 387052c9ce25SScott Long 38718b8a9b1dSJustin T. Gibbs /* 38728b8a9b1dSJustin T. Gibbs * A sim structure, listing the SIM entry points and instance 38738b8a9b1dSJustin T. Gibbs * identification info is passed to xpt_bus_register to hook the SIM 38748b8a9b1dSJustin T. Gibbs * into the CAM framework. xpt_bus_register creates a cam_eb entry 3875db4fcadfSConrad Meyer * for this new bus and places it in the array of buses and assigns 38768b8a9b1dSJustin T. Gibbs * it a path_id. The path_id may be influenced by "hard wiring" 38778b8a9b1dSJustin T. Gibbs * information specified by the user. Once interrupt services are 387802caf36eSEdward Tomasz Napierala * available, the bus will be probed. 38798b8a9b1dSJustin T. Gibbs */ 38808b8a9b1dSJustin T. Gibbs int32_t 3881b50569b7SScott Long xpt_bus_register(struct cam_sim *sim, device_t parent, u_int32_t bus) 38828b8a9b1dSJustin T. Gibbs { 38838b8a9b1dSJustin T. Gibbs struct cam_eb *new_bus; 3884434bbf6eSJustin T. Gibbs struct cam_eb *old_bus; 38858b8a9b1dSJustin T. Gibbs struct ccb_pathinq cpi; 388683c5d981SAlexander Motin struct cam_path *path; 388752c9ce25SScott Long cam_status status; 38888b8a9b1dSJustin T. Gibbs 38892b83592fSScott Long mtx_assert(sim->mtx, MA_OWNED); 389068153f43SScott Long 38918b8a9b1dSJustin T. Gibbs sim->bus_id = bus; 38928b8a9b1dSJustin T. Gibbs new_bus = (struct cam_eb *)malloc(sizeof(*new_bus), 3893227d67aaSAlexander Motin M_CAMXPT, M_NOWAIT|M_ZERO); 38948b8a9b1dSJustin T. Gibbs if (new_bus == NULL) { 38958b8a9b1dSJustin T. Gibbs /* Couldn't satisfy request */ 38968b8a9b1dSJustin T. Gibbs return (CAM_RESRC_UNAVAIL); 38978b8a9b1dSJustin T. Gibbs } 38988b8a9b1dSJustin T. Gibbs 3899227d67aaSAlexander Motin mtx_init(&new_bus->eb_mtx, "CAM bus lock", NULL, MTX_DEF); 3900434bbf6eSJustin T. Gibbs TAILQ_INIT(&new_bus->et_entries); 3901fa6099fdSEdward Tomasz Napierala cam_sim_hold(sim); 39028b8a9b1dSJustin T. Gibbs new_bus->sim = sim; 390387cfaf0eSJustin T. Gibbs timevalclear(&new_bus->last_reset); 3904434bbf6eSJustin T. Gibbs new_bus->flags = 0; 3905a5479bc5SJustin T. Gibbs new_bus->refcount = 1; /* Held until a bus_deregister event */ 3906434bbf6eSJustin T. Gibbs new_bus->generation = 0; 390752c9ce25SScott Long 39089a7c2696SAlexander Motin xpt_lock_buses(); 39096dfc67e3SAlexander Motin sim->path_id = new_bus->path_id = 39106dfc67e3SAlexander Motin xptpathid(sim->sim_name, sim->unit_number, sim->bus_id); 39112b83592fSScott Long old_bus = TAILQ_FIRST(&xsoftc.xpt_busses); 3912434bbf6eSJustin T. Gibbs while (old_bus != NULL 3913434bbf6eSJustin T. Gibbs && old_bus->path_id < new_bus->path_id) 3914434bbf6eSJustin T. Gibbs old_bus = TAILQ_NEXT(old_bus, links); 3915434bbf6eSJustin T. Gibbs if (old_bus != NULL) 3916434bbf6eSJustin T. Gibbs TAILQ_INSERT_BEFORE(old_bus, new_bus, links); 3917434bbf6eSJustin T. Gibbs else 39182b83592fSScott Long TAILQ_INSERT_TAIL(&xsoftc.xpt_busses, new_bus, links); 39192b83592fSScott Long xsoftc.bus_generation++; 39209a7c2696SAlexander Motin xpt_unlock_buses(); 39218b8a9b1dSJustin T. Gibbs 392252c9ce25SScott Long /* 392352c9ce25SScott Long * Set a default transport so that a PATH_INQ can be issued to 392452c9ce25SScott Long * the SIM. This will then allow for probing and attaching of 392552c9ce25SScott Long * a more appropriate transport. 392652c9ce25SScott Long */ 392752c9ce25SScott Long new_bus->xport = &xport_default; 39288b8a9b1dSJustin T. Gibbs 392932aa80a6SAlexander Motin status = xpt_create_path(&path, /*periph*/NULL, sim->path_id, 39308b8a9b1dSJustin T. Gibbs CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD); 3931627995dcSAlexander Motin if (status != CAM_REQ_CMP) { 3932627995dcSAlexander Motin xpt_release_bus(new_bus); 3933627995dcSAlexander Motin free(path, M_CAMXPT); 3934627995dcSAlexander Motin return (CAM_RESRC_UNAVAIL); 3935627995dcSAlexander Motin } 393652c9ce25SScott Long 393783c5d981SAlexander Motin xpt_setup_ccb(&cpi.ccb_h, path, CAM_PRIORITY_NORMAL); 39388b8a9b1dSJustin T. Gibbs cpi.ccb_h.func_code = XPT_PATH_INQ; 39398b8a9b1dSJustin T. Gibbs xpt_action((union ccb *)&cpi); 394052c9ce25SScott Long 394152c9ce25SScott Long if (cpi.ccb_h.status == CAM_REQ_CMP) { 3942ded2b706SWarner Losh struct xpt_xport **xpt; 3943ded2b706SWarner Losh 3944ded2b706SWarner Losh SET_FOREACH(xpt, cam_xpt_xport_set) { 3945ded2b706SWarner Losh if ((*xpt)->xport == cpi.transport) { 3946ded2b706SWarner Losh new_bus->xport = *xpt; 394752c9ce25SScott Long break; 3948ded2b706SWarner Losh } 3949ded2b706SWarner Losh } 3950ded2b706SWarner Losh if (new_bus->xport == NULL) { 3951bf1a8895SScott Long xpt_print(path, 3952bf1a8895SScott Long "No transport found for %d\n", cpi.transport); 3953ded2b706SWarner Losh xpt_release_bus(new_bus); 3954ded2b706SWarner Losh free(path, M_CAMXPT); 3955ded2b706SWarner Losh return (CAM_RESRC_UNAVAIL); 39568b8a9b1dSJustin T. Gibbs } 395752c9ce25SScott Long } 395852c9ce25SScott Long 395952c9ce25SScott Long /* Notify interested parties */ 396052c9ce25SScott Long if (sim->path_id != CAM_XPT_PATH_ID) { 396183c5d981SAlexander Motin 396283c5d981SAlexander Motin xpt_async(AC_PATH_REGISTERED, path, &cpi); 3963b01773b0SKenneth D. Merry if ((cpi.hba_misc & PIM_NOSCAN) == 0) { 3964b01773b0SKenneth D. Merry union ccb *scan_ccb; 3965b01773b0SKenneth D. Merry 396683c5d981SAlexander Motin /* Initiate bus rescan. */ 396783c5d981SAlexander Motin scan_ccb = xpt_alloc_ccb_nowait(); 3968e5736ac8SAlexander Motin if (scan_ccb != NULL) { 396983c5d981SAlexander Motin scan_ccb->ccb_h.path = path; 397083c5d981SAlexander Motin scan_ccb->ccb_h.func_code = XPT_SCAN_BUS; 397183c5d981SAlexander Motin scan_ccb->crcn.flags = 0; 397283c5d981SAlexander Motin xpt_rescan(scan_ccb); 39737f7aacb4SAlexander Motin } else { 3974b01773b0SKenneth D. Merry xpt_print(path, 3975b01773b0SKenneth D. Merry "Can't allocate CCB to scan bus\n"); 39767f7aacb4SAlexander Motin xpt_free_path(path); 39777f7aacb4SAlexander Motin } 3978b01773b0SKenneth D. Merry } else 3979b01773b0SKenneth D. Merry xpt_free_path(path); 3980e5736ac8SAlexander Motin } else 398183c5d981SAlexander Motin xpt_free_path(path); 39828b8a9b1dSJustin T. Gibbs return (CAM_SUCCESS); 39838b8a9b1dSJustin T. Gibbs } 39848b8a9b1dSJustin T. Gibbs 3985434bbf6eSJustin T. Gibbs int32_t 3986434bbf6eSJustin T. Gibbs xpt_bus_deregister(path_id_t pathid) 39878b8a9b1dSJustin T. Gibbs { 3988434bbf6eSJustin T. Gibbs struct cam_path bus_path; 3989434bbf6eSJustin T. Gibbs cam_status status; 3990434bbf6eSJustin T. Gibbs 3991434bbf6eSJustin T. Gibbs status = xpt_compile_path(&bus_path, NULL, pathid, 3992434bbf6eSJustin T. Gibbs CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD); 3993434bbf6eSJustin T. Gibbs if (status != CAM_REQ_CMP) 3994434bbf6eSJustin T. Gibbs return (status); 3995434bbf6eSJustin T. Gibbs 3996434bbf6eSJustin T. Gibbs xpt_async(AC_LOST_DEVICE, &bus_path, NULL); 3997434bbf6eSJustin T. Gibbs xpt_async(AC_PATH_DEREGISTERED, &bus_path, NULL); 3998434bbf6eSJustin T. Gibbs 3999434bbf6eSJustin T. Gibbs /* Release the reference count held while registered. */ 4000434bbf6eSJustin T. Gibbs xpt_release_bus(bus_path.bus); 4001434bbf6eSJustin T. Gibbs xpt_release_path(&bus_path); 4002434bbf6eSJustin T. Gibbs 4003434bbf6eSJustin T. Gibbs return (CAM_REQ_CMP); 4004434bbf6eSJustin T. Gibbs } 4005434bbf6eSJustin T. Gibbs 4006434bbf6eSJustin T. Gibbs static path_id_t 4007434bbf6eSJustin T. Gibbs xptnextfreepathid(void) 4008434bbf6eSJustin T. Gibbs { 4009434bbf6eSJustin T. Gibbs struct cam_eb *bus; 4010434bbf6eSJustin T. Gibbs path_id_t pathid; 40112398f0cdSPeter Wemm const char *strval; 40128b8a9b1dSJustin T. Gibbs 40136dfc67e3SAlexander Motin mtx_assert(&xsoftc.xpt_topo_lock, MA_OWNED); 4014434bbf6eSJustin T. Gibbs pathid = 0; 40152b83592fSScott Long bus = TAILQ_FIRST(&xsoftc.xpt_busses); 4016434bbf6eSJustin T. Gibbs retry: 4017434bbf6eSJustin T. Gibbs /* Find an unoccupied pathid */ 40189e6461a2SMatt Jacob while (bus != NULL && bus->path_id <= pathid) { 4019434bbf6eSJustin T. Gibbs if (bus->path_id == pathid) 4020434bbf6eSJustin T. Gibbs pathid++; 4021434bbf6eSJustin T. Gibbs bus = TAILQ_NEXT(bus, links); 4022434bbf6eSJustin T. Gibbs } 4023434bbf6eSJustin T. Gibbs 4024434bbf6eSJustin T. Gibbs /* 4025434bbf6eSJustin T. Gibbs * Ensure that this pathid is not reserved for 4026434bbf6eSJustin T. Gibbs * a bus that may be registered in the future. 4027434bbf6eSJustin T. Gibbs */ 402875f51904SPeter Wemm if (resource_string_value("scbus", pathid, "at", &strval) == 0) { 4029434bbf6eSJustin T. Gibbs ++pathid; 40308b8a9b1dSJustin T. Gibbs /* Start the search over */ 4031434bbf6eSJustin T. Gibbs goto retry; 40328b8a9b1dSJustin T. Gibbs } 4033434bbf6eSJustin T. Gibbs return (pathid); 40348b8a9b1dSJustin T. Gibbs } 40358b8a9b1dSJustin T. Gibbs 4036434bbf6eSJustin T. Gibbs static path_id_t 4037434bbf6eSJustin T. Gibbs xptpathid(const char *sim_name, int sim_unit, int sim_bus) 40388b8a9b1dSJustin T. Gibbs { 40398b8a9b1dSJustin T. Gibbs path_id_t pathid; 404075f51904SPeter Wemm int i, dunit, val; 4041642f0c46SPeter Wemm char buf[32]; 40422398f0cdSPeter Wemm const char *dname; 40438b8a9b1dSJustin T. Gibbs 40448b8a9b1dSJustin T. Gibbs pathid = CAM_XPT_PATH_ID; 404575f51904SPeter Wemm snprintf(buf, sizeof(buf), "%s%d", sim_name, sim_unit); 40466dfc67e3SAlexander Motin if (strcmp(buf, "xpt0") == 0 && sim_bus == 0) 40476dfc67e3SAlexander Motin return (pathid); 40482398f0cdSPeter Wemm i = 0; 40492398f0cdSPeter Wemm while ((resource_find_match(&i, &dname, &dunit, "at", buf)) == 0) { 40502398f0cdSPeter Wemm if (strcmp(dname, "scbus")) { 4051642f0c46SPeter Wemm /* Avoid a bit of foot shooting. */ 4052642f0c46SPeter Wemm continue; 4053642f0c46SPeter Wemm } 405475f51904SPeter Wemm if (dunit < 0) /* unwired?! */ 40558b8a9b1dSJustin T. Gibbs continue; 405675f51904SPeter Wemm if (resource_int_value("scbus", dunit, "bus", &val) == 0) { 405775f51904SPeter Wemm if (sim_bus == val) { 405875f51904SPeter Wemm pathid = dunit; 40598b8a9b1dSJustin T. Gibbs break; 40608b8a9b1dSJustin T. Gibbs } 40618b8a9b1dSJustin T. Gibbs } else if (sim_bus == 0) { 40628b8a9b1dSJustin T. Gibbs /* Unspecified matches bus 0 */ 406375f51904SPeter Wemm pathid = dunit; 40648b8a9b1dSJustin T. Gibbs break; 40658b8a9b1dSJustin T. Gibbs } else { 40668b8a9b1dSJustin T. Gibbs printf("Ambiguous scbus configuration for %s%d " 40678b8a9b1dSJustin T. Gibbs "bus %d, cannot wire down. The kernel " 40688b8a9b1dSJustin T. Gibbs "config entry for scbus%d should " 40698b8a9b1dSJustin T. Gibbs "specify a controller bus.\n" 40708b8a9b1dSJustin T. Gibbs "Scbus will be assigned dynamically.\n", 407175f51904SPeter Wemm sim_name, sim_unit, sim_bus, dunit); 40728b8a9b1dSJustin T. Gibbs break; 40738b8a9b1dSJustin T. Gibbs } 40748b8a9b1dSJustin T. Gibbs } 40758b8a9b1dSJustin T. Gibbs 4076434bbf6eSJustin T. Gibbs if (pathid == CAM_XPT_PATH_ID) 4077434bbf6eSJustin T. Gibbs pathid = xptnextfreepathid(); 40788b8a9b1dSJustin T. Gibbs return (pathid); 40798b8a9b1dSJustin T. Gibbs } 40808b8a9b1dSJustin T. Gibbs 408122c7d606SAlexander Motin static const char * 408222c7d606SAlexander Motin xpt_async_string(u_int32_t async_code) 408322c7d606SAlexander Motin { 408422c7d606SAlexander Motin 408522c7d606SAlexander Motin switch (async_code) { 408622c7d606SAlexander Motin case AC_BUS_RESET: return ("AC_BUS_RESET"); 408722c7d606SAlexander Motin case AC_UNSOL_RESEL: return ("AC_UNSOL_RESEL"); 408822c7d606SAlexander Motin case AC_SCSI_AEN: return ("AC_SCSI_AEN"); 408922c7d606SAlexander Motin case AC_SENT_BDR: return ("AC_SENT_BDR"); 409022c7d606SAlexander Motin case AC_PATH_REGISTERED: return ("AC_PATH_REGISTERED"); 409122c7d606SAlexander Motin case AC_PATH_DEREGISTERED: return ("AC_PATH_DEREGISTERED"); 409222c7d606SAlexander Motin case AC_FOUND_DEVICE: return ("AC_FOUND_DEVICE"); 409322c7d606SAlexander Motin case AC_LOST_DEVICE: return ("AC_LOST_DEVICE"); 409422c7d606SAlexander Motin case AC_TRANSFER_NEG: return ("AC_TRANSFER_NEG"); 409522c7d606SAlexander Motin case AC_INQ_CHANGED: return ("AC_INQ_CHANGED"); 409622c7d606SAlexander Motin case AC_GETDEV_CHANGED: return ("AC_GETDEV_CHANGED"); 409722c7d606SAlexander Motin case AC_CONTRACT: return ("AC_CONTRACT"); 409822c7d606SAlexander Motin case AC_ADVINFO_CHANGED: return ("AC_ADVINFO_CHANGED"); 40993631c638SAlexander Motin case AC_UNIT_ATTENTION: return ("AC_UNIT_ATTENTION"); 410022c7d606SAlexander Motin } 410122c7d606SAlexander Motin return ("AC_UNKNOWN"); 410222c7d606SAlexander Motin } 410322c7d606SAlexander Motin 4104227d67aaSAlexander Motin static int 4105227d67aaSAlexander Motin xpt_async_size(u_int32_t async_code) 41068b8a9b1dSJustin T. Gibbs { 41078b8a9b1dSJustin T. Gibbs 4108227d67aaSAlexander Motin switch (async_code) { 4109227d67aaSAlexander Motin case AC_BUS_RESET: return (0); 4110227d67aaSAlexander Motin case AC_UNSOL_RESEL: return (0); 4111227d67aaSAlexander Motin case AC_SCSI_AEN: return (0); 4112227d67aaSAlexander Motin case AC_SENT_BDR: return (0); 4113227d67aaSAlexander Motin case AC_PATH_REGISTERED: return (sizeof(struct ccb_pathinq)); 4114227d67aaSAlexander Motin case AC_PATH_DEREGISTERED: return (0); 4115227d67aaSAlexander Motin case AC_FOUND_DEVICE: return (sizeof(struct ccb_getdev)); 4116227d67aaSAlexander Motin case AC_LOST_DEVICE: return (0); 4117227d67aaSAlexander Motin case AC_TRANSFER_NEG: return (sizeof(struct ccb_trans_settings)); 4118227d67aaSAlexander Motin case AC_INQ_CHANGED: return (0); 4119227d67aaSAlexander Motin case AC_GETDEV_CHANGED: return (0); 4120227d67aaSAlexander Motin case AC_CONTRACT: return (sizeof(struct ac_contract)); 4121227d67aaSAlexander Motin case AC_ADVINFO_CHANGED: return (-1); 4122227d67aaSAlexander Motin case AC_UNIT_ATTENTION: return (sizeof(struct ccb_scsiio)); 4123227d67aaSAlexander Motin } 4124227d67aaSAlexander Motin return (0); 4125227d67aaSAlexander Motin } 4126227d67aaSAlexander Motin 4127227d67aaSAlexander Motin static int 4128227d67aaSAlexander Motin xpt_async_process_dev(struct cam_ed *device, void *arg) 4129227d67aaSAlexander Motin { 4130227d67aaSAlexander Motin union ccb *ccb = arg; 4131227d67aaSAlexander Motin struct cam_path *path = ccb->ccb_h.path; 4132227d67aaSAlexander Motin void *async_arg = ccb->casync.async_arg_ptr; 4133227d67aaSAlexander Motin u_int32_t async_code = ccb->casync.async_code; 4134227d67aaSAlexander Motin int relock; 4135227d67aaSAlexander Motin 4136227d67aaSAlexander Motin if (path->device != device 4137227d67aaSAlexander Motin && path->device->lun_id != CAM_LUN_WILDCARD 4138227d67aaSAlexander Motin && device->lun_id != CAM_LUN_WILDCARD) 4139227d67aaSAlexander Motin return (1); 41408b8a9b1dSJustin T. Gibbs 4141a5479bc5SJustin T. Gibbs /* 4142227d67aaSAlexander Motin * The async callback could free the device. 4143227d67aaSAlexander Motin * If it is a broadcast async, it doesn't hold 4144227d67aaSAlexander Motin * device reference, so take our own reference. 4145a5479bc5SJustin T. Gibbs */ 4146227d67aaSAlexander Motin xpt_acquire_device(device); 41478b8a9b1dSJustin T. Gibbs 4148227d67aaSAlexander Motin /* 4149227d67aaSAlexander Motin * If async for specific device is to be delivered to 4150227d67aaSAlexander Motin * the wildcard client, take the specific device lock. 4151227d67aaSAlexander Motin * XXX: We may need a way for client to specify it. 4152227d67aaSAlexander Motin */ 4153227d67aaSAlexander Motin if ((device->lun_id == CAM_LUN_WILDCARD && 4154227d67aaSAlexander Motin path->device->lun_id != CAM_LUN_WILDCARD) || 4155227d67aaSAlexander Motin (device->target->target_id == CAM_TARGET_WILDCARD && 4156227d67aaSAlexander Motin path->target->target_id != CAM_TARGET_WILDCARD) || 4157227d67aaSAlexander Motin (device->target->bus->path_id == CAM_BUS_WILDCARD && 4158227d67aaSAlexander Motin path->target->bus->path_id != CAM_BUS_WILDCARD)) { 4159227d67aaSAlexander Motin mtx_unlock(&device->device_mtx); 4160227d67aaSAlexander Motin xpt_path_lock(path); 4161227d67aaSAlexander Motin relock = 1; 4162227d67aaSAlexander Motin } else 4163227d67aaSAlexander Motin relock = 0; 4164227d67aaSAlexander Motin 4165ded2b706SWarner Losh (*(device->target->bus->xport->ops->async))(async_code, 4166227d67aaSAlexander Motin device->target->bus, device->target, device, async_arg); 4167227d67aaSAlexander Motin xpt_async_bcast(&device->asyncs, async_code, path, async_arg); 4168227d67aaSAlexander Motin 4169227d67aaSAlexander Motin if (relock) { 4170227d67aaSAlexander Motin xpt_path_unlock(path); 4171227d67aaSAlexander Motin mtx_lock(&device->device_mtx); 4172227d67aaSAlexander Motin } 4173227d67aaSAlexander Motin xpt_release_device(device); 4174227d67aaSAlexander Motin return (1); 4175227d67aaSAlexander Motin } 4176227d67aaSAlexander Motin 4177227d67aaSAlexander Motin static int 4178227d67aaSAlexander Motin xpt_async_process_tgt(struct cam_et *target, void *arg) 4179227d67aaSAlexander Motin { 4180227d67aaSAlexander Motin union ccb *ccb = arg; 4181227d67aaSAlexander Motin struct cam_path *path = ccb->ccb_h.path; 4182227d67aaSAlexander Motin 4183227d67aaSAlexander Motin if (path->target != target 4184227d67aaSAlexander Motin && path->target->target_id != CAM_TARGET_WILDCARD 4185227d67aaSAlexander Motin && target->target_id != CAM_TARGET_WILDCARD) 4186227d67aaSAlexander Motin return (1); 4187227d67aaSAlexander Motin 4188227d67aaSAlexander Motin if (ccb->casync.async_code == AC_SENT_BDR) { 4189227d67aaSAlexander Motin /* Update our notion of when the last reset occurred */ 4190227d67aaSAlexander Motin microtime(&target->last_reset); 4191227d67aaSAlexander Motin } 4192227d67aaSAlexander Motin 4193227d67aaSAlexander Motin return (xptdevicetraverse(target, NULL, xpt_async_process_dev, ccb)); 4194227d67aaSAlexander Motin } 4195227d67aaSAlexander Motin 4196227d67aaSAlexander Motin static void 4197227d67aaSAlexander Motin xpt_async_process(struct cam_periph *periph, union ccb *ccb) 4198227d67aaSAlexander Motin { 4199227d67aaSAlexander Motin struct cam_eb *bus; 4200227d67aaSAlexander Motin struct cam_path *path; 4201227d67aaSAlexander Motin void *async_arg; 4202227d67aaSAlexander Motin u_int32_t async_code; 4203227d67aaSAlexander Motin 4204227d67aaSAlexander Motin path = ccb->ccb_h.path; 4205227d67aaSAlexander Motin async_code = ccb->casync.async_code; 4206227d67aaSAlexander Motin async_arg = ccb->casync.async_arg_ptr; 4207227d67aaSAlexander Motin CAM_DEBUG(path, CAM_DEBUG_TRACE | CAM_DEBUG_INFO, 4208227d67aaSAlexander Motin ("xpt_async(%s)\n", xpt_async_string(async_code))); 42098b8a9b1dSJustin T. Gibbs bus = path->bus; 42108b8a9b1dSJustin T. Gibbs 42118b8a9b1dSJustin T. Gibbs if (async_code == AC_BUS_RESET) { 421287cfaf0eSJustin T. Gibbs /* Update our notion of when the last reset occurred */ 421387cfaf0eSJustin T. Gibbs microtime(&bus->last_reset); 42148b8a9b1dSJustin T. Gibbs } 42158b8a9b1dSJustin T. Gibbs 4216227d67aaSAlexander Motin xpttargettraverse(bus, NULL, xpt_async_process_tgt, ccb); 4217c8bead2aSJustin T. Gibbs 4218c8bead2aSJustin T. Gibbs /* 4219c8bead2aSJustin T. Gibbs * If this wasn't a fully wildcarded async, tell all 4220c8bead2aSJustin T. Gibbs * clients that want all async events. 4221c8bead2aSJustin T. Gibbs */ 4222227d67aaSAlexander Motin if (bus != xpt_periph->path->bus) { 4223227d67aaSAlexander Motin xpt_path_lock(xpt_periph->path); 4224227d67aaSAlexander Motin xpt_async_process_dev(xpt_periph->path->device, ccb); 4225227d67aaSAlexander Motin xpt_path_unlock(xpt_periph->path); 4226227d67aaSAlexander Motin } 4227227d67aaSAlexander Motin 4228227d67aaSAlexander Motin if (path->device != NULL && path->device->lun_id != CAM_LUN_WILDCARD) 4229227d67aaSAlexander Motin xpt_release_devq(path, 1, TRUE); 4230227d67aaSAlexander Motin else 4231227d67aaSAlexander Motin xpt_release_simq(path->bus->sim, TRUE); 4232227d67aaSAlexander Motin if (ccb->casync.async_arg_size > 0) 4233227d67aaSAlexander Motin free(async_arg, M_CAMXPT); 4234227d67aaSAlexander Motin xpt_free_path(path); 4235227d67aaSAlexander Motin xpt_free_ccb(ccb); 42368b8a9b1dSJustin T. Gibbs } 42378b8a9b1dSJustin T. Gibbs 42388b8a9b1dSJustin T. Gibbs static void 42398b8a9b1dSJustin T. Gibbs xpt_async_bcast(struct async_list *async_head, 42408b8a9b1dSJustin T. Gibbs u_int32_t async_code, 42418b8a9b1dSJustin T. Gibbs struct cam_path *path, void *async_arg) 42428b8a9b1dSJustin T. Gibbs { 42438b8a9b1dSJustin T. Gibbs struct async_node *cur_entry; 4244227d67aaSAlexander Motin int lock; 42458b8a9b1dSJustin T. Gibbs 42468b8a9b1dSJustin T. Gibbs cur_entry = SLIST_FIRST(async_head); 42478b8a9b1dSJustin T. Gibbs while (cur_entry != NULL) { 42488b8a9b1dSJustin T. Gibbs struct async_node *next_entry; 42498b8a9b1dSJustin T. Gibbs /* 42508b8a9b1dSJustin T. Gibbs * Grab the next list entry before we call the current 42518b8a9b1dSJustin T. Gibbs * entry's callback. This is because the callback function 42528b8a9b1dSJustin T. Gibbs * can delete its async callback entry. 42538b8a9b1dSJustin T. Gibbs */ 42548b8a9b1dSJustin T. Gibbs next_entry = SLIST_NEXT(cur_entry, links); 4255227d67aaSAlexander Motin if ((cur_entry->event_enable & async_code) != 0) { 4256227d67aaSAlexander Motin lock = cur_entry->event_lock; 4257227d67aaSAlexander Motin if (lock) 4258227d67aaSAlexander Motin CAM_SIM_LOCK(path->device->sim); 42598b8a9b1dSJustin T. Gibbs cur_entry->callback(cur_entry->callback_arg, 42608b8a9b1dSJustin T. Gibbs async_code, path, 42618b8a9b1dSJustin T. Gibbs async_arg); 4262227d67aaSAlexander Motin if (lock) 4263227d67aaSAlexander Motin CAM_SIM_UNLOCK(path->device->sim); 4264227d67aaSAlexander Motin } 42658b8a9b1dSJustin T. Gibbs cur_entry = next_entry; 42668b8a9b1dSJustin T. Gibbs } 42678b8a9b1dSJustin T. Gibbs } 42688b8a9b1dSJustin T. Gibbs 4269227d67aaSAlexander Motin void 4270227d67aaSAlexander Motin xpt_async(u_int32_t async_code, struct cam_path *path, void *async_arg) 4271227d67aaSAlexander Motin { 4272227d67aaSAlexander Motin union ccb *ccb; 4273227d67aaSAlexander Motin int size; 4274227d67aaSAlexander Motin 4275227d67aaSAlexander Motin ccb = xpt_alloc_ccb_nowait(); 4276227d67aaSAlexander Motin if (ccb == NULL) { 4277227d67aaSAlexander Motin xpt_print(path, "Can't allocate CCB to send %s\n", 4278227d67aaSAlexander Motin xpt_async_string(async_code)); 4279227d67aaSAlexander Motin return; 4280227d67aaSAlexander Motin } 4281227d67aaSAlexander Motin 4282227d67aaSAlexander Motin if (xpt_clone_path(&ccb->ccb_h.path, path) != CAM_REQ_CMP) { 4283227d67aaSAlexander Motin xpt_print(path, "Can't allocate path to send %s\n", 4284227d67aaSAlexander Motin xpt_async_string(async_code)); 4285227d67aaSAlexander Motin xpt_free_ccb(ccb); 4286227d67aaSAlexander Motin return; 4287227d67aaSAlexander Motin } 4288227d67aaSAlexander Motin ccb->ccb_h.path->periph = NULL; 4289227d67aaSAlexander Motin ccb->ccb_h.func_code = XPT_ASYNC; 4290227d67aaSAlexander Motin ccb->ccb_h.cbfcnp = xpt_async_process; 4291227d67aaSAlexander Motin ccb->ccb_h.flags |= CAM_UNLOCKED; 4292227d67aaSAlexander Motin ccb->casync.async_code = async_code; 4293227d67aaSAlexander Motin ccb->casync.async_arg_size = 0; 4294227d67aaSAlexander Motin size = xpt_async_size(async_code); 429569be012fSWarner Losh CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE, 429669be012fSWarner Losh ("xpt_async: func %#x %s aync_code %d %s\n", 429769be012fSWarner Losh ccb->ccb_h.func_code, 429869be012fSWarner Losh xpt_action_name(ccb->ccb_h.func_code), 429969be012fSWarner Losh async_code, 430069be012fSWarner Losh xpt_async_string(async_code))); 4301227d67aaSAlexander Motin if (size > 0 && async_arg != NULL) { 4302227d67aaSAlexander Motin ccb->casync.async_arg_ptr = malloc(size, M_CAMXPT, M_NOWAIT); 4303227d67aaSAlexander Motin if (ccb->casync.async_arg_ptr == NULL) { 4304227d67aaSAlexander Motin xpt_print(path, "Can't allocate argument to send %s\n", 4305227d67aaSAlexander Motin xpt_async_string(async_code)); 4306227d67aaSAlexander Motin xpt_free_path(ccb->ccb_h.path); 4307227d67aaSAlexander Motin xpt_free_ccb(ccb); 4308227d67aaSAlexander Motin return; 4309227d67aaSAlexander Motin } 4310227d67aaSAlexander Motin memcpy(ccb->casync.async_arg_ptr, async_arg, size); 4311227d67aaSAlexander Motin ccb->casync.async_arg_size = size; 4312738fd166SAlan Somers } else if (size < 0) { 4313738fd166SAlan Somers ccb->casync.async_arg_ptr = async_arg; 4314227d67aaSAlexander Motin ccb->casync.async_arg_size = size; 4315738fd166SAlan Somers } 4316227d67aaSAlexander Motin if (path->device != NULL && path->device->lun_id != CAM_LUN_WILDCARD) 4317227d67aaSAlexander Motin xpt_freeze_devq(path, 1); 4318227d67aaSAlexander Motin else 4319227d67aaSAlexander Motin xpt_freeze_simq(path->bus->sim, 1); 4320227d67aaSAlexander Motin xpt_done(ccb); 4321227d67aaSAlexander Motin } 4322227d67aaSAlexander Motin 43232f22d08dSJustin T. Gibbs static void 432452c9ce25SScott Long xpt_dev_async_default(u_int32_t async_code, struct cam_eb *bus, 432552c9ce25SScott Long struct cam_et *target, struct cam_ed *device, 432652c9ce25SScott Long void *async_arg) 43272f22d08dSJustin T. Gibbs { 4328227d67aaSAlexander Motin 4329227d67aaSAlexander Motin /* 4330227d67aaSAlexander Motin * We only need to handle events for real devices. 4331227d67aaSAlexander Motin */ 4332227d67aaSAlexander Motin if (target->target_id == CAM_TARGET_WILDCARD 4333227d67aaSAlexander Motin || device->lun_id == CAM_LUN_WILDCARD) 4334227d67aaSAlexander Motin return; 4335227d67aaSAlexander Motin 4336b882a6d3SMatt Jacob printf("%s called\n", __func__); 43372f22d08dSJustin T. Gibbs } 43382f22d08dSJustin T. Gibbs 4339daa5487fSAlexander Motin static uint32_t 4340daa5487fSAlexander Motin xpt_freeze_devq_device(struct cam_ed *dev, u_int count) 4341daa5487fSAlexander Motin { 4342daa5487fSAlexander Motin struct cam_devq *devq; 4343daa5487fSAlexander Motin uint32_t freeze; 4344daa5487fSAlexander Motin 4345daa5487fSAlexander Motin devq = dev->sim->devq; 4346daa5487fSAlexander Motin mtx_assert(&devq->send_mtx, MA_OWNED); 4347daa5487fSAlexander Motin CAM_DEBUG_DEV(dev, CAM_DEBUG_TRACE, 4348daa5487fSAlexander Motin ("xpt_freeze_devq_device(%d) %u->%u\n", count, 4349daa5487fSAlexander Motin dev->ccbq.queue.qfrozen_cnt, dev->ccbq.queue.qfrozen_cnt + count)); 4350daa5487fSAlexander Motin freeze = (dev->ccbq.queue.qfrozen_cnt += count); 4351daa5487fSAlexander Motin /* Remove frozen device from sendq. */ 4352daa5487fSAlexander Motin if (device_is_queued(dev)) 4353daa5487fSAlexander Motin camq_remove(&devq->send_queue, dev->devq_entry.index); 4354daa5487fSAlexander Motin return (freeze); 4355daa5487fSAlexander Motin } 4356daa5487fSAlexander Motin 43578b8a9b1dSJustin T. Gibbs u_int32_t 4358cccf4220SAlexander Motin xpt_freeze_devq(struct cam_path *path, u_int count) 435983c5d981SAlexander Motin { 436083c5d981SAlexander Motin struct cam_ed *dev = path->device; 4361227d67aaSAlexander Motin struct cam_devq *devq; 4362227d67aaSAlexander Motin uint32_t freeze; 436383c5d981SAlexander Motin 4364227d67aaSAlexander Motin devq = dev->sim->devq; 4365227d67aaSAlexander Motin mtx_lock(&devq->send_mtx); 4366daa5487fSAlexander Motin CAM_DEBUG(path, CAM_DEBUG_TRACE, ("xpt_freeze_devq(%d)\n", count)); 4367daa5487fSAlexander Motin freeze = xpt_freeze_devq_device(dev, count); 4368227d67aaSAlexander Motin mtx_unlock(&devq->send_mtx); 4369227d67aaSAlexander Motin return (freeze); 43708b8a9b1dSJustin T. Gibbs } 43718b8a9b1dSJustin T. Gibbs 43728b8a9b1dSJustin T. Gibbs u_int32_t 43738b8a9b1dSJustin T. Gibbs xpt_freeze_simq(struct cam_sim *sim, u_int count) 43748b8a9b1dSJustin T. Gibbs { 4375227d67aaSAlexander Motin struct cam_devq *devq; 4376227d67aaSAlexander Motin uint32_t freeze; 4377ec700f26SAlexander Motin 4378227d67aaSAlexander Motin devq = sim->devq; 4379227d67aaSAlexander Motin mtx_lock(&devq->send_mtx); 4380227d67aaSAlexander Motin freeze = (devq->send_queue.qfrozen_cnt += count); 4381227d67aaSAlexander Motin mtx_unlock(&devq->send_mtx); 4382227d67aaSAlexander Motin return (freeze); 43838b8a9b1dSJustin T. Gibbs } 43848b8a9b1dSJustin T. Gibbs 43858b8a9b1dSJustin T. Gibbs static void 43868b8a9b1dSJustin T. Gibbs xpt_release_devq_timeout(void *arg) 43878b8a9b1dSJustin T. Gibbs { 4388227d67aaSAlexander Motin struct cam_ed *dev; 4389227d67aaSAlexander Motin struct cam_devq *devq; 43908b8a9b1dSJustin T. Gibbs 4391227d67aaSAlexander Motin dev = (struct cam_ed *)arg; 4392227d67aaSAlexander Motin CAM_DEBUG_DEV(dev, CAM_DEBUG_TRACE, ("xpt_release_devq_timeout\n")); 4393227d67aaSAlexander Motin devq = dev->sim->devq; 4394227d67aaSAlexander Motin mtx_assert(&devq->send_mtx, MA_OWNED); 4395227d67aaSAlexander Motin if (xpt_release_devq_device(dev, /*count*/1, /*run_queue*/TRUE)) 4396227d67aaSAlexander Motin xpt_run_devq(devq); 43978b8a9b1dSJustin T. Gibbs } 43988b8a9b1dSJustin T. Gibbs 43998b8a9b1dSJustin T. Gibbs void 44002cefde5fSJustin T. Gibbs xpt_release_devq(struct cam_path *path, u_int count, int run_queue) 44012cefde5fSJustin T. Gibbs { 4402227d67aaSAlexander Motin struct cam_ed *dev; 4403227d67aaSAlexander Motin struct cam_devq *devq; 440468153f43SScott Long 44050d4f3c31SAlexander Motin CAM_DEBUG(path, CAM_DEBUG_TRACE, ("xpt_release_devq(%d, %d)\n", 44060d4f3c31SAlexander Motin count, run_queue)); 4407227d67aaSAlexander Motin dev = path->device; 4408227d67aaSAlexander Motin devq = dev->sim->devq; 4409227d67aaSAlexander Motin mtx_lock(&devq->send_mtx); 4410227d67aaSAlexander Motin if (xpt_release_devq_device(dev, count, run_queue)) 4411227d67aaSAlexander Motin xpt_run_devq(dev->sim->devq); 4412227d67aaSAlexander Motin mtx_unlock(&devq->send_mtx); 441383c5d981SAlexander Motin } 441483c5d981SAlexander Motin 4415227d67aaSAlexander Motin static int 4416cccf4220SAlexander Motin xpt_release_devq_device(struct cam_ed *dev, u_int count, int run_queue) 44178b8a9b1dSJustin T. Gibbs { 44188b8a9b1dSJustin T. Gibbs 4419227d67aaSAlexander Motin mtx_assert(&dev->sim->devq->send_mtx, MA_OWNED); 44200d4f3c31SAlexander Motin CAM_DEBUG_DEV(dev, CAM_DEBUG_TRACE, 44210d4f3c31SAlexander Motin ("xpt_release_devq_device(%d, %d) %u->%u\n", count, run_queue, 44220d4f3c31SAlexander Motin dev->ccbq.queue.qfrozen_cnt, dev->ccbq.queue.qfrozen_cnt - count)); 4423cccf4220SAlexander Motin if (count > dev->ccbq.queue.qfrozen_cnt) { 442483c5d981SAlexander Motin #ifdef INVARIANTS 4425cccf4220SAlexander Motin printf("xpt_release_devq(): requested %u > present %u\n", 4426cccf4220SAlexander Motin count, dev->ccbq.queue.qfrozen_cnt); 442783c5d981SAlexander Motin #endif 4428cccf4220SAlexander Motin count = dev->ccbq.queue.qfrozen_cnt; 442983c5d981SAlexander Motin } 4430cccf4220SAlexander Motin dev->ccbq.queue.qfrozen_cnt -= count; 4431cccf4220SAlexander Motin if (dev->ccbq.queue.qfrozen_cnt == 0) { 44328b8a9b1dSJustin T. Gibbs /* 44338b8a9b1dSJustin T. Gibbs * No longer need to wait for a successful 44348b8a9b1dSJustin T. Gibbs * command completion. 44358b8a9b1dSJustin T. Gibbs */ 44368b8a9b1dSJustin T. Gibbs dev->flags &= ~CAM_DEV_REL_ON_COMPLETE; 44378b8a9b1dSJustin T. Gibbs /* 44388b8a9b1dSJustin T. Gibbs * Remove any timeouts that might be scheduled 44398b8a9b1dSJustin T. Gibbs * to release this queue. 44408b8a9b1dSJustin T. Gibbs */ 44418b8a9b1dSJustin T. Gibbs if ((dev->flags & CAM_DEV_REL_TIMEOUT_PENDING) != 0) { 44422b83592fSScott Long callout_stop(&dev->callout); 44438b8a9b1dSJustin T. Gibbs dev->flags &= ~CAM_DEV_REL_TIMEOUT_PENDING; 44448b8a9b1dSJustin T. Gibbs } 44458b8a9b1dSJustin T. Gibbs /* 44468b8a9b1dSJustin T. Gibbs * Now that we are unfrozen schedule the 44478b8a9b1dSJustin T. Gibbs * device so any pending transactions are 44488b8a9b1dSJustin T. Gibbs * run. 44498b8a9b1dSJustin T. Gibbs */ 4450227d67aaSAlexander Motin xpt_schedule_devq(dev->sim->devq, dev); 4451227d67aaSAlexander Motin } else 4452227d67aaSAlexander Motin run_queue = 0; 4453227d67aaSAlexander Motin return (run_queue); 445483c5d981SAlexander Motin } 44558b8a9b1dSJustin T. Gibbs 44568b8a9b1dSJustin T. Gibbs void 44578b8a9b1dSJustin T. Gibbs xpt_release_simq(struct cam_sim *sim, int run_queue) 44588b8a9b1dSJustin T. Gibbs { 4459227d67aaSAlexander Motin struct cam_devq *devq; 44608b8a9b1dSJustin T. Gibbs 4461227d67aaSAlexander Motin devq = sim->devq; 4462227d67aaSAlexander Motin mtx_lock(&devq->send_mtx); 4463227d67aaSAlexander Motin if (devq->send_queue.qfrozen_cnt <= 0) { 446483c5d981SAlexander Motin #ifdef INVARIANTS 446583c5d981SAlexander Motin printf("xpt_release_simq: requested 1 > present %u\n", 4466227d67aaSAlexander Motin devq->send_queue.qfrozen_cnt); 446783c5d981SAlexander Motin #endif 446883c5d981SAlexander Motin } else 4469227d67aaSAlexander Motin devq->send_queue.qfrozen_cnt--; 4470227d67aaSAlexander Motin if (devq->send_queue.qfrozen_cnt == 0) { 44718b8a9b1dSJustin T. Gibbs /* 44728b8a9b1dSJustin T. Gibbs * If there is a timeout scheduled to release this 44738b8a9b1dSJustin T. Gibbs * sim queue, remove it. The queue frozen count is 44748b8a9b1dSJustin T. Gibbs * already at 0. 44758b8a9b1dSJustin T. Gibbs */ 44768b8a9b1dSJustin T. Gibbs if ((sim->flags & CAM_SIM_REL_TIMEOUT_PENDING) != 0){ 44772b83592fSScott Long callout_stop(&sim->callout); 44788b8a9b1dSJustin T. Gibbs sim->flags &= ~CAM_SIM_REL_TIMEOUT_PENDING; 44798b8a9b1dSJustin T. Gibbs } 44808b8a9b1dSJustin T. Gibbs if (run_queue) { 44818b8a9b1dSJustin T. Gibbs /* 44828b8a9b1dSJustin T. Gibbs * Now that we are unfrozen run the send queue. 44838b8a9b1dSJustin T. Gibbs */ 4484cccf4220SAlexander Motin xpt_run_devq(sim->devq); 448577dc25ccSScott Long } 448677dc25ccSScott Long } 4487227d67aaSAlexander Motin mtx_unlock(&devq->send_mtx); 44888b8a9b1dSJustin T. Gibbs } 44898b8a9b1dSJustin T. Gibbs 44902b83592fSScott Long /* 44912b83592fSScott Long * XXX Appears to be unused. 44922b83592fSScott Long */ 44938b8a9b1dSJustin T. Gibbs static void 44948b8a9b1dSJustin T. Gibbs xpt_release_simq_timeout(void *arg) 44958b8a9b1dSJustin T. Gibbs { 44968b8a9b1dSJustin T. Gibbs struct cam_sim *sim; 44978b8a9b1dSJustin T. Gibbs 44988b8a9b1dSJustin T. Gibbs sim = (struct cam_sim *)arg; 44998b8a9b1dSJustin T. Gibbs xpt_release_simq(sim, /* run_queue */ TRUE); 45008b8a9b1dSJustin T. Gibbs } 45018b8a9b1dSJustin T. Gibbs 45028b8a9b1dSJustin T. Gibbs void 4503a5479bc5SJustin T. Gibbs xpt_done(union ccb *done_ccb) 45048b8a9b1dSJustin T. Gibbs { 4505227d67aaSAlexander Motin struct cam_doneq *queue; 4506227d67aaSAlexander Motin int run, hash; 45078b8a9b1dSJustin T. Gibbs 45088532d381SConrad Meyer #if defined(BUF_TRACKING) || defined(FULL_BUF_TRACKING) 45098532d381SConrad Meyer if (done_ccb->ccb_h.func_code == XPT_SCSI_IO && 45108532d381SConrad Meyer done_ccb->csio.bio != NULL) 45118532d381SConrad Meyer biotrack(done_ccb->csio.bio, __func__); 45128532d381SConrad Meyer #endif 45138532d381SConrad Meyer 451469be012fSWarner Losh CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_TRACE, 451569be012fSWarner Losh ("xpt_done: func= %#x %s status %#x\n", 451669be012fSWarner Losh done_ccb->ccb_h.func_code, 451769be012fSWarner Losh xpt_action_name(done_ccb->ccb_h.func_code), 451869be012fSWarner Losh done_ccb->ccb_h.status)); 4519227d67aaSAlexander Motin if ((done_ccb->ccb_h.func_code & XPT_FC_QUEUED) == 0) 4520227d67aaSAlexander Motin return; 4521227d67aaSAlexander Motin 4522a6e0c5daSWarner Losh /* Store the time the ccb was in the sim */ 4523a6e0c5daSWarner Losh done_ccb->ccb_h.qos.sim_data = sbinuptime() - done_ccb->ccb_h.qos.sim_data; 4524227d67aaSAlexander Motin hash = (done_ccb->ccb_h.path_id + done_ccb->ccb_h.target_id + 4525227d67aaSAlexander Motin done_ccb->ccb_h.target_lun) % cam_num_doneqs; 4526227d67aaSAlexander Motin queue = &cam_doneqs[hash]; 4527227d67aaSAlexander Motin mtx_lock(&queue->cam_doneq_mtx); 4528227d67aaSAlexander Motin run = (queue->cam_doneq_sleep && STAILQ_EMPTY(&queue->cam_doneq)); 4529227d67aaSAlexander Motin STAILQ_INSERT_TAIL(&queue->cam_doneq, &done_ccb->ccb_h, sim_links.stqe); 45308b8a9b1dSJustin T. Gibbs done_ccb->ccb_h.pinfo.index = CAM_DONEQ_INDEX; 4531227d67aaSAlexander Motin mtx_unlock(&queue->cam_doneq_mtx); 4532227d67aaSAlexander Motin if (run) 4533227d67aaSAlexander Motin wakeup(&queue->cam_doneq); 45348b8a9b1dSJustin T. Gibbs } 45358b8a9b1dSJustin T. Gibbs 4536711f6613SAlexander Motin void 4537227d67aaSAlexander Motin xpt_done_direct(union ccb *done_ccb) 4538711f6613SAlexander Motin { 4539711f6613SAlexander Motin 454069be012fSWarner Losh CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_TRACE, 454169be012fSWarner Losh ("xpt_done_direct: status %#x\n", done_ccb->ccb_h.status)); 4542227d67aaSAlexander Motin if ((done_ccb->ccb_h.func_code & XPT_FC_QUEUED) == 0) 4543227d67aaSAlexander Motin return; 4544711f6613SAlexander Motin 4545a6e0c5daSWarner Losh /* Store the time the ccb was in the sim */ 4546a6e0c5daSWarner Losh done_ccb->ccb_h.qos.sim_data = sbinuptime() - done_ccb->ccb_h.qos.sim_data; 4547227d67aaSAlexander Motin xpt_done_process(&done_ccb->ccb_h); 4548711f6613SAlexander Motin } 4549711f6613SAlexander Motin 45508b8a9b1dSJustin T. Gibbs union ccb * 45518008a935SScott Long xpt_alloc_ccb() 45528b8a9b1dSJustin T. Gibbs { 45538b8a9b1dSJustin T. Gibbs union ccb *new_ccb; 45548b8a9b1dSJustin T. Gibbs 4555596ee08fSAlexander Motin new_ccb = malloc(sizeof(*new_ccb), M_CAMCCB, M_ZERO|M_WAITOK); 4556362abc44STai-hwa Liang return (new_ccb); 4557362abc44STai-hwa Liang } 4558362abc44STai-hwa Liang 4559362abc44STai-hwa Liang union ccb * 45608008a935SScott Long xpt_alloc_ccb_nowait() 4561362abc44STai-hwa Liang { 4562362abc44STai-hwa Liang union ccb *new_ccb; 4563362abc44STai-hwa Liang 4564596ee08fSAlexander Motin new_ccb = malloc(sizeof(*new_ccb), M_CAMCCB, M_ZERO|M_NOWAIT); 45658b8a9b1dSJustin T. Gibbs return (new_ccb); 45668b8a9b1dSJustin T. Gibbs } 45678b8a9b1dSJustin T. Gibbs 45688b8a9b1dSJustin T. Gibbs void 45698b8a9b1dSJustin T. Gibbs xpt_free_ccb(union ccb *free_ccb) 45708b8a9b1dSJustin T. Gibbs { 4571596ee08fSAlexander Motin free(free_ccb, M_CAMCCB); 45728b8a9b1dSJustin T. Gibbs } 45738b8a9b1dSJustin T. Gibbs 45748b8a9b1dSJustin T. Gibbs 45758b8a9b1dSJustin T. Gibbs 45768b8a9b1dSJustin T. Gibbs /* Private XPT functions */ 45778b8a9b1dSJustin T. Gibbs 45788b8a9b1dSJustin T. Gibbs /* 45798b8a9b1dSJustin T. Gibbs * Get a CAM control block for the caller. Charge the structure to the device 4580227d67aaSAlexander Motin * referenced by the path. If we don't have sufficient resources to allocate 4581227d67aaSAlexander Motin * more ccbs, we return NULL. 45828b8a9b1dSJustin T. Gibbs */ 45838b8a9b1dSJustin T. Gibbs static union ccb * 4584227d67aaSAlexander Motin xpt_get_ccb_nowait(struct cam_periph *periph) 45858b8a9b1dSJustin T. Gibbs { 45868b8a9b1dSJustin T. Gibbs union ccb *new_ccb; 45878b8a9b1dSJustin T. Gibbs 4588d3995fddSBenno Rice new_ccb = malloc(sizeof(*new_ccb), M_CAMCCB, M_ZERO|M_NOWAIT); 4589227d67aaSAlexander Motin if (new_ccb == NULL) 45908b8a9b1dSJustin T. Gibbs return (NULL); 4591227d67aaSAlexander Motin periph->periph_allocated++; 4592227d67aaSAlexander Motin cam_ccbq_take_opening(&periph->path->device->ccbq); 45938b8a9b1dSJustin T. Gibbs return (new_ccb); 45948b8a9b1dSJustin T. Gibbs } 45958b8a9b1dSJustin T. Gibbs 4596227d67aaSAlexander Motin static union ccb * 4597227d67aaSAlexander Motin xpt_get_ccb(struct cam_periph *periph) 4598227d67aaSAlexander Motin { 4599227d67aaSAlexander Motin union ccb *new_ccb; 4600227d67aaSAlexander Motin 4601227d67aaSAlexander Motin cam_periph_unlock(periph); 4602d3995fddSBenno Rice new_ccb = malloc(sizeof(*new_ccb), M_CAMCCB, M_ZERO|M_WAITOK); 4603227d67aaSAlexander Motin cam_periph_lock(periph); 4604227d67aaSAlexander Motin periph->periph_allocated++; 4605227d67aaSAlexander Motin cam_ccbq_take_opening(&periph->path->device->ccbq); 4606227d67aaSAlexander Motin return (new_ccb); 4607227d67aaSAlexander Motin } 4608227d67aaSAlexander Motin 4609227d67aaSAlexander Motin union ccb * 4610227d67aaSAlexander Motin cam_periph_getccb(struct cam_periph *periph, u_int32_t priority) 4611227d67aaSAlexander Motin { 4612227d67aaSAlexander Motin struct ccb_hdr *ccb_h; 4613227d67aaSAlexander Motin 4614227d67aaSAlexander Motin CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("cam_periph_getccb\n")); 4615227d67aaSAlexander Motin cam_periph_assert(periph, MA_OWNED); 4616227d67aaSAlexander Motin while ((ccb_h = SLIST_FIRST(&periph->ccb_list)) == NULL || 4617227d67aaSAlexander Motin ccb_h->pinfo.priority != priority) { 4618227d67aaSAlexander Motin if (priority < periph->immediate_priority) { 4619227d67aaSAlexander Motin periph->immediate_priority = priority; 4620227d67aaSAlexander Motin xpt_run_allocq(periph, 0); 4621227d67aaSAlexander Motin } else 4622227d67aaSAlexander Motin cam_periph_sleep(periph, &periph->ccb_list, PRIBIO, 4623227d67aaSAlexander Motin "cgticb", 0); 4624227d67aaSAlexander Motin } 4625227d67aaSAlexander Motin SLIST_REMOVE_HEAD(&periph->ccb_list, periph_links.sle); 4626227d67aaSAlexander Motin return ((union ccb *)ccb_h); 4627227d67aaSAlexander Motin } 4628227d67aaSAlexander Motin 4629227d67aaSAlexander Motin static void 4630227d67aaSAlexander Motin xpt_acquire_bus(struct cam_eb *bus) 4631227d67aaSAlexander Motin { 4632227d67aaSAlexander Motin 4633227d67aaSAlexander Motin xpt_lock_buses(); 4634227d67aaSAlexander Motin bus->refcount++; 4635227d67aaSAlexander Motin xpt_unlock_buses(); 4636227d67aaSAlexander Motin } 4637227d67aaSAlexander Motin 4638a5479bc5SJustin T. Gibbs static void 4639a5479bc5SJustin T. Gibbs xpt_release_bus(struct cam_eb *bus) 4640a5479bc5SJustin T. Gibbs { 4641a5479bc5SJustin T. Gibbs 46429a7c2696SAlexander Motin xpt_lock_buses(); 464315975b7bSMatt Jacob KASSERT(bus->refcount >= 1, ("bus->refcount >= 1")); 4644dcdf6e74SAlexander Motin if (--bus->refcount > 0) { 4645dcdf6e74SAlexander Motin xpt_unlock_buses(); 4646dcdf6e74SAlexander Motin return; 4647dcdf6e74SAlexander Motin } 46482b83592fSScott Long TAILQ_REMOVE(&xsoftc.xpt_busses, bus, links); 46492b83592fSScott Long xsoftc.bus_generation++; 46509a7c2696SAlexander Motin xpt_unlock_buses(); 4651227d67aaSAlexander Motin KASSERT(TAILQ_EMPTY(&bus->et_entries), 4652227d67aaSAlexander Motin ("destroying bus, but target list is not empty")); 4653fa6099fdSEdward Tomasz Napierala cam_sim_release(bus->sim); 4654227d67aaSAlexander Motin mtx_destroy(&bus->eb_mtx); 4655362abc44STai-hwa Liang free(bus, M_CAMXPT); 4656a5479bc5SJustin T. Gibbs } 46578b8a9b1dSJustin T. Gibbs 46588b8a9b1dSJustin T. Gibbs static struct cam_et * 46598b8a9b1dSJustin T. Gibbs xpt_alloc_target(struct cam_eb *bus, target_id_t target_id) 46608b8a9b1dSJustin T. Gibbs { 4661dcdf6e74SAlexander Motin struct cam_et *cur_target, *target; 46628b8a9b1dSJustin T. Gibbs 4663227d67aaSAlexander Motin mtx_assert(&xsoftc.xpt_topo_lock, MA_OWNED); 4664227d67aaSAlexander Motin mtx_assert(&bus->eb_mtx, MA_OWNED); 46653501942bSJustin T. Gibbs target = (struct cam_et *)malloc(sizeof(*target), M_CAMXPT, 46663501942bSJustin T. Gibbs M_NOWAIT|M_ZERO); 4667dcdf6e74SAlexander Motin if (target == NULL) 4668dcdf6e74SAlexander Motin return (NULL); 46698b8a9b1dSJustin T. Gibbs 4670434bbf6eSJustin T. Gibbs TAILQ_INIT(&target->ed_entries); 46718b8a9b1dSJustin T. Gibbs target->bus = bus; 46728b8a9b1dSJustin T. Gibbs target->target_id = target_id; 46738b8a9b1dSJustin T. Gibbs target->refcount = 1; 4674434bbf6eSJustin T. Gibbs target->generation = 0; 467582b361b1SMatt Jacob target->luns = NULL; 4676227d67aaSAlexander Motin mtx_init(&target->luns_mtx, "CAM LUNs lock", NULL, MTX_DEF); 4677434bbf6eSJustin T. Gibbs timevalclear(&target->last_reset); 4678a5479bc5SJustin T. Gibbs /* 4679a5479bc5SJustin T. Gibbs * Hold a reference to our parent bus so it 4680a5479bc5SJustin T. Gibbs * will not go away before we do. 4681a5479bc5SJustin T. Gibbs */ 4682a5479bc5SJustin T. Gibbs bus->refcount++; 46838b8a9b1dSJustin T. Gibbs 46848b8a9b1dSJustin T. Gibbs /* Insertion sort into our bus's target list */ 46858b8a9b1dSJustin T. Gibbs cur_target = TAILQ_FIRST(&bus->et_entries); 46868b8a9b1dSJustin T. Gibbs while (cur_target != NULL && cur_target->target_id < target_id) 46878b8a9b1dSJustin T. Gibbs cur_target = TAILQ_NEXT(cur_target, links); 46888b8a9b1dSJustin T. Gibbs if (cur_target != NULL) { 46898b8a9b1dSJustin T. Gibbs TAILQ_INSERT_BEFORE(cur_target, target, links); 46908b8a9b1dSJustin T. Gibbs } else { 46918b8a9b1dSJustin T. Gibbs TAILQ_INSERT_TAIL(&bus->et_entries, target, links); 46928b8a9b1dSJustin T. Gibbs } 4693a5479bc5SJustin T. Gibbs bus->generation++; 46948b8a9b1dSJustin T. Gibbs return (target); 46958b8a9b1dSJustin T. Gibbs } 46968b8a9b1dSJustin T. Gibbs 4697a5479bc5SJustin T. Gibbs static void 4698227d67aaSAlexander Motin xpt_acquire_target(struct cam_et *target) 4699227d67aaSAlexander Motin { 4700227d67aaSAlexander Motin struct cam_eb *bus = target->bus; 4701227d67aaSAlexander Motin 4702227d67aaSAlexander Motin mtx_lock(&bus->eb_mtx); 4703227d67aaSAlexander Motin target->refcount++; 4704227d67aaSAlexander Motin mtx_unlock(&bus->eb_mtx); 4705227d67aaSAlexander Motin } 4706227d67aaSAlexander Motin 4707227d67aaSAlexander Motin static void 4708f98d7a47SAlexander Motin xpt_release_target(struct cam_et *target) 47098b8a9b1dSJustin T. Gibbs { 4710227d67aaSAlexander Motin struct cam_eb *bus = target->bus; 4711a5479bc5SJustin T. Gibbs 4712227d67aaSAlexander Motin mtx_lock(&bus->eb_mtx); 4713227d67aaSAlexander Motin if (--target->refcount > 0) { 4714227d67aaSAlexander Motin mtx_unlock(&bus->eb_mtx); 4715dcdf6e74SAlexander Motin return; 4716227d67aaSAlexander Motin } 4717227d67aaSAlexander Motin TAILQ_REMOVE(&bus->et_entries, target, links); 4718227d67aaSAlexander Motin bus->generation++; 4719227d67aaSAlexander Motin mtx_unlock(&bus->eb_mtx); 4720dcdf6e74SAlexander Motin KASSERT(TAILQ_EMPTY(&target->ed_entries), 4721227d67aaSAlexander Motin ("destroying target, but device list is not empty")); 4722227d67aaSAlexander Motin xpt_release_bus(bus); 4723227d67aaSAlexander Motin mtx_destroy(&target->luns_mtx); 472482b361b1SMatt Jacob if (target->luns) 472582b361b1SMatt Jacob free(target->luns, M_CAMXPT); 4726362abc44STai-hwa Liang free(target, M_CAMXPT); 472777dc25ccSScott Long } 47288b8a9b1dSJustin T. Gibbs 47298b8a9b1dSJustin T. Gibbs static struct cam_ed * 473052c9ce25SScott Long xpt_alloc_device_default(struct cam_eb *bus, struct cam_et *target, 473152c9ce25SScott Long lun_id_t lun_id) 473252c9ce25SScott Long { 4733dcdf6e74SAlexander Motin struct cam_ed *device; 473452c9ce25SScott Long 473552c9ce25SScott Long device = xpt_alloc_device(bus, target, lun_id); 473652c9ce25SScott Long if (device == NULL) 473752c9ce25SScott Long return (NULL); 473852c9ce25SScott Long 473952c9ce25SScott Long device->mintags = 1; 474052c9ce25SScott Long device->maxtags = 1; 474152c9ce25SScott Long return (device); 474252c9ce25SScott Long } 474352c9ce25SScott Long 4744227d67aaSAlexander Motin static void 4745227d67aaSAlexander Motin xpt_destroy_device(void *context, int pending) 4746227d67aaSAlexander Motin { 4747227d67aaSAlexander Motin struct cam_ed *device = context; 4748227d67aaSAlexander Motin 4749227d67aaSAlexander Motin mtx_lock(&device->device_mtx); 4750227d67aaSAlexander Motin mtx_destroy(&device->device_mtx); 4751227d67aaSAlexander Motin free(device, M_CAMDEV); 4752227d67aaSAlexander Motin } 4753227d67aaSAlexander Motin 475452c9ce25SScott Long struct cam_ed * 47558b8a9b1dSJustin T. Gibbs xpt_alloc_device(struct cam_eb *bus, struct cam_et *target, lun_id_t lun_id) 47568b8a9b1dSJustin T. Gibbs { 4757dcdf6e74SAlexander Motin struct cam_ed *cur_device, *device; 47588b8a9b1dSJustin T. Gibbs struct cam_devq *devq; 4759a5479bc5SJustin T. Gibbs cam_status status; 47608b8a9b1dSJustin T. Gibbs 4761227d67aaSAlexander Motin mtx_assert(&bus->eb_mtx, MA_OWNED); 47628b8a9b1dSJustin T. Gibbs /* Make space for us in the device queue on our bus */ 47638b8a9b1dSJustin T. Gibbs devq = bus->sim->devq; 4764227d67aaSAlexander Motin mtx_lock(&devq->send_mtx); 4765cccf4220SAlexander Motin status = cam_devq_resize(devq, devq->send_queue.array_size + 1); 4766227d67aaSAlexander Motin mtx_unlock(&devq->send_mtx); 4767dcdf6e74SAlexander Motin if (status != CAM_REQ_CMP) 4768dcdf6e74SAlexander Motin return (NULL); 47698b8a9b1dSJustin T. Gibbs 47708b8a9b1dSJustin T. Gibbs device = (struct cam_ed *)malloc(sizeof(*device), 4771596ee08fSAlexander Motin M_CAMDEV, M_NOWAIT|M_ZERO); 4772dcdf6e74SAlexander Motin if (device == NULL) 4773dcdf6e74SAlexander Motin return (NULL); 47748b8a9b1dSJustin T. Gibbs 4775227d67aaSAlexander Motin cam_init_pinfo(&device->devq_entry); 47768b8a9b1dSJustin T. Gibbs device->target = target; 47778b8a9b1dSJustin T. Gibbs device->lun_id = lun_id; 47782b83592fSScott Long device->sim = bus->sim; 47798b8a9b1dSJustin T. Gibbs if (cam_ccbq_init(&device->ccbq, 47808b8a9b1dSJustin T. Gibbs bus->sim->max_dev_openings) != 0) { 4781596ee08fSAlexander Motin free(device, M_CAMDEV); 47828b8a9b1dSJustin T. Gibbs return (NULL); 47838b8a9b1dSJustin T. Gibbs } 4784434bbf6eSJustin T. Gibbs SLIST_INIT(&device->asyncs); 4785434bbf6eSJustin T. Gibbs SLIST_INIT(&device->periphs); 4786434bbf6eSJustin T. Gibbs device->generation = 0; 4787434bbf6eSJustin T. Gibbs device->flags = CAM_DEV_UNCONFIGURED; 4788434bbf6eSJustin T. Gibbs device->tag_delay_count = 0; 4789df8f9080SJustin T. Gibbs device->tag_saved_openings = 0; 4790434bbf6eSJustin T. Gibbs device->refcount = 1; 4791227d67aaSAlexander Motin mtx_init(&device->device_mtx, "CAM device lock", NULL, MTX_DEF); 4792227d67aaSAlexander Motin callout_init_mtx(&device->callout, &devq->send_mtx, 0); 4793227d67aaSAlexander Motin TASK_INIT(&device->device_destroy_task, 0, xpt_destroy_device, device); 4794227d67aaSAlexander Motin /* 4795227d67aaSAlexander Motin * Hold a reference to our parent bus so it 4796227d67aaSAlexander Motin * will not go away before we do. 4797227d67aaSAlexander Motin */ 4798227d67aaSAlexander Motin target->refcount++; 4799434bbf6eSJustin T. Gibbs 4800dcdf6e74SAlexander Motin cur_device = TAILQ_FIRST(&target->ed_entries); 4801dcdf6e74SAlexander Motin while (cur_device != NULL && cur_device->lun_id < lun_id) 4802dcdf6e74SAlexander Motin cur_device = TAILQ_NEXT(cur_device, links); 4803dcdf6e74SAlexander Motin if (cur_device != NULL) 4804dcdf6e74SAlexander Motin TAILQ_INSERT_BEFORE(cur_device, device, links); 4805dcdf6e74SAlexander Motin else 4806dcdf6e74SAlexander Motin TAILQ_INSERT_TAIL(&target->ed_entries, device, links); 4807dcdf6e74SAlexander Motin target->generation++; 48088b8a9b1dSJustin T. Gibbs return (device); 48098b8a9b1dSJustin T. Gibbs } 48108b8a9b1dSJustin T. Gibbs 4811f98d7a47SAlexander Motin void 4812f98d7a47SAlexander Motin xpt_acquire_device(struct cam_ed *device) 48138b8a9b1dSJustin T. Gibbs { 4814227d67aaSAlexander Motin struct cam_eb *bus = device->target->bus; 48158b8a9b1dSJustin T. Gibbs 4816227d67aaSAlexander Motin mtx_lock(&bus->eb_mtx); 4817f98d7a47SAlexander Motin device->refcount++; 4818227d67aaSAlexander Motin mtx_unlock(&bus->eb_mtx); 4819f98d7a47SAlexander Motin } 4820f98d7a47SAlexander Motin 4821f98d7a47SAlexander Motin void 4822f98d7a47SAlexander Motin xpt_release_device(struct cam_ed *device) 4823f98d7a47SAlexander Motin { 4824227d67aaSAlexander Motin struct cam_eb *bus = device->target->bus; 48258b8a9b1dSJustin T. Gibbs struct cam_devq *devq; 48268b8a9b1dSJustin T. Gibbs 4827227d67aaSAlexander Motin mtx_lock(&bus->eb_mtx); 4828227d67aaSAlexander Motin if (--device->refcount > 0) { 4829227d67aaSAlexander Motin mtx_unlock(&bus->eb_mtx); 4830dcdf6e74SAlexander Motin return; 4831227d67aaSAlexander Motin } 4832227d67aaSAlexander Motin 4833227d67aaSAlexander Motin TAILQ_REMOVE(&device->target->ed_entries, device,links); 4834227d67aaSAlexander Motin device->target->generation++; 4835227d67aaSAlexander Motin mtx_unlock(&bus->eb_mtx); 4836227d67aaSAlexander Motin 4837227d67aaSAlexander Motin /* Release our slot in the devq */ 4838227d67aaSAlexander Motin devq = bus->sim->devq; 4839227d67aaSAlexander Motin mtx_lock(&devq->send_mtx); 4840227d67aaSAlexander Motin cam_devq_resize(devq, devq->send_queue.array_size - 1); 4841227d67aaSAlexander Motin mtx_unlock(&devq->send_mtx); 4842dcdf6e74SAlexander Motin 4843dcdf6e74SAlexander Motin KASSERT(SLIST_EMPTY(&device->periphs), 4844227d67aaSAlexander Motin ("destroying device, but periphs list is not empty")); 4845227d67aaSAlexander Motin KASSERT(device->devq_entry.index == CAM_UNQUEUED_INDEX, 4846227d67aaSAlexander Motin ("destroying device while still queued for ccbs")); 48472cefde5fSJustin T. Gibbs 48482cefde5fSJustin T. Gibbs if ((device->flags & CAM_DEV_REL_TIMEOUT_PENDING) != 0) 48492b83592fSScott Long callout_stop(&device->callout); 48502cefde5fSJustin T. Gibbs 4851227d67aaSAlexander Motin xpt_release_target(device->target); 4852227d67aaSAlexander Motin 485320a7933fSAlexander Motin cam_ccbq_fini(&device->ccbq); 4854e6bd5983SKenneth D. Merry /* 4855e6bd5983SKenneth D. Merry * Free allocated memory. free(9) does nothing if the 4856e6bd5983SKenneth D. Merry * supplied pointer is NULL, so it is safe to call without 4857e6bd5983SKenneth D. Merry * checking. 4858e6bd5983SKenneth D. Merry */ 4859e6bd5983SKenneth D. Merry free(device->supported_vpds, M_CAMXPT); 4860e6bd5983SKenneth D. Merry free(device->device_id, M_CAMXPT); 48613bba3152SKenneth D. Merry free(device->ext_inq, M_CAMXPT); 4862e6bd5983SKenneth D. Merry free(device->physpath, M_CAMXPT); 4863e6bd5983SKenneth D. Merry free(device->rcap_buf, M_CAMXPT); 4864e6bd5983SKenneth D. Merry free(device->serial_num, M_CAMXPT); 4865227d67aaSAlexander Motin taskqueue_enqueue(xsoftc.xpt_taskq, &device->device_destroy_task); 48668b8a9b1dSJustin T. Gibbs } 48678b8a9b1dSJustin T. Gibbs 486852c9ce25SScott Long u_int32_t 48698b8a9b1dSJustin T. Gibbs xpt_dev_ccbq_resize(struct cam_path *path, int newopenings) 48708b8a9b1dSJustin T. Gibbs { 48718b8a9b1dSJustin T. Gibbs int result; 48728b8a9b1dSJustin T. Gibbs struct cam_ed *dev; 48738b8a9b1dSJustin T. Gibbs 48748b8a9b1dSJustin T. Gibbs dev = path->device; 4875227d67aaSAlexander Motin mtx_lock(&dev->sim->devq->send_mtx); 48768b8a9b1dSJustin T. Gibbs result = cam_ccbq_resize(&dev->ccbq, newopenings); 4877227d67aaSAlexander Motin mtx_unlock(&dev->sim->devq->send_mtx); 4878df8f9080SJustin T. Gibbs if ((dev->flags & CAM_DEV_TAG_AFTER_COUNT) != 0 4879df8f9080SJustin T. Gibbs || (dev->inq_flags & SID_CmdQue) != 0) 4880df8f9080SJustin T. Gibbs dev->tag_saved_openings = newopenings; 48818b8a9b1dSJustin T. Gibbs return (result); 48828b8a9b1dSJustin T. Gibbs } 48838b8a9b1dSJustin T. Gibbs 48848b8a9b1dSJustin T. Gibbs static struct cam_eb * 48858b8a9b1dSJustin T. Gibbs xpt_find_bus(path_id_t path_id) 48868b8a9b1dSJustin T. Gibbs { 48878b8a9b1dSJustin T. Gibbs struct cam_eb *bus; 48888b8a9b1dSJustin T. Gibbs 48899a7c2696SAlexander Motin xpt_lock_buses(); 48902b83592fSScott Long for (bus = TAILQ_FIRST(&xsoftc.xpt_busses); 48918b8a9b1dSJustin T. Gibbs bus != NULL; 48928b8a9b1dSJustin T. Gibbs bus = TAILQ_NEXT(bus, links)) { 4893a5479bc5SJustin T. Gibbs if (bus->path_id == path_id) { 4894a5479bc5SJustin T. Gibbs bus->refcount++; 48958b8a9b1dSJustin T. Gibbs break; 48968b8a9b1dSJustin T. Gibbs } 4897a5479bc5SJustin T. Gibbs } 48989a7c2696SAlexander Motin xpt_unlock_buses(); 48998b8a9b1dSJustin T. Gibbs return (bus); 49008b8a9b1dSJustin T. Gibbs } 49018b8a9b1dSJustin T. Gibbs 49028b8a9b1dSJustin T. Gibbs static struct cam_et * 49038b8a9b1dSJustin T. Gibbs xpt_find_target(struct cam_eb *bus, target_id_t target_id) 49048b8a9b1dSJustin T. Gibbs { 49058b8a9b1dSJustin T. Gibbs struct cam_et *target; 49068b8a9b1dSJustin T. Gibbs 4907227d67aaSAlexander Motin mtx_assert(&bus->eb_mtx, MA_OWNED); 49088b8a9b1dSJustin T. Gibbs for (target = TAILQ_FIRST(&bus->et_entries); 49098b8a9b1dSJustin T. Gibbs target != NULL; 49108b8a9b1dSJustin T. Gibbs target = TAILQ_NEXT(target, links)) { 49118b8a9b1dSJustin T. Gibbs if (target->target_id == target_id) { 49128b8a9b1dSJustin T. Gibbs target->refcount++; 49138b8a9b1dSJustin T. Gibbs break; 49148b8a9b1dSJustin T. Gibbs } 49158b8a9b1dSJustin T. Gibbs } 49168b8a9b1dSJustin T. Gibbs return (target); 49178b8a9b1dSJustin T. Gibbs } 49188b8a9b1dSJustin T. Gibbs 49198b8a9b1dSJustin T. Gibbs static struct cam_ed * 49208b8a9b1dSJustin T. Gibbs xpt_find_device(struct cam_et *target, lun_id_t lun_id) 49218b8a9b1dSJustin T. Gibbs { 49228b8a9b1dSJustin T. Gibbs struct cam_ed *device; 49238b8a9b1dSJustin T. Gibbs 4924227d67aaSAlexander Motin mtx_assert(&target->bus->eb_mtx, MA_OWNED); 49258b8a9b1dSJustin T. Gibbs for (device = TAILQ_FIRST(&target->ed_entries); 49268b8a9b1dSJustin T. Gibbs device != NULL; 49278b8a9b1dSJustin T. Gibbs device = TAILQ_NEXT(device, links)) { 49288b8a9b1dSJustin T. Gibbs if (device->lun_id == lun_id) { 49298b8a9b1dSJustin T. Gibbs device->refcount++; 49308b8a9b1dSJustin T. Gibbs break; 49318b8a9b1dSJustin T. Gibbs } 49328b8a9b1dSJustin T. Gibbs } 49338b8a9b1dSJustin T. Gibbs return (device); 49348b8a9b1dSJustin T. Gibbs } 49358b8a9b1dSJustin T. Gibbs 493630a4094fSAlexander Motin void 4937f0adc790SJustin T. Gibbs xpt_start_tags(struct cam_path *path) 4938f0adc790SJustin T. Gibbs { 4939fd21cc5eSJustin T. Gibbs struct ccb_relsim crs; 4940fd21cc5eSJustin T. Gibbs struct cam_ed *device; 4941fd21cc5eSJustin T. Gibbs struct cam_sim *sim; 4942fd21cc5eSJustin T. Gibbs int newopenings; 4943fd21cc5eSJustin T. Gibbs 4944fd21cc5eSJustin T. Gibbs device = path->device; 4945fd21cc5eSJustin T. Gibbs sim = path->bus->sim; 4946fd21cc5eSJustin T. Gibbs device->flags &= ~CAM_DEV_TAG_AFTER_COUNT; 4947fd21cc5eSJustin T. Gibbs xpt_freeze_devq(path, /*count*/1); 4948fd21cc5eSJustin T. Gibbs device->inq_flags |= SID_CmdQue; 4949df8f9080SJustin T. Gibbs if (device->tag_saved_openings != 0) 4950df8f9080SJustin T. Gibbs newopenings = device->tag_saved_openings; 4951df8f9080SJustin T. Gibbs else 495252c9ce25SScott Long newopenings = min(device->maxtags, 4953df8f9080SJustin T. Gibbs sim->max_tagged_dev_openings); 4954f0adc790SJustin T. Gibbs xpt_dev_ccbq_resize(path, newopenings); 4955581b2e78SAlexander Motin xpt_async(AC_GETDEV_CHANGED, path, NULL); 4956bbfa4aa1SAlexander Motin xpt_setup_ccb(&crs.ccb_h, path, CAM_PRIORITY_NORMAL); 4957fd21cc5eSJustin T. Gibbs crs.ccb_h.func_code = XPT_REL_SIMQ; 4958fd21cc5eSJustin T. Gibbs crs.release_flags = RELSIM_RELEASE_AFTER_QEMPTY; 4959fd21cc5eSJustin T. Gibbs crs.openings 4960fd21cc5eSJustin T. Gibbs = crs.release_timeout 4961fd21cc5eSJustin T. Gibbs = crs.qfrozen_cnt 4962fd21cc5eSJustin T. Gibbs = 0; 4963fd21cc5eSJustin T. Gibbs xpt_action((union ccb *)&crs); 4964fd21cc5eSJustin T. Gibbs } 4965fd21cc5eSJustin T. Gibbs 496630a4094fSAlexander Motin void 496730a4094fSAlexander Motin xpt_stop_tags(struct cam_path *path) 496830a4094fSAlexander Motin { 496930a4094fSAlexander Motin struct ccb_relsim crs; 497030a4094fSAlexander Motin struct cam_ed *device; 497130a4094fSAlexander Motin struct cam_sim *sim; 497230a4094fSAlexander Motin 497330a4094fSAlexander Motin device = path->device; 497430a4094fSAlexander Motin sim = path->bus->sim; 497530a4094fSAlexander Motin device->flags &= ~CAM_DEV_TAG_AFTER_COUNT; 497630a4094fSAlexander Motin device->tag_delay_count = 0; 497730a4094fSAlexander Motin xpt_freeze_devq(path, /*count*/1); 497830a4094fSAlexander Motin device->inq_flags &= ~SID_CmdQue; 497930a4094fSAlexander Motin xpt_dev_ccbq_resize(path, sim->max_dev_openings); 4980581b2e78SAlexander Motin xpt_async(AC_GETDEV_CHANGED, path, NULL); 498130a4094fSAlexander Motin xpt_setup_ccb(&crs.ccb_h, path, CAM_PRIORITY_NORMAL); 498230a4094fSAlexander Motin crs.ccb_h.func_code = XPT_REL_SIMQ; 498330a4094fSAlexander Motin crs.release_flags = RELSIM_RELEASE_AFTER_QEMPTY; 498430a4094fSAlexander Motin crs.openings 498530a4094fSAlexander Motin = crs.release_timeout 498630a4094fSAlexander Motin = crs.qfrozen_cnt 498730a4094fSAlexander Motin = 0; 498830a4094fSAlexander Motin xpt_action((union ccb *)&crs); 498930a4094fSAlexander Motin } 499030a4094fSAlexander Motin 499183c5d981SAlexander Motin static void 499283c5d981SAlexander Motin xpt_boot_delay(void *arg) 49938b8a9b1dSJustin T. Gibbs { 49942b83592fSScott Long 499583c5d981SAlexander Motin xpt_release_boot(); 49968b8a9b1dSJustin T. Gibbs } 49978b8a9b1dSJustin T. Gibbs 49988b8a9b1dSJustin T. Gibbs static void 49998b8a9b1dSJustin T. Gibbs xpt_config(void *arg) 50008b8a9b1dSJustin T. Gibbs { 50013393f8daSKenneth D. Merry /* 50023393f8daSKenneth D. Merry * Now that interrupts are enabled, go find our devices 50033393f8daSKenneth D. Merry */ 5004227d67aaSAlexander Motin if (taskqueue_start_threads(&xsoftc.xpt_taskq, 1, PRIBIO, "CAM taskq")) 5005227d67aaSAlexander Motin printf("xpt_config: failed to create taskqueue thread.\n"); 50068b8a9b1dSJustin T. Gibbs 5007f0f25b9cSAlexander Motin /* Setup debugging path */ 50088b8a9b1dSJustin T. Gibbs if (cam_dflags != CAM_DEBUG_NONE) { 5009227d67aaSAlexander Motin if (xpt_create_path(&cam_dpath, NULL, 50108b8a9b1dSJustin T. Gibbs CAM_DEBUG_BUS, CAM_DEBUG_TARGET, 50118b8a9b1dSJustin T. Gibbs CAM_DEBUG_LUN) != CAM_REQ_CMP) { 50128b8a9b1dSJustin T. Gibbs printf("xpt_config: xpt_create_path() failed for debug" 50138b8a9b1dSJustin T. Gibbs " target %d:%d:%d, debugging disabled\n", 50148b8a9b1dSJustin T. Gibbs CAM_DEBUG_BUS, CAM_DEBUG_TARGET, CAM_DEBUG_LUN); 50158b8a9b1dSJustin T. Gibbs cam_dflags = CAM_DEBUG_NONE; 50168b8a9b1dSJustin T. Gibbs } 50178b8a9b1dSJustin T. Gibbs } else 50188b8a9b1dSJustin T. Gibbs cam_dpath = NULL; 50198b8a9b1dSJustin T. Gibbs 502083c5d981SAlexander Motin periphdriver_init(1); 502183c5d981SAlexander Motin xpt_hold_boot(); 502283c5d981SAlexander Motin callout_init(&xsoftc.boot_callout, 1); 502385c9dd9dSSteven Hartland callout_reset_sbt(&xsoftc.boot_callout, SBT_1MS * xsoftc.boot_delay, 0, 502485c9dd9dSSteven Hartland xpt_boot_delay, NULL, 0); 502583c5d981SAlexander Motin /* Fire up rescan thread. */ 5026227d67aaSAlexander Motin if (kproc_kthread_add(xpt_scanner_thread, NULL, &cam_proc, NULL, 0, 0, 5027227d67aaSAlexander Motin "cam", "scanner")) { 50286f15a274SAlexander Motin printf("xpt_config: failed to create rescan thread.\n"); 50291e637ba6SAlexander Motin } 503083c5d981SAlexander Motin } 50318b8a9b1dSJustin T. Gibbs 503283c5d981SAlexander Motin void 503383c5d981SAlexander Motin xpt_hold_boot(void) 503483c5d981SAlexander Motin { 503583c5d981SAlexander Motin xpt_lock_buses(); 503683c5d981SAlexander Motin xsoftc.buses_to_config++; 503783c5d981SAlexander Motin xpt_unlock_buses(); 503883c5d981SAlexander Motin } 503983c5d981SAlexander Motin 504083c5d981SAlexander Motin void 504183c5d981SAlexander Motin xpt_release_boot(void) 504283c5d981SAlexander Motin { 504383c5d981SAlexander Motin xpt_lock_buses(); 504483c5d981SAlexander Motin xsoftc.buses_to_config--; 504583c5d981SAlexander Motin if (xsoftc.buses_to_config == 0 && xsoftc.buses_config_done == 0) { 504683c5d981SAlexander Motin struct xpt_task *task; 504783c5d981SAlexander Motin 504883c5d981SAlexander Motin xsoftc.buses_config_done = 1; 504983c5d981SAlexander Motin xpt_unlock_buses(); 5050db4fcadfSConrad Meyer /* Call manually because we don't have any buses */ 505183c5d981SAlexander Motin task = malloc(sizeof(struct xpt_task), M_CAMXPT, M_NOWAIT); 505283c5d981SAlexander Motin if (task != NULL) { 505383c5d981SAlexander Motin TASK_INIT(&task->task, 0, xpt_finishconfig_task, task); 505483c5d981SAlexander Motin taskqueue_enqueue(taskqueue_thread, &task->task); 50552863f7b1SJustin T. Gibbs } 505683c5d981SAlexander Motin } else 505783c5d981SAlexander Motin xpt_unlock_buses(); 50582863f7b1SJustin T. Gibbs } 50598b8a9b1dSJustin T. Gibbs 50608b8a9b1dSJustin T. Gibbs /* 50618b8a9b1dSJustin T. Gibbs * If the given device only has one peripheral attached to it, and if that 50628b8a9b1dSJustin T. Gibbs * peripheral is the passthrough driver, announce it. This insures that the 50638b8a9b1dSJustin T. Gibbs * user sees some sort of announcement for every peripheral in their system. 50648b8a9b1dSJustin T. Gibbs */ 50658b8a9b1dSJustin T. Gibbs static int 50668b8a9b1dSJustin T. Gibbs xptpassannouncefunc(struct cam_ed *device, void *arg) 50678b8a9b1dSJustin T. Gibbs { 50688b8a9b1dSJustin T. Gibbs struct cam_periph *periph; 50698b8a9b1dSJustin T. Gibbs int i; 50708b8a9b1dSJustin T. Gibbs 50718b8a9b1dSJustin T. Gibbs for (periph = SLIST_FIRST(&device->periphs), i = 0; periph != NULL; 50728b8a9b1dSJustin T. Gibbs periph = SLIST_NEXT(periph, periph_links), i++); 50738b8a9b1dSJustin T. Gibbs 50748b8a9b1dSJustin T. Gibbs periph = SLIST_FIRST(&device->periphs); 50758b8a9b1dSJustin T. Gibbs if ((i == 1) 50768b8a9b1dSJustin T. Gibbs && (strncmp(periph->periph_name, "pass", 4) == 0)) 50778b8a9b1dSJustin T. Gibbs xpt_announce_periph(periph, NULL); 50788b8a9b1dSJustin T. Gibbs 50798b8a9b1dSJustin T. Gibbs return(1); 50808b8a9b1dSJustin T. Gibbs } 50818b8a9b1dSJustin T. Gibbs 50828b8a9b1dSJustin T. Gibbs static void 50832b83592fSScott Long xpt_finishconfig_task(void *context, int pending) 50848b8a9b1dSJustin T. Gibbs { 50858b8a9b1dSJustin T. Gibbs 508683c5d981SAlexander Motin periphdriver_init(2); 50872b83592fSScott Long /* 50882b83592fSScott Long * Check for devices with no "standard" peripheral driver 50892b83592fSScott Long * attached. For any devices like that, announce the 50902b83592fSScott Long * passthrough driver so the user will see something. 50912b83592fSScott Long */ 50923089bb2eSAlexander Motin if (!bootverbose) 50932b83592fSScott Long xpt_for_all_devices(xptpassannouncefunc, NULL); 50942b83592fSScott Long 50952b83592fSScott Long /* Release our hook so that the boot can continue. */ 50962b83592fSScott Long config_intrhook_disestablish(xsoftc.xpt_config_hook); 50970dd50e9bSScott Long free(xsoftc.xpt_config_hook, M_CAMXPT); 50982b83592fSScott Long xsoftc.xpt_config_hook = NULL; 50992b83592fSScott Long 51002b83592fSScott Long free(context, M_CAMXPT); 51012b83592fSScott Long } 51022b83592fSScott Long 510385d92640SScott Long cam_status 510485d92640SScott Long xpt_register_async(int event, ac_callback_t *cbfunc, void *cbarg, 510585d92640SScott Long struct cam_path *path) 510685d92640SScott Long { 510785d92640SScott Long struct ccb_setasync csa; 510885d92640SScott Long cam_status status; 510985d92640SScott Long int xptpath = 0; 511085d92640SScott Long 511185d92640SScott Long if (path == NULL) { 511285d92640SScott Long status = xpt_create_path(&path, /*periph*/NULL, CAM_XPT_PATH_ID, 511385d92640SScott Long CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD); 5114227d67aaSAlexander Motin if (status != CAM_REQ_CMP) 511585d92640SScott Long return (status); 5116227d67aaSAlexander Motin xpt_path_lock(path); 511785d92640SScott Long xptpath = 1; 511885d92640SScott Long } 511985d92640SScott Long 512083c5d981SAlexander Motin xpt_setup_ccb(&csa.ccb_h, path, CAM_PRIORITY_NORMAL); 512185d92640SScott Long csa.ccb_h.func_code = XPT_SASYNC_CB; 512285d92640SScott Long csa.event_enable = event; 512385d92640SScott Long csa.callback = cbfunc; 512485d92640SScott Long csa.callback_arg = cbarg; 512585d92640SScott Long xpt_action((union ccb *)&csa); 512685d92640SScott Long status = csa.ccb_h.status; 51273501942bSJustin T. Gibbs 512869be012fSWarner Losh CAM_DEBUG(csa.ccb_h.path, CAM_DEBUG_TRACE, 512969be012fSWarner Losh ("xpt_register_async: func %p\n", cbfunc)); 513069be012fSWarner Losh 513185d92640SScott Long if (xptpath) { 5132227d67aaSAlexander Motin xpt_path_unlock(path); 513385d92640SScott Long xpt_free_path(path); 51343501942bSJustin T. Gibbs } 51357685edecSAlexander Motin 51367685edecSAlexander Motin if ((status == CAM_REQ_CMP) && 51377685edecSAlexander Motin (csa.event_enable & AC_FOUND_DEVICE)) { 51387685edecSAlexander Motin /* 51397685edecSAlexander Motin * Get this peripheral up to date with all 51407685edecSAlexander Motin * the currently existing devices. 51417685edecSAlexander Motin */ 51427685edecSAlexander Motin xpt_for_all_devices(xptsetasyncfunc, &csa); 51437685edecSAlexander Motin } 51447685edecSAlexander Motin if ((status == CAM_REQ_CMP) && 51457685edecSAlexander Motin (csa.event_enable & AC_PATH_REGISTERED)) { 51467685edecSAlexander Motin /* 51477685edecSAlexander Motin * Get this peripheral up to date with all 5148db4fcadfSConrad Meyer * the currently existing buses. 51497685edecSAlexander Motin */ 51507685edecSAlexander Motin xpt_for_all_busses(xptsetasyncbusfunc, &csa); 51517685edecSAlexander Motin } 51523501942bSJustin T. Gibbs 515385d92640SScott Long return (status); 515485d92640SScott Long } 515585d92640SScott Long 51568b8a9b1dSJustin T. Gibbs static void 51578b8a9b1dSJustin T. Gibbs xptaction(struct cam_sim *sim, union ccb *work_ccb) 51588b8a9b1dSJustin T. Gibbs { 51598b8a9b1dSJustin T. Gibbs CAM_DEBUG(work_ccb->ccb_h.path, CAM_DEBUG_TRACE, ("xptaction\n")); 51608b8a9b1dSJustin T. Gibbs 51618b8a9b1dSJustin T. Gibbs switch (work_ccb->ccb_h.func_code) { 51628b8a9b1dSJustin T. Gibbs /* Common cases first */ 51638b8a9b1dSJustin T. Gibbs case XPT_PATH_INQ: /* Path routing inquiry */ 51648b8a9b1dSJustin T. Gibbs { 51658b8a9b1dSJustin T. Gibbs struct ccb_pathinq *cpi; 51668b8a9b1dSJustin T. Gibbs 51678b8a9b1dSJustin T. Gibbs cpi = &work_ccb->cpi; 51688b8a9b1dSJustin T. Gibbs cpi->version_num = 1; /* XXX??? */ 51698b8a9b1dSJustin T. Gibbs cpi->hba_inquiry = 0; 51708b8a9b1dSJustin T. Gibbs cpi->target_sprt = 0; 51718b8a9b1dSJustin T. Gibbs cpi->hba_misc = 0; 51728b8a9b1dSJustin T. Gibbs cpi->hba_eng_cnt = 0; 51738b8a9b1dSJustin T. Gibbs cpi->max_target = 0; 51748b8a9b1dSJustin T. Gibbs cpi->max_lun = 0; 51758b8a9b1dSJustin T. Gibbs cpi->initiator_id = 0; 51764195c7deSAlan Somers strlcpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN); 51774195c7deSAlan Somers strlcpy(cpi->hba_vid, "", HBA_IDLEN); 51784195c7deSAlan Somers strlcpy(cpi->dev_name, sim->sim_name, DEV_IDLEN); 51798b8a9b1dSJustin T. Gibbs cpi->unit_number = sim->unit_number; 51808b8a9b1dSJustin T. Gibbs cpi->bus_id = sim->bus_id; 51819deea857SKenneth D. Merry cpi->base_transfer_speed = 0; 51823393f8daSKenneth D. Merry cpi->protocol = PROTO_UNSPECIFIED; 51833393f8daSKenneth D. Merry cpi->protocol_version = PROTO_VERSION_UNSPECIFIED; 51843393f8daSKenneth D. Merry cpi->transport = XPORT_UNSPECIFIED; 51853393f8daSKenneth D. Merry cpi->transport_version = XPORT_VERSION_UNSPECIFIED; 51868b8a9b1dSJustin T. Gibbs cpi->ccb_h.status = CAM_REQ_CMP; 51878b8a9b1dSJustin T. Gibbs xpt_done(work_ccb); 51888b8a9b1dSJustin T. Gibbs break; 51898b8a9b1dSJustin T. Gibbs } 51908b8a9b1dSJustin T. Gibbs default: 51918b8a9b1dSJustin T. Gibbs work_ccb->ccb_h.status = CAM_REQ_INVALID; 51928b8a9b1dSJustin T. Gibbs xpt_done(work_ccb); 51938b8a9b1dSJustin T. Gibbs break; 51948b8a9b1dSJustin T. Gibbs } 51958b8a9b1dSJustin T. Gibbs } 51968b8a9b1dSJustin T. Gibbs 51978b8a9b1dSJustin T. Gibbs /* 5198434bbf6eSJustin T. Gibbs * The xpt as a "controller" has no interrupt sources, so polling 5199434bbf6eSJustin T. Gibbs * is a no-op. 5200434bbf6eSJustin T. Gibbs */ 5201434bbf6eSJustin T. Gibbs static void 5202434bbf6eSJustin T. Gibbs xptpoll(struct cam_sim *sim) 5203434bbf6eSJustin T. Gibbs { 5204434bbf6eSJustin T. Gibbs } 5205434bbf6eSJustin T. Gibbs 52062b83592fSScott Long void 52072b83592fSScott Long xpt_lock_buses(void) 52082b83592fSScott Long { 52092b83592fSScott Long mtx_lock(&xsoftc.xpt_topo_lock); 52102b83592fSScott Long } 52112b83592fSScott Long 52122b83592fSScott Long void 52132b83592fSScott Long xpt_unlock_buses(void) 52142b83592fSScott Long { 52152b83592fSScott Long mtx_unlock(&xsoftc.xpt_topo_lock); 52162b83592fSScott Long } 52172b83592fSScott Long 5218227d67aaSAlexander Motin struct mtx * 5219227d67aaSAlexander Motin xpt_path_mtx(struct cam_path *path) 52208b8a9b1dSJustin T. Gibbs { 5221227d67aaSAlexander Motin 5222227d67aaSAlexander Motin return (&path->device->device_mtx); 5223227d67aaSAlexander Motin } 5224227d67aaSAlexander Motin 5225227d67aaSAlexander Motin static void 5226227d67aaSAlexander Motin xpt_done_process(struct ccb_hdr *ccb_h) 5227227d67aaSAlexander Motin { 52282b83592fSScott Long struct cam_sim *sim; 5229227d67aaSAlexander Motin struct cam_devq *devq; 5230227d67aaSAlexander Motin struct mtx *mtx = NULL; 52318b8a9b1dSJustin T. Gibbs 52328532d381SConrad Meyer #if defined(BUF_TRACKING) || defined(FULL_BUF_TRACKING) 52338532d381SConrad Meyer struct ccb_scsiio *csio; 52348532d381SConrad Meyer 52358532d381SConrad Meyer if (ccb_h->func_code == XPT_SCSI_IO) { 52368532d381SConrad Meyer csio = &((union ccb *)ccb_h)->csio; 52378532d381SConrad Meyer if (csio->bio != NULL) 52388532d381SConrad Meyer biotrack(csio->bio, __func__); 52398532d381SConrad Meyer } 52408532d381SConrad Meyer #endif 52418532d381SConrad Meyer 52428b8a9b1dSJustin T. Gibbs if (ccb_h->flags & CAM_HIGH_POWER) { 52438b8a9b1dSJustin T. Gibbs struct highpowerlist *hphead; 5244ea541bfdSAlexander Motin struct cam_ed *device; 52458b8a9b1dSJustin T. Gibbs 5246daa5487fSAlexander Motin mtx_lock(&xsoftc.xpt_highpower_lock); 52472b83592fSScott Long hphead = &xsoftc.highpowerq; 52488b8a9b1dSJustin T. Gibbs 5249ea541bfdSAlexander Motin device = STAILQ_FIRST(hphead); 52508b8a9b1dSJustin T. Gibbs 52518b8a9b1dSJustin T. Gibbs /* 52528b8a9b1dSJustin T. Gibbs * Increment the count since this command is done. 52538b8a9b1dSJustin T. Gibbs */ 52542b83592fSScott Long xsoftc.num_highpower++; 52558b8a9b1dSJustin T. Gibbs 52568b8a9b1dSJustin T. Gibbs /* 52578b8a9b1dSJustin T. Gibbs * Any high powered commands queued up? 52588b8a9b1dSJustin T. Gibbs */ 5259ea541bfdSAlexander Motin if (device != NULL) { 52608b8a9b1dSJustin T. Gibbs 5261ea541bfdSAlexander Motin STAILQ_REMOVE_HEAD(hphead, highpowerq_entry); 5262daa5487fSAlexander Motin mtx_unlock(&xsoftc.xpt_highpower_lock); 52638b8a9b1dSJustin T. Gibbs 5264227d67aaSAlexander Motin mtx_lock(&device->sim->devq->send_mtx); 5265ea541bfdSAlexander Motin xpt_release_devq_device(device, 52662cefde5fSJustin T. Gibbs /*count*/1, /*runqueue*/TRUE); 5267227d67aaSAlexander Motin mtx_unlock(&device->sim->devq->send_mtx); 52682b83592fSScott Long } else 5269daa5487fSAlexander Motin mtx_unlock(&xsoftc.xpt_highpower_lock); 52708b8a9b1dSJustin T. Gibbs } 52712b83592fSScott Long 5272227d67aaSAlexander Motin sim = ccb_h->path->bus->sim; 5273227d67aaSAlexander Motin 5274227d67aaSAlexander Motin if (ccb_h->status & CAM_RELEASE_SIMQ) { 5275227d67aaSAlexander Motin xpt_release_simq(sim, /*run_queue*/FALSE); 5276227d67aaSAlexander Motin ccb_h->status &= ~CAM_RELEASE_SIMQ; 5277227d67aaSAlexander Motin } 5278227d67aaSAlexander Motin 5279227d67aaSAlexander Motin if ((ccb_h->flags & CAM_DEV_QFRZDIS) 5280227d67aaSAlexander Motin && (ccb_h->status & CAM_DEV_QFRZN)) { 5281d718926bSAlexander Motin xpt_release_devq(ccb_h->path, /*count*/1, /*run_queue*/TRUE); 5282227d67aaSAlexander Motin ccb_h->status &= ~CAM_DEV_QFRZN; 5283227d67aaSAlexander Motin } 5284227d67aaSAlexander Motin 5285227d67aaSAlexander Motin devq = sim->devq; 52869deea857SKenneth D. Merry if ((ccb_h->func_code & XPT_FC_USER_CCB) == 0) { 5287227d67aaSAlexander Motin struct cam_ed *dev = ccb_h->path->device; 52888b8a9b1dSJustin T. Gibbs 5289227d67aaSAlexander Motin mtx_lock(&devq->send_mtx); 5290227d67aaSAlexander Motin devq->send_active--; 5291227d67aaSAlexander Motin devq->send_openings++; 52928b8a9b1dSJustin T. Gibbs cam_ccbq_ccb_done(&dev->ccbq, (union ccb *)ccb_h); 52938b8a9b1dSJustin T. Gibbs 5294b9c473b2SAlexander Motin if (((dev->flags & CAM_DEV_REL_ON_QUEUE_EMPTY) != 0 52958b8a9b1dSJustin T. Gibbs && (dev->ccbq.dev_active == 0))) { 5296b9c473b2SAlexander Motin dev->flags &= ~CAM_DEV_REL_ON_QUEUE_EMPTY; 5297227d67aaSAlexander Motin xpt_release_devq_device(dev, /*count*/1, 5298b9c473b2SAlexander Motin /*run_queue*/FALSE); 5299b9c473b2SAlexander Motin } 5300b9c473b2SAlexander Motin 5301b9c473b2SAlexander Motin if (((dev->flags & CAM_DEV_REL_ON_COMPLETE) != 0 5302b9c473b2SAlexander Motin && (ccb_h->status&CAM_STATUS_MASK) != CAM_REQUEUE_REQ)) { 5303b9c473b2SAlexander Motin dev->flags &= ~CAM_DEV_REL_ON_COMPLETE; 5304227d67aaSAlexander Motin xpt_release_devq_device(dev, /*count*/1, 530583c5d981SAlexander Motin /*run_queue*/FALSE); 53068b8a9b1dSJustin T. Gibbs } 53078b8a9b1dSJustin T. Gibbs 5308227d67aaSAlexander Motin if (!device_is_queued(dev)) 5309227d67aaSAlexander Motin (void)xpt_schedule_devq(devq, dev); 5310d718926bSAlexander Motin xpt_run_devq(devq); 5311227d67aaSAlexander Motin mtx_unlock(&devq->send_mtx); 5312227d67aaSAlexander Motin 5313227d67aaSAlexander Motin if ((dev->flags & CAM_DEV_TAG_AFTER_COUNT) != 0) { 5314227d67aaSAlexander Motin mtx = xpt_path_mtx(ccb_h->path); 5315227d67aaSAlexander Motin mtx_lock(mtx); 5316227d67aaSAlexander Motin 5317fd21cc5eSJustin T. Gibbs if ((dev->flags & CAM_DEV_TAG_AFTER_COUNT) != 0 5318fd21cc5eSJustin T. Gibbs && (--dev->tag_delay_count == 0)) 5319fd21cc5eSJustin T. Gibbs xpt_start_tags(ccb_h->path); 53203501942bSJustin T. Gibbs } 53218b8a9b1dSJustin T. Gibbs } 53228b8a9b1dSJustin T. Gibbs 5323227d67aaSAlexander Motin if ((ccb_h->flags & CAM_UNLOCKED) == 0) { 5324227d67aaSAlexander Motin if (mtx == NULL) { 5325227d67aaSAlexander Motin mtx = xpt_path_mtx(ccb_h->path); 5326227d67aaSAlexander Motin mtx_lock(mtx); 5327434bbf6eSJustin T. Gibbs } 5328227d67aaSAlexander Motin } else { 5329227d67aaSAlexander Motin if (mtx != NULL) { 5330227d67aaSAlexander Motin mtx_unlock(mtx); 5331227d67aaSAlexander Motin mtx = NULL; 5332227d67aaSAlexander Motin } 53338b8a9b1dSJustin T. Gibbs } 53348b8a9b1dSJustin T. Gibbs 53358b8a9b1dSJustin T. Gibbs /* Call the peripheral driver's callback */ 5336f1486b51SAlexander Motin ccb_h->pinfo.index = CAM_UNQUEUED_INDEX; 5337434bbf6eSJustin T. Gibbs (*ccb_h->cbfcnp)(ccb_h->path->periph, (union ccb *)ccb_h); 5338227d67aaSAlexander Motin if (mtx != NULL) 5339227d67aaSAlexander Motin mtx_unlock(mtx); 5340227d67aaSAlexander Motin } 5341227d67aaSAlexander Motin 5342227d67aaSAlexander Motin void 5343227d67aaSAlexander Motin xpt_done_td(void *arg) 5344227d67aaSAlexander Motin { 5345227d67aaSAlexander Motin struct cam_doneq *queue = arg; 5346227d67aaSAlexander Motin struct ccb_hdr *ccb_h; 5347227d67aaSAlexander Motin STAILQ_HEAD(, ccb_hdr) doneq; 5348227d67aaSAlexander Motin 5349227d67aaSAlexander Motin STAILQ_INIT(&doneq); 5350227d67aaSAlexander Motin mtx_lock(&queue->cam_doneq_mtx); 5351227d67aaSAlexander Motin while (1) { 5352227d67aaSAlexander Motin while (STAILQ_EMPTY(&queue->cam_doneq)) { 5353227d67aaSAlexander Motin queue->cam_doneq_sleep = 1; 5354227d67aaSAlexander Motin msleep(&queue->cam_doneq, &queue->cam_doneq_mtx, 5355227d67aaSAlexander Motin PRIBIO, "-", 0); 5356227d67aaSAlexander Motin queue->cam_doneq_sleep = 0; 5357227d67aaSAlexander Motin } 5358227d67aaSAlexander Motin STAILQ_CONCAT(&doneq, &queue->cam_doneq); 5359227d67aaSAlexander Motin mtx_unlock(&queue->cam_doneq_mtx); 5360227d67aaSAlexander Motin 5361227d67aaSAlexander Motin THREAD_NO_SLEEPING(); 5362227d67aaSAlexander Motin while ((ccb_h = STAILQ_FIRST(&doneq)) != NULL) { 5363227d67aaSAlexander Motin STAILQ_REMOVE_HEAD(&doneq, sim_links.stqe); 5364227d67aaSAlexander Motin xpt_done_process(ccb_h); 5365227d67aaSAlexander Motin } 5366227d67aaSAlexander Motin THREAD_SLEEPING_OK(); 5367227d67aaSAlexander Motin 5368227d67aaSAlexander Motin mtx_lock(&queue->cam_doneq_mtx); 5369227d67aaSAlexander Motin } 5370227d67aaSAlexander Motin } 5371227d67aaSAlexander Motin 5372227d67aaSAlexander Motin static void 5373227d67aaSAlexander Motin camisr_runqueue(void) 5374227d67aaSAlexander Motin { 5375227d67aaSAlexander Motin struct ccb_hdr *ccb_h; 5376227d67aaSAlexander Motin struct cam_doneq *queue; 5377227d67aaSAlexander Motin int i; 5378227d67aaSAlexander Motin 5379227d67aaSAlexander Motin /* Process global queues. */ 5380227d67aaSAlexander Motin for (i = 0; i < cam_num_doneqs; i++) { 5381227d67aaSAlexander Motin queue = &cam_doneqs[i]; 5382227d67aaSAlexander Motin mtx_lock(&queue->cam_doneq_mtx); 5383227d67aaSAlexander Motin while ((ccb_h = STAILQ_FIRST(&queue->cam_doneq)) != NULL) { 5384227d67aaSAlexander Motin STAILQ_REMOVE_HEAD(&queue->cam_doneq, sim_links.stqe); 5385227d67aaSAlexander Motin mtx_unlock(&queue->cam_doneq_mtx); 5386227d67aaSAlexander Motin xpt_done_process(ccb_h); 5387227d67aaSAlexander Motin mtx_lock(&queue->cam_doneq_mtx); 5388227d67aaSAlexander Motin } 5389227d67aaSAlexander Motin mtx_unlock(&queue->cam_doneq_mtx); 53908b8a9b1dSJustin T. Gibbs } 53918b8a9b1dSJustin T. Gibbs } 539269be012fSWarner Losh 539369be012fSWarner Losh struct kv 539469be012fSWarner Losh { 539569be012fSWarner Losh uint32_t v; 539669be012fSWarner Losh const char *name; 539769be012fSWarner Losh }; 539869be012fSWarner Losh 539969be012fSWarner Losh static struct kv map[] = { 540069be012fSWarner Losh { XPT_NOOP, "XPT_NOOP" }, 540169be012fSWarner Losh { XPT_SCSI_IO, "XPT_SCSI_IO" }, 540269be012fSWarner Losh { XPT_GDEV_TYPE, "XPT_GDEV_TYPE" }, 540369be012fSWarner Losh { XPT_GDEVLIST, "XPT_GDEVLIST" }, 540469be012fSWarner Losh { XPT_PATH_INQ, "XPT_PATH_INQ" }, 540569be012fSWarner Losh { XPT_REL_SIMQ, "XPT_REL_SIMQ" }, 540669be012fSWarner Losh { XPT_SASYNC_CB, "XPT_SASYNC_CB" }, 540769be012fSWarner Losh { XPT_SDEV_TYPE, "XPT_SDEV_TYPE" }, 540869be012fSWarner Losh { XPT_SCAN_BUS, "XPT_SCAN_BUS" }, 540969be012fSWarner Losh { XPT_DEV_MATCH, "XPT_DEV_MATCH" }, 541069be012fSWarner Losh { XPT_DEBUG, "XPT_DEBUG" }, 541169be012fSWarner Losh { XPT_PATH_STATS, "XPT_PATH_STATS" }, 541269be012fSWarner Losh { XPT_GDEV_STATS, "XPT_GDEV_STATS" }, 541369be012fSWarner Losh { XPT_DEV_ADVINFO, "XPT_DEV_ADVINFO" }, 541469be012fSWarner Losh { XPT_ASYNC, "XPT_ASYNC" }, 541569be012fSWarner Losh { XPT_ABORT, "XPT_ABORT" }, 541669be012fSWarner Losh { XPT_RESET_BUS, "XPT_RESET_BUS" }, 541769be012fSWarner Losh { XPT_RESET_DEV, "XPT_RESET_DEV" }, 541869be012fSWarner Losh { XPT_TERM_IO, "XPT_TERM_IO" }, 541969be012fSWarner Losh { XPT_SCAN_LUN, "XPT_SCAN_LUN" }, 542069be012fSWarner Losh { XPT_GET_TRAN_SETTINGS, "XPT_GET_TRAN_SETTINGS" }, 542169be012fSWarner Losh { XPT_SET_TRAN_SETTINGS, "XPT_SET_TRAN_SETTINGS" }, 542269be012fSWarner Losh { XPT_CALC_GEOMETRY, "XPT_CALC_GEOMETRY" }, 542369be012fSWarner Losh { XPT_ATA_IO, "XPT_ATA_IO" }, 542469be012fSWarner Losh { XPT_GET_SIM_KNOB, "XPT_GET_SIM_KNOB" }, 542569be012fSWarner Losh { XPT_SET_SIM_KNOB, "XPT_SET_SIM_KNOB" }, 54267b05c3e3SWarner Losh { XPT_NVME_IO, "XPT_NVME_IO" }, 5427bbb19fc7SWarner Losh { XPT_MMCSD_IO, "XPT_MMCSD_IO" }, 542869be012fSWarner Losh { XPT_SMP_IO, "XPT_SMP_IO" }, 542969be012fSWarner Losh { XPT_SCAN_TGT, "XPT_SCAN_TGT" }, 543069be012fSWarner Losh { XPT_ENG_INQ, "XPT_ENG_INQ" }, 543169be012fSWarner Losh { XPT_ENG_EXEC, "XPT_ENG_EXEC" }, 543269be012fSWarner Losh { XPT_EN_LUN, "XPT_EN_LUN" }, 543369be012fSWarner Losh { XPT_TARGET_IO, "XPT_TARGET_IO" }, 543469be012fSWarner Losh { XPT_ACCEPT_TARGET_IO, "XPT_ACCEPT_TARGET_IO" }, 543569be012fSWarner Losh { XPT_CONT_TARGET_IO, "XPT_CONT_TARGET_IO" }, 543669be012fSWarner Losh { XPT_IMMED_NOTIFY, "XPT_IMMED_NOTIFY" }, 543769be012fSWarner Losh { XPT_NOTIFY_ACK, "XPT_NOTIFY_ACK" }, 543869be012fSWarner Losh { XPT_IMMEDIATE_NOTIFY, "XPT_IMMEDIATE_NOTIFY" }, 543969be012fSWarner Losh { XPT_NOTIFY_ACKNOWLEDGE, "XPT_NOTIFY_ACKNOWLEDGE" }, 544069be012fSWarner Losh { 0, 0 } 544169be012fSWarner Losh }; 544269be012fSWarner Losh 544369be012fSWarner Losh static const char * 544469be012fSWarner Losh xpt_action_name(uint32_t action) 544569be012fSWarner Losh { 544669be012fSWarner Losh static char buffer[32]; /* Only for unknown messages -- racy */ 544769be012fSWarner Losh struct kv *walker = map; 544869be012fSWarner Losh 544969be012fSWarner Losh while (walker->name != NULL) { 545069be012fSWarner Losh if (walker->v == action) 545169be012fSWarner Losh return (walker->name); 545269be012fSWarner Losh walker++; 545369be012fSWarner Losh } 545469be012fSWarner Losh 545569be012fSWarner Losh snprintf(buffer, sizeof(buffer), "%#x", action); 545669be012fSWarner Losh return (buffer); 545769be012fSWarner Losh } 5458