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 309c963d87SDavid E. O'Brien #include <sys/cdefs.h> 319c963d87SDavid E. O'Brien __FBSDID("$FreeBSD$"); 329c963d87SDavid E. O'Brien 338b8a9b1dSJustin T. Gibbs #include <sys/param.h> 349a94c9c5SJohn Baldwin #include <sys/bus.h> 358b8a9b1dSJustin T. Gibbs #include <sys/systm.h> 368b8a9b1dSJustin T. Gibbs #include <sys/types.h> 378b8a9b1dSJustin T. Gibbs #include <sys/malloc.h> 388b8a9b1dSJustin T. Gibbs #include <sys/kernel.h> 3987cfaf0eSJustin T. Gibbs #include <sys/time.h> 408b8a9b1dSJustin T. Gibbs #include <sys/conf.h> 418b8a9b1dSJustin T. Gibbs #include <sys/fcntl.h> 425d754af7SMatt Jacob #include <sys/interrupt.h> 433393f8daSKenneth D. Merry #include <sys/sbuf.h> 442b83592fSScott Long #include <sys/taskqueue.h> 458b8a9b1dSJustin T. Gibbs 46ef3cf714SScott Long #include <sys/lock.h> 47ef3cf714SScott Long #include <sys/mutex.h> 483b87a552SMatt Jacob #include <sys/sysctl.h> 499e6461a2SMatt Jacob #include <sys/kthread.h> 50ef3cf714SScott Long 518b8a9b1dSJustin T. Gibbs #include <cam/cam.h> 528b8a9b1dSJustin T. Gibbs #include <cam/cam_ccb.h> 538b8a9b1dSJustin T. Gibbs #include <cam/cam_periph.h> 5452c9ce25SScott Long #include <cam/cam_queue.h> 558b8a9b1dSJustin T. Gibbs #include <cam/cam_sim.h> 568b8a9b1dSJustin T. Gibbs #include <cam/cam_xpt.h> 578b8a9b1dSJustin T. Gibbs #include <cam/cam_xpt_sim.h> 588b8a9b1dSJustin T. Gibbs #include <cam/cam_xpt_periph.h> 5952c9ce25SScott Long #include <cam/cam_xpt_internal.h> 608b8a9b1dSJustin T. Gibbs #include <cam/cam_debug.h> 6125a2902cSScott Long #include <cam/cam_compat.h> 628b8a9b1dSJustin T. Gibbs 638b8a9b1dSJustin T. Gibbs #include <cam/scsi/scsi_all.h> 648b8a9b1dSJustin T. Gibbs #include <cam/scsi/scsi_message.h> 658b8a9b1dSJustin T. Gibbs #include <cam/scsi/scsi_pass.h> 66abef0e67SMarius Strobl 67abef0e67SMarius Strobl #include <machine/md_var.h> /* geometry translation */ 68f0d9af51SMatt Jacob #include <machine/stdarg.h> /* for xpt_print below */ 69abef0e67SMarius Strobl 708b8a9b1dSJustin T. Gibbs #include "opt_cam.h" 718b8a9b1dSJustin T. Gibbs 7252c9ce25SScott Long /* 7352c9ce25SScott Long * This is the maximum number of high powered commands (e.g. start unit) 7452c9ce25SScott Long * that can be outstanding at a particular time. 7552c9ce25SScott Long */ 7652c9ce25SScott Long #ifndef CAM_MAX_HIGHPOWER 7752c9ce25SScott Long #define CAM_MAX_HIGHPOWER 4 7852c9ce25SScott Long #endif 7952c9ce25SScott Long 808b8a9b1dSJustin T. Gibbs /* Datastructures internal to the xpt layer */ 81362abc44STai-hwa Liang MALLOC_DEFINE(M_CAMXPT, "CAM XPT", "CAM XPT buffers"); 82596ee08fSAlexander Motin MALLOC_DEFINE(M_CAMDEV, "CAM DEV", "CAM devices"); 83596ee08fSAlexander Motin MALLOC_DEFINE(M_CAMCCB, "CAM CCB", "CAM CCBs"); 84596ee08fSAlexander Motin MALLOC_DEFINE(M_CAMPATH, "CAM path", "CAM paths"); 858b8a9b1dSJustin T. Gibbs 862b83592fSScott Long /* Object for defering XPT actions to a taskqueue */ 872b83592fSScott Long struct xpt_task { 882b83592fSScott Long struct task task; 8984f82481SScott Long void *data1; 9084f82481SScott Long uintptr_t data2; 912b83592fSScott Long }; 922b83592fSScott Long 938b8a9b1dSJustin T. Gibbs typedef enum { 948b8a9b1dSJustin T. Gibbs XPT_FLAG_OPEN = 0x01 958b8a9b1dSJustin T. Gibbs } xpt_flags; 968b8a9b1dSJustin T. Gibbs 978b8a9b1dSJustin T. Gibbs struct xpt_softc { 988b8a9b1dSJustin T. Gibbs xpt_flags flags; 992b83592fSScott Long 1002b83592fSScott Long /* number of high powered commands that can go through right now */ 101ea541bfdSAlexander Motin STAILQ_HEAD(highpowerlist, cam_ed) highpowerq; 1022b83592fSScott Long int num_highpower; 1032b83592fSScott Long 1042b83592fSScott Long /* queue for handling async rescan requests. */ 1052b83592fSScott Long TAILQ_HEAD(, ccb_hdr) ccb_scanq; 10683c5d981SAlexander Motin int buses_to_config; 10783c5d981SAlexander Motin int buses_config_done; 1082b83592fSScott Long 1092b83592fSScott Long /* Registered busses */ 1102b83592fSScott Long TAILQ_HEAD(,cam_eb) xpt_busses; 1112b83592fSScott Long u_int bus_generation; 1122b83592fSScott Long 1132b83592fSScott Long struct intr_config_hook *xpt_config_hook; 1142b83592fSScott Long 11583c5d981SAlexander Motin int boot_delay; 11683c5d981SAlexander Motin struct callout boot_callout; 11783c5d981SAlexander Motin 1182b83592fSScott Long struct mtx xpt_topo_lock; 1192b83592fSScott Long struct mtx xpt_lock; 1208b8a9b1dSJustin T. Gibbs }; 1218b8a9b1dSJustin T. Gibbs 1228b8a9b1dSJustin T. Gibbs typedef enum { 1238b8a9b1dSJustin T. Gibbs DM_RET_COPY = 0x01, 1248b8a9b1dSJustin T. Gibbs DM_RET_FLAG_MASK = 0x0f, 1258b8a9b1dSJustin T. Gibbs DM_RET_NONE = 0x00, 1268b8a9b1dSJustin T. Gibbs DM_RET_STOP = 0x10, 1278b8a9b1dSJustin T. Gibbs DM_RET_DESCEND = 0x20, 1288b8a9b1dSJustin T. Gibbs DM_RET_ERROR = 0x30, 1298b8a9b1dSJustin T. Gibbs DM_RET_ACTION_MASK = 0xf0 1308b8a9b1dSJustin T. Gibbs } dev_match_ret; 1318b8a9b1dSJustin T. Gibbs 1328b8a9b1dSJustin T. Gibbs typedef enum { 1338b8a9b1dSJustin T. Gibbs XPT_DEPTH_BUS, 1348b8a9b1dSJustin T. Gibbs XPT_DEPTH_TARGET, 1358b8a9b1dSJustin T. Gibbs XPT_DEPTH_DEVICE, 1368b8a9b1dSJustin T. Gibbs XPT_DEPTH_PERIPH 1378b8a9b1dSJustin T. Gibbs } xpt_traverse_depth; 1388b8a9b1dSJustin T. Gibbs 1398b8a9b1dSJustin T. Gibbs struct xpt_traverse_config { 1408b8a9b1dSJustin T. Gibbs xpt_traverse_depth depth; 1418b8a9b1dSJustin T. Gibbs void *tr_func; 1428b8a9b1dSJustin T. Gibbs void *tr_arg; 1438b8a9b1dSJustin T. Gibbs }; 1448b8a9b1dSJustin T. Gibbs 1458b8a9b1dSJustin T. Gibbs typedef int xpt_busfunc_t (struct cam_eb *bus, void *arg); 1468b8a9b1dSJustin T. Gibbs typedef int xpt_targetfunc_t (struct cam_et *target, void *arg); 1478b8a9b1dSJustin T. Gibbs typedef int xpt_devicefunc_t (struct cam_ed *device, void *arg); 1488b8a9b1dSJustin T. Gibbs typedef int xpt_periphfunc_t (struct cam_periph *periph, void *arg); 1498b8a9b1dSJustin T. Gibbs typedef int xpt_pdrvfunc_t (struct periph_driver **pdrv, void *arg); 1508b8a9b1dSJustin T. Gibbs 1518b8a9b1dSJustin T. Gibbs /* Transport layer configuration information */ 1528b8a9b1dSJustin T. Gibbs static struct xpt_softc xsoftc; 1538b8a9b1dSJustin T. Gibbs 15483c5d981SAlexander Motin TUNABLE_INT("kern.cam.boot_delay", &xsoftc.boot_delay); 15583c5d981SAlexander Motin SYSCTL_INT(_kern_cam, OID_AUTO, boot_delay, CTLFLAG_RDTUN, 15683c5d981SAlexander Motin &xsoftc.boot_delay, 0, "Bus registration wait time"); 15783c5d981SAlexander Motin 1588b8a9b1dSJustin T. Gibbs /* Queues for our software interrupt handler */ 159e3975643SJake Burkholder typedef TAILQ_HEAD(cam_isrq, ccb_hdr) cam_isrq_t; 1609758cc83SScott Long typedef TAILQ_HEAD(cam_simq, cam_sim) cam_simq_t; 1619758cc83SScott Long static cam_simq_t cam_simq; 1629758cc83SScott Long static struct mtx cam_simq_lock; 1638b8a9b1dSJustin T. Gibbs 1642b83592fSScott Long /* Pointers to software interrupt handlers */ 1652b83592fSScott Long static void *cambio_ih; 1668b8a9b1dSJustin T. Gibbs 1679a1c8571SNick Hibma struct cam_periph *xpt_periph; 1689a1c8571SNick Hibma 1698b8a9b1dSJustin T. Gibbs static periph_init_t xpt_periph_init; 1708b8a9b1dSJustin T. Gibbs 1718b8a9b1dSJustin T. Gibbs static struct periph_driver xpt_driver = 1728b8a9b1dSJustin T. Gibbs { 1738b8a9b1dSJustin T. Gibbs xpt_periph_init, "xpt", 1741e637ba6SAlexander Motin TAILQ_HEAD_INITIALIZER(xpt_driver.units), /* generation */ 0, 1751e637ba6SAlexander Motin CAM_PERIPH_DRV_EARLY 1768b8a9b1dSJustin T. Gibbs }; 1778b8a9b1dSJustin T. Gibbs 1780b7c27b9SPeter Wemm PERIPHDRIVER_DECLARE(xpt, xpt_driver); 1798b8a9b1dSJustin T. Gibbs 1808b8a9b1dSJustin T. Gibbs static d_open_t xptopen; 1818b8a9b1dSJustin T. Gibbs static d_close_t xptclose; 1828b8a9b1dSJustin T. Gibbs static d_ioctl_t xptioctl; 18325a2902cSScott Long static d_ioctl_t xptdoioctl; 1848b8a9b1dSJustin T. Gibbs 1854e2f199eSPoul-Henning Kamp static struct cdevsw xpt_cdevsw = { 186dc08ffecSPoul-Henning Kamp .d_version = D_VERSION, 1872b83592fSScott Long .d_flags = 0, 1887ac40f5fSPoul-Henning Kamp .d_open = xptopen, 1897ac40f5fSPoul-Henning Kamp .d_close = xptclose, 1907ac40f5fSPoul-Henning Kamp .d_ioctl = xptioctl, 1917ac40f5fSPoul-Henning Kamp .d_name = "xpt", 1928b8a9b1dSJustin T. Gibbs }; 1938b8a9b1dSJustin T. Gibbs 1948b8a9b1dSJustin T. Gibbs /* Storage for debugging datastructures */ 1958b8a9b1dSJustin T. Gibbs struct cam_path *cam_dpath; 19682b361b1SMatt Jacob u_int32_t cam_dflags = CAM_DEBUG_FLAGS; 19782b361b1SMatt Jacob TUNABLE_INT("kern.cam.dflags", &cam_dflags); 198240577c2SMatthew D Fleming SYSCTL_UINT(_kern_cam, OID_AUTO, dflags, CTLFLAG_RW, 199f0f25b9cSAlexander Motin &cam_dflags, 0, "Enabled debug flags"); 200f0f25b9cSAlexander Motin u_int32_t cam_debug_delay = CAM_DEBUG_DELAY; 20182b361b1SMatt Jacob TUNABLE_INT("kern.cam.debug_delay", &cam_debug_delay); 202240577c2SMatthew D Fleming SYSCTL_UINT(_kern_cam, OID_AUTO, debug_delay, CTLFLAG_RW, 203f0f25b9cSAlexander Motin &cam_debug_delay, 0, "Delay in us after each debug message"); 2048b8a9b1dSJustin T. Gibbs 2056d2a8f1cSPeter Wemm /* Our boot-time initialization hook */ 20674bd1c10SNick Hibma static int cam_module_event_handler(module_t, int /*modeventtype_t*/, void *); 20774bd1c10SNick Hibma 20874bd1c10SNick Hibma static moduledata_t cam_moduledata = { 20974bd1c10SNick Hibma "cam", 21074bd1c10SNick Hibma cam_module_event_handler, 21174bd1c10SNick Hibma NULL 21274bd1c10SNick Hibma }; 21374bd1c10SNick Hibma 2142b83592fSScott Long static int xpt_init(void *); 21574bd1c10SNick Hibma 21674bd1c10SNick Hibma DECLARE_MODULE(cam, cam_moduledata, SI_SUB_CONFIGURE, SI_ORDER_SECOND); 21774bd1c10SNick Hibma MODULE_VERSION(cam, 1); 21874bd1c10SNick Hibma 2198b8a9b1dSJustin T. Gibbs 2208b8a9b1dSJustin T. Gibbs static void xpt_async_bcast(struct async_list *async_head, 2218b8a9b1dSJustin T. Gibbs u_int32_t async_code, 2228b8a9b1dSJustin T. Gibbs struct cam_path *path, 2238b8a9b1dSJustin T. Gibbs void *async_arg); 224434bbf6eSJustin T. Gibbs static path_id_t xptnextfreepathid(void); 225434bbf6eSJustin T. Gibbs static path_id_t xptpathid(const char *sim_name, int sim_unit, int sim_bus); 2268b8a9b1dSJustin T. Gibbs static union ccb *xpt_get_ccb(struct cam_ed *device); 227cccf4220SAlexander Motin static void xpt_run_dev_allocq(struct cam_ed *device); 228cccf4220SAlexander Motin static void xpt_run_devq(struct cam_devq *devq); 2298b8a9b1dSJustin T. Gibbs static timeout_t xpt_release_devq_timeout; 2302b83592fSScott Long static void xpt_release_simq_timeout(void *arg) __unused; 231a5479bc5SJustin T. Gibbs static void xpt_release_bus(struct cam_eb *bus); 232cccf4220SAlexander Motin static void xpt_release_devq_device(struct cam_ed *dev, u_int count, 233cccf4220SAlexander Motin int run_queue); 2348b8a9b1dSJustin T. Gibbs static struct cam_et* 2358b8a9b1dSJustin T. Gibbs xpt_alloc_target(struct cam_eb *bus, target_id_t target_id); 236f98d7a47SAlexander Motin static void xpt_release_target(struct cam_et *target); 2378b8a9b1dSJustin T. Gibbs static struct cam_eb* 2388b8a9b1dSJustin T. Gibbs xpt_find_bus(path_id_t path_id); 2398b8a9b1dSJustin T. Gibbs static struct cam_et* 2408b8a9b1dSJustin T. Gibbs xpt_find_target(struct cam_eb *bus, target_id_t target_id); 2418b8a9b1dSJustin T. Gibbs static struct cam_ed* 2428b8a9b1dSJustin T. Gibbs xpt_find_device(struct cam_et *target, lun_id_t lun_id); 2438b8a9b1dSJustin T. Gibbs static void xpt_config(void *arg); 2448b8a9b1dSJustin T. Gibbs static xpt_devicefunc_t xptpassannouncefunc; 2458b8a9b1dSJustin T. Gibbs static void xptaction(struct cam_sim *sim, union ccb *work_ccb); 246434bbf6eSJustin T. Gibbs static void xptpoll(struct cam_sim *sim); 2478088699fSJohn Baldwin static void camisr(void *); 24839fe6d85SAlexander Motin static void camisr_runqueue(struct cam_sim *); 2498b8a9b1dSJustin T. Gibbs static dev_match_ret xptbusmatch(struct dev_match_pattern *patterns, 2503393f8daSKenneth D. Merry u_int num_patterns, struct cam_eb *bus); 2518b8a9b1dSJustin T. Gibbs static dev_match_ret xptdevicematch(struct dev_match_pattern *patterns, 2523393f8daSKenneth D. Merry u_int num_patterns, 2533393f8daSKenneth D. Merry struct cam_ed *device); 2548b8a9b1dSJustin T. Gibbs static dev_match_ret xptperiphmatch(struct dev_match_pattern *patterns, 2553393f8daSKenneth D. Merry u_int num_patterns, 2568b8a9b1dSJustin T. Gibbs struct cam_periph *periph); 2578b8a9b1dSJustin T. Gibbs static xpt_busfunc_t xptedtbusfunc; 2588b8a9b1dSJustin T. Gibbs static xpt_targetfunc_t xptedttargetfunc; 2598b8a9b1dSJustin T. Gibbs static xpt_devicefunc_t xptedtdevicefunc; 2608b8a9b1dSJustin T. Gibbs static xpt_periphfunc_t xptedtperiphfunc; 2618b8a9b1dSJustin T. Gibbs static xpt_pdrvfunc_t xptplistpdrvfunc; 2628b8a9b1dSJustin T. Gibbs static xpt_periphfunc_t xptplistperiphfunc; 2638b8a9b1dSJustin T. Gibbs static int xptedtmatch(struct ccb_dev_match *cdm); 2648b8a9b1dSJustin T. Gibbs static int xptperiphlistmatch(struct ccb_dev_match *cdm); 2658b8a9b1dSJustin T. Gibbs static int xptbustraverse(struct cam_eb *start_bus, 2668b8a9b1dSJustin T. Gibbs xpt_busfunc_t *tr_func, void *arg); 2678b8a9b1dSJustin T. Gibbs static int xpttargettraverse(struct cam_eb *bus, 2688b8a9b1dSJustin T. Gibbs struct cam_et *start_target, 2698b8a9b1dSJustin T. Gibbs xpt_targetfunc_t *tr_func, void *arg); 2708b8a9b1dSJustin T. Gibbs static int xptdevicetraverse(struct cam_et *target, 2718b8a9b1dSJustin T. Gibbs struct cam_ed *start_device, 2728b8a9b1dSJustin T. Gibbs xpt_devicefunc_t *tr_func, void *arg); 2738b8a9b1dSJustin T. Gibbs static int xptperiphtraverse(struct cam_ed *device, 2748b8a9b1dSJustin T. Gibbs struct cam_periph *start_periph, 2758b8a9b1dSJustin T. Gibbs xpt_periphfunc_t *tr_func, void *arg); 2768b8a9b1dSJustin T. Gibbs static int xptpdrvtraverse(struct periph_driver **start_pdrv, 2778b8a9b1dSJustin T. Gibbs xpt_pdrvfunc_t *tr_func, void *arg); 2788b8a9b1dSJustin T. Gibbs static int xptpdperiphtraverse(struct periph_driver **pdrv, 2798b8a9b1dSJustin T. Gibbs struct cam_periph *start_periph, 2808b8a9b1dSJustin T. Gibbs xpt_periphfunc_t *tr_func, 2818b8a9b1dSJustin T. Gibbs void *arg); 2828b8a9b1dSJustin T. Gibbs static xpt_busfunc_t xptdefbusfunc; 2838b8a9b1dSJustin T. Gibbs static xpt_targetfunc_t xptdeftargetfunc; 2848b8a9b1dSJustin T. Gibbs static xpt_devicefunc_t xptdefdevicefunc; 2858b8a9b1dSJustin T. Gibbs static xpt_periphfunc_t xptdefperiphfunc; 28683c5d981SAlexander Motin static void xpt_finishconfig_task(void *context, int pending); 28752c9ce25SScott Long static void xpt_dev_async_default(u_int32_t async_code, 28852c9ce25SScott Long struct cam_eb *bus, 28952c9ce25SScott Long struct cam_et *target, 29052c9ce25SScott Long struct cam_ed *device, 29152c9ce25SScott Long void *async_arg); 29252c9ce25SScott Long static struct cam_ed * xpt_alloc_device_default(struct cam_eb *bus, 29352c9ce25SScott Long struct cam_et *target, 29452c9ce25SScott Long lun_id_t lun_id); 2958b8a9b1dSJustin T. Gibbs static xpt_devicefunc_t xptsetasyncfunc; 2968b8a9b1dSJustin T. Gibbs static xpt_busfunc_t xptsetasyncbusfunc; 2978b8a9b1dSJustin T. Gibbs static cam_status xptregister(struct cam_periph *periph, 2988b8a9b1dSJustin T. Gibbs void *arg); 2998b8a9b1dSJustin T. Gibbs static __inline int periph_is_queued(struct cam_periph *periph); 300cccf4220SAlexander Motin static __inline int device_is_queued(struct cam_ed *device); 3018b8a9b1dSJustin T. Gibbs 3028b8a9b1dSJustin T. Gibbs static __inline int 303cccf4220SAlexander Motin xpt_schedule_devq(struct cam_devq *devq, struct cam_ed *dev) 30430a4094fSAlexander Motin { 30530a4094fSAlexander Motin int retval; 30630a4094fSAlexander Motin 30783c5d981SAlexander Motin if ((dev->ccbq.queue.entries > 0) && 30883c5d981SAlexander Motin (dev->ccbq.dev_openings > 0) && 309cccf4220SAlexander Motin (dev->ccbq.queue.qfrozen_cnt == 0)) { 31030a4094fSAlexander Motin /* 31130a4094fSAlexander Motin * The priority of a device waiting for controller 3126bccea7cSRebecca Cran * resources is that of the highest priority CCB 31330a4094fSAlexander Motin * enqueued. 31430a4094fSAlexander Motin */ 31530a4094fSAlexander Motin retval = 316cccf4220SAlexander Motin xpt_schedule_dev(&devq->send_queue, 317cccf4220SAlexander Motin &dev->devq_entry.pinfo, 31883c5d981SAlexander Motin CAMQ_GET_PRIO(&dev->ccbq.queue)); 31930a4094fSAlexander Motin } else { 32030a4094fSAlexander Motin retval = 0; 32130a4094fSAlexander Motin } 32230a4094fSAlexander Motin return (retval); 32330a4094fSAlexander Motin } 32430a4094fSAlexander Motin 32530a4094fSAlexander Motin static __inline int 3268b8a9b1dSJustin T. Gibbs periph_is_queued(struct cam_periph *periph) 3278b8a9b1dSJustin T. Gibbs { 3288b8a9b1dSJustin T. Gibbs return (periph->pinfo.index != CAM_UNQUEUED_INDEX); 3298b8a9b1dSJustin T. Gibbs } 3308b8a9b1dSJustin T. Gibbs 3318b8a9b1dSJustin T. Gibbs static __inline int 332cccf4220SAlexander Motin device_is_queued(struct cam_ed *device) 3338b8a9b1dSJustin T. Gibbs { 334cccf4220SAlexander Motin return (device->devq_entry.pinfo.index != CAM_UNQUEUED_INDEX); 3358b8a9b1dSJustin T. Gibbs } 3368b8a9b1dSJustin T. Gibbs 3378b8a9b1dSJustin T. Gibbs static void 3388b8a9b1dSJustin T. Gibbs xpt_periph_init() 3398b8a9b1dSJustin T. Gibbs { 34073d26919SKenneth D. Merry make_dev(&xpt_cdevsw, 0, UID_ROOT, GID_OPERATOR, 0600, "xpt0"); 3418b8a9b1dSJustin T. Gibbs } 3428b8a9b1dSJustin T. Gibbs 3438b8a9b1dSJustin T. Gibbs static void 3448b8a9b1dSJustin T. Gibbs xptdone(struct cam_periph *periph, union ccb *done_ccb) 3458b8a9b1dSJustin T. Gibbs { 3468b8a9b1dSJustin T. Gibbs /* Caller will release the CCB */ 3478b8a9b1dSJustin T. Gibbs wakeup(&done_ccb->ccb_h.cbfcnp); 3488b8a9b1dSJustin T. Gibbs } 3498b8a9b1dSJustin T. Gibbs 3508b8a9b1dSJustin T. Gibbs static int 35189c9c53dSPoul-Henning Kamp xptopen(struct cdev *dev, int flags, int fmt, struct thread *td) 3528b8a9b1dSJustin T. Gibbs { 3538b8a9b1dSJustin T. Gibbs 3548b8a9b1dSJustin T. Gibbs /* 35566a0780eSKenneth D. Merry * Only allow read-write access. 35666a0780eSKenneth D. Merry */ 35766a0780eSKenneth D. Merry if (((flags & FWRITE) == 0) || ((flags & FREAD) == 0)) 35866a0780eSKenneth D. Merry return(EPERM); 35966a0780eSKenneth D. Merry 36066a0780eSKenneth D. Merry /* 3618b8a9b1dSJustin T. Gibbs * We don't allow nonblocking access. 3628b8a9b1dSJustin T. Gibbs */ 3638b8a9b1dSJustin T. Gibbs if ((flags & O_NONBLOCK) != 0) { 3642b83592fSScott Long printf("%s: can't do nonblocking access\n", devtoname(dev)); 3658b8a9b1dSJustin T. Gibbs return(ENODEV); 3668b8a9b1dSJustin T. Gibbs } 3678b8a9b1dSJustin T. Gibbs 3688b8a9b1dSJustin T. Gibbs /* Mark ourselves open */ 3692b83592fSScott Long mtx_lock(&xsoftc.xpt_lock); 3708b8a9b1dSJustin T. Gibbs xsoftc.flags |= XPT_FLAG_OPEN; 3712b83592fSScott Long mtx_unlock(&xsoftc.xpt_lock); 3728b8a9b1dSJustin T. Gibbs 3738b8a9b1dSJustin T. Gibbs return(0); 3748b8a9b1dSJustin T. Gibbs } 3758b8a9b1dSJustin T. Gibbs 3768b8a9b1dSJustin T. Gibbs static int 37789c9c53dSPoul-Henning Kamp xptclose(struct cdev *dev, int flag, int fmt, struct thread *td) 3788b8a9b1dSJustin T. Gibbs { 3798b8a9b1dSJustin T. Gibbs 3808b8a9b1dSJustin T. Gibbs /* Mark ourselves closed */ 3812b83592fSScott Long mtx_lock(&xsoftc.xpt_lock); 3828b8a9b1dSJustin T. Gibbs xsoftc.flags &= ~XPT_FLAG_OPEN; 3832b83592fSScott Long mtx_unlock(&xsoftc.xpt_lock); 3848b8a9b1dSJustin T. Gibbs 3858b8a9b1dSJustin T. Gibbs return(0); 3868b8a9b1dSJustin T. Gibbs } 3878b8a9b1dSJustin T. Gibbs 3882b83592fSScott Long /* 3892b83592fSScott Long * Don't automatically grab the xpt softc lock here even though this is going 3902b83592fSScott Long * through the xpt device. The xpt device is really just a back door for 3912b83592fSScott Long * accessing other devices and SIMs, so the right thing to do is to grab 3922b83592fSScott Long * the appropriate SIM lock once the bus/SIM is located. 3932b83592fSScott Long */ 3948b8a9b1dSJustin T. Gibbs static int 39589c9c53dSPoul-Henning Kamp xptioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, struct thread *td) 3968b8a9b1dSJustin T. Gibbs { 3972b83592fSScott Long int error; 3988b8a9b1dSJustin T. Gibbs 39925a2902cSScott Long if ((error = xptdoioctl(dev, cmd, addr, flag, td)) == ENOTTY) { 400f564de00SScott Long error = cam_compat_ioctl(dev, cmd, addr, flag, td, xptdoioctl); 40125a2902cSScott Long } 40225a2902cSScott Long return (error); 40325a2902cSScott Long } 40425a2902cSScott Long 40525a2902cSScott Long static int 40625a2902cSScott Long xptdoioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, struct thread *td) 40725a2902cSScott Long { 40825a2902cSScott Long int error; 40925a2902cSScott Long 4108b8a9b1dSJustin T. Gibbs error = 0; 4118b8a9b1dSJustin T. Gibbs 4128b8a9b1dSJustin T. Gibbs switch(cmd) { 4138b8a9b1dSJustin T. Gibbs /* 4148b8a9b1dSJustin T. Gibbs * For the transport layer CAMIOCOMMAND ioctl, we really only want 4158b8a9b1dSJustin T. Gibbs * to accept CCB types that don't quite make sense to send through a 4168c7a96c5SScott Long * passthrough driver. XPT_PATH_INQ is an exception to this, as stated 4178c7a96c5SScott Long * in the CAM spec. 4188b8a9b1dSJustin T. Gibbs */ 4198b8a9b1dSJustin T. Gibbs case CAMIOCOMMAND: { 4208b8a9b1dSJustin T. Gibbs union ccb *ccb; 4218b8a9b1dSJustin T. Gibbs union ccb *inccb; 4222b83592fSScott Long struct cam_eb *bus; 4238b8a9b1dSJustin T. Gibbs 4248b8a9b1dSJustin T. Gibbs inccb = (union ccb *)addr; 4258b8a9b1dSJustin T. Gibbs 4262b83592fSScott Long bus = xpt_find_bus(inccb->ccb_h.path_id); 4270e85f214SMatt Jacob if (bus == NULL) 4280e85f214SMatt Jacob return (EINVAL); 4290e85f214SMatt Jacob 4300e85f214SMatt Jacob switch (inccb->ccb_h.func_code) { 4310e85f214SMatt Jacob case XPT_SCAN_BUS: 4320e85f214SMatt Jacob case XPT_RESET_BUS: 4330e85f214SMatt Jacob if (inccb->ccb_h.target_id != CAM_TARGET_WILDCARD || 4340e85f214SMatt Jacob inccb->ccb_h.target_lun != CAM_LUN_WILDCARD) { 4350e85f214SMatt Jacob xpt_release_bus(bus); 4360e85f214SMatt Jacob return (EINVAL); 4370e85f214SMatt Jacob } 4380e85f214SMatt Jacob break; 4390e85f214SMatt Jacob case XPT_SCAN_TGT: 4400e85f214SMatt Jacob if (inccb->ccb_h.target_id == CAM_TARGET_WILDCARD || 4410e85f214SMatt Jacob inccb->ccb_h.target_lun != CAM_LUN_WILDCARD) { 4420e85f214SMatt Jacob xpt_release_bus(bus); 4430e85f214SMatt Jacob return (EINVAL); 4440e85f214SMatt Jacob } 4450e85f214SMatt Jacob break; 4460e85f214SMatt Jacob default: 4472b83592fSScott Long break; 4482b83592fSScott Long } 4492b83592fSScott Long 4508b8a9b1dSJustin T. Gibbs switch(inccb->ccb_h.func_code) { 4518b8a9b1dSJustin T. Gibbs case XPT_SCAN_BUS: 4528b8a9b1dSJustin T. Gibbs case XPT_RESET_BUS: 4538c7a96c5SScott Long case XPT_PATH_INQ: 4548fcf57f5SJustin T. Gibbs case XPT_ENG_INQ: 4558b8a9b1dSJustin T. Gibbs case XPT_SCAN_LUN: 4560e85f214SMatt Jacob case XPT_SCAN_TGT: 4578b8a9b1dSJustin T. Gibbs 4588008a935SScott Long ccb = xpt_alloc_ccb(); 4592b83592fSScott Long 4602b83592fSScott Long CAM_SIM_LOCK(bus->sim); 4616ee4d869SAlexander Motin 4628b8a9b1dSJustin T. Gibbs /* 4638b8a9b1dSJustin T. Gibbs * Create a path using the bus, target, and lun the 4648b8a9b1dSJustin T. Gibbs * user passed in. 4658b8a9b1dSJustin T. Gibbs */ 466e5dfa058SAlexander Motin if (xpt_create_path(&ccb->ccb_h.path, NULL, 4678b8a9b1dSJustin T. Gibbs inccb->ccb_h.path_id, 4688b8a9b1dSJustin T. Gibbs inccb->ccb_h.target_id, 4698b8a9b1dSJustin T. Gibbs inccb->ccb_h.target_lun) != 4708b8a9b1dSJustin T. Gibbs CAM_REQ_CMP){ 4718b8a9b1dSJustin T. Gibbs error = EINVAL; 4722b83592fSScott Long CAM_SIM_UNLOCK(bus->sim); 4738b8a9b1dSJustin T. Gibbs xpt_free_ccb(ccb); 4748b8a9b1dSJustin T. Gibbs break; 4758b8a9b1dSJustin T. Gibbs } 4768b8a9b1dSJustin T. Gibbs /* Ensure all of our fields are correct */ 4778b8a9b1dSJustin T. Gibbs xpt_setup_ccb(&ccb->ccb_h, ccb->ccb_h.path, 4788b8a9b1dSJustin T. Gibbs inccb->ccb_h.pinfo.priority); 4798b8a9b1dSJustin T. Gibbs xpt_merge_ccb(ccb, inccb); 4808b8a9b1dSJustin T. Gibbs ccb->ccb_h.cbfcnp = xptdone; 4818b8a9b1dSJustin T. Gibbs cam_periph_runccb(ccb, NULL, 0, 0, NULL); 4828b8a9b1dSJustin T. Gibbs bcopy(ccb, inccb, sizeof(union ccb)); 4838b8a9b1dSJustin T. Gibbs xpt_free_path(ccb->ccb_h.path); 4848b8a9b1dSJustin T. Gibbs xpt_free_ccb(ccb); 4852b83592fSScott Long CAM_SIM_UNLOCK(bus->sim); 4868b8a9b1dSJustin T. Gibbs break; 4878b8a9b1dSJustin T. Gibbs 4888b8a9b1dSJustin T. Gibbs case XPT_DEBUG: { 4898b8a9b1dSJustin T. Gibbs union ccb ccb; 4908b8a9b1dSJustin T. Gibbs 4918b8a9b1dSJustin T. Gibbs /* 492aa872be6SMatt Jacob * This is an immediate CCB, so it's okay to 4938b8a9b1dSJustin T. Gibbs * allocate it on the stack. 4948b8a9b1dSJustin T. Gibbs */ 4958b8a9b1dSJustin T. Gibbs 4962b83592fSScott Long CAM_SIM_LOCK(bus->sim); 4972b83592fSScott Long 4988b8a9b1dSJustin T. Gibbs /* 4998b8a9b1dSJustin T. Gibbs * Create a path using the bus, target, and lun the 5008b8a9b1dSJustin T. Gibbs * user passed in. 5018b8a9b1dSJustin T. Gibbs */ 502e5dfa058SAlexander Motin if (xpt_create_path(&ccb.ccb_h.path, NULL, 5038b8a9b1dSJustin T. Gibbs inccb->ccb_h.path_id, 5048b8a9b1dSJustin T. Gibbs inccb->ccb_h.target_id, 5058b8a9b1dSJustin T. Gibbs inccb->ccb_h.target_lun) != 5068b8a9b1dSJustin T. Gibbs CAM_REQ_CMP){ 5078b8a9b1dSJustin T. Gibbs error = EINVAL; 5082ca9ba94SScott Long CAM_SIM_UNLOCK(bus->sim); 5098b8a9b1dSJustin T. Gibbs break; 5108b8a9b1dSJustin T. Gibbs } 5118b8a9b1dSJustin T. Gibbs /* Ensure all of our fields are correct */ 5128b8a9b1dSJustin T. Gibbs xpt_setup_ccb(&ccb.ccb_h, ccb.ccb_h.path, 5138b8a9b1dSJustin T. Gibbs inccb->ccb_h.pinfo.priority); 5148b8a9b1dSJustin T. Gibbs xpt_merge_ccb(&ccb, inccb); 5158b8a9b1dSJustin T. Gibbs ccb.ccb_h.cbfcnp = xptdone; 5168b8a9b1dSJustin T. Gibbs xpt_action(&ccb); 5178b8a9b1dSJustin T. Gibbs bcopy(&ccb, inccb, sizeof(union ccb)); 5188b8a9b1dSJustin T. Gibbs xpt_free_path(ccb.ccb_h.path); 51980d6987cSAlexander Motin CAM_SIM_UNLOCK(bus->sim); 5208b8a9b1dSJustin T. Gibbs break; 5218b8a9b1dSJustin T. Gibbs 5228b8a9b1dSJustin T. Gibbs } 5238b8a9b1dSJustin T. Gibbs case XPT_DEV_MATCH: { 5248b8a9b1dSJustin T. Gibbs struct cam_periph_map_info mapinfo; 52559190eaaSKenneth D. Merry struct cam_path *old_path; 5268b8a9b1dSJustin T. Gibbs 5278b8a9b1dSJustin T. Gibbs /* 5288b8a9b1dSJustin T. Gibbs * We can't deal with physical addresses for this 5298b8a9b1dSJustin T. Gibbs * type of transaction. 5308b8a9b1dSJustin T. Gibbs */ 531dd0b4fb6SKonstantin Belousov if ((inccb->ccb_h.flags & CAM_DATA_MASK) != 532dd0b4fb6SKonstantin Belousov CAM_DATA_VADDR) { 5338b8a9b1dSJustin T. Gibbs error = EINVAL; 5348b8a9b1dSJustin T. Gibbs break; 5358b8a9b1dSJustin T. Gibbs } 53659190eaaSKenneth D. Merry 53759190eaaSKenneth D. Merry /* 53859190eaaSKenneth D. Merry * Save this in case the caller had it set to 53959190eaaSKenneth D. Merry * something in particular. 54059190eaaSKenneth D. Merry */ 54159190eaaSKenneth D. Merry old_path = inccb->ccb_h.path; 54259190eaaSKenneth D. Merry 54359190eaaSKenneth D. Merry /* 54459190eaaSKenneth D. Merry * We really don't need a path for the matching 54559190eaaSKenneth D. Merry * code. The path is needed because of the 54659190eaaSKenneth D. Merry * debugging statements in xpt_action(). They 54759190eaaSKenneth D. Merry * assume that the CCB has a valid path. 54859190eaaSKenneth D. Merry */ 54959190eaaSKenneth D. Merry inccb->ccb_h.path = xpt_periph->path; 55059190eaaSKenneth D. Merry 5518b8a9b1dSJustin T. Gibbs bzero(&mapinfo, sizeof(mapinfo)); 5528b8a9b1dSJustin T. Gibbs 5538b8a9b1dSJustin T. Gibbs /* 5548b8a9b1dSJustin T. Gibbs * Map the pattern and match buffers into kernel 5558b8a9b1dSJustin T. Gibbs * virtual address space. 5568b8a9b1dSJustin T. Gibbs */ 5578b8a9b1dSJustin T. Gibbs error = cam_periph_mapmem(inccb, &mapinfo); 5588b8a9b1dSJustin T. Gibbs 55959190eaaSKenneth D. Merry if (error) { 56059190eaaSKenneth D. Merry inccb->ccb_h.path = old_path; 5618b8a9b1dSJustin T. Gibbs break; 56259190eaaSKenneth D. Merry } 5638b8a9b1dSJustin T. Gibbs 5648b8a9b1dSJustin T. Gibbs /* 5658b8a9b1dSJustin T. Gibbs * This is an immediate CCB, we can send it on directly. 5668b8a9b1dSJustin T. Gibbs */ 56792c40f40SAlexander Motin CAM_SIM_LOCK(xpt_path_sim(xpt_periph->path)); 5688b8a9b1dSJustin T. Gibbs xpt_action(inccb); 56992c40f40SAlexander Motin CAM_SIM_UNLOCK(xpt_path_sim(xpt_periph->path)); 5708b8a9b1dSJustin T. Gibbs 5718b8a9b1dSJustin T. Gibbs /* 5728b8a9b1dSJustin T. Gibbs * Map the buffers back into user space. 5738b8a9b1dSJustin T. Gibbs */ 5748b8a9b1dSJustin T. Gibbs cam_periph_unmapmem(inccb, &mapinfo); 5758b8a9b1dSJustin T. Gibbs 57659190eaaSKenneth D. Merry inccb->ccb_h.path = old_path; 57759190eaaSKenneth D. Merry 5788b8a9b1dSJustin T. Gibbs error = 0; 5798b8a9b1dSJustin T. Gibbs break; 5808b8a9b1dSJustin T. Gibbs } 5818b8a9b1dSJustin T. Gibbs default: 5828fcf57f5SJustin T. Gibbs error = ENOTSUP; 5838b8a9b1dSJustin T. Gibbs break; 5848b8a9b1dSJustin T. Gibbs } 585daddc001SScott Long xpt_release_bus(bus); 5868b8a9b1dSJustin T. Gibbs break; 5878b8a9b1dSJustin T. Gibbs } 5888b8a9b1dSJustin T. Gibbs /* 5898b8a9b1dSJustin T. Gibbs * This is the getpassthru ioctl. It takes a XPT_GDEVLIST ccb as input, 5908b8a9b1dSJustin T. Gibbs * with the periphal driver name and unit name filled in. The other 5918b8a9b1dSJustin T. Gibbs * fields don't really matter as input. The passthrough driver name 5928b8a9b1dSJustin T. Gibbs * ("pass"), and unit number are passed back in the ccb. The current 5938b8a9b1dSJustin T. Gibbs * device generation number, and the index into the device peripheral 5948b8a9b1dSJustin T. Gibbs * driver list, and the status are also passed back. Note that 5958b8a9b1dSJustin T. Gibbs * since we do everything in one pass, unlike the XPT_GDEVLIST ccb, 5968b8a9b1dSJustin T. Gibbs * we never return a status of CAM_GDEVLIST_LIST_CHANGED. It is 5978b8a9b1dSJustin T. Gibbs * (or rather should be) impossible for the device peripheral driver 5988b8a9b1dSJustin T. Gibbs * list to change since we look at the whole thing in one pass, and 59977dc25ccSScott Long * we do it with lock protection. 6008b8a9b1dSJustin T. Gibbs * 6018b8a9b1dSJustin T. Gibbs */ 6028b8a9b1dSJustin T. Gibbs case CAMGETPASSTHRU: { 6038b8a9b1dSJustin T. Gibbs union ccb *ccb; 6048b8a9b1dSJustin T. Gibbs struct cam_periph *periph; 6058b8a9b1dSJustin T. Gibbs struct periph_driver **p_drv; 6068b8a9b1dSJustin T. Gibbs char *name; 6073393f8daSKenneth D. Merry u_int unit; 608621a60d4SKenneth D. Merry int base_periph_found; 6098b8a9b1dSJustin T. Gibbs 6108b8a9b1dSJustin T. Gibbs ccb = (union ccb *)addr; 6118b8a9b1dSJustin T. Gibbs unit = ccb->cgdl.unit_number; 6128b8a9b1dSJustin T. Gibbs name = ccb->cgdl.periph_name; 613621a60d4SKenneth D. Merry base_periph_found = 0; 614621a60d4SKenneth D. Merry 6158b8a9b1dSJustin T. Gibbs /* 6168b8a9b1dSJustin T. Gibbs * Sanity check -- make sure we don't get a null peripheral 6178b8a9b1dSJustin T. Gibbs * driver name. 6188b8a9b1dSJustin T. Gibbs */ 6198b8a9b1dSJustin T. Gibbs if (*ccb->cgdl.periph_name == '\0') { 6208b8a9b1dSJustin T. Gibbs error = EINVAL; 6218b8a9b1dSJustin T. Gibbs break; 6228b8a9b1dSJustin T. Gibbs } 6238b8a9b1dSJustin T. Gibbs 6248b8a9b1dSJustin T. Gibbs /* Keep the list from changing while we traverse it */ 6259a7c2696SAlexander Motin xpt_lock_buses(); 6268b8a9b1dSJustin T. Gibbs 6278b8a9b1dSJustin T. Gibbs /* first find our driver in the list of drivers */ 6280b7c27b9SPeter Wemm for (p_drv = periph_drivers; *p_drv != NULL; p_drv++) 6298b8a9b1dSJustin T. Gibbs if (strcmp((*p_drv)->driver_name, name) == 0) 6308b8a9b1dSJustin T. Gibbs break; 6318b8a9b1dSJustin T. Gibbs 6328b8a9b1dSJustin T. Gibbs if (*p_drv == NULL) { 6339a7c2696SAlexander Motin xpt_unlock_buses(); 6348b8a9b1dSJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_CMP_ERR; 6358b8a9b1dSJustin T. Gibbs ccb->cgdl.status = CAM_GDEVLIST_ERROR; 6368b8a9b1dSJustin T. Gibbs *ccb->cgdl.periph_name = '\0'; 6378b8a9b1dSJustin T. Gibbs ccb->cgdl.unit_number = 0; 6388b8a9b1dSJustin T. Gibbs error = ENOENT; 6398b8a9b1dSJustin T. Gibbs break; 6408b8a9b1dSJustin T. Gibbs } 6418b8a9b1dSJustin T. Gibbs 6428b8a9b1dSJustin T. Gibbs /* 6438b8a9b1dSJustin T. Gibbs * Run through every peripheral instance of this driver 6448b8a9b1dSJustin T. Gibbs * and check to see whether it matches the unit passed 6458b8a9b1dSJustin T. Gibbs * in by the user. If it does, get out of the loops and 6468b8a9b1dSJustin T. Gibbs * find the passthrough driver associated with that 6478b8a9b1dSJustin T. Gibbs * peripheral driver. 6488b8a9b1dSJustin T. Gibbs */ 6498b8a9b1dSJustin T. Gibbs for (periph = TAILQ_FIRST(&(*p_drv)->units); periph != NULL; 6508b8a9b1dSJustin T. Gibbs periph = TAILQ_NEXT(periph, unit_links)) { 6518b8a9b1dSJustin T. Gibbs 652a29779e8SAlexander Motin if (periph->unit_number == unit) 6538b8a9b1dSJustin T. Gibbs break; 6548b8a9b1dSJustin T. Gibbs } 6558b8a9b1dSJustin T. Gibbs /* 6568b8a9b1dSJustin T. Gibbs * If we found the peripheral driver that the user passed 6578b8a9b1dSJustin T. Gibbs * in, go through all of the peripheral drivers for that 6588b8a9b1dSJustin T. Gibbs * particular device and look for a passthrough driver. 6598b8a9b1dSJustin T. Gibbs */ 6608b8a9b1dSJustin T. Gibbs if (periph != NULL) { 6618b8a9b1dSJustin T. Gibbs struct cam_ed *device; 6628b8a9b1dSJustin T. Gibbs int i; 6638b8a9b1dSJustin T. Gibbs 664621a60d4SKenneth D. Merry base_periph_found = 1; 6658b8a9b1dSJustin T. Gibbs device = periph->path->device; 666fc2ffbe6SPoul-Henning Kamp for (i = 0, periph = SLIST_FIRST(&device->periphs); 6678b8a9b1dSJustin T. Gibbs periph != NULL; 668fc2ffbe6SPoul-Henning Kamp periph = SLIST_NEXT(periph, periph_links), i++) { 6698b8a9b1dSJustin T. Gibbs /* 6708b8a9b1dSJustin T. Gibbs * Check to see whether we have a 6718b8a9b1dSJustin T. Gibbs * passthrough device or not. 6728b8a9b1dSJustin T. Gibbs */ 6738b8a9b1dSJustin T. Gibbs if (strcmp(periph->periph_name, "pass") == 0) { 6748b8a9b1dSJustin T. Gibbs /* 6758b8a9b1dSJustin T. Gibbs * Fill in the getdevlist fields. 6768b8a9b1dSJustin T. Gibbs */ 6778b8a9b1dSJustin T. Gibbs strcpy(ccb->cgdl.periph_name, 6788b8a9b1dSJustin T. Gibbs periph->periph_name); 6798b8a9b1dSJustin T. Gibbs ccb->cgdl.unit_number = 6808b8a9b1dSJustin T. Gibbs periph->unit_number; 681fc2ffbe6SPoul-Henning Kamp if (SLIST_NEXT(periph, periph_links)) 6828b8a9b1dSJustin T. Gibbs ccb->cgdl.status = 6838b8a9b1dSJustin T. Gibbs CAM_GDEVLIST_MORE_DEVS; 6848b8a9b1dSJustin T. Gibbs else 6858b8a9b1dSJustin T. Gibbs ccb->cgdl.status = 6868b8a9b1dSJustin T. Gibbs CAM_GDEVLIST_LAST_DEVICE; 6878b8a9b1dSJustin T. Gibbs ccb->cgdl.generation = 6888b8a9b1dSJustin T. Gibbs device->generation; 6898b8a9b1dSJustin T. Gibbs ccb->cgdl.index = i; 6908b8a9b1dSJustin T. Gibbs /* 6918b8a9b1dSJustin T. Gibbs * Fill in some CCB header fields 6928b8a9b1dSJustin T. Gibbs * that the user may want. 6938b8a9b1dSJustin T. Gibbs */ 6948b8a9b1dSJustin T. Gibbs ccb->ccb_h.path_id = 6958b8a9b1dSJustin T. Gibbs periph->path->bus->path_id; 6968b8a9b1dSJustin T. Gibbs ccb->ccb_h.target_id = 6978b8a9b1dSJustin T. Gibbs periph->path->target->target_id; 6988b8a9b1dSJustin T. Gibbs ccb->ccb_h.target_lun = 6998b8a9b1dSJustin T. Gibbs periph->path->device->lun_id; 7008b8a9b1dSJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_CMP; 7018b8a9b1dSJustin T. Gibbs break; 7028b8a9b1dSJustin T. Gibbs } 7038b8a9b1dSJustin T. Gibbs } 7048b8a9b1dSJustin T. Gibbs } 7058b8a9b1dSJustin T. Gibbs 7068b8a9b1dSJustin T. Gibbs /* 7078b8a9b1dSJustin T. Gibbs * If the periph is null here, one of two things has 7088b8a9b1dSJustin T. Gibbs * happened. The first possibility is that we couldn't 7098b8a9b1dSJustin T. Gibbs * find the unit number of the particular peripheral driver 7108b8a9b1dSJustin T. Gibbs * that the user is asking about. e.g. the user asks for 7118b8a9b1dSJustin T. Gibbs * the passthrough driver for "da11". We find the list of 7128b8a9b1dSJustin T. Gibbs * "da" peripherals all right, but there is no unit 11. 7138b8a9b1dSJustin T. Gibbs * The other possibility is that we went through the list 7148b8a9b1dSJustin T. Gibbs * of peripheral drivers attached to the device structure, 7158b8a9b1dSJustin T. Gibbs * but didn't find one with the name "pass". Either way, 7168b8a9b1dSJustin T. Gibbs * we return ENOENT, since we couldn't find something. 7178b8a9b1dSJustin T. Gibbs */ 7188b8a9b1dSJustin T. Gibbs if (periph == NULL) { 7198b8a9b1dSJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_CMP_ERR; 7208b8a9b1dSJustin T. Gibbs ccb->cgdl.status = CAM_GDEVLIST_ERROR; 7218b8a9b1dSJustin T. Gibbs *ccb->cgdl.periph_name = '\0'; 7228b8a9b1dSJustin T. Gibbs ccb->cgdl.unit_number = 0; 7238b8a9b1dSJustin T. Gibbs error = ENOENT; 724621a60d4SKenneth D. Merry /* 725621a60d4SKenneth D. Merry * It is unfortunate that this is even necessary, 726621a60d4SKenneth D. Merry * but there are many, many clueless users out there. 727621a60d4SKenneth D. Merry * If this is true, the user is looking for the 728621a60d4SKenneth D. Merry * passthrough driver, but doesn't have one in his 729621a60d4SKenneth D. Merry * kernel. 730621a60d4SKenneth D. Merry */ 731621a60d4SKenneth D. Merry if (base_periph_found == 1) { 732621a60d4SKenneth D. Merry printf("xptioctl: pass driver is not in the " 733621a60d4SKenneth D. Merry "kernel\n"); 734935c968aSChristian Brueffer printf("xptioctl: put \"device pass\" in " 735621a60d4SKenneth D. Merry "your kernel config file\n"); 736621a60d4SKenneth D. Merry } 7378b8a9b1dSJustin T. Gibbs } 7389a7c2696SAlexander Motin xpt_unlock_buses(); 7398b8a9b1dSJustin T. Gibbs break; 7408b8a9b1dSJustin T. Gibbs } 7418b8a9b1dSJustin T. Gibbs default: 7428b8a9b1dSJustin T. Gibbs error = ENOTTY; 7438b8a9b1dSJustin T. Gibbs break; 7448b8a9b1dSJustin T. Gibbs } 7458b8a9b1dSJustin T. Gibbs 7468b8a9b1dSJustin T. Gibbs return(error); 7478b8a9b1dSJustin T. Gibbs } 7488b8a9b1dSJustin T. Gibbs 74974bd1c10SNick Hibma static int 75074bd1c10SNick Hibma cam_module_event_handler(module_t mod, int what, void *arg) 75174bd1c10SNick Hibma { 7522b83592fSScott Long int error; 7532b83592fSScott Long 7542b83592fSScott Long switch (what) { 7552b83592fSScott Long case MOD_LOAD: 7562b83592fSScott Long if ((error = xpt_init(NULL)) != 0) 7572b83592fSScott Long return (error); 7582b83592fSScott Long break; 7592b83592fSScott Long case MOD_UNLOAD: 76074bd1c10SNick Hibma return EBUSY; 7612b83592fSScott Long default: 7623e019deaSPoul-Henning Kamp return EOPNOTSUPP; 76374bd1c10SNick Hibma } 76474bd1c10SNick Hibma 76574bd1c10SNick Hibma return 0; 76674bd1c10SNick Hibma } 76774bd1c10SNick Hibma 76883c5d981SAlexander Motin static void 76983c5d981SAlexander Motin xpt_rescan_done(struct cam_periph *periph, union ccb *done_ccb) 77083c5d981SAlexander Motin { 77183c5d981SAlexander Motin 77283c5d981SAlexander Motin if (done_ccb->ccb_h.ppriv_ptr1 == NULL) { 77383c5d981SAlexander Motin xpt_free_path(done_ccb->ccb_h.path); 77483c5d981SAlexander Motin xpt_free_ccb(done_ccb); 77583c5d981SAlexander Motin } else { 77683c5d981SAlexander Motin done_ccb->ccb_h.cbfcnp = done_ccb->ccb_h.ppriv_ptr1; 77783c5d981SAlexander Motin (*done_ccb->ccb_h.cbfcnp)(periph, done_ccb); 77883c5d981SAlexander Motin } 77983c5d981SAlexander Motin xpt_release_boot(); 78083c5d981SAlexander Motin } 78183c5d981SAlexander Motin 7829e6461a2SMatt Jacob /* thread to handle bus rescans */ 7839e6461a2SMatt Jacob static void 7849e6461a2SMatt Jacob xpt_scanner_thread(void *dummy) 7859e6461a2SMatt Jacob { 7869e6461a2SMatt Jacob union ccb *ccb; 7872b83592fSScott Long struct cam_sim *sim; 7882b83592fSScott Long 7892b83592fSScott Long xpt_lock_buses(); 79083c5d981SAlexander Motin for (;;) { 7915a73cc12SKenneth D. Merry if (TAILQ_EMPTY(&xsoftc.ccb_scanq)) 7922b83592fSScott Long msleep(&xsoftc.ccb_scanq, &xsoftc.xpt_topo_lock, PRIBIO, 7932b83592fSScott Long "ccb_scanq", 0); 79483c5d981SAlexander Motin if ((ccb = (union ccb *)TAILQ_FIRST(&xsoftc.ccb_scanq)) != NULL) { 79583c5d981SAlexander Motin TAILQ_REMOVE(&xsoftc.ccb_scanq, &ccb->ccb_h, sim_links.tqe); 7962b83592fSScott Long xpt_unlock_buses(); 7972b83592fSScott Long 7982b83592fSScott Long sim = ccb->ccb_h.path->bus->sim; 79911e4faceSScott Long CAM_SIM_LOCK(sim); 80083c5d981SAlexander Motin xpt_action(ccb); 80111e4faceSScott Long CAM_SIM_UNLOCK(sim); 80283c5d981SAlexander Motin 80383c5d981SAlexander Motin xpt_lock_buses(); 8049e6461a2SMatt Jacob } 8059e6461a2SMatt Jacob } 8069e6461a2SMatt Jacob } 8079e6461a2SMatt Jacob 8089e6461a2SMatt Jacob void 8099e6461a2SMatt Jacob xpt_rescan(union ccb *ccb) 8109e6461a2SMatt Jacob { 8119e6461a2SMatt Jacob struct ccb_hdr *hdr; 8122b83592fSScott Long 81383c5d981SAlexander Motin /* Prepare request */ 8140e85f214SMatt Jacob if (ccb->ccb_h.path->target->target_id == CAM_TARGET_WILDCARD && 815411cadaeSAlexander Motin ccb->ccb_h.path->device->lun_id == CAM_LUN_WILDCARD) 81683c5d981SAlexander Motin ccb->ccb_h.func_code = XPT_SCAN_BUS; 8170e85f214SMatt Jacob else if (ccb->ccb_h.path->target->target_id != CAM_TARGET_WILDCARD && 8180e85f214SMatt Jacob ccb->ccb_h.path->device->lun_id == CAM_LUN_WILDCARD) 8190e85f214SMatt Jacob ccb->ccb_h.func_code = XPT_SCAN_TGT; 8200e85f214SMatt Jacob else if (ccb->ccb_h.path->target->target_id != CAM_TARGET_WILDCARD && 8210e85f214SMatt Jacob ccb->ccb_h.path->device->lun_id != CAM_LUN_WILDCARD) 82283c5d981SAlexander Motin ccb->ccb_h.func_code = XPT_SCAN_LUN; 8230e85f214SMatt Jacob else { 8240e85f214SMatt Jacob xpt_print(ccb->ccb_h.path, "illegal scan path\n"); 8250e85f214SMatt Jacob xpt_free_path(ccb->ccb_h.path); 8260e85f214SMatt Jacob xpt_free_ccb(ccb); 8270e85f214SMatt Jacob return; 8280e85f214SMatt Jacob } 82983c5d981SAlexander Motin ccb->ccb_h.ppriv_ptr1 = ccb->ccb_h.cbfcnp; 83083c5d981SAlexander Motin ccb->ccb_h.cbfcnp = xpt_rescan_done; 83183c5d981SAlexander Motin xpt_setup_ccb(&ccb->ccb_h, ccb->ccb_h.path, CAM_PRIORITY_XPT); 83283c5d981SAlexander Motin /* Don't make duplicate entries for the same paths. */ 8332b83592fSScott Long xpt_lock_buses(); 83483c5d981SAlexander Motin if (ccb->ccb_h.ppriv_ptr1 == NULL) { 8352b83592fSScott Long TAILQ_FOREACH(hdr, &xsoftc.ccb_scanq, sim_links.tqe) { 8369e6461a2SMatt Jacob if (xpt_path_comp(hdr->path, ccb->ccb_h.path) == 0) { 8375a73cc12SKenneth D. Merry wakeup(&xsoftc.ccb_scanq); 8382b83592fSScott Long xpt_unlock_buses(); 8399e6461a2SMatt Jacob xpt_print(ccb->ccb_h.path, "rescan already queued\n"); 8409e6461a2SMatt Jacob xpt_free_path(ccb->ccb_h.path); 8419e6461a2SMatt Jacob xpt_free_ccb(ccb); 8429e6461a2SMatt Jacob return; 8439e6461a2SMatt Jacob } 8449e6461a2SMatt Jacob } 84583c5d981SAlexander Motin } 8462b83592fSScott Long TAILQ_INSERT_TAIL(&xsoftc.ccb_scanq, &ccb->ccb_h, sim_links.tqe); 84783c5d981SAlexander Motin xsoftc.buses_to_config++; 8482b83592fSScott Long wakeup(&xsoftc.ccb_scanq); 8492b83592fSScott Long xpt_unlock_buses(); 8509e6461a2SMatt Jacob } 8519e6461a2SMatt Jacob 8528b8a9b1dSJustin T. Gibbs /* Functions accessed by the peripheral drivers */ 8532b83592fSScott Long static int 8549e6461a2SMatt Jacob xpt_init(void *dummy) 8558b8a9b1dSJustin T. Gibbs { 8568b8a9b1dSJustin T. Gibbs struct cam_sim *xpt_sim; 8578b8a9b1dSJustin T. Gibbs struct cam_path *path; 858434bbf6eSJustin T. Gibbs struct cam_devq *devq; 8598b8a9b1dSJustin T. Gibbs cam_status status; 8608b8a9b1dSJustin T. Gibbs 8612b83592fSScott Long TAILQ_INIT(&xsoftc.xpt_busses); 8629758cc83SScott Long TAILQ_INIT(&cam_simq); 8632b83592fSScott Long TAILQ_INIT(&xsoftc.ccb_scanq); 8642b83592fSScott Long STAILQ_INIT(&xsoftc.highpowerq); 8652b83592fSScott Long xsoftc.num_highpower = CAM_MAX_HIGHPOWER; 8668b8a9b1dSJustin T. Gibbs 8679758cc83SScott Long mtx_init(&cam_simq_lock, "CAM SIMQ lock", NULL, MTX_DEF); 8682b83592fSScott Long mtx_init(&xsoftc.xpt_lock, "XPT lock", NULL, MTX_DEF); 8692b83592fSScott Long mtx_init(&xsoftc.xpt_topo_lock, "XPT topology lock", NULL, MTX_DEF); 870ef3cf714SScott Long 8716b156f61SSean Bruno #ifdef CAM_BOOT_DELAY 8726b156f61SSean Bruno /* 8736b156f61SSean Bruno * Override this value at compile time to assist our users 8746b156f61SSean Bruno * who don't use loader to boot a kernel. 8756b156f61SSean Bruno */ 8766b156f61SSean Bruno xsoftc.boot_delay = CAM_BOOT_DELAY; 8776b156f61SSean Bruno #endif 8788b8a9b1dSJustin T. Gibbs /* 8798b8a9b1dSJustin T. Gibbs * The xpt layer is, itself, the equivelent of a SIM. 8808b8a9b1dSJustin T. Gibbs * Allow 16 ccbs in the ccb pool for it. This should 8818b8a9b1dSJustin T. Gibbs * give decent parallelism when we probe busses and 8828b8a9b1dSJustin T. Gibbs * perform other XPT functions. 8838b8a9b1dSJustin T. Gibbs */ 884434bbf6eSJustin T. Gibbs devq = cam_simq_alloc(16); 885434bbf6eSJustin T. Gibbs xpt_sim = cam_sim_alloc(xptaction, 886434bbf6eSJustin T. Gibbs xptpoll, 887434bbf6eSJustin T. Gibbs "xpt", 888434bbf6eSJustin T. Gibbs /*softc*/NULL, 889434bbf6eSJustin T. Gibbs /*unit*/0, 8902b83592fSScott Long /*mtx*/&xsoftc.xpt_lock, 891434bbf6eSJustin T. Gibbs /*max_dev_transactions*/0, 892434bbf6eSJustin T. Gibbs /*max_tagged_dev_transactions*/0, 893434bbf6eSJustin T. Gibbs devq); 8942b83592fSScott Long if (xpt_sim == NULL) 8952b83592fSScott Long return (ENOMEM); 8968b8a9b1dSJustin T. Gibbs 8972b83592fSScott Long mtx_lock(&xsoftc.xpt_lock); 898b50569b7SScott Long if ((status = xpt_bus_register(xpt_sim, NULL, 0)) != CAM_SUCCESS) { 89983c5d981SAlexander Motin mtx_unlock(&xsoftc.xpt_lock); 900a2821e04SMatt Jacob printf("xpt_init: xpt_bus_register failed with status %#x," 901df826980SMatt Jacob " failing attach\n", status); 9022b83592fSScott Long return (EINVAL); 903df826980SMatt Jacob } 9048b8a9b1dSJustin T. Gibbs 9058b8a9b1dSJustin T. Gibbs /* 9068b8a9b1dSJustin T. Gibbs * Looking at the XPT from the SIM layer, the XPT is 9078b8a9b1dSJustin T. Gibbs * the equivelent of a peripheral driver. Allocate 9088b8a9b1dSJustin T. Gibbs * a peripheral driver entry for us. 9098b8a9b1dSJustin T. Gibbs */ 9108b8a9b1dSJustin T. Gibbs if ((status = xpt_create_path(&path, NULL, CAM_XPT_PATH_ID, 9118b8a9b1dSJustin T. Gibbs CAM_TARGET_WILDCARD, 9128b8a9b1dSJustin T. Gibbs CAM_LUN_WILDCARD)) != CAM_REQ_CMP) { 91383c5d981SAlexander Motin mtx_unlock(&xsoftc.xpt_lock); 9148b8a9b1dSJustin T. Gibbs printf("xpt_init: xpt_create_path failed with status %#x," 9158b8a9b1dSJustin T. Gibbs " failing attach\n", status); 9162b83592fSScott Long return (EINVAL); 9178b8a9b1dSJustin T. Gibbs } 9188b8a9b1dSJustin T. Gibbs 919ee9c90c7SKenneth D. Merry cam_periph_alloc(xptregister, NULL, NULL, NULL, "xpt", CAM_PERIPH_BIO, 9202b83592fSScott Long path, NULL, 0, xpt_sim); 9218b8a9b1dSJustin T. Gibbs xpt_free_path(path); 9222b83592fSScott Long mtx_unlock(&xsoftc.xpt_lock); 92383c5d981SAlexander Motin /* Install our software interrupt handlers */ 92483c5d981SAlexander Motin swi_add(NULL, "cambio", camisr, NULL, SWI_CAMBIO, INTR_MPSAFE, &cambio_ih); 9258b8a9b1dSJustin T. Gibbs /* 9268b8a9b1dSJustin T. Gibbs * Register a callback for when interrupts are enabled. 9278b8a9b1dSJustin T. Gibbs */ 9282b83592fSScott Long xsoftc.xpt_config_hook = 9298b8a9b1dSJustin T. Gibbs (struct intr_config_hook *)malloc(sizeof(struct intr_config_hook), 9300dd50e9bSScott Long M_CAMXPT, M_NOWAIT | M_ZERO); 9312b83592fSScott Long if (xsoftc.xpt_config_hook == NULL) { 9328b8a9b1dSJustin T. Gibbs printf("xpt_init: Cannot malloc config hook " 9338b8a9b1dSJustin T. Gibbs "- failing attach\n"); 9342b83592fSScott Long return (ENOMEM); 9358b8a9b1dSJustin T. Gibbs } 9362b83592fSScott Long xsoftc.xpt_config_hook->ich_func = xpt_config; 9372b83592fSScott Long if (config_intrhook_establish(xsoftc.xpt_config_hook) != 0) { 9380dd50e9bSScott Long free (xsoftc.xpt_config_hook, M_CAMXPT); 9398b8a9b1dSJustin T. Gibbs printf("xpt_init: config_intrhook_establish failed " 9408b8a9b1dSJustin T. Gibbs "- failing attach\n"); 9418b8a9b1dSJustin T. Gibbs } 9428b8a9b1dSJustin T. Gibbs 9432b83592fSScott Long return (0); 9448b8a9b1dSJustin T. Gibbs } 9458b8a9b1dSJustin T. Gibbs 9468b8a9b1dSJustin T. Gibbs static cam_status 9478b8a9b1dSJustin T. Gibbs xptregister(struct cam_periph *periph, void *arg) 9488b8a9b1dSJustin T. Gibbs { 9492b83592fSScott Long struct cam_sim *xpt_sim; 9502b83592fSScott Long 9518b8a9b1dSJustin T. Gibbs if (periph == NULL) { 9528b8a9b1dSJustin T. Gibbs printf("xptregister: periph was NULL!!\n"); 9538b8a9b1dSJustin T. Gibbs return(CAM_REQ_CMP_ERR); 9548b8a9b1dSJustin T. Gibbs } 9558b8a9b1dSJustin T. Gibbs 9562b83592fSScott Long xpt_sim = (struct cam_sim *)arg; 9572b83592fSScott Long xpt_sim->softc = periph; 9588b8a9b1dSJustin T. Gibbs xpt_periph = periph; 9592b83592fSScott Long periph->softc = NULL; 9608b8a9b1dSJustin T. Gibbs 9618b8a9b1dSJustin T. Gibbs return(CAM_REQ_CMP); 9628b8a9b1dSJustin T. Gibbs } 9638b8a9b1dSJustin T. Gibbs 9648b8a9b1dSJustin T. Gibbs int32_t 9658b8a9b1dSJustin T. Gibbs xpt_add_periph(struct cam_periph *periph) 9668b8a9b1dSJustin T. Gibbs { 9678b8a9b1dSJustin T. Gibbs struct cam_ed *device; 9688b8a9b1dSJustin T. Gibbs int32_t status; 9698b8a9b1dSJustin T. Gibbs struct periph_list *periph_head; 9708b8a9b1dSJustin T. Gibbs 9712b83592fSScott Long mtx_assert(periph->sim->mtx, MA_OWNED); 97268153f43SScott Long 9738b8a9b1dSJustin T. Gibbs device = periph->path->device; 9748b8a9b1dSJustin T. Gibbs 9758b8a9b1dSJustin T. Gibbs periph_head = &device->periphs; 9768b8a9b1dSJustin T. Gibbs 9778b8a9b1dSJustin T. Gibbs status = CAM_REQ_CMP; 9788b8a9b1dSJustin T. Gibbs 9798b8a9b1dSJustin T. Gibbs if (device != NULL) { 9808b8a9b1dSJustin T. Gibbs /* 9818b8a9b1dSJustin T. Gibbs * Make room for this peripheral 9828b8a9b1dSJustin T. Gibbs * so it will fit in the queue 9838b8a9b1dSJustin T. Gibbs * when it's scheduled to run 9848b8a9b1dSJustin T. Gibbs */ 9858b8a9b1dSJustin T. Gibbs status = camq_resize(&device->drvq, 9868b8a9b1dSJustin T. Gibbs device->drvq.array_size + 1); 9878b8a9b1dSJustin T. Gibbs 9888b8a9b1dSJustin T. Gibbs device->generation++; 9898b8a9b1dSJustin T. Gibbs 9908b8a9b1dSJustin T. Gibbs SLIST_INSERT_HEAD(periph_head, periph, periph_links); 9918b8a9b1dSJustin T. Gibbs } 9928b8a9b1dSJustin T. Gibbs 9938b8a9b1dSJustin T. Gibbs return (status); 9948b8a9b1dSJustin T. Gibbs } 9958b8a9b1dSJustin T. Gibbs 9968b8a9b1dSJustin T. Gibbs void 997a29779e8SAlexander Motin xpt_remove_periph(struct cam_periph *periph) 9988b8a9b1dSJustin T. Gibbs { 9998b8a9b1dSJustin T. Gibbs struct cam_ed *device; 10008b8a9b1dSJustin T. Gibbs 10011fa9ee7dSEdward Tomasz Napierala mtx_assert(periph->sim->mtx, MA_OWNED); 100268153f43SScott Long 10038b8a9b1dSJustin T. Gibbs device = periph->path->device; 10048b8a9b1dSJustin T. Gibbs 10058b8a9b1dSJustin T. Gibbs if (device != NULL) { 10068b8a9b1dSJustin T. Gibbs struct periph_list *periph_head; 10078b8a9b1dSJustin T. Gibbs 10088b8a9b1dSJustin T. Gibbs periph_head = &device->periphs; 10098b8a9b1dSJustin T. Gibbs 10108b8a9b1dSJustin T. Gibbs /* Release the slot for this peripheral */ 10118b8a9b1dSJustin T. Gibbs camq_resize(&device->drvq, device->drvq.array_size - 1); 10128b8a9b1dSJustin T. Gibbs 10138b8a9b1dSJustin T. Gibbs device->generation++; 10148b8a9b1dSJustin T. Gibbs 1015e3975643SJake Burkholder SLIST_REMOVE(periph_head, periph, cam_periph, periph_links); 10168b8a9b1dSJustin T. Gibbs } 10178b8a9b1dSJustin T. Gibbs } 10188b8a9b1dSJustin T. Gibbs 10193393f8daSKenneth D. Merry 10203393f8daSKenneth D. Merry void 10213393f8daSKenneth D. Merry xpt_announce_periph(struct cam_periph *periph, char *announce_string) 10223393f8daSKenneth D. Merry { 102357079b17SAlexander Motin struct cam_path *path = periph->path; 10243393f8daSKenneth D. Merry 10252b83592fSScott Long mtx_assert(periph->sim->mtx, MA_OWNED); 102668153f43SScott Long 1027ad413009SAlexander Motin printf("%s%d at %s%d bus %d scbus%d target %d lun %d\n", 10283393f8daSKenneth D. Merry periph->periph_name, periph->unit_number, 10293393f8daSKenneth D. Merry path->bus->sim->sim_name, 10303393f8daSKenneth D. Merry path->bus->sim->unit_number, 10313393f8daSKenneth D. Merry path->bus->sim->bus_id, 1032ad413009SAlexander Motin path->bus->path_id, 10333393f8daSKenneth D. Merry path->target->target_id, 10343393f8daSKenneth D. Merry path->device->lun_id); 10353393f8daSKenneth D. Merry printf("%s%d: ", periph->periph_name, periph->unit_number); 103652c9ce25SScott Long if (path->device->protocol == PROTO_SCSI) 10373393f8daSKenneth D. Merry scsi_print_inquiry(&path->device->inq_data); 103852c9ce25SScott Long else if (path->device->protocol == PROTO_ATA || 103952c9ce25SScott Long path->device->protocol == PROTO_SATAPM) 104052c9ce25SScott Long ata_print_ident(&path->device->ident_data); 10413089bb2eSAlexander Motin else if (path->device->protocol == PROTO_SEMB) 10423089bb2eSAlexander Motin semb_print_ident( 10433089bb2eSAlexander Motin (struct sep_identify_data *)&path->device->ident_data); 104452c9ce25SScott Long else 104552c9ce25SScott Long printf("Unknown protocol device\n"); 1046f053d777SMatt Jacob if (bootverbose && path->device->serial_num_len > 0) { 10473393f8daSKenneth D. Merry /* Don't wrap the screen - print only the first 60 chars */ 10483393f8daSKenneth D. Merry printf("%s%d: Serial Number %.60s\n", periph->periph_name, 10493393f8daSKenneth D. Merry periph->unit_number, path->device->serial_num); 10503393f8daSKenneth D. Merry } 105157079b17SAlexander Motin /* Announce transport details. */ 105257079b17SAlexander Motin (*(path->bus->xport->announce))(periph); 105357079b17SAlexander Motin /* Announce command queueing. */ 10543393f8daSKenneth D. Merry if (path->device->inq_flags & SID_CmdQue 10553393f8daSKenneth D. Merry || path->device->flags & CAM_DEV_TAG_AFTER_COUNT) { 10560aacc535SAlexander Motin printf("%s%d: Command Queueing enabled\n", 10573393f8daSKenneth D. Merry periph->periph_name, periph->unit_number); 10583393f8daSKenneth D. Merry } 105957079b17SAlexander Motin /* Announce caller's details if they've passed in. */ 10603393f8daSKenneth D. Merry if (announce_string != NULL) 10613393f8daSKenneth D. Merry printf("%s%d: %s\n", periph->periph_name, 10623393f8daSKenneth D. Merry periph->unit_number, announce_string); 10633393f8daSKenneth D. Merry } 10648b8a9b1dSJustin T. Gibbs 10656fb5c84eSSteven Hartland void 10666fb5c84eSSteven Hartland xpt_announce_quirks(struct cam_periph *periph, int quirks, char *bit_string) 10676fb5c84eSSteven Hartland { 10686fb5c84eSSteven Hartland if (quirks != 0) { 10696fb5c84eSSteven Hartland printf("%s%d: quirks=0x%b\n", periph->periph_name, 10706fb5c84eSSteven Hartland periph->unit_number, quirks, bit_string); 10716fb5c84eSSteven Hartland } 10726fb5c84eSSteven Hartland } 10736fb5c84eSSteven Hartland 10743501942bSJustin T. Gibbs int 10753501942bSJustin T. Gibbs xpt_getattr(char *buf, size_t len, const char *attr, struct cam_path *path) 10763501942bSJustin T. Gibbs { 1077ccba7102SAlexander Motin int ret = -1, l; 10783501942bSJustin T. Gibbs struct ccb_dev_advinfo cdai; 1079ccba7102SAlexander Motin struct scsi_vpd_id_descriptor *idd; 10803501942bSJustin T. Gibbs 10816884b662SAlexander Motin mtx_assert(path->bus->sim->mtx, MA_OWNED); 10826884b662SAlexander Motin 10833501942bSJustin T. Gibbs memset(&cdai, 0, sizeof(cdai)); 10843501942bSJustin T. Gibbs xpt_setup_ccb(&cdai.ccb_h, path, CAM_PRIORITY_NORMAL); 10853501942bSJustin T. Gibbs cdai.ccb_h.func_code = XPT_DEV_ADVINFO; 10863501942bSJustin T. Gibbs cdai.bufsiz = len; 10873501942bSJustin T. Gibbs 10883501942bSJustin T. Gibbs if (!strcmp(attr, "GEOM::ident")) 10893501942bSJustin T. Gibbs cdai.buftype = CDAI_TYPE_SERIAL_NUM; 10903501942bSJustin T. Gibbs else if (!strcmp(attr, "GEOM::physpath")) 10913501942bSJustin T. Gibbs cdai.buftype = CDAI_TYPE_PHYS_PATH; 109240f27d7cSAlexander Motin else if (strcmp(attr, "GEOM::lunid") == 0 || 109340f27d7cSAlexander Motin strcmp(attr, "GEOM::lunname") == 0) { 1094ccba7102SAlexander Motin cdai.buftype = CDAI_TYPE_SCSI_DEVID; 1095ccba7102SAlexander Motin cdai.bufsiz = CAM_SCSI_DEVID_MAXLEN; 1096ccba7102SAlexander Motin } else 10973501942bSJustin T. Gibbs goto out; 10983501942bSJustin T. Gibbs 10993501942bSJustin T. Gibbs cdai.buf = malloc(cdai.bufsiz, M_CAMXPT, M_NOWAIT|M_ZERO); 11003501942bSJustin T. Gibbs if (cdai.buf == NULL) { 11013501942bSJustin T. Gibbs ret = ENOMEM; 11023501942bSJustin T. Gibbs goto out; 11033501942bSJustin T. Gibbs } 11043501942bSJustin T. Gibbs xpt_action((union ccb *)&cdai); /* can only be synchronous */ 11053501942bSJustin T. Gibbs if ((cdai.ccb_h.status & CAM_DEV_QFRZN) != 0) 11063501942bSJustin T. Gibbs cam_release_devq(cdai.ccb_h.path, 0, 0, 0, FALSE); 11073501942bSJustin T. Gibbs if (cdai.provsiz == 0) 11083501942bSJustin T. Gibbs goto out; 1109ccba7102SAlexander Motin if (cdai.buftype == CDAI_TYPE_SCSI_DEVID) { 111040f27d7cSAlexander Motin if (strcmp(attr, "GEOM::lunid") == 0) { 1111ccba7102SAlexander Motin idd = scsi_get_devid((struct scsi_vpd_device_id *)cdai.buf, 1112ccba7102SAlexander Motin cdai.provsiz, scsi_devid_is_lun_naa); 1113ccba7102SAlexander Motin if (idd == NULL) 1114ccba7102SAlexander Motin idd = scsi_get_devid((struct scsi_vpd_device_id *)cdai.buf, 1115ccba7102SAlexander Motin cdai.provsiz, scsi_devid_is_lun_eui64); 111640f27d7cSAlexander Motin } else 111740f27d7cSAlexander Motin idd = NULL; 1118ccba7102SAlexander Motin if (idd == NULL) 1119ccba7102SAlexander Motin idd = scsi_get_devid((struct scsi_vpd_device_id *)cdai.buf, 1120ccba7102SAlexander Motin cdai.provsiz, scsi_devid_is_lun_t10); 1121ccba7102SAlexander Motin if (idd == NULL) 1122ccba7102SAlexander Motin idd = scsi_get_devid((struct scsi_vpd_device_id *)cdai.buf, 1123ccba7102SAlexander Motin cdai.provsiz, scsi_devid_is_lun_name); 1124ccba7102SAlexander Motin if (idd == NULL) 1125ccba7102SAlexander Motin goto out; 1126ccba7102SAlexander Motin ret = 0; 1127ccba7102SAlexander Motin if ((idd->proto_codeset & SVPD_ID_CODESET_MASK) == SVPD_ID_CODESET_ASCII || 1128ccba7102SAlexander Motin (idd->proto_codeset & SVPD_ID_CODESET_MASK) == SVPD_ID_CODESET_UTF8) { 1129ccba7102SAlexander Motin l = strnlen(idd->identifier, idd->length); 1130ccba7102SAlexander Motin if (l < len) { 1131ccba7102SAlexander Motin bcopy(idd->identifier, buf, l); 1132ccba7102SAlexander Motin buf[l] = 0; 1133ccba7102SAlexander Motin } else 1134ccba7102SAlexander Motin ret = EFAULT; 1135ccba7102SAlexander Motin } else { 1136ccba7102SAlexander Motin if (idd->length * 2 < len) { 1137ccba7102SAlexander Motin for (l = 0; l < idd->length; l++) 1138ccba7102SAlexander Motin sprintf(buf + l * 2, "%02x", 1139ccba7102SAlexander Motin idd->identifier[l]); 1140ccba7102SAlexander Motin } else 1141ccba7102SAlexander Motin ret = EFAULT; 1142ccba7102SAlexander Motin } 1143ccba7102SAlexander Motin } else { 11443501942bSJustin T. Gibbs ret = 0; 11453501942bSJustin T. Gibbs if (strlcpy(buf, cdai.buf, len) >= len) 11463501942bSJustin T. Gibbs ret = EFAULT; 1147ccba7102SAlexander Motin } 11483501942bSJustin T. Gibbs 11493501942bSJustin T. Gibbs out: 11503501942bSJustin T. Gibbs if (cdai.buf != NULL) 11513501942bSJustin T. Gibbs free(cdai.buf, M_CAMXPT); 11523501942bSJustin T. Gibbs return ret; 11533501942bSJustin T. Gibbs } 11543501942bSJustin T. Gibbs 11558b8a9b1dSJustin T. Gibbs static dev_match_ret 11563393f8daSKenneth D. Merry xptbusmatch(struct dev_match_pattern *patterns, u_int num_patterns, 11578b8a9b1dSJustin T. Gibbs struct cam_eb *bus) 11588b8a9b1dSJustin T. Gibbs { 11598b8a9b1dSJustin T. Gibbs dev_match_ret retval; 11608b8a9b1dSJustin T. Gibbs int i; 11618b8a9b1dSJustin T. Gibbs 11628b8a9b1dSJustin T. Gibbs retval = DM_RET_NONE; 11638b8a9b1dSJustin T. Gibbs 11648b8a9b1dSJustin T. Gibbs /* 11658b8a9b1dSJustin T. Gibbs * If we aren't given something to match against, that's an error. 11668b8a9b1dSJustin T. Gibbs */ 11678b8a9b1dSJustin T. Gibbs if (bus == NULL) 11688b8a9b1dSJustin T. Gibbs return(DM_RET_ERROR); 11698b8a9b1dSJustin T. Gibbs 11708b8a9b1dSJustin T. Gibbs /* 11718b8a9b1dSJustin T. Gibbs * If there are no match entries, then this bus matches no 11728b8a9b1dSJustin T. Gibbs * matter what. 11738b8a9b1dSJustin T. Gibbs */ 11748b8a9b1dSJustin T. Gibbs if ((patterns == NULL) || (num_patterns == 0)) 11758b8a9b1dSJustin T. Gibbs return(DM_RET_DESCEND | DM_RET_COPY); 11768b8a9b1dSJustin T. Gibbs 11778b8a9b1dSJustin T. Gibbs for (i = 0; i < num_patterns; i++) { 11788b8a9b1dSJustin T. Gibbs struct bus_match_pattern *cur_pattern; 11798b8a9b1dSJustin T. Gibbs 11808b8a9b1dSJustin T. Gibbs /* 11818b8a9b1dSJustin T. Gibbs * If the pattern in question isn't for a bus node, we 11828b8a9b1dSJustin T. Gibbs * aren't interested. However, we do indicate to the 11838b8a9b1dSJustin T. Gibbs * calling routine that we should continue descending the 11848b8a9b1dSJustin T. Gibbs * tree, since the user wants to match against lower-level 11858b8a9b1dSJustin T. Gibbs * EDT elements. 11868b8a9b1dSJustin T. Gibbs */ 11878b8a9b1dSJustin T. Gibbs if (patterns[i].type != DEV_MATCH_BUS) { 11888b8a9b1dSJustin T. Gibbs if ((retval & DM_RET_ACTION_MASK) == DM_RET_NONE) 11898b8a9b1dSJustin T. Gibbs retval |= DM_RET_DESCEND; 11908b8a9b1dSJustin T. Gibbs continue; 11918b8a9b1dSJustin T. Gibbs } 11928b8a9b1dSJustin T. Gibbs 11938b8a9b1dSJustin T. Gibbs cur_pattern = &patterns[i].pattern.bus_pattern; 11948b8a9b1dSJustin T. Gibbs 11958b8a9b1dSJustin T. Gibbs /* 11968b8a9b1dSJustin T. Gibbs * If they want to match any bus node, we give them any 11978b8a9b1dSJustin T. Gibbs * device node. 11988b8a9b1dSJustin T. Gibbs */ 11998b8a9b1dSJustin T. Gibbs if (cur_pattern->flags == BUS_MATCH_ANY) { 12008b8a9b1dSJustin T. Gibbs /* set the copy flag */ 12018b8a9b1dSJustin T. Gibbs retval |= DM_RET_COPY; 12028b8a9b1dSJustin T. Gibbs 12038b8a9b1dSJustin T. Gibbs /* 12048b8a9b1dSJustin T. Gibbs * If we've already decided on an action, go ahead 12058b8a9b1dSJustin T. Gibbs * and return. 12068b8a9b1dSJustin T. Gibbs */ 12078b8a9b1dSJustin T. Gibbs if ((retval & DM_RET_ACTION_MASK) != DM_RET_NONE) 12088b8a9b1dSJustin T. Gibbs return(retval); 12098b8a9b1dSJustin T. Gibbs } 12108b8a9b1dSJustin T. Gibbs 12118b8a9b1dSJustin T. Gibbs /* 12128b8a9b1dSJustin T. Gibbs * Not sure why someone would do this... 12138b8a9b1dSJustin T. Gibbs */ 12148b8a9b1dSJustin T. Gibbs if (cur_pattern->flags == BUS_MATCH_NONE) 12158b8a9b1dSJustin T. Gibbs continue; 12168b8a9b1dSJustin T. Gibbs 12178b8a9b1dSJustin T. Gibbs if (((cur_pattern->flags & BUS_MATCH_PATH) != 0) 12188b8a9b1dSJustin T. Gibbs && (cur_pattern->path_id != bus->path_id)) 12198b8a9b1dSJustin T. Gibbs continue; 12208b8a9b1dSJustin T. Gibbs 12218b8a9b1dSJustin T. Gibbs if (((cur_pattern->flags & BUS_MATCH_BUS_ID) != 0) 12228b8a9b1dSJustin T. Gibbs && (cur_pattern->bus_id != bus->sim->bus_id)) 12238b8a9b1dSJustin T. Gibbs continue; 12248b8a9b1dSJustin T. Gibbs 12258b8a9b1dSJustin T. Gibbs if (((cur_pattern->flags & BUS_MATCH_UNIT) != 0) 12268b8a9b1dSJustin T. Gibbs && (cur_pattern->unit_number != bus->sim->unit_number)) 12278b8a9b1dSJustin T. Gibbs continue; 12288b8a9b1dSJustin T. Gibbs 12298b8a9b1dSJustin T. Gibbs if (((cur_pattern->flags & BUS_MATCH_NAME) != 0) 12308b8a9b1dSJustin T. Gibbs && (strncmp(cur_pattern->dev_name, bus->sim->sim_name, 12318b8a9b1dSJustin T. Gibbs DEV_IDLEN) != 0)) 12328b8a9b1dSJustin T. Gibbs continue; 12338b8a9b1dSJustin T. Gibbs 12348b8a9b1dSJustin T. Gibbs /* 12358b8a9b1dSJustin T. Gibbs * If we get to this point, the user definitely wants 12368b8a9b1dSJustin T. Gibbs * information on this bus. So tell the caller to copy the 12378b8a9b1dSJustin T. Gibbs * data out. 12388b8a9b1dSJustin T. Gibbs */ 12398b8a9b1dSJustin T. Gibbs retval |= DM_RET_COPY; 12408b8a9b1dSJustin T. Gibbs 12418b8a9b1dSJustin T. Gibbs /* 12428b8a9b1dSJustin T. Gibbs * If the return action has been set to descend, then we 12438b8a9b1dSJustin T. Gibbs * know that we've already seen a non-bus matching 12448b8a9b1dSJustin T. Gibbs * expression, therefore we need to further descend the tree. 12458b8a9b1dSJustin T. Gibbs * This won't change by continuing around the loop, so we 12468b8a9b1dSJustin T. Gibbs * go ahead and return. If we haven't seen a non-bus 12478b8a9b1dSJustin T. Gibbs * matching expression, we keep going around the loop until 12488b8a9b1dSJustin T. Gibbs * we exhaust the matching expressions. We'll set the stop 12498b8a9b1dSJustin T. Gibbs * flag once we fall out of the loop. 12508b8a9b1dSJustin T. Gibbs */ 12518b8a9b1dSJustin T. Gibbs if ((retval & DM_RET_ACTION_MASK) == DM_RET_DESCEND) 12528b8a9b1dSJustin T. Gibbs return(retval); 12538b8a9b1dSJustin T. Gibbs } 12548b8a9b1dSJustin T. Gibbs 12558b8a9b1dSJustin T. Gibbs /* 12568b8a9b1dSJustin T. Gibbs * If the return action hasn't been set to descend yet, that means 12578b8a9b1dSJustin T. Gibbs * we haven't seen anything other than bus matching patterns. So 12588b8a9b1dSJustin T. Gibbs * tell the caller to stop descending the tree -- the user doesn't 12598b8a9b1dSJustin T. Gibbs * want to match against lower level tree elements. 12608b8a9b1dSJustin T. Gibbs */ 12618b8a9b1dSJustin T. Gibbs if ((retval & DM_RET_ACTION_MASK) == DM_RET_NONE) 12628b8a9b1dSJustin T. Gibbs retval |= DM_RET_STOP; 12638b8a9b1dSJustin T. Gibbs 12648b8a9b1dSJustin T. Gibbs return(retval); 12658b8a9b1dSJustin T. Gibbs } 12668b8a9b1dSJustin T. Gibbs 12678b8a9b1dSJustin T. Gibbs static dev_match_ret 12683393f8daSKenneth D. Merry xptdevicematch(struct dev_match_pattern *patterns, u_int num_patterns, 12698b8a9b1dSJustin T. Gibbs struct cam_ed *device) 12708b8a9b1dSJustin T. Gibbs { 12718b8a9b1dSJustin T. Gibbs dev_match_ret retval; 12728b8a9b1dSJustin T. Gibbs int i; 12738b8a9b1dSJustin T. Gibbs 12748b8a9b1dSJustin T. Gibbs retval = DM_RET_NONE; 12758b8a9b1dSJustin T. Gibbs 12768b8a9b1dSJustin T. Gibbs /* 12778b8a9b1dSJustin T. Gibbs * If we aren't given something to match against, that's an error. 12788b8a9b1dSJustin T. Gibbs */ 12798b8a9b1dSJustin T. Gibbs if (device == NULL) 12808b8a9b1dSJustin T. Gibbs return(DM_RET_ERROR); 12818b8a9b1dSJustin T. Gibbs 12828b8a9b1dSJustin T. Gibbs /* 12838b8a9b1dSJustin T. Gibbs * If there are no match entries, then this device matches no 12848b8a9b1dSJustin T. Gibbs * matter what. 12858b8a9b1dSJustin T. Gibbs */ 128659e75884SColin Percival if ((patterns == NULL) || (num_patterns == 0)) 12878b8a9b1dSJustin T. Gibbs return(DM_RET_DESCEND | DM_RET_COPY); 12888b8a9b1dSJustin T. Gibbs 12898b8a9b1dSJustin T. Gibbs for (i = 0; i < num_patterns; i++) { 12908b8a9b1dSJustin T. Gibbs struct device_match_pattern *cur_pattern; 12913501942bSJustin T. Gibbs struct scsi_vpd_device_id *device_id_page; 12928b8a9b1dSJustin T. Gibbs 12938b8a9b1dSJustin T. Gibbs /* 12948b8a9b1dSJustin T. Gibbs * If the pattern in question isn't for a device node, we 12958b8a9b1dSJustin T. Gibbs * aren't interested. 12968b8a9b1dSJustin T. Gibbs */ 12978b8a9b1dSJustin T. Gibbs if (patterns[i].type != DEV_MATCH_DEVICE) { 12988b8a9b1dSJustin T. Gibbs if ((patterns[i].type == DEV_MATCH_PERIPH) 12998b8a9b1dSJustin T. Gibbs && ((retval & DM_RET_ACTION_MASK) == DM_RET_NONE)) 13008b8a9b1dSJustin T. Gibbs retval |= DM_RET_DESCEND; 13018b8a9b1dSJustin T. Gibbs continue; 13028b8a9b1dSJustin T. Gibbs } 13038b8a9b1dSJustin T. Gibbs 13048b8a9b1dSJustin T. Gibbs cur_pattern = &patterns[i].pattern.device_pattern; 13058b8a9b1dSJustin T. Gibbs 13063501942bSJustin T. Gibbs /* Error out if mutually exclusive options are specified. */ 13073501942bSJustin T. Gibbs if ((cur_pattern->flags & (DEV_MATCH_INQUIRY|DEV_MATCH_DEVID)) 13083501942bSJustin T. Gibbs == (DEV_MATCH_INQUIRY|DEV_MATCH_DEVID)) 13093501942bSJustin T. Gibbs return(DM_RET_ERROR); 13103501942bSJustin T. Gibbs 13118b8a9b1dSJustin T. Gibbs /* 13128b8a9b1dSJustin T. Gibbs * If they want to match any device node, we give them any 13138b8a9b1dSJustin T. Gibbs * device node. 13148b8a9b1dSJustin T. Gibbs */ 13153501942bSJustin T. Gibbs if (cur_pattern->flags == DEV_MATCH_ANY) 13163501942bSJustin T. Gibbs goto copy_dev_node; 13178b8a9b1dSJustin T. Gibbs 13188b8a9b1dSJustin T. Gibbs /* 13198b8a9b1dSJustin T. Gibbs * Not sure why someone would do this... 13208b8a9b1dSJustin T. Gibbs */ 13218b8a9b1dSJustin T. Gibbs if (cur_pattern->flags == DEV_MATCH_NONE) 13228b8a9b1dSJustin T. Gibbs continue; 13238b8a9b1dSJustin T. Gibbs 13248b8a9b1dSJustin T. Gibbs if (((cur_pattern->flags & DEV_MATCH_PATH) != 0) 13258b8a9b1dSJustin T. Gibbs && (cur_pattern->path_id != device->target->bus->path_id)) 13268b8a9b1dSJustin T. Gibbs continue; 13278b8a9b1dSJustin T. Gibbs 13288b8a9b1dSJustin T. Gibbs if (((cur_pattern->flags & DEV_MATCH_TARGET) != 0) 13298b8a9b1dSJustin T. Gibbs && (cur_pattern->target_id != device->target->target_id)) 13308b8a9b1dSJustin T. Gibbs continue; 13318b8a9b1dSJustin T. Gibbs 13328b8a9b1dSJustin T. Gibbs if (((cur_pattern->flags & DEV_MATCH_LUN) != 0) 13338b8a9b1dSJustin T. Gibbs && (cur_pattern->target_lun != device->lun_id)) 13348b8a9b1dSJustin T. Gibbs continue; 13358b8a9b1dSJustin T. Gibbs 13368b8a9b1dSJustin T. Gibbs if (((cur_pattern->flags & DEV_MATCH_INQUIRY) != 0) 13378b8a9b1dSJustin T. Gibbs && (cam_quirkmatch((caddr_t)&device->inq_data, 13383501942bSJustin T. Gibbs (caddr_t)&cur_pattern->data.inq_pat, 13393501942bSJustin T. Gibbs 1, sizeof(cur_pattern->data.inq_pat), 13408b8a9b1dSJustin T. Gibbs scsi_static_inquiry_match) == NULL)) 13418b8a9b1dSJustin T. Gibbs continue; 13428b8a9b1dSJustin T. Gibbs 13433501942bSJustin T. Gibbs device_id_page = (struct scsi_vpd_device_id *)device->device_id; 13443501942bSJustin T. Gibbs if (((cur_pattern->flags & DEV_MATCH_DEVID) != 0) 13453501942bSJustin T. Gibbs && (device->device_id_len < SVPD_DEVICE_ID_HDR_LEN 13463501942bSJustin T. Gibbs || scsi_devid_match((uint8_t *)device_id_page->desc_list, 13473501942bSJustin T. Gibbs device->device_id_len 13483501942bSJustin T. Gibbs - SVPD_DEVICE_ID_HDR_LEN, 13493501942bSJustin T. Gibbs cur_pattern->data.devid_pat.id, 13503501942bSJustin T. Gibbs cur_pattern->data.devid_pat.id_len) != 0)) 13513501942bSJustin T. Gibbs continue; 13523501942bSJustin T. Gibbs 13533501942bSJustin T. Gibbs copy_dev_node: 13548b8a9b1dSJustin T. Gibbs /* 13558b8a9b1dSJustin T. Gibbs * If we get to this point, the user definitely wants 13568b8a9b1dSJustin T. Gibbs * information on this device. So tell the caller to copy 13578b8a9b1dSJustin T. Gibbs * the data out. 13588b8a9b1dSJustin T. Gibbs */ 13598b8a9b1dSJustin T. Gibbs retval |= DM_RET_COPY; 13608b8a9b1dSJustin T. Gibbs 13618b8a9b1dSJustin T. Gibbs /* 13628b8a9b1dSJustin T. Gibbs * If the return action has been set to descend, then we 13638b8a9b1dSJustin T. Gibbs * know that we've already seen a peripheral matching 13648b8a9b1dSJustin T. Gibbs * expression, therefore we need to further descend the tree. 13658b8a9b1dSJustin T. Gibbs * This won't change by continuing around the loop, so we 13668b8a9b1dSJustin T. Gibbs * go ahead and return. If we haven't seen a peripheral 13678b8a9b1dSJustin T. Gibbs * matching expression, we keep going around the loop until 13688b8a9b1dSJustin T. Gibbs * we exhaust the matching expressions. We'll set the stop 13698b8a9b1dSJustin T. Gibbs * flag once we fall out of the loop. 13708b8a9b1dSJustin T. Gibbs */ 13718b8a9b1dSJustin T. Gibbs if ((retval & DM_RET_ACTION_MASK) == DM_RET_DESCEND) 13728b8a9b1dSJustin T. Gibbs return(retval); 13738b8a9b1dSJustin T. Gibbs } 13748b8a9b1dSJustin T. Gibbs 13758b8a9b1dSJustin T. Gibbs /* 13768b8a9b1dSJustin T. Gibbs * If the return action hasn't been set to descend yet, that means 13778b8a9b1dSJustin T. Gibbs * we haven't seen any peripheral matching patterns. So tell the 13788b8a9b1dSJustin T. Gibbs * caller to stop descending the tree -- the user doesn't want to 13798b8a9b1dSJustin T. Gibbs * match against lower level tree elements. 13808b8a9b1dSJustin T. Gibbs */ 13818b8a9b1dSJustin T. Gibbs if ((retval & DM_RET_ACTION_MASK) == DM_RET_NONE) 13828b8a9b1dSJustin T. Gibbs retval |= DM_RET_STOP; 13838b8a9b1dSJustin T. Gibbs 13848b8a9b1dSJustin T. Gibbs return(retval); 13858b8a9b1dSJustin T. Gibbs } 13868b8a9b1dSJustin T. Gibbs 13878b8a9b1dSJustin T. Gibbs /* 13888b8a9b1dSJustin T. Gibbs * Match a single peripheral against any number of match patterns. 13898b8a9b1dSJustin T. Gibbs */ 13908b8a9b1dSJustin T. Gibbs static dev_match_ret 13913393f8daSKenneth D. Merry xptperiphmatch(struct dev_match_pattern *patterns, u_int num_patterns, 13928b8a9b1dSJustin T. Gibbs struct cam_periph *periph) 13938b8a9b1dSJustin T. Gibbs { 13948b8a9b1dSJustin T. Gibbs dev_match_ret retval; 13958b8a9b1dSJustin T. Gibbs int i; 13968b8a9b1dSJustin T. Gibbs 13978b8a9b1dSJustin T. Gibbs /* 13988b8a9b1dSJustin T. Gibbs * If we aren't given something to match against, that's an error. 13998b8a9b1dSJustin T. Gibbs */ 14008b8a9b1dSJustin T. Gibbs if (periph == NULL) 14018b8a9b1dSJustin T. Gibbs return(DM_RET_ERROR); 14028b8a9b1dSJustin T. Gibbs 14038b8a9b1dSJustin T. Gibbs /* 14048b8a9b1dSJustin T. Gibbs * If there are no match entries, then this peripheral matches no 14058b8a9b1dSJustin T. Gibbs * matter what. 14068b8a9b1dSJustin T. Gibbs */ 14078b8a9b1dSJustin T. Gibbs if ((patterns == NULL) || (num_patterns == 0)) 14088b8a9b1dSJustin T. Gibbs return(DM_RET_STOP | DM_RET_COPY); 14098b8a9b1dSJustin T. Gibbs 14108b8a9b1dSJustin T. Gibbs /* 14118b8a9b1dSJustin T. Gibbs * There aren't any nodes below a peripheral node, so there's no 14128b8a9b1dSJustin T. Gibbs * reason to descend the tree any further. 14138b8a9b1dSJustin T. Gibbs */ 14148b8a9b1dSJustin T. Gibbs retval = DM_RET_STOP; 14158b8a9b1dSJustin T. Gibbs 14168b8a9b1dSJustin T. Gibbs for (i = 0; i < num_patterns; i++) { 14178b8a9b1dSJustin T. Gibbs struct periph_match_pattern *cur_pattern; 14188b8a9b1dSJustin T. Gibbs 14198b8a9b1dSJustin T. Gibbs /* 14208b8a9b1dSJustin T. Gibbs * If the pattern in question isn't for a peripheral, we 14218b8a9b1dSJustin T. Gibbs * aren't interested. 14228b8a9b1dSJustin T. Gibbs */ 14238b8a9b1dSJustin T. Gibbs if (patterns[i].type != DEV_MATCH_PERIPH) 14248b8a9b1dSJustin T. Gibbs continue; 14258b8a9b1dSJustin T. Gibbs 14268b8a9b1dSJustin T. Gibbs cur_pattern = &patterns[i].pattern.periph_pattern; 14278b8a9b1dSJustin T. Gibbs 14288b8a9b1dSJustin T. Gibbs /* 14298b8a9b1dSJustin T. Gibbs * If they want to match on anything, then we will do so. 14308b8a9b1dSJustin T. Gibbs */ 14318b8a9b1dSJustin T. Gibbs if (cur_pattern->flags == PERIPH_MATCH_ANY) { 14328b8a9b1dSJustin T. Gibbs /* set the copy flag */ 14338b8a9b1dSJustin T. Gibbs retval |= DM_RET_COPY; 14348b8a9b1dSJustin T. Gibbs 14358b8a9b1dSJustin T. Gibbs /* 14368b8a9b1dSJustin T. Gibbs * We've already set the return action to stop, 14378b8a9b1dSJustin T. Gibbs * since there are no nodes below peripherals in 14388b8a9b1dSJustin T. Gibbs * the tree. 14398b8a9b1dSJustin T. Gibbs */ 14408b8a9b1dSJustin T. Gibbs return(retval); 14418b8a9b1dSJustin T. Gibbs } 14428b8a9b1dSJustin T. Gibbs 14438b8a9b1dSJustin T. Gibbs /* 14448b8a9b1dSJustin T. Gibbs * Not sure why someone would do this... 14458b8a9b1dSJustin T. Gibbs */ 14468b8a9b1dSJustin T. Gibbs if (cur_pattern->flags == PERIPH_MATCH_NONE) 14478b8a9b1dSJustin T. Gibbs continue; 14488b8a9b1dSJustin T. Gibbs 14498b8a9b1dSJustin T. Gibbs if (((cur_pattern->flags & PERIPH_MATCH_PATH) != 0) 14508b8a9b1dSJustin T. Gibbs && (cur_pattern->path_id != periph->path->bus->path_id)) 14518b8a9b1dSJustin T. Gibbs continue; 14528b8a9b1dSJustin T. Gibbs 14538b8a9b1dSJustin T. Gibbs /* 14548b8a9b1dSJustin T. Gibbs * For the target and lun id's, we have to make sure the 14558b8a9b1dSJustin T. Gibbs * target and lun pointers aren't NULL. The xpt peripheral 14568b8a9b1dSJustin T. Gibbs * has a wildcard target and device. 14578b8a9b1dSJustin T. Gibbs */ 14588b8a9b1dSJustin T. Gibbs if (((cur_pattern->flags & PERIPH_MATCH_TARGET) != 0) 14598b8a9b1dSJustin T. Gibbs && ((periph->path->target == NULL) 14608b8a9b1dSJustin T. Gibbs ||(cur_pattern->target_id != periph->path->target->target_id))) 14618b8a9b1dSJustin T. Gibbs continue; 14628b8a9b1dSJustin T. Gibbs 14638b8a9b1dSJustin T. Gibbs if (((cur_pattern->flags & PERIPH_MATCH_LUN) != 0) 14648b8a9b1dSJustin T. Gibbs && ((periph->path->device == NULL) 14658b8a9b1dSJustin T. Gibbs || (cur_pattern->target_lun != periph->path->device->lun_id))) 14668b8a9b1dSJustin T. Gibbs continue; 14678b8a9b1dSJustin T. Gibbs 14688b8a9b1dSJustin T. Gibbs if (((cur_pattern->flags & PERIPH_MATCH_UNIT) != 0) 14698b8a9b1dSJustin T. Gibbs && (cur_pattern->unit_number != periph->unit_number)) 14708b8a9b1dSJustin T. Gibbs continue; 14718b8a9b1dSJustin T. Gibbs 14728b8a9b1dSJustin T. Gibbs if (((cur_pattern->flags & PERIPH_MATCH_NAME) != 0) 14738b8a9b1dSJustin T. Gibbs && (strncmp(cur_pattern->periph_name, periph->periph_name, 14748b8a9b1dSJustin T. Gibbs DEV_IDLEN) != 0)) 14758b8a9b1dSJustin T. Gibbs continue; 14768b8a9b1dSJustin T. Gibbs 14778b8a9b1dSJustin T. Gibbs /* 14788b8a9b1dSJustin T. Gibbs * If we get to this point, the user definitely wants 14798b8a9b1dSJustin T. Gibbs * information on this peripheral. So tell the caller to 14808b8a9b1dSJustin T. Gibbs * copy the data out. 14818b8a9b1dSJustin T. Gibbs */ 14828b8a9b1dSJustin T. Gibbs retval |= DM_RET_COPY; 14838b8a9b1dSJustin T. Gibbs 14848b8a9b1dSJustin T. Gibbs /* 14858b8a9b1dSJustin T. Gibbs * The return action has already been set to stop, since 14868b8a9b1dSJustin T. Gibbs * peripherals don't have any nodes below them in the EDT. 14878b8a9b1dSJustin T. Gibbs */ 14888b8a9b1dSJustin T. Gibbs return(retval); 14898b8a9b1dSJustin T. Gibbs } 14908b8a9b1dSJustin T. Gibbs 14918b8a9b1dSJustin T. Gibbs /* 14928b8a9b1dSJustin T. Gibbs * If we get to this point, the peripheral that was passed in 14938b8a9b1dSJustin T. Gibbs * doesn't match any of the patterns. 14948b8a9b1dSJustin T. Gibbs */ 14958b8a9b1dSJustin T. Gibbs return(retval); 14968b8a9b1dSJustin T. Gibbs } 14978b8a9b1dSJustin T. Gibbs 14988b8a9b1dSJustin T. Gibbs static int 14998b8a9b1dSJustin T. Gibbs xptedtbusfunc(struct cam_eb *bus, void *arg) 15008b8a9b1dSJustin T. Gibbs { 15018b8a9b1dSJustin T. Gibbs struct ccb_dev_match *cdm; 15028b8a9b1dSJustin T. Gibbs dev_match_ret retval; 15038b8a9b1dSJustin T. Gibbs 15048b8a9b1dSJustin T. Gibbs cdm = (struct ccb_dev_match *)arg; 15058b8a9b1dSJustin T. Gibbs 15068b8a9b1dSJustin T. Gibbs /* 15078b8a9b1dSJustin T. Gibbs * If our position is for something deeper in the tree, that means 15088b8a9b1dSJustin T. Gibbs * that we've already seen this node. So, we keep going down. 15098b8a9b1dSJustin T. Gibbs */ 15108b8a9b1dSJustin T. Gibbs if ((cdm->pos.position_type & CAM_DEV_POS_BUS) 15118b8a9b1dSJustin T. Gibbs && (cdm->pos.cookie.bus == bus) 15128b8a9b1dSJustin T. Gibbs && (cdm->pos.position_type & CAM_DEV_POS_TARGET) 15138b8a9b1dSJustin T. Gibbs && (cdm->pos.cookie.target != NULL)) 15148b8a9b1dSJustin T. Gibbs retval = DM_RET_DESCEND; 15158b8a9b1dSJustin T. Gibbs else 15168b8a9b1dSJustin T. Gibbs retval = xptbusmatch(cdm->patterns, cdm->num_patterns, bus); 15178b8a9b1dSJustin T. Gibbs 15188b8a9b1dSJustin T. Gibbs /* 15198b8a9b1dSJustin T. Gibbs * If we got an error, bail out of the search. 15208b8a9b1dSJustin T. Gibbs */ 15218b8a9b1dSJustin T. Gibbs if ((retval & DM_RET_ACTION_MASK) == DM_RET_ERROR) { 15228b8a9b1dSJustin T. Gibbs cdm->status = CAM_DEV_MATCH_ERROR; 15238b8a9b1dSJustin T. Gibbs return(0); 15248b8a9b1dSJustin T. Gibbs } 15258b8a9b1dSJustin T. Gibbs 15268b8a9b1dSJustin T. Gibbs /* 15278b8a9b1dSJustin T. Gibbs * If the copy flag is set, copy this bus out. 15288b8a9b1dSJustin T. Gibbs */ 15298b8a9b1dSJustin T. Gibbs if (retval & DM_RET_COPY) { 15308b8a9b1dSJustin T. Gibbs int spaceleft, j; 15318b8a9b1dSJustin T. Gibbs 15328b8a9b1dSJustin T. Gibbs spaceleft = cdm->match_buf_len - (cdm->num_matches * 15338b8a9b1dSJustin T. Gibbs sizeof(struct dev_match_result)); 15348b8a9b1dSJustin T. Gibbs 15358b8a9b1dSJustin T. Gibbs /* 15368b8a9b1dSJustin T. Gibbs * If we don't have enough space to put in another 15378b8a9b1dSJustin T. Gibbs * match result, save our position and tell the 15388b8a9b1dSJustin T. Gibbs * user there are more devices to check. 15398b8a9b1dSJustin T. Gibbs */ 15408b8a9b1dSJustin T. Gibbs if (spaceleft < sizeof(struct dev_match_result)) { 15418b8a9b1dSJustin T. Gibbs bzero(&cdm->pos, sizeof(cdm->pos)); 15428b8a9b1dSJustin T. Gibbs cdm->pos.position_type = 15438b8a9b1dSJustin T. Gibbs CAM_DEV_POS_EDT | CAM_DEV_POS_BUS; 15448b8a9b1dSJustin T. Gibbs 15458b8a9b1dSJustin T. Gibbs cdm->pos.cookie.bus = bus; 15468b8a9b1dSJustin T. Gibbs cdm->pos.generations[CAM_BUS_GENERATION]= 15472b83592fSScott Long xsoftc.bus_generation; 15488b8a9b1dSJustin T. Gibbs cdm->status = CAM_DEV_MATCH_MORE; 15498b8a9b1dSJustin T. Gibbs return(0); 15508b8a9b1dSJustin T. Gibbs } 15518b8a9b1dSJustin T. Gibbs j = cdm->num_matches; 15528b8a9b1dSJustin T. Gibbs cdm->num_matches++; 15538b8a9b1dSJustin T. Gibbs cdm->matches[j].type = DEV_MATCH_BUS; 15548b8a9b1dSJustin T. Gibbs cdm->matches[j].result.bus_result.path_id = bus->path_id; 15558b8a9b1dSJustin T. Gibbs cdm->matches[j].result.bus_result.bus_id = bus->sim->bus_id; 15568b8a9b1dSJustin T. Gibbs cdm->matches[j].result.bus_result.unit_number = 15578b8a9b1dSJustin T. Gibbs bus->sim->unit_number; 15588b8a9b1dSJustin T. Gibbs strncpy(cdm->matches[j].result.bus_result.dev_name, 15598b8a9b1dSJustin T. Gibbs bus->sim->sim_name, DEV_IDLEN); 15608b8a9b1dSJustin T. Gibbs } 15618b8a9b1dSJustin T. Gibbs 15628b8a9b1dSJustin T. Gibbs /* 15638b8a9b1dSJustin T. Gibbs * If the user is only interested in busses, there's no 15648b8a9b1dSJustin T. Gibbs * reason to descend to the next level in the tree. 15658b8a9b1dSJustin T. Gibbs */ 15668b8a9b1dSJustin T. Gibbs if ((retval & DM_RET_ACTION_MASK) == DM_RET_STOP) 15678b8a9b1dSJustin T. Gibbs return(1); 15688b8a9b1dSJustin T. Gibbs 15698b8a9b1dSJustin T. Gibbs /* 15708b8a9b1dSJustin T. Gibbs * If there is a target generation recorded, check it to 15718b8a9b1dSJustin T. Gibbs * make sure the target list hasn't changed. 15728b8a9b1dSJustin T. Gibbs */ 15738b8a9b1dSJustin T. Gibbs if ((cdm->pos.position_type & CAM_DEV_POS_BUS) 15748b8a9b1dSJustin T. Gibbs && (bus == cdm->pos.cookie.bus) 15758b8a9b1dSJustin T. Gibbs && (cdm->pos.position_type & CAM_DEV_POS_TARGET) 15768b8a9b1dSJustin T. Gibbs && (cdm->pos.generations[CAM_TARGET_GENERATION] != 0) 15778b8a9b1dSJustin T. Gibbs && (cdm->pos.generations[CAM_TARGET_GENERATION] != 15788b8a9b1dSJustin T. Gibbs bus->generation)) { 15798b8a9b1dSJustin T. Gibbs cdm->status = CAM_DEV_MATCH_LIST_CHANGED; 15808b8a9b1dSJustin T. Gibbs return(0); 15818b8a9b1dSJustin T. Gibbs } 15828b8a9b1dSJustin T. Gibbs 15838b8a9b1dSJustin T. Gibbs if ((cdm->pos.position_type & CAM_DEV_POS_BUS) 15848b8a9b1dSJustin T. Gibbs && (cdm->pos.cookie.bus == bus) 15858b8a9b1dSJustin T. Gibbs && (cdm->pos.position_type & CAM_DEV_POS_TARGET) 15868b8a9b1dSJustin T. Gibbs && (cdm->pos.cookie.target != NULL)) 15878b8a9b1dSJustin T. Gibbs return(xpttargettraverse(bus, 15888b8a9b1dSJustin T. Gibbs (struct cam_et *)cdm->pos.cookie.target, 15898b8a9b1dSJustin T. Gibbs xptedttargetfunc, arg)); 15908b8a9b1dSJustin T. Gibbs else 15918b8a9b1dSJustin T. Gibbs return(xpttargettraverse(bus, NULL, xptedttargetfunc, arg)); 15928b8a9b1dSJustin T. Gibbs } 15938b8a9b1dSJustin T. Gibbs 15948b8a9b1dSJustin T. Gibbs static int 15958b8a9b1dSJustin T. Gibbs xptedttargetfunc(struct cam_et *target, void *arg) 15968b8a9b1dSJustin T. Gibbs { 15978b8a9b1dSJustin T. Gibbs struct ccb_dev_match *cdm; 15988b8a9b1dSJustin T. Gibbs 15998b8a9b1dSJustin T. Gibbs cdm = (struct ccb_dev_match *)arg; 16008b8a9b1dSJustin T. Gibbs 16018b8a9b1dSJustin T. Gibbs /* 16028b8a9b1dSJustin T. Gibbs * If there is a device list generation recorded, check it to 16038b8a9b1dSJustin T. Gibbs * make sure the device list hasn't changed. 16048b8a9b1dSJustin T. Gibbs */ 16058b8a9b1dSJustin T. Gibbs if ((cdm->pos.position_type & CAM_DEV_POS_BUS) 16068b8a9b1dSJustin T. Gibbs && (cdm->pos.cookie.bus == target->bus) 16078b8a9b1dSJustin T. Gibbs && (cdm->pos.position_type & CAM_DEV_POS_TARGET) 16088b8a9b1dSJustin T. Gibbs && (cdm->pos.cookie.target == target) 16098b8a9b1dSJustin T. Gibbs && (cdm->pos.position_type & CAM_DEV_POS_DEVICE) 16108b8a9b1dSJustin T. Gibbs && (cdm->pos.generations[CAM_DEV_GENERATION] != 0) 16118b8a9b1dSJustin T. Gibbs && (cdm->pos.generations[CAM_DEV_GENERATION] != 16128b8a9b1dSJustin T. Gibbs target->generation)) { 16138b8a9b1dSJustin T. Gibbs cdm->status = CAM_DEV_MATCH_LIST_CHANGED; 16148b8a9b1dSJustin T. Gibbs return(0); 16158b8a9b1dSJustin T. Gibbs } 16168b8a9b1dSJustin T. Gibbs 16178b8a9b1dSJustin T. Gibbs if ((cdm->pos.position_type & CAM_DEV_POS_BUS) 16188b8a9b1dSJustin T. Gibbs && (cdm->pos.cookie.bus == target->bus) 16198b8a9b1dSJustin T. Gibbs && (cdm->pos.position_type & CAM_DEV_POS_TARGET) 16208b8a9b1dSJustin T. Gibbs && (cdm->pos.cookie.target == target) 16218b8a9b1dSJustin T. Gibbs && (cdm->pos.position_type & CAM_DEV_POS_DEVICE) 16228b8a9b1dSJustin T. Gibbs && (cdm->pos.cookie.device != NULL)) 16238b8a9b1dSJustin T. Gibbs return(xptdevicetraverse(target, 16248b8a9b1dSJustin T. Gibbs (struct cam_ed *)cdm->pos.cookie.device, 16258b8a9b1dSJustin T. Gibbs xptedtdevicefunc, arg)); 16268b8a9b1dSJustin T. Gibbs else 16278b8a9b1dSJustin T. Gibbs return(xptdevicetraverse(target, NULL, xptedtdevicefunc, arg)); 16288b8a9b1dSJustin T. Gibbs } 16298b8a9b1dSJustin T. Gibbs 16308b8a9b1dSJustin T. Gibbs static int 16318b8a9b1dSJustin T. Gibbs xptedtdevicefunc(struct cam_ed *device, void *arg) 16328b8a9b1dSJustin T. Gibbs { 16338b8a9b1dSJustin T. Gibbs 16348b8a9b1dSJustin T. Gibbs struct ccb_dev_match *cdm; 16358b8a9b1dSJustin T. Gibbs dev_match_ret retval; 16368b8a9b1dSJustin T. Gibbs 16378b8a9b1dSJustin T. Gibbs cdm = (struct ccb_dev_match *)arg; 16388b8a9b1dSJustin T. Gibbs 16398b8a9b1dSJustin T. Gibbs /* 16408b8a9b1dSJustin T. Gibbs * If our position is for something deeper in the tree, that means 16418b8a9b1dSJustin T. Gibbs * that we've already seen this node. So, we keep going down. 16428b8a9b1dSJustin T. Gibbs */ 16438b8a9b1dSJustin T. Gibbs if ((cdm->pos.position_type & CAM_DEV_POS_DEVICE) 16448b8a9b1dSJustin T. Gibbs && (cdm->pos.cookie.device == device) 16458b8a9b1dSJustin T. Gibbs && (cdm->pos.position_type & CAM_DEV_POS_PERIPH) 16468b8a9b1dSJustin T. Gibbs && (cdm->pos.cookie.periph != NULL)) 16478b8a9b1dSJustin T. Gibbs retval = DM_RET_DESCEND; 16488b8a9b1dSJustin T. Gibbs else 16498b8a9b1dSJustin T. Gibbs retval = xptdevicematch(cdm->patterns, cdm->num_patterns, 16508b8a9b1dSJustin T. Gibbs device); 16518b8a9b1dSJustin T. Gibbs 16528b8a9b1dSJustin T. Gibbs if ((retval & DM_RET_ACTION_MASK) == DM_RET_ERROR) { 16538b8a9b1dSJustin T. Gibbs cdm->status = CAM_DEV_MATCH_ERROR; 16548b8a9b1dSJustin T. Gibbs return(0); 16558b8a9b1dSJustin T. Gibbs } 16568b8a9b1dSJustin T. Gibbs 16578b8a9b1dSJustin T. Gibbs /* 16588b8a9b1dSJustin T. Gibbs * If the copy flag is set, copy this device out. 16598b8a9b1dSJustin T. Gibbs */ 16608b8a9b1dSJustin T. Gibbs if (retval & DM_RET_COPY) { 16618b8a9b1dSJustin T. Gibbs int spaceleft, j; 16628b8a9b1dSJustin T. Gibbs 16638b8a9b1dSJustin T. Gibbs spaceleft = cdm->match_buf_len - (cdm->num_matches * 16648b8a9b1dSJustin T. Gibbs sizeof(struct dev_match_result)); 16658b8a9b1dSJustin T. Gibbs 16668b8a9b1dSJustin T. Gibbs /* 16678b8a9b1dSJustin T. Gibbs * If we don't have enough space to put in another 16688b8a9b1dSJustin T. Gibbs * match result, save our position and tell the 16698b8a9b1dSJustin T. Gibbs * user there are more devices to check. 16708b8a9b1dSJustin T. Gibbs */ 16718b8a9b1dSJustin T. Gibbs if (spaceleft < sizeof(struct dev_match_result)) { 16728b8a9b1dSJustin T. Gibbs bzero(&cdm->pos, sizeof(cdm->pos)); 16738b8a9b1dSJustin T. Gibbs cdm->pos.position_type = 16748b8a9b1dSJustin T. Gibbs CAM_DEV_POS_EDT | CAM_DEV_POS_BUS | 16758b8a9b1dSJustin T. Gibbs CAM_DEV_POS_TARGET | CAM_DEV_POS_DEVICE; 16768b8a9b1dSJustin T. Gibbs 16778b8a9b1dSJustin T. Gibbs cdm->pos.cookie.bus = device->target->bus; 16788b8a9b1dSJustin T. Gibbs cdm->pos.generations[CAM_BUS_GENERATION]= 16792b83592fSScott Long xsoftc.bus_generation; 16808b8a9b1dSJustin T. Gibbs cdm->pos.cookie.target = device->target; 16818b8a9b1dSJustin T. Gibbs cdm->pos.generations[CAM_TARGET_GENERATION] = 16828b8a9b1dSJustin T. Gibbs device->target->bus->generation; 16838b8a9b1dSJustin T. Gibbs cdm->pos.cookie.device = device; 16848b8a9b1dSJustin T. Gibbs cdm->pos.generations[CAM_DEV_GENERATION] = 16858b8a9b1dSJustin T. Gibbs device->target->generation; 16868b8a9b1dSJustin T. Gibbs cdm->status = CAM_DEV_MATCH_MORE; 16878b8a9b1dSJustin T. Gibbs return(0); 16888b8a9b1dSJustin T. Gibbs } 16898b8a9b1dSJustin T. Gibbs j = cdm->num_matches; 16908b8a9b1dSJustin T. Gibbs cdm->num_matches++; 16918b8a9b1dSJustin T. Gibbs cdm->matches[j].type = DEV_MATCH_DEVICE; 16928b8a9b1dSJustin T. Gibbs cdm->matches[j].result.device_result.path_id = 16938b8a9b1dSJustin T. Gibbs device->target->bus->path_id; 16948b8a9b1dSJustin T. Gibbs cdm->matches[j].result.device_result.target_id = 16958b8a9b1dSJustin T. Gibbs device->target->target_id; 16968b8a9b1dSJustin T. Gibbs cdm->matches[j].result.device_result.target_lun = 16978b8a9b1dSJustin T. Gibbs device->lun_id; 169852c9ce25SScott Long cdm->matches[j].result.device_result.protocol = 169952c9ce25SScott Long device->protocol; 17008b8a9b1dSJustin T. Gibbs bcopy(&device->inq_data, 17018b8a9b1dSJustin T. Gibbs &cdm->matches[j].result.device_result.inq_data, 17028b8a9b1dSJustin T. Gibbs sizeof(struct scsi_inquiry_data)); 170352c9ce25SScott Long bcopy(&device->ident_data, 170452c9ce25SScott Long &cdm->matches[j].result.device_result.ident_data, 170552c9ce25SScott Long sizeof(struct ata_params)); 17069deea857SKenneth D. Merry 17079deea857SKenneth D. Merry /* Let the user know whether this device is unconfigured */ 17089deea857SKenneth D. Merry if (device->flags & CAM_DEV_UNCONFIGURED) 17099deea857SKenneth D. Merry cdm->matches[j].result.device_result.flags = 17109deea857SKenneth D. Merry DEV_RESULT_UNCONFIGURED; 17119deea857SKenneth D. Merry else 17129deea857SKenneth D. Merry cdm->matches[j].result.device_result.flags = 17139deea857SKenneth D. Merry DEV_RESULT_NOFLAG; 17148b8a9b1dSJustin T. Gibbs } 17158b8a9b1dSJustin T. Gibbs 17168b8a9b1dSJustin T. Gibbs /* 17178b8a9b1dSJustin T. Gibbs * If the user isn't interested in peripherals, don't descend 17188b8a9b1dSJustin T. Gibbs * the tree any further. 17198b8a9b1dSJustin T. Gibbs */ 17208b8a9b1dSJustin T. Gibbs if ((retval & DM_RET_ACTION_MASK) == DM_RET_STOP) 17218b8a9b1dSJustin T. Gibbs return(1); 17228b8a9b1dSJustin T. Gibbs 17238b8a9b1dSJustin T. Gibbs /* 17248b8a9b1dSJustin T. Gibbs * If there is a peripheral list generation recorded, make sure 17258b8a9b1dSJustin T. Gibbs * it hasn't changed. 17268b8a9b1dSJustin T. Gibbs */ 17278b8a9b1dSJustin T. Gibbs if ((cdm->pos.position_type & CAM_DEV_POS_BUS) 17288b8a9b1dSJustin T. Gibbs && (device->target->bus == cdm->pos.cookie.bus) 17298b8a9b1dSJustin T. Gibbs && (cdm->pos.position_type & CAM_DEV_POS_TARGET) 17308b8a9b1dSJustin T. Gibbs && (device->target == cdm->pos.cookie.target) 17318b8a9b1dSJustin T. Gibbs && (cdm->pos.position_type & CAM_DEV_POS_DEVICE) 17328b8a9b1dSJustin T. Gibbs && (device == cdm->pos.cookie.device) 17338b8a9b1dSJustin T. Gibbs && (cdm->pos.position_type & CAM_DEV_POS_PERIPH) 17348b8a9b1dSJustin T. Gibbs && (cdm->pos.generations[CAM_PERIPH_GENERATION] != 0) 17358b8a9b1dSJustin T. Gibbs && (cdm->pos.generations[CAM_PERIPH_GENERATION] != 17368b8a9b1dSJustin T. Gibbs device->generation)){ 17378b8a9b1dSJustin T. Gibbs cdm->status = CAM_DEV_MATCH_LIST_CHANGED; 17388b8a9b1dSJustin T. Gibbs return(0); 17398b8a9b1dSJustin T. Gibbs } 17408b8a9b1dSJustin T. Gibbs 17418b8a9b1dSJustin T. Gibbs if ((cdm->pos.position_type & CAM_DEV_POS_BUS) 17428b8a9b1dSJustin T. Gibbs && (cdm->pos.cookie.bus == device->target->bus) 17438b8a9b1dSJustin T. Gibbs && (cdm->pos.position_type & CAM_DEV_POS_TARGET) 17448b8a9b1dSJustin T. Gibbs && (cdm->pos.cookie.target == device->target) 17458b8a9b1dSJustin T. Gibbs && (cdm->pos.position_type & CAM_DEV_POS_DEVICE) 17468b8a9b1dSJustin T. Gibbs && (cdm->pos.cookie.device == device) 17478b8a9b1dSJustin T. Gibbs && (cdm->pos.position_type & CAM_DEV_POS_PERIPH) 17488b8a9b1dSJustin T. Gibbs && (cdm->pos.cookie.periph != NULL)) 17498b8a9b1dSJustin T. Gibbs return(xptperiphtraverse(device, 17508b8a9b1dSJustin T. Gibbs (struct cam_periph *)cdm->pos.cookie.periph, 17518b8a9b1dSJustin T. Gibbs xptedtperiphfunc, arg)); 17528b8a9b1dSJustin T. Gibbs else 17538b8a9b1dSJustin T. Gibbs return(xptperiphtraverse(device, NULL, xptedtperiphfunc, arg)); 17548b8a9b1dSJustin T. Gibbs } 17558b8a9b1dSJustin T. Gibbs 17568b8a9b1dSJustin T. Gibbs static int 17578b8a9b1dSJustin T. Gibbs xptedtperiphfunc(struct cam_periph *periph, void *arg) 17588b8a9b1dSJustin T. Gibbs { 17598b8a9b1dSJustin T. Gibbs struct ccb_dev_match *cdm; 17608b8a9b1dSJustin T. Gibbs dev_match_ret retval; 17618b8a9b1dSJustin T. Gibbs 17628b8a9b1dSJustin T. Gibbs cdm = (struct ccb_dev_match *)arg; 17638b8a9b1dSJustin T. Gibbs 17648b8a9b1dSJustin T. Gibbs retval = xptperiphmatch(cdm->patterns, cdm->num_patterns, periph); 17658b8a9b1dSJustin T. Gibbs 17668b8a9b1dSJustin T. Gibbs if ((retval & DM_RET_ACTION_MASK) == DM_RET_ERROR) { 17678b8a9b1dSJustin T. Gibbs cdm->status = CAM_DEV_MATCH_ERROR; 17688b8a9b1dSJustin T. Gibbs return(0); 17698b8a9b1dSJustin T. Gibbs } 17708b8a9b1dSJustin T. Gibbs 17718b8a9b1dSJustin T. Gibbs /* 17728b8a9b1dSJustin T. Gibbs * If the copy flag is set, copy this peripheral out. 17738b8a9b1dSJustin T. Gibbs */ 17748b8a9b1dSJustin T. Gibbs if (retval & DM_RET_COPY) { 17758b8a9b1dSJustin T. Gibbs int spaceleft, j; 17768b8a9b1dSJustin T. Gibbs 17778b8a9b1dSJustin T. Gibbs spaceleft = cdm->match_buf_len - (cdm->num_matches * 17788b8a9b1dSJustin T. Gibbs sizeof(struct dev_match_result)); 17798b8a9b1dSJustin T. Gibbs 17808b8a9b1dSJustin T. Gibbs /* 17818b8a9b1dSJustin T. Gibbs * If we don't have enough space to put in another 17828b8a9b1dSJustin T. Gibbs * match result, save our position and tell the 17838b8a9b1dSJustin T. Gibbs * user there are more devices to check. 17848b8a9b1dSJustin T. Gibbs */ 17858b8a9b1dSJustin T. Gibbs if (spaceleft < sizeof(struct dev_match_result)) { 17868b8a9b1dSJustin T. Gibbs bzero(&cdm->pos, sizeof(cdm->pos)); 17878b8a9b1dSJustin T. Gibbs cdm->pos.position_type = 17888b8a9b1dSJustin T. Gibbs CAM_DEV_POS_EDT | CAM_DEV_POS_BUS | 17898b8a9b1dSJustin T. Gibbs CAM_DEV_POS_TARGET | CAM_DEV_POS_DEVICE | 17908b8a9b1dSJustin T. Gibbs CAM_DEV_POS_PERIPH; 17918b8a9b1dSJustin T. Gibbs 17928b8a9b1dSJustin T. Gibbs cdm->pos.cookie.bus = periph->path->bus; 17938b8a9b1dSJustin T. Gibbs cdm->pos.generations[CAM_BUS_GENERATION]= 17942b83592fSScott Long xsoftc.bus_generation; 17958b8a9b1dSJustin T. Gibbs cdm->pos.cookie.target = periph->path->target; 17968b8a9b1dSJustin T. Gibbs cdm->pos.generations[CAM_TARGET_GENERATION] = 17978b8a9b1dSJustin T. Gibbs periph->path->bus->generation; 17988b8a9b1dSJustin T. Gibbs cdm->pos.cookie.device = periph->path->device; 17998b8a9b1dSJustin T. Gibbs cdm->pos.generations[CAM_DEV_GENERATION] = 18008b8a9b1dSJustin T. Gibbs periph->path->target->generation; 18018b8a9b1dSJustin T. Gibbs cdm->pos.cookie.periph = periph; 18028b8a9b1dSJustin T. Gibbs cdm->pos.generations[CAM_PERIPH_GENERATION] = 18038b8a9b1dSJustin T. Gibbs periph->path->device->generation; 18048b8a9b1dSJustin T. Gibbs cdm->status = CAM_DEV_MATCH_MORE; 18058b8a9b1dSJustin T. Gibbs return(0); 18068b8a9b1dSJustin T. Gibbs } 18078b8a9b1dSJustin T. Gibbs 18088b8a9b1dSJustin T. Gibbs j = cdm->num_matches; 18098b8a9b1dSJustin T. Gibbs cdm->num_matches++; 18108b8a9b1dSJustin T. Gibbs cdm->matches[j].type = DEV_MATCH_PERIPH; 18118b8a9b1dSJustin T. Gibbs cdm->matches[j].result.periph_result.path_id = 18128b8a9b1dSJustin T. Gibbs periph->path->bus->path_id; 18138b8a9b1dSJustin T. Gibbs cdm->matches[j].result.periph_result.target_id = 18148b8a9b1dSJustin T. Gibbs periph->path->target->target_id; 18158b8a9b1dSJustin T. Gibbs cdm->matches[j].result.periph_result.target_lun = 18168b8a9b1dSJustin T. Gibbs periph->path->device->lun_id; 18178b8a9b1dSJustin T. Gibbs cdm->matches[j].result.periph_result.unit_number = 18188b8a9b1dSJustin T. Gibbs periph->unit_number; 18198b8a9b1dSJustin T. Gibbs strncpy(cdm->matches[j].result.periph_result.periph_name, 18208b8a9b1dSJustin T. Gibbs periph->periph_name, DEV_IDLEN); 18218b8a9b1dSJustin T. Gibbs } 18228b8a9b1dSJustin T. Gibbs 18238b8a9b1dSJustin T. Gibbs return(1); 18248b8a9b1dSJustin T. Gibbs } 18258b8a9b1dSJustin T. Gibbs 18268b8a9b1dSJustin T. Gibbs static int 18278b8a9b1dSJustin T. Gibbs xptedtmatch(struct ccb_dev_match *cdm) 18288b8a9b1dSJustin T. Gibbs { 18298b8a9b1dSJustin T. Gibbs int ret; 18308b8a9b1dSJustin T. Gibbs 18318b8a9b1dSJustin T. Gibbs cdm->num_matches = 0; 18328b8a9b1dSJustin T. Gibbs 18338b8a9b1dSJustin T. Gibbs /* 18348b8a9b1dSJustin T. Gibbs * Check the bus list generation. If it has changed, the user 18358b8a9b1dSJustin T. Gibbs * needs to reset everything and start over. 18368b8a9b1dSJustin T. Gibbs */ 18378b8a9b1dSJustin T. Gibbs if ((cdm->pos.position_type & CAM_DEV_POS_BUS) 18388b8a9b1dSJustin T. Gibbs && (cdm->pos.generations[CAM_BUS_GENERATION] != 0) 18392b83592fSScott Long && (cdm->pos.generations[CAM_BUS_GENERATION] != xsoftc.bus_generation)) { 18408b8a9b1dSJustin T. Gibbs cdm->status = CAM_DEV_MATCH_LIST_CHANGED; 18418b8a9b1dSJustin T. Gibbs return(0); 18428b8a9b1dSJustin T. Gibbs } 18438b8a9b1dSJustin T. Gibbs 18448b8a9b1dSJustin T. Gibbs if ((cdm->pos.position_type & CAM_DEV_POS_BUS) 18458b8a9b1dSJustin T. Gibbs && (cdm->pos.cookie.bus != NULL)) 18468b8a9b1dSJustin T. Gibbs ret = xptbustraverse((struct cam_eb *)cdm->pos.cookie.bus, 18478b8a9b1dSJustin T. Gibbs xptedtbusfunc, cdm); 18488b8a9b1dSJustin T. Gibbs else 18498b8a9b1dSJustin T. Gibbs ret = xptbustraverse(NULL, xptedtbusfunc, cdm); 18508b8a9b1dSJustin T. Gibbs 18518b8a9b1dSJustin T. Gibbs /* 18528b8a9b1dSJustin T. Gibbs * If we get back 0, that means that we had to stop before fully 18538b8a9b1dSJustin T. Gibbs * traversing the EDT. It also means that one of the subroutines 18548b8a9b1dSJustin T. Gibbs * has set the status field to the proper value. If we get back 1, 18558b8a9b1dSJustin T. Gibbs * we've fully traversed the EDT and copied out any matching entries. 18568b8a9b1dSJustin T. Gibbs */ 18578b8a9b1dSJustin T. Gibbs if (ret == 1) 18588b8a9b1dSJustin T. Gibbs cdm->status = CAM_DEV_MATCH_LAST; 18598b8a9b1dSJustin T. Gibbs 18608b8a9b1dSJustin T. Gibbs return(ret); 18618b8a9b1dSJustin T. Gibbs } 18628b8a9b1dSJustin T. Gibbs 18638b8a9b1dSJustin T. Gibbs static int 18648b8a9b1dSJustin T. Gibbs xptplistpdrvfunc(struct periph_driver **pdrv, void *arg) 18658b8a9b1dSJustin T. Gibbs { 18668b8a9b1dSJustin T. Gibbs struct ccb_dev_match *cdm; 18678b8a9b1dSJustin T. Gibbs 18688b8a9b1dSJustin T. Gibbs cdm = (struct ccb_dev_match *)arg; 18698b8a9b1dSJustin T. Gibbs 18708b8a9b1dSJustin T. Gibbs if ((cdm->pos.position_type & CAM_DEV_POS_PDPTR) 18718b8a9b1dSJustin T. Gibbs && (cdm->pos.cookie.pdrv == pdrv) 18728b8a9b1dSJustin T. Gibbs && (cdm->pos.position_type & CAM_DEV_POS_PERIPH) 18738b8a9b1dSJustin T. Gibbs && (cdm->pos.generations[CAM_PERIPH_GENERATION] != 0) 18748b8a9b1dSJustin T. Gibbs && (cdm->pos.generations[CAM_PERIPH_GENERATION] != 18758b8a9b1dSJustin T. Gibbs (*pdrv)->generation)) { 18768b8a9b1dSJustin T. Gibbs cdm->status = CAM_DEV_MATCH_LIST_CHANGED; 18778b8a9b1dSJustin T. Gibbs return(0); 18788b8a9b1dSJustin T. Gibbs } 18798b8a9b1dSJustin T. Gibbs 18808b8a9b1dSJustin T. Gibbs if ((cdm->pos.position_type & CAM_DEV_POS_PDPTR) 18818b8a9b1dSJustin T. Gibbs && (cdm->pos.cookie.pdrv == pdrv) 18828b8a9b1dSJustin T. Gibbs && (cdm->pos.position_type & CAM_DEV_POS_PERIPH) 18838b8a9b1dSJustin T. Gibbs && (cdm->pos.cookie.periph != NULL)) 18848b8a9b1dSJustin T. Gibbs return(xptpdperiphtraverse(pdrv, 18858b8a9b1dSJustin T. Gibbs (struct cam_periph *)cdm->pos.cookie.periph, 18868b8a9b1dSJustin T. Gibbs xptplistperiphfunc, arg)); 18878b8a9b1dSJustin T. Gibbs else 18888b8a9b1dSJustin T. Gibbs return(xptpdperiphtraverse(pdrv, NULL,xptplistperiphfunc, arg)); 18898b8a9b1dSJustin T. Gibbs } 18908b8a9b1dSJustin T. Gibbs 18918b8a9b1dSJustin T. Gibbs static int 18928b8a9b1dSJustin T. Gibbs xptplistperiphfunc(struct cam_periph *periph, void *arg) 18938b8a9b1dSJustin T. Gibbs { 18948b8a9b1dSJustin T. Gibbs struct ccb_dev_match *cdm; 18958b8a9b1dSJustin T. Gibbs dev_match_ret retval; 18968b8a9b1dSJustin T. Gibbs 18978b8a9b1dSJustin T. Gibbs cdm = (struct ccb_dev_match *)arg; 18988b8a9b1dSJustin T. Gibbs 18998b8a9b1dSJustin T. Gibbs retval = xptperiphmatch(cdm->patterns, cdm->num_patterns, periph); 19008b8a9b1dSJustin T. Gibbs 19018b8a9b1dSJustin T. Gibbs if ((retval & DM_RET_ACTION_MASK) == DM_RET_ERROR) { 19028b8a9b1dSJustin T. Gibbs cdm->status = CAM_DEV_MATCH_ERROR; 19038b8a9b1dSJustin T. Gibbs return(0); 19048b8a9b1dSJustin T. Gibbs } 19058b8a9b1dSJustin T. Gibbs 19068b8a9b1dSJustin T. Gibbs /* 19078b8a9b1dSJustin T. Gibbs * If the copy flag is set, copy this peripheral out. 19088b8a9b1dSJustin T. Gibbs */ 19098b8a9b1dSJustin T. Gibbs if (retval & DM_RET_COPY) { 19108b8a9b1dSJustin T. Gibbs int spaceleft, j; 19118b8a9b1dSJustin T. Gibbs 19128b8a9b1dSJustin T. Gibbs spaceleft = cdm->match_buf_len - (cdm->num_matches * 19138b8a9b1dSJustin T. Gibbs sizeof(struct dev_match_result)); 19148b8a9b1dSJustin T. Gibbs 19158b8a9b1dSJustin T. Gibbs /* 19168b8a9b1dSJustin T. Gibbs * If we don't have enough space to put in another 19178b8a9b1dSJustin T. Gibbs * match result, save our position and tell the 19188b8a9b1dSJustin T. Gibbs * user there are more devices to check. 19198b8a9b1dSJustin T. Gibbs */ 19208b8a9b1dSJustin T. Gibbs if (spaceleft < sizeof(struct dev_match_result)) { 19218b8a9b1dSJustin T. Gibbs struct periph_driver **pdrv; 19228b8a9b1dSJustin T. Gibbs 19238b8a9b1dSJustin T. Gibbs pdrv = NULL; 19248b8a9b1dSJustin T. Gibbs bzero(&cdm->pos, sizeof(cdm->pos)); 19258b8a9b1dSJustin T. Gibbs cdm->pos.position_type = 19268b8a9b1dSJustin T. Gibbs CAM_DEV_POS_PDRV | CAM_DEV_POS_PDPTR | 19278b8a9b1dSJustin T. Gibbs CAM_DEV_POS_PERIPH; 19288b8a9b1dSJustin T. Gibbs 19298b8a9b1dSJustin T. Gibbs /* 19308b8a9b1dSJustin T. Gibbs * This may look a bit non-sensical, but it is 19318b8a9b1dSJustin T. Gibbs * actually quite logical. There are very few 19328b8a9b1dSJustin T. Gibbs * peripheral drivers, and bloating every peripheral 19338b8a9b1dSJustin T. Gibbs * structure with a pointer back to its parent 19348b8a9b1dSJustin T. Gibbs * peripheral driver linker set entry would cost 19358b8a9b1dSJustin T. Gibbs * more in the long run than doing this quick lookup. 19368b8a9b1dSJustin T. Gibbs */ 19370b7c27b9SPeter Wemm for (pdrv = periph_drivers; *pdrv != NULL; pdrv++) { 19388b8a9b1dSJustin T. Gibbs if (strcmp((*pdrv)->driver_name, 19398b8a9b1dSJustin T. Gibbs periph->periph_name) == 0) 19408b8a9b1dSJustin T. Gibbs break; 19418b8a9b1dSJustin T. Gibbs } 19428b8a9b1dSJustin T. Gibbs 194301910babSScott Long if (*pdrv == NULL) { 19448b8a9b1dSJustin T. Gibbs cdm->status = CAM_DEV_MATCH_ERROR; 19458b8a9b1dSJustin T. Gibbs return(0); 19468b8a9b1dSJustin T. Gibbs } 19478b8a9b1dSJustin T. Gibbs 19488b8a9b1dSJustin T. Gibbs cdm->pos.cookie.pdrv = pdrv; 19498b8a9b1dSJustin T. Gibbs /* 19508b8a9b1dSJustin T. Gibbs * The periph generation slot does double duty, as 19518b8a9b1dSJustin T. Gibbs * does the periph pointer slot. They are used for 19528b8a9b1dSJustin T. Gibbs * both edt and pdrv lookups and positioning. 19538b8a9b1dSJustin T. Gibbs */ 19548b8a9b1dSJustin T. Gibbs cdm->pos.cookie.periph = periph; 19558b8a9b1dSJustin T. Gibbs cdm->pos.generations[CAM_PERIPH_GENERATION] = 19568b8a9b1dSJustin T. Gibbs (*pdrv)->generation; 19578b8a9b1dSJustin T. Gibbs cdm->status = CAM_DEV_MATCH_MORE; 19588b8a9b1dSJustin T. Gibbs return(0); 19598b8a9b1dSJustin T. Gibbs } 19608b8a9b1dSJustin T. Gibbs 19618b8a9b1dSJustin T. Gibbs j = cdm->num_matches; 19628b8a9b1dSJustin T. Gibbs cdm->num_matches++; 19638b8a9b1dSJustin T. Gibbs cdm->matches[j].type = DEV_MATCH_PERIPH; 19648b8a9b1dSJustin T. Gibbs cdm->matches[j].result.periph_result.path_id = 19658b8a9b1dSJustin T. Gibbs periph->path->bus->path_id; 19668b8a9b1dSJustin T. Gibbs 19678b8a9b1dSJustin T. Gibbs /* 19688b8a9b1dSJustin T. Gibbs * The transport layer peripheral doesn't have a target or 19698b8a9b1dSJustin T. Gibbs * lun. 19708b8a9b1dSJustin T. Gibbs */ 19718b8a9b1dSJustin T. Gibbs if (periph->path->target) 19728b8a9b1dSJustin T. Gibbs cdm->matches[j].result.periph_result.target_id = 19738b8a9b1dSJustin T. Gibbs periph->path->target->target_id; 19748b8a9b1dSJustin T. Gibbs else 19758b8a9b1dSJustin T. Gibbs cdm->matches[j].result.periph_result.target_id = -1; 19768b8a9b1dSJustin T. Gibbs 19778b8a9b1dSJustin T. Gibbs if (periph->path->device) 19788b8a9b1dSJustin T. Gibbs cdm->matches[j].result.periph_result.target_lun = 19798b8a9b1dSJustin T. Gibbs periph->path->device->lun_id; 19808b8a9b1dSJustin T. Gibbs else 19818b8a9b1dSJustin T. Gibbs cdm->matches[j].result.periph_result.target_lun = -1; 19828b8a9b1dSJustin T. Gibbs 19838b8a9b1dSJustin T. Gibbs cdm->matches[j].result.periph_result.unit_number = 19848b8a9b1dSJustin T. Gibbs periph->unit_number; 19858b8a9b1dSJustin T. Gibbs strncpy(cdm->matches[j].result.periph_result.periph_name, 19868b8a9b1dSJustin T. Gibbs periph->periph_name, DEV_IDLEN); 19878b8a9b1dSJustin T. Gibbs } 19888b8a9b1dSJustin T. Gibbs 19898b8a9b1dSJustin T. Gibbs return(1); 19908b8a9b1dSJustin T. Gibbs } 19918b8a9b1dSJustin T. Gibbs 19928b8a9b1dSJustin T. Gibbs static int 19938b8a9b1dSJustin T. Gibbs xptperiphlistmatch(struct ccb_dev_match *cdm) 19948b8a9b1dSJustin T. Gibbs { 19958b8a9b1dSJustin T. Gibbs int ret; 19968b8a9b1dSJustin T. Gibbs 19978b8a9b1dSJustin T. Gibbs cdm->num_matches = 0; 19988b8a9b1dSJustin T. Gibbs 19998b8a9b1dSJustin T. Gibbs /* 20008b8a9b1dSJustin T. Gibbs * At this point in the edt traversal function, we check the bus 20018b8a9b1dSJustin T. Gibbs * list generation to make sure that no busses have been added or 20028b8a9b1dSJustin T. Gibbs * removed since the user last sent a XPT_DEV_MATCH ccb through. 20038b8a9b1dSJustin T. Gibbs * For the peripheral driver list traversal function, however, we 20048b8a9b1dSJustin T. Gibbs * don't have to worry about new peripheral driver types coming or 20058b8a9b1dSJustin T. Gibbs * going; they're in a linker set, and therefore can't change 20068b8a9b1dSJustin T. Gibbs * without a recompile. 20078b8a9b1dSJustin T. Gibbs */ 20088b8a9b1dSJustin T. Gibbs 20098b8a9b1dSJustin T. Gibbs if ((cdm->pos.position_type & CAM_DEV_POS_PDPTR) 20108b8a9b1dSJustin T. Gibbs && (cdm->pos.cookie.pdrv != NULL)) 20118b8a9b1dSJustin T. Gibbs ret = xptpdrvtraverse( 20128b8a9b1dSJustin T. Gibbs (struct periph_driver **)cdm->pos.cookie.pdrv, 20138b8a9b1dSJustin T. Gibbs xptplistpdrvfunc, cdm); 20148b8a9b1dSJustin T. Gibbs else 20158b8a9b1dSJustin T. Gibbs ret = xptpdrvtraverse(NULL, xptplistpdrvfunc, cdm); 20168b8a9b1dSJustin T. Gibbs 20178b8a9b1dSJustin T. Gibbs /* 20188b8a9b1dSJustin T. Gibbs * If we get back 0, that means that we had to stop before fully 20198b8a9b1dSJustin T. Gibbs * traversing the peripheral driver tree. It also means that one of 20208b8a9b1dSJustin T. Gibbs * the subroutines has set the status field to the proper value. If 20218b8a9b1dSJustin T. Gibbs * we get back 1, we've fully traversed the EDT and copied out any 20228b8a9b1dSJustin T. Gibbs * matching entries. 20238b8a9b1dSJustin T. Gibbs */ 20248b8a9b1dSJustin T. Gibbs if (ret == 1) 20258b8a9b1dSJustin T. Gibbs cdm->status = CAM_DEV_MATCH_LAST; 20268b8a9b1dSJustin T. Gibbs 20278b8a9b1dSJustin T. Gibbs return(ret); 20288b8a9b1dSJustin T. Gibbs } 20298b8a9b1dSJustin T. Gibbs 20308b8a9b1dSJustin T. Gibbs static int 20318b8a9b1dSJustin T. Gibbs xptbustraverse(struct cam_eb *start_bus, xpt_busfunc_t *tr_func, void *arg) 20328b8a9b1dSJustin T. Gibbs { 20338b8a9b1dSJustin T. Gibbs struct cam_eb *bus, *next_bus; 20348b8a9b1dSJustin T. Gibbs int retval; 20358b8a9b1dSJustin T. Gibbs 20368b8a9b1dSJustin T. Gibbs retval = 1; 20378b8a9b1dSJustin T. Gibbs 20389a7c2696SAlexander Motin xpt_lock_buses(); 20392b83592fSScott Long for (bus = (start_bus ? start_bus : TAILQ_FIRST(&xsoftc.xpt_busses)); 20408b8a9b1dSJustin T. Gibbs bus != NULL; 20418b8a9b1dSJustin T. Gibbs bus = next_bus) { 20428b8a9b1dSJustin T. Gibbs 20438900f4b8SKenneth D. Merry bus->refcount++; 20448900f4b8SKenneth D. Merry 20458900f4b8SKenneth D. Merry /* 20468900f4b8SKenneth D. Merry * XXX The locking here is obviously very complex. We 20478900f4b8SKenneth D. Merry * should work to simplify it. 20488900f4b8SKenneth D. Merry */ 20499a7c2696SAlexander Motin xpt_unlock_buses(); 205011e4faceSScott Long CAM_SIM_LOCK(bus->sim); 20518b8a9b1dSJustin T. Gibbs retval = tr_func(bus, arg); 205211e4faceSScott Long CAM_SIM_UNLOCK(bus->sim); 20538900f4b8SKenneth D. Merry 20549a7c2696SAlexander Motin xpt_lock_buses(); 20558900f4b8SKenneth D. Merry next_bus = TAILQ_NEXT(bus, links); 20569a7c2696SAlexander Motin xpt_unlock_buses(); 20578900f4b8SKenneth D. Merry 20588900f4b8SKenneth D. Merry xpt_release_bus(bus); 20598900f4b8SKenneth D. Merry 20608b8a9b1dSJustin T. Gibbs if (retval == 0) 20618b8a9b1dSJustin T. Gibbs return(retval); 20629a7c2696SAlexander Motin xpt_lock_buses(); 20638b8a9b1dSJustin T. Gibbs } 20649a7c2696SAlexander Motin xpt_unlock_buses(); 20658b8a9b1dSJustin T. Gibbs 20668b8a9b1dSJustin T. Gibbs return(retval); 20678b8a9b1dSJustin T. Gibbs } 20688b8a9b1dSJustin T. Gibbs 20698b8a9b1dSJustin T. Gibbs static int 20708b8a9b1dSJustin T. Gibbs xpttargettraverse(struct cam_eb *bus, struct cam_et *start_target, 20718b8a9b1dSJustin T. Gibbs xpt_targetfunc_t *tr_func, void *arg) 20728b8a9b1dSJustin T. Gibbs { 20738b8a9b1dSJustin T. Gibbs struct cam_et *target, *next_target; 20748b8a9b1dSJustin T. Gibbs int retval; 20758b8a9b1dSJustin T. Gibbs 2076dcdf6e74SAlexander Motin mtx_assert(bus->sim->mtx, MA_OWNED); 20778b8a9b1dSJustin T. Gibbs retval = 1; 20788b8a9b1dSJustin T. Gibbs for (target = (start_target ? start_target : 20798b8a9b1dSJustin T. Gibbs TAILQ_FIRST(&bus->et_entries)); 20808b8a9b1dSJustin T. Gibbs target != NULL; target = next_target) { 20818b8a9b1dSJustin T. Gibbs 20828900f4b8SKenneth D. Merry target->refcount++; 20838b8a9b1dSJustin T. Gibbs 20848b8a9b1dSJustin T. Gibbs retval = tr_func(target, arg); 20858b8a9b1dSJustin T. Gibbs 20868900f4b8SKenneth D. Merry next_target = TAILQ_NEXT(target, links); 20878900f4b8SKenneth D. Merry 20888900f4b8SKenneth D. Merry xpt_release_target(target); 20898900f4b8SKenneth D. Merry 20908b8a9b1dSJustin T. Gibbs if (retval == 0) 20918b8a9b1dSJustin T. Gibbs return(retval); 20928b8a9b1dSJustin T. Gibbs } 20938b8a9b1dSJustin T. Gibbs 20948b8a9b1dSJustin T. Gibbs return(retval); 20958b8a9b1dSJustin T. Gibbs } 20968b8a9b1dSJustin T. Gibbs 20978b8a9b1dSJustin T. Gibbs static int 20988b8a9b1dSJustin T. Gibbs xptdevicetraverse(struct cam_et *target, struct cam_ed *start_device, 20998b8a9b1dSJustin T. Gibbs xpt_devicefunc_t *tr_func, void *arg) 21008b8a9b1dSJustin T. Gibbs { 21018b8a9b1dSJustin T. Gibbs struct cam_ed *device, *next_device; 21028b8a9b1dSJustin T. Gibbs int retval; 21038b8a9b1dSJustin T. Gibbs 2104dcdf6e74SAlexander Motin mtx_assert(target->bus->sim->mtx, MA_OWNED); 21058b8a9b1dSJustin T. Gibbs retval = 1; 21068b8a9b1dSJustin T. Gibbs for (device = (start_device ? start_device : 21078b8a9b1dSJustin T. Gibbs TAILQ_FIRST(&target->ed_entries)); 21088b8a9b1dSJustin T. Gibbs device != NULL; 21098b8a9b1dSJustin T. Gibbs device = next_device) { 21108b8a9b1dSJustin T. Gibbs 21118900f4b8SKenneth D. Merry /* 21128900f4b8SKenneth D. Merry * Hold a reference so the current device does not go away 21138900f4b8SKenneth D. Merry * on us. 21148900f4b8SKenneth D. Merry */ 21158900f4b8SKenneth D. Merry device->refcount++; 21168b8a9b1dSJustin T. Gibbs 21178b8a9b1dSJustin T. Gibbs retval = tr_func(device, arg); 21188b8a9b1dSJustin T. Gibbs 21198900f4b8SKenneth D. Merry /* 21208900f4b8SKenneth D. Merry * Grab our next pointer before we release the current 21218900f4b8SKenneth D. Merry * device. 21228900f4b8SKenneth D. Merry */ 21238900f4b8SKenneth D. Merry next_device = TAILQ_NEXT(device, links); 21248900f4b8SKenneth D. Merry 21258900f4b8SKenneth D. Merry xpt_release_device(device); 21268900f4b8SKenneth D. Merry 21278b8a9b1dSJustin T. Gibbs if (retval == 0) 21288b8a9b1dSJustin T. Gibbs return(retval); 21298b8a9b1dSJustin T. Gibbs } 21308b8a9b1dSJustin T. Gibbs 21318b8a9b1dSJustin T. Gibbs return(retval); 21328b8a9b1dSJustin T. Gibbs } 21338b8a9b1dSJustin T. Gibbs 21348b8a9b1dSJustin T. Gibbs static int 21358b8a9b1dSJustin T. Gibbs xptperiphtraverse(struct cam_ed *device, struct cam_periph *start_periph, 21368b8a9b1dSJustin T. Gibbs xpt_periphfunc_t *tr_func, void *arg) 21378b8a9b1dSJustin T. Gibbs { 21388b8a9b1dSJustin T. Gibbs struct cam_periph *periph, *next_periph; 21398b8a9b1dSJustin T. Gibbs int retval; 21408b8a9b1dSJustin T. Gibbs 21418b8a9b1dSJustin T. Gibbs retval = 1; 21428b8a9b1dSJustin T. Gibbs 2143dcdf6e74SAlexander Motin mtx_assert(device->sim->mtx, MA_OWNED); 21448900f4b8SKenneth D. Merry xpt_lock_buses(); 21458b8a9b1dSJustin T. Gibbs for (periph = (start_periph ? start_periph : 21468b8a9b1dSJustin T. Gibbs SLIST_FIRST(&device->periphs)); 21478b8a9b1dSJustin T. Gibbs periph != NULL; 21488b8a9b1dSJustin T. Gibbs periph = next_periph) { 21498b8a9b1dSJustin T. Gibbs 21508900f4b8SKenneth D. Merry 21518900f4b8SKenneth D. Merry /* 21528900f4b8SKenneth D. Merry * In this case, we want to show peripherals that have been 21538900f4b8SKenneth D. Merry * invalidated, but not peripherals that are scheduled to 21548900f4b8SKenneth D. Merry * be freed. So instead of calling cam_periph_acquire(), 21558900f4b8SKenneth D. Merry * which will fail if the periph has been invalidated, we 215633a38f74SKenneth D. Merry * just check for the free flag here. If it is in the 215733a38f74SKenneth D. Merry * process of being freed, we skip to the next periph. 21588900f4b8SKenneth D. Merry */ 21598900f4b8SKenneth D. Merry if (periph->flags & CAM_PERIPH_FREE) { 21608b8a9b1dSJustin T. Gibbs next_periph = SLIST_NEXT(periph, periph_links); 21618900f4b8SKenneth D. Merry continue; 21628900f4b8SKenneth D. Merry } 21638900f4b8SKenneth D. Merry 21648900f4b8SKenneth D. Merry /* 21658900f4b8SKenneth D. Merry * Acquire a reference to this periph while we call the 21668900f4b8SKenneth D. Merry * traversal function, so it can't go away. 21678900f4b8SKenneth D. Merry */ 21688900f4b8SKenneth D. Merry periph->refcount++; 21698900f4b8SKenneth D. Merry 21708b8a9b1dSJustin T. Gibbs retval = tr_func(periph, arg); 21718900f4b8SKenneth D. Merry 21728900f4b8SKenneth D. Merry /* 21738900f4b8SKenneth D. Merry * Grab the next peripheral before we release this one, so 21748900f4b8SKenneth D. Merry * our next pointer is still valid. 21758900f4b8SKenneth D. Merry */ 21768900f4b8SKenneth D. Merry next_periph = SLIST_NEXT(periph, periph_links); 21778900f4b8SKenneth D. Merry 21788900f4b8SKenneth D. Merry cam_periph_release_locked_buses(periph); 21798900f4b8SKenneth D. Merry 21808b8a9b1dSJustin T. Gibbs if (retval == 0) 21818900f4b8SKenneth D. Merry goto bailout_done; 21828b8a9b1dSJustin T. Gibbs } 21838b8a9b1dSJustin T. Gibbs 21848900f4b8SKenneth D. Merry bailout_done: 21858900f4b8SKenneth D. Merry 21868900f4b8SKenneth D. Merry xpt_unlock_buses(); 21878900f4b8SKenneth D. Merry 21888b8a9b1dSJustin T. Gibbs return(retval); 21898b8a9b1dSJustin T. Gibbs } 21908b8a9b1dSJustin T. Gibbs 21918b8a9b1dSJustin T. Gibbs static int 21928b8a9b1dSJustin T. Gibbs xptpdrvtraverse(struct periph_driver **start_pdrv, 21938b8a9b1dSJustin T. Gibbs xpt_pdrvfunc_t *tr_func, void *arg) 21948b8a9b1dSJustin T. Gibbs { 21958b8a9b1dSJustin T. Gibbs struct periph_driver **pdrv; 21968b8a9b1dSJustin T. Gibbs int retval; 21978b8a9b1dSJustin T. Gibbs 21988b8a9b1dSJustin T. Gibbs retval = 1; 21998b8a9b1dSJustin T. Gibbs 22008b8a9b1dSJustin T. Gibbs /* 22018b8a9b1dSJustin T. Gibbs * We don't traverse the peripheral driver list like we do the 22028b8a9b1dSJustin T. Gibbs * other lists, because it is a linker set, and therefore cannot be 22038b8a9b1dSJustin T. Gibbs * changed during runtime. If the peripheral driver list is ever 22048b8a9b1dSJustin T. Gibbs * re-done to be something other than a linker set (i.e. it can 22058b8a9b1dSJustin T. Gibbs * change while the system is running), the list traversal should 22068b8a9b1dSJustin T. Gibbs * be modified to work like the other traversal functions. 22078b8a9b1dSJustin T. Gibbs */ 22080b7c27b9SPeter Wemm for (pdrv = (start_pdrv ? start_pdrv : periph_drivers); 22098b8a9b1dSJustin T. Gibbs *pdrv != NULL; pdrv++) { 22108b8a9b1dSJustin T. Gibbs retval = tr_func(pdrv, arg); 22118b8a9b1dSJustin T. Gibbs 22128b8a9b1dSJustin T. Gibbs if (retval == 0) 22138b8a9b1dSJustin T. Gibbs return(retval); 22148b8a9b1dSJustin T. Gibbs } 22158b8a9b1dSJustin T. Gibbs 22168b8a9b1dSJustin T. Gibbs return(retval); 22178b8a9b1dSJustin T. Gibbs } 22188b8a9b1dSJustin T. Gibbs 22198b8a9b1dSJustin T. Gibbs static int 22208b8a9b1dSJustin T. Gibbs xptpdperiphtraverse(struct periph_driver **pdrv, 22218b8a9b1dSJustin T. Gibbs struct cam_periph *start_periph, 22228b8a9b1dSJustin T. Gibbs xpt_periphfunc_t *tr_func, void *arg) 22238b8a9b1dSJustin T. Gibbs { 22248b8a9b1dSJustin T. Gibbs struct cam_periph *periph, *next_periph; 2225dcdf6e74SAlexander Motin struct cam_sim *sim; 22268b8a9b1dSJustin T. Gibbs int retval; 22278b8a9b1dSJustin T. Gibbs 22288b8a9b1dSJustin T. Gibbs retval = 1; 22298b8a9b1dSJustin T. Gibbs 2230f1e2546aSMatt Jacob xpt_lock_buses(); 22318b8a9b1dSJustin T. Gibbs for (periph = (start_periph ? start_periph : 22328b8a9b1dSJustin T. Gibbs TAILQ_FIRST(&(*pdrv)->units)); periph != NULL; 22338b8a9b1dSJustin T. Gibbs periph = next_periph) { 22348b8a9b1dSJustin T. Gibbs 22358900f4b8SKenneth D. Merry 22368900f4b8SKenneth D. Merry /* 22378900f4b8SKenneth D. Merry * In this case, we want to show peripherals that have been 22388900f4b8SKenneth D. Merry * invalidated, but not peripherals that are scheduled to 22398900f4b8SKenneth D. Merry * be freed. So instead of calling cam_periph_acquire(), 22408900f4b8SKenneth D. Merry * which will fail if the periph has been invalidated, we 22418900f4b8SKenneth D. Merry * just check for the free flag here. If it is free, we 22428900f4b8SKenneth D. Merry * skip to the next periph. 22438900f4b8SKenneth D. Merry */ 22448900f4b8SKenneth D. Merry if (periph->flags & CAM_PERIPH_FREE) { 22458900f4b8SKenneth D. Merry next_periph = TAILQ_NEXT(periph, unit_links); 22468900f4b8SKenneth D. Merry continue; 22478900f4b8SKenneth D. Merry } 22488900f4b8SKenneth D. Merry 22498900f4b8SKenneth D. Merry /* 22508900f4b8SKenneth D. Merry * Acquire a reference to this periph while we call the 22518900f4b8SKenneth D. Merry * traversal function, so it can't go away. 22528900f4b8SKenneth D. Merry */ 22538900f4b8SKenneth D. Merry periph->refcount++; 2254dcdf6e74SAlexander Motin sim = periph->sim; 2255dcdf6e74SAlexander Motin xpt_unlock_buses(); 2256dcdf6e74SAlexander Motin CAM_SIM_LOCK(sim); 2257dcdf6e74SAlexander Motin xpt_lock_buses(); 22588900f4b8SKenneth D. Merry retval = tr_func(periph, arg); 22598900f4b8SKenneth D. Merry 22608900f4b8SKenneth D. Merry /* 22618900f4b8SKenneth D. Merry * Grab the next peripheral before we release this one, so 22628900f4b8SKenneth D. Merry * our next pointer is still valid. 22638900f4b8SKenneth D. Merry */ 22648b8a9b1dSJustin T. Gibbs next_periph = TAILQ_NEXT(periph, unit_links); 22658b8a9b1dSJustin T. Gibbs 22668900f4b8SKenneth D. Merry cam_periph_release_locked_buses(periph); 2267dcdf6e74SAlexander Motin CAM_SIM_UNLOCK(sim); 22688900f4b8SKenneth D. Merry 22698900f4b8SKenneth D. Merry if (retval == 0) 22708900f4b8SKenneth D. Merry goto bailout_done; 22718b8a9b1dSJustin T. Gibbs } 22728900f4b8SKenneth D. Merry bailout_done: 22738900f4b8SKenneth D. Merry 2274f1e2546aSMatt Jacob xpt_unlock_buses(); 22758900f4b8SKenneth D. Merry 22768b8a9b1dSJustin T. Gibbs return(retval); 22778b8a9b1dSJustin T. Gibbs } 22788b8a9b1dSJustin T. Gibbs 22798b8a9b1dSJustin T. Gibbs static int 22808b8a9b1dSJustin T. Gibbs xptdefbusfunc(struct cam_eb *bus, void *arg) 22818b8a9b1dSJustin T. Gibbs { 22828b8a9b1dSJustin T. Gibbs struct xpt_traverse_config *tr_config; 22838b8a9b1dSJustin T. Gibbs 22848b8a9b1dSJustin T. Gibbs tr_config = (struct xpt_traverse_config *)arg; 22858b8a9b1dSJustin T. Gibbs 22868b8a9b1dSJustin T. Gibbs if (tr_config->depth == XPT_DEPTH_BUS) { 22878b8a9b1dSJustin T. Gibbs xpt_busfunc_t *tr_func; 22888b8a9b1dSJustin T. Gibbs 22898b8a9b1dSJustin T. Gibbs tr_func = (xpt_busfunc_t *)tr_config->tr_func; 22908b8a9b1dSJustin T. Gibbs 22918b8a9b1dSJustin T. Gibbs return(tr_func(bus, tr_config->tr_arg)); 22928b8a9b1dSJustin T. Gibbs } else 22938b8a9b1dSJustin T. Gibbs return(xpttargettraverse(bus, NULL, xptdeftargetfunc, arg)); 22948b8a9b1dSJustin T. Gibbs } 22958b8a9b1dSJustin T. Gibbs 22968b8a9b1dSJustin T. Gibbs static int 22978b8a9b1dSJustin T. Gibbs xptdeftargetfunc(struct cam_et *target, void *arg) 22988b8a9b1dSJustin T. Gibbs { 22998b8a9b1dSJustin T. Gibbs struct xpt_traverse_config *tr_config; 23008b8a9b1dSJustin T. Gibbs 23018b8a9b1dSJustin T. Gibbs tr_config = (struct xpt_traverse_config *)arg; 23028b8a9b1dSJustin T. Gibbs 23038b8a9b1dSJustin T. Gibbs if (tr_config->depth == XPT_DEPTH_TARGET) { 23048b8a9b1dSJustin T. Gibbs xpt_targetfunc_t *tr_func; 23058b8a9b1dSJustin T. Gibbs 23068b8a9b1dSJustin T. Gibbs tr_func = (xpt_targetfunc_t *)tr_config->tr_func; 23078b8a9b1dSJustin T. Gibbs 23088b8a9b1dSJustin T. Gibbs return(tr_func(target, tr_config->tr_arg)); 23098b8a9b1dSJustin T. Gibbs } else 23108b8a9b1dSJustin T. Gibbs return(xptdevicetraverse(target, NULL, xptdefdevicefunc, arg)); 23118b8a9b1dSJustin T. Gibbs } 23128b8a9b1dSJustin T. Gibbs 23138b8a9b1dSJustin T. Gibbs static int 23148b8a9b1dSJustin T. Gibbs xptdefdevicefunc(struct cam_ed *device, void *arg) 23158b8a9b1dSJustin T. Gibbs { 23168b8a9b1dSJustin T. Gibbs struct xpt_traverse_config *tr_config; 23178b8a9b1dSJustin T. Gibbs 23188b8a9b1dSJustin T. Gibbs tr_config = (struct xpt_traverse_config *)arg; 23198b8a9b1dSJustin T. Gibbs 23208b8a9b1dSJustin T. Gibbs if (tr_config->depth == XPT_DEPTH_DEVICE) { 23218b8a9b1dSJustin T. Gibbs xpt_devicefunc_t *tr_func; 23228b8a9b1dSJustin T. Gibbs 23238b8a9b1dSJustin T. Gibbs tr_func = (xpt_devicefunc_t *)tr_config->tr_func; 23248b8a9b1dSJustin T. Gibbs 23258b8a9b1dSJustin T. Gibbs return(tr_func(device, tr_config->tr_arg)); 23268b8a9b1dSJustin T. Gibbs } else 23278b8a9b1dSJustin T. Gibbs return(xptperiphtraverse(device, NULL, xptdefperiphfunc, arg)); 23288b8a9b1dSJustin T. Gibbs } 23298b8a9b1dSJustin T. Gibbs 23308b8a9b1dSJustin T. Gibbs static int 23318b8a9b1dSJustin T. Gibbs xptdefperiphfunc(struct cam_periph *periph, void *arg) 23328b8a9b1dSJustin T. Gibbs { 23338b8a9b1dSJustin T. Gibbs struct xpt_traverse_config *tr_config; 23348b8a9b1dSJustin T. Gibbs xpt_periphfunc_t *tr_func; 23358b8a9b1dSJustin T. Gibbs 23368b8a9b1dSJustin T. Gibbs tr_config = (struct xpt_traverse_config *)arg; 23378b8a9b1dSJustin T. Gibbs 23388b8a9b1dSJustin T. Gibbs tr_func = (xpt_periphfunc_t *)tr_config->tr_func; 23398b8a9b1dSJustin T. Gibbs 23408b8a9b1dSJustin T. Gibbs /* 23418b8a9b1dSJustin T. Gibbs * Unlike the other default functions, we don't check for depth 23428b8a9b1dSJustin T. Gibbs * here. The peripheral driver level is the last level in the EDT, 23438b8a9b1dSJustin T. Gibbs * so if we're here, we should execute the function in question. 23448b8a9b1dSJustin T. Gibbs */ 23458b8a9b1dSJustin T. Gibbs return(tr_func(periph, tr_config->tr_arg)); 23468b8a9b1dSJustin T. Gibbs } 23478b8a9b1dSJustin T. Gibbs 23488b8a9b1dSJustin T. Gibbs /* 23498b8a9b1dSJustin T. Gibbs * Execute the given function for every bus in the EDT. 23508b8a9b1dSJustin T. Gibbs */ 23518b8a9b1dSJustin T. Gibbs static int 23528b8a9b1dSJustin T. Gibbs xpt_for_all_busses(xpt_busfunc_t *tr_func, void *arg) 23538b8a9b1dSJustin T. Gibbs { 23548b8a9b1dSJustin T. Gibbs struct xpt_traverse_config tr_config; 23558b8a9b1dSJustin T. Gibbs 23568b8a9b1dSJustin T. Gibbs tr_config.depth = XPT_DEPTH_BUS; 23578b8a9b1dSJustin T. Gibbs tr_config.tr_func = tr_func; 23588b8a9b1dSJustin T. Gibbs tr_config.tr_arg = arg; 23598b8a9b1dSJustin T. Gibbs 23608b8a9b1dSJustin T. Gibbs return(xptbustraverse(NULL, xptdefbusfunc, &tr_config)); 23618b8a9b1dSJustin T. Gibbs } 23628b8a9b1dSJustin T. Gibbs 23638b8a9b1dSJustin T. Gibbs /* 23648b8a9b1dSJustin T. Gibbs * Execute the given function for every device in the EDT. 23658b8a9b1dSJustin T. Gibbs */ 23668b8a9b1dSJustin T. Gibbs static int 23678b8a9b1dSJustin T. Gibbs xpt_for_all_devices(xpt_devicefunc_t *tr_func, void *arg) 23688b8a9b1dSJustin T. Gibbs { 23698b8a9b1dSJustin T. Gibbs struct xpt_traverse_config tr_config; 23708b8a9b1dSJustin T. Gibbs 23718b8a9b1dSJustin T. Gibbs tr_config.depth = XPT_DEPTH_DEVICE; 23728b8a9b1dSJustin T. Gibbs tr_config.tr_func = tr_func; 23738b8a9b1dSJustin T. Gibbs tr_config.tr_arg = arg; 23748b8a9b1dSJustin T. Gibbs 23758b8a9b1dSJustin T. Gibbs return(xptbustraverse(NULL, xptdefbusfunc, &tr_config)); 23768b8a9b1dSJustin T. Gibbs } 23778b8a9b1dSJustin T. Gibbs 23788b8a9b1dSJustin T. Gibbs static int 23798b8a9b1dSJustin T. Gibbs xptsetasyncfunc(struct cam_ed *device, void *arg) 23808b8a9b1dSJustin T. Gibbs { 23818b8a9b1dSJustin T. Gibbs struct cam_path path; 23828b8a9b1dSJustin T. Gibbs struct ccb_getdev cgd; 23837685edecSAlexander Motin struct ccb_setasync *csa = (struct ccb_setasync *)arg; 23848b8a9b1dSJustin T. Gibbs 2385c8bead2aSJustin T. Gibbs /* 2386c8bead2aSJustin T. Gibbs * Don't report unconfigured devices (Wildcard devs, 2387c8bead2aSJustin T. Gibbs * devices only for target mode, device instances 2388c8bead2aSJustin T. Gibbs * that have been invalidated but are waiting for 2389c8bead2aSJustin T. Gibbs * their last reference count to be released). 2390c8bead2aSJustin T. Gibbs */ 2391c8bead2aSJustin T. Gibbs if ((device->flags & CAM_DEV_UNCONFIGURED) != 0) 2392c8bead2aSJustin T. Gibbs return (1); 2393c8bead2aSJustin T. Gibbs 23948b8a9b1dSJustin T. Gibbs xpt_compile_path(&path, 23958b8a9b1dSJustin T. Gibbs NULL, 23968b8a9b1dSJustin T. Gibbs device->target->bus->path_id, 23978b8a9b1dSJustin T. Gibbs device->target->target_id, 23988b8a9b1dSJustin T. Gibbs device->lun_id); 2399bbfa4aa1SAlexander Motin xpt_setup_ccb(&cgd.ccb_h, &path, CAM_PRIORITY_NORMAL); 24008b8a9b1dSJustin T. Gibbs cgd.ccb_h.func_code = XPT_GDEV_TYPE; 24018b8a9b1dSJustin T. Gibbs xpt_action((union ccb *)&cgd); 24027685edecSAlexander Motin csa->callback(csa->callback_arg, 24038b8a9b1dSJustin T. Gibbs AC_FOUND_DEVICE, 24048b8a9b1dSJustin T. Gibbs &path, &cgd); 24058b8a9b1dSJustin T. Gibbs xpt_release_path(&path); 24068b8a9b1dSJustin T. Gibbs 24078b8a9b1dSJustin T. Gibbs return(1); 24088b8a9b1dSJustin T. Gibbs } 2409c8bead2aSJustin T. Gibbs 24108b8a9b1dSJustin T. Gibbs static int 24118b8a9b1dSJustin T. Gibbs xptsetasyncbusfunc(struct cam_eb *bus, void *arg) 24128b8a9b1dSJustin T. Gibbs { 24138b8a9b1dSJustin T. Gibbs struct cam_path path; 24148b8a9b1dSJustin T. Gibbs struct ccb_pathinq cpi; 24157685edecSAlexander Motin struct ccb_setasync *csa = (struct ccb_setasync *)arg; 24168b8a9b1dSJustin T. Gibbs 24178b8a9b1dSJustin T. Gibbs xpt_compile_path(&path, /*periph*/NULL, 24188b8a9b1dSJustin T. Gibbs bus->sim->path_id, 24198b8a9b1dSJustin T. Gibbs CAM_TARGET_WILDCARD, 24208b8a9b1dSJustin T. Gibbs CAM_LUN_WILDCARD); 2421bbfa4aa1SAlexander Motin xpt_setup_ccb(&cpi.ccb_h, &path, CAM_PRIORITY_NORMAL); 24228b8a9b1dSJustin T. Gibbs cpi.ccb_h.func_code = XPT_PATH_INQ; 24238b8a9b1dSJustin T. Gibbs xpt_action((union ccb *)&cpi); 24247685edecSAlexander Motin csa->callback(csa->callback_arg, 24258b8a9b1dSJustin T. Gibbs AC_PATH_REGISTERED, 24268b8a9b1dSJustin T. Gibbs &path, &cpi); 24278b8a9b1dSJustin T. Gibbs xpt_release_path(&path); 24288b8a9b1dSJustin T. Gibbs 24298b8a9b1dSJustin T. Gibbs return(1); 24308b8a9b1dSJustin T. Gibbs } 24318b8a9b1dSJustin T. Gibbs 24328b8a9b1dSJustin T. Gibbs void 24338b8a9b1dSJustin T. Gibbs xpt_action(union ccb *start_ccb) 24348b8a9b1dSJustin T. Gibbs { 24359911ecf9SJustin T. Gibbs 24368b8a9b1dSJustin T. Gibbs CAM_DEBUG(start_ccb->ccb_h.path, CAM_DEBUG_TRACE, ("xpt_action\n")); 24378b8a9b1dSJustin T. Gibbs 24388b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.status = CAM_REQ_INPROG; 243952c9ce25SScott Long (*(start_ccb->ccb_h.path->bus->xport->action))(start_ccb); 244052c9ce25SScott Long } 244152c9ce25SScott Long 244252c9ce25SScott Long void 244352c9ce25SScott Long xpt_action_default(union ccb *start_ccb) 244452c9ce25SScott Long { 2445da396db2SAlexander Motin struct cam_path *path; 244652c9ce25SScott Long 2447da396db2SAlexander Motin path = start_ccb->ccb_h.path; 2448da396db2SAlexander Motin CAM_DEBUG(path, CAM_DEBUG_TRACE, ("xpt_action_default\n")); 244952c9ce25SScott Long 24508b8a9b1dSJustin T. Gibbs switch (start_ccb->ccb_h.func_code) { 24518b8a9b1dSJustin T. Gibbs case XPT_SCSI_IO: 2452d05caa00SKenneth D. Merry { 24533393f8daSKenneth D. Merry struct cam_ed *device; 2454d05caa00SKenneth D. Merry 24558b8a9b1dSJustin T. Gibbs /* 24568b8a9b1dSJustin T. Gibbs * For the sake of compatibility with SCSI-1 24578b8a9b1dSJustin T. Gibbs * devices that may not understand the identify 24588b8a9b1dSJustin T. Gibbs * message, we include lun information in the 24598b8a9b1dSJustin T. Gibbs * second byte of all commands. SCSI-1 specifies 24608b8a9b1dSJustin T. Gibbs * that luns are a 3 bit value and reserves only 3 24618b8a9b1dSJustin T. Gibbs * bits for lun information in the CDB. Later 24628b8a9b1dSJustin T. Gibbs * revisions of the SCSI spec allow for more than 8 24638b8a9b1dSJustin T. Gibbs * luns, but have deprecated lun information in the 24648b8a9b1dSJustin T. Gibbs * CDB. So, if the lun won't fit, we must omit. 24658b8a9b1dSJustin T. Gibbs * 24668b8a9b1dSJustin T. Gibbs * Also be aware that during initial probing for devices, 24678b8a9b1dSJustin T. Gibbs * the inquiry information is unknown but initialized to 0. 24688b8a9b1dSJustin T. Gibbs * This means that this code will be exercised while probing 24698b8a9b1dSJustin T. Gibbs * devices with an ANSI revision greater than 2. 24708b8a9b1dSJustin T. Gibbs */ 2471da396db2SAlexander Motin device = path->device; 24723393f8daSKenneth D. Merry if (device->protocol_version <= SCSI_REV_2 24738b8a9b1dSJustin T. Gibbs && start_ccb->ccb_h.target_lun < 8 24748b8a9b1dSJustin T. Gibbs && (start_ccb->ccb_h.flags & CAM_CDB_POINTER) == 0) { 24758b8a9b1dSJustin T. Gibbs 24768b8a9b1dSJustin T. Gibbs start_ccb->csio.cdb_io.cdb_bytes[1] |= 24778b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.target_lun << 5; 24788b8a9b1dSJustin T. Gibbs } 24798b8a9b1dSJustin T. Gibbs start_ccb->csio.scsi_status = SCSI_STATUS_OK; 2480d05caa00SKenneth D. Merry } 248107c6eac9SPoul-Henning Kamp /* FALLTHROUGH */ 24828b8a9b1dSJustin T. Gibbs case XPT_TARGET_IO: 24838b8a9b1dSJustin T. Gibbs case XPT_CONT_TARGET_IO: 24842cefde5fSJustin T. Gibbs start_ccb->csio.sense_resid = 0; 24852cefde5fSJustin T. Gibbs start_ccb->csio.resid = 0; 24862cefde5fSJustin T. Gibbs /* FALLTHROUGH */ 248752c9ce25SScott Long case XPT_ATA_IO: 2488de9ebb68SAlexander Motin if (start_ccb->ccb_h.func_code == XPT_ATA_IO) 248952c9ce25SScott Long start_ccb->ataio.resid = 0; 2490b882a6d3SMatt Jacob /* FALLTHROUGH */ 249110e1cf63SKenneth D. Merry case XPT_RESET_DEV: 24928b8a9b1dSJustin T. Gibbs case XPT_ENG_EXEC: 249306e79492SKenneth D. Merry case XPT_SMP_IO: 2494cccf4220SAlexander Motin cam_ccbq_insert_ccb(&path->device->ccbq, start_ccb); 2495cccf4220SAlexander Motin if (xpt_schedule_devq(path->bus->sim->devq, path->device)) 2496cccf4220SAlexander Motin xpt_run_devq(path->bus->sim->devq); 24978b8a9b1dSJustin T. Gibbs break; 24988b8a9b1dSJustin T. Gibbs case XPT_CALC_GEOMETRY: 24992cefde5fSJustin T. Gibbs { 25002cefde5fSJustin T. Gibbs struct cam_sim *sim; 25012cefde5fSJustin T. Gibbs 25028b8a9b1dSJustin T. Gibbs /* Filter out garbage */ 25038b8a9b1dSJustin T. Gibbs if (start_ccb->ccg.block_size == 0 25048b8a9b1dSJustin T. Gibbs || start_ccb->ccg.volume_size == 0) { 25058b8a9b1dSJustin T. Gibbs start_ccb->ccg.cylinders = 0; 25068b8a9b1dSJustin T. Gibbs start_ccb->ccg.heads = 0; 25078b8a9b1dSJustin T. Gibbs start_ccb->ccg.secs_per_track = 0; 25088b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.status = CAM_REQ_CMP; 25098b8a9b1dSJustin T. Gibbs break; 25108b8a9b1dSJustin T. Gibbs } 2511abef0e67SMarius Strobl #if defined(PC98) || defined(__sparc64__) 25128b8a9b1dSJustin T. Gibbs /* 25138b8a9b1dSJustin T. Gibbs * In a PC-98 system, geometry translation depens on 25148b8a9b1dSJustin T. Gibbs * the "real" device geometry obtained from mode page 4. 25158b8a9b1dSJustin T. Gibbs * SCSI geometry translation is performed in the 25168b8a9b1dSJustin T. Gibbs * initialization routine of the SCSI BIOS and the result 25178b8a9b1dSJustin T. Gibbs * stored in host memory. If the translation is available 25188b8a9b1dSJustin T. Gibbs * in host memory, use it. If not, rely on the default 25198b8a9b1dSJustin T. Gibbs * translation the device driver performs. 2520abef0e67SMarius Strobl * For sparc64, we may need adjust the geometry of large 2521abef0e67SMarius Strobl * disks in order to fit the limitations of the 16-bit 2522abef0e67SMarius Strobl * fields of the VTOC8 disk label. 25238b8a9b1dSJustin T. Gibbs */ 25248b8a9b1dSJustin T. Gibbs if (scsi_da_bios_params(&start_ccb->ccg) != 0) { 25258b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.status = CAM_REQ_CMP; 25268b8a9b1dSJustin T. Gibbs break; 25278b8a9b1dSJustin T. Gibbs } 25288b8a9b1dSJustin T. Gibbs #endif 2529da396db2SAlexander Motin sim = path->bus->sim; 25302cefde5fSJustin T. Gibbs (*(sim->sim_action))(sim, start_ccb); 25312cefde5fSJustin T. Gibbs break; 25322cefde5fSJustin T. Gibbs } 2533bb6087e5SJustin T. Gibbs case XPT_ABORT: 25342cefde5fSJustin T. Gibbs { 25352cefde5fSJustin T. Gibbs union ccb* abort_ccb; 25362cefde5fSJustin T. Gibbs 25372cefde5fSJustin T. Gibbs abort_ccb = start_ccb->cab.abort_ccb; 25382cefde5fSJustin T. Gibbs if (XPT_FC_IS_DEV_QUEUED(abort_ccb)) { 25392cefde5fSJustin T. Gibbs 25402cefde5fSJustin T. Gibbs if (abort_ccb->ccb_h.pinfo.index >= 0) { 25412cefde5fSJustin T. Gibbs struct cam_ccbq *ccbq; 254283c5d981SAlexander Motin struct cam_ed *device; 25432cefde5fSJustin T. Gibbs 254483c5d981SAlexander Motin device = abort_ccb->ccb_h.path->device; 254583c5d981SAlexander Motin ccbq = &device->ccbq; 25462cefde5fSJustin T. Gibbs cam_ccbq_remove_ccb(ccbq, abort_ccb); 25472cefde5fSJustin T. Gibbs abort_ccb->ccb_h.status = 25482cefde5fSJustin T. Gibbs CAM_REQ_ABORTED|CAM_DEV_QFRZN; 25492cefde5fSJustin T. Gibbs xpt_freeze_devq(abort_ccb->ccb_h.path, 1); 25502cefde5fSJustin T. Gibbs xpt_done(abort_ccb); 25512cefde5fSJustin T. Gibbs start_ccb->ccb_h.status = CAM_REQ_CMP; 25522cefde5fSJustin T. Gibbs break; 25532cefde5fSJustin T. Gibbs } 25542cefde5fSJustin T. Gibbs if (abort_ccb->ccb_h.pinfo.index == CAM_UNQUEUED_INDEX 25552cefde5fSJustin T. Gibbs && (abort_ccb->ccb_h.status & CAM_SIM_QUEUED) == 0) { 25562cefde5fSJustin T. Gibbs /* 25572cefde5fSJustin T. Gibbs * We've caught this ccb en route to 25582cefde5fSJustin T. Gibbs * the SIM. Flag it for abort and the 25592cefde5fSJustin T. Gibbs * SIM will do so just before starting 25602cefde5fSJustin T. Gibbs * real work on the CCB. 25612cefde5fSJustin T. Gibbs */ 25622cefde5fSJustin T. Gibbs abort_ccb->ccb_h.status = 25632cefde5fSJustin T. Gibbs CAM_REQ_ABORTED|CAM_DEV_QFRZN; 25642cefde5fSJustin T. Gibbs xpt_freeze_devq(abort_ccb->ccb_h.path, 1); 25652cefde5fSJustin T. Gibbs start_ccb->ccb_h.status = CAM_REQ_CMP; 25662cefde5fSJustin T. Gibbs break; 25672cefde5fSJustin T. Gibbs } 25682cefde5fSJustin T. Gibbs } 25692cefde5fSJustin T. Gibbs if (XPT_FC_IS_QUEUED(abort_ccb) 25702cefde5fSJustin T. Gibbs && (abort_ccb->ccb_h.pinfo.index == CAM_DONEQ_INDEX)) { 25712cefde5fSJustin T. Gibbs /* 25722cefde5fSJustin T. Gibbs * It's already completed but waiting 25732cefde5fSJustin T. Gibbs * for our SWI to get to it. 25742cefde5fSJustin T. Gibbs */ 25752cefde5fSJustin T. Gibbs start_ccb->ccb_h.status = CAM_UA_ABORT; 25762cefde5fSJustin T. Gibbs break; 25772cefde5fSJustin T. Gibbs } 25782cefde5fSJustin T. Gibbs /* 25792cefde5fSJustin T. Gibbs * If we weren't able to take care of the abort request 25802cefde5fSJustin T. Gibbs * in the XPT, pass the request down to the SIM for processing. 25812cefde5fSJustin T. Gibbs */ 25822cefde5fSJustin T. Gibbs } 258307c6eac9SPoul-Henning Kamp /* FALLTHROUGH */ 25848b8a9b1dSJustin T. Gibbs case XPT_ACCEPT_TARGET_IO: 25858b8a9b1dSJustin T. Gibbs case XPT_EN_LUN: 25868b8a9b1dSJustin T. Gibbs case XPT_IMMED_NOTIFY: 25878b8a9b1dSJustin T. Gibbs case XPT_NOTIFY_ACK: 25888b8a9b1dSJustin T. Gibbs case XPT_RESET_BUS: 25892df76c16SMatt Jacob case XPT_IMMEDIATE_NOTIFY: 25902df76c16SMatt Jacob case XPT_NOTIFY_ACKNOWLEDGE: 25912df76c16SMatt Jacob case XPT_GET_SIM_KNOB: 25922df76c16SMatt Jacob case XPT_SET_SIM_KNOB: 25938b8a9b1dSJustin T. Gibbs { 25948b8a9b1dSJustin T. Gibbs struct cam_sim *sim; 25958b8a9b1dSJustin T. Gibbs 2596da396db2SAlexander Motin sim = path->bus->sim; 25978b8a9b1dSJustin T. Gibbs (*(sim->sim_action))(sim, start_ccb); 25988b8a9b1dSJustin T. Gibbs break; 25998b8a9b1dSJustin T. Gibbs } 260087cfaf0eSJustin T. Gibbs case XPT_PATH_INQ: 260187cfaf0eSJustin T. Gibbs { 260287cfaf0eSJustin T. Gibbs struct cam_sim *sim; 260387cfaf0eSJustin T. Gibbs 2604da396db2SAlexander Motin sim = path->bus->sim; 260587cfaf0eSJustin T. Gibbs (*(sim->sim_action))(sim, start_ccb); 260687cfaf0eSJustin T. Gibbs break; 260787cfaf0eSJustin T. Gibbs } 260887cfaf0eSJustin T. Gibbs case XPT_PATH_STATS: 2609da396db2SAlexander Motin start_ccb->cpis.last_reset = path->bus->last_reset; 261087cfaf0eSJustin T. Gibbs start_ccb->ccb_h.status = CAM_REQ_CMP; 261187cfaf0eSJustin T. Gibbs break; 26128b8a9b1dSJustin T. Gibbs case XPT_GDEV_TYPE: 2613a5479bc5SJustin T. Gibbs { 261487cfaf0eSJustin T. Gibbs struct cam_ed *dev; 2615a5479bc5SJustin T. Gibbs 2616da396db2SAlexander Motin dev = path->device; 261787cfaf0eSJustin T. Gibbs if ((dev->flags & CAM_DEV_UNCONFIGURED) != 0) { 26188b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.status = CAM_DEV_NOT_THERE; 26198b8a9b1dSJustin T. Gibbs } else { 26208b8a9b1dSJustin T. Gibbs struct ccb_getdev *cgd; 26218b8a9b1dSJustin T. Gibbs 26228b8a9b1dSJustin T. Gibbs cgd = &start_ccb->cgd; 262352c9ce25SScott Long cgd->protocol = dev->protocol; 26248b8a9b1dSJustin T. Gibbs cgd->inq_data = dev->inq_data; 262552c9ce25SScott Long cgd->ident_data = dev->ident_data; 262630a4094fSAlexander Motin cgd->inq_flags = dev->inq_flags; 26278b8a9b1dSJustin T. Gibbs cgd->ccb_h.status = CAM_REQ_CMP; 26288b8a9b1dSJustin T. Gibbs cgd->serial_num_len = dev->serial_num_len; 26298b8a9b1dSJustin T. Gibbs if ((dev->serial_num_len > 0) 26308b8a9b1dSJustin T. Gibbs && (dev->serial_num != NULL)) 26318b8a9b1dSJustin T. Gibbs bcopy(dev->serial_num, cgd->serial_num, 26328b8a9b1dSJustin T. Gibbs dev->serial_num_len); 26338b8a9b1dSJustin T. Gibbs } 26348b8a9b1dSJustin T. Gibbs break; 2635a5479bc5SJustin T. Gibbs } 263687cfaf0eSJustin T. Gibbs case XPT_GDEV_STATS: 263787cfaf0eSJustin T. Gibbs { 263887cfaf0eSJustin T. Gibbs struct cam_ed *dev; 263987cfaf0eSJustin T. Gibbs 2640da396db2SAlexander Motin dev = path->device; 264187cfaf0eSJustin T. Gibbs if ((dev->flags & CAM_DEV_UNCONFIGURED) != 0) { 264287cfaf0eSJustin T. Gibbs start_ccb->ccb_h.status = CAM_DEV_NOT_THERE; 264387cfaf0eSJustin T. Gibbs } else { 264487cfaf0eSJustin T. Gibbs struct ccb_getdevstats *cgds; 264587cfaf0eSJustin T. Gibbs struct cam_eb *bus; 264687cfaf0eSJustin T. Gibbs struct cam_et *tar; 264787cfaf0eSJustin T. Gibbs 264887cfaf0eSJustin T. Gibbs cgds = &start_ccb->cgds; 2649da396db2SAlexander Motin bus = path->bus; 2650da396db2SAlexander Motin tar = path->target; 265187cfaf0eSJustin T. Gibbs cgds->dev_openings = dev->ccbq.dev_openings; 265287cfaf0eSJustin T. Gibbs cgds->dev_active = dev->ccbq.dev_active; 265387cfaf0eSJustin T. Gibbs cgds->devq_openings = dev->ccbq.devq_openings; 2654ea541bfdSAlexander Motin cgds->devq_queued = cam_ccbq_pending_ccb_count(&dev->ccbq); 265587cfaf0eSJustin T. Gibbs cgds->held = dev->ccbq.held; 265687cfaf0eSJustin T. Gibbs cgds->last_reset = tar->last_reset; 265752c9ce25SScott Long cgds->maxtags = dev->maxtags; 265852c9ce25SScott Long cgds->mintags = dev->mintags; 265987cfaf0eSJustin T. Gibbs if (timevalcmp(&tar->last_reset, &bus->last_reset, <)) 266087cfaf0eSJustin T. Gibbs cgds->last_reset = bus->last_reset; 266187cfaf0eSJustin T. Gibbs cgds->ccb_h.status = CAM_REQ_CMP; 266287cfaf0eSJustin T. Gibbs } 266387cfaf0eSJustin T. Gibbs break; 266487cfaf0eSJustin T. Gibbs } 26658b8a9b1dSJustin T. Gibbs case XPT_GDEVLIST: 26668b8a9b1dSJustin T. Gibbs { 26678b8a9b1dSJustin T. Gibbs struct cam_periph *nperiph; 26688b8a9b1dSJustin T. Gibbs struct periph_list *periph_head; 26698b8a9b1dSJustin T. Gibbs struct ccb_getdevlist *cgdl; 26703393f8daSKenneth D. Merry u_int i; 26718b8a9b1dSJustin T. Gibbs struct cam_ed *device; 26728b8a9b1dSJustin T. Gibbs int found; 26738b8a9b1dSJustin T. Gibbs 26748b8a9b1dSJustin T. Gibbs 26758b8a9b1dSJustin T. Gibbs found = 0; 26768b8a9b1dSJustin T. Gibbs 26778b8a9b1dSJustin T. Gibbs /* 26788b8a9b1dSJustin T. Gibbs * Don't want anyone mucking with our data. 26798b8a9b1dSJustin T. Gibbs */ 2680da396db2SAlexander Motin device = path->device; 26818b8a9b1dSJustin T. Gibbs periph_head = &device->periphs; 26828b8a9b1dSJustin T. Gibbs cgdl = &start_ccb->cgdl; 26838b8a9b1dSJustin T. Gibbs 26848b8a9b1dSJustin T. Gibbs /* 26858b8a9b1dSJustin T. Gibbs * Check and see if the list has changed since the user 26868b8a9b1dSJustin T. Gibbs * last requested a list member. If so, tell them that the 26878b8a9b1dSJustin T. Gibbs * list has changed, and therefore they need to start over 26888b8a9b1dSJustin T. Gibbs * from the beginning. 26898b8a9b1dSJustin T. Gibbs */ 26908b8a9b1dSJustin T. Gibbs if ((cgdl->index != 0) && 26918b8a9b1dSJustin T. Gibbs (cgdl->generation != device->generation)) { 26928b8a9b1dSJustin T. Gibbs cgdl->status = CAM_GDEVLIST_LIST_CHANGED; 26938b8a9b1dSJustin T. Gibbs break; 26948b8a9b1dSJustin T. Gibbs } 26958b8a9b1dSJustin T. Gibbs 26968b8a9b1dSJustin T. Gibbs /* 26978b8a9b1dSJustin T. Gibbs * Traverse the list of peripherals and attempt to find 26988b8a9b1dSJustin T. Gibbs * the requested peripheral. 26998b8a9b1dSJustin T. Gibbs */ 2700fc2ffbe6SPoul-Henning Kamp for (nperiph = SLIST_FIRST(periph_head), i = 0; 27018b8a9b1dSJustin T. Gibbs (nperiph != NULL) && (i <= cgdl->index); 2702fc2ffbe6SPoul-Henning Kamp nperiph = SLIST_NEXT(nperiph, periph_links), i++) { 27038b8a9b1dSJustin T. Gibbs if (i == cgdl->index) { 27048b8a9b1dSJustin T. Gibbs strncpy(cgdl->periph_name, 27058b8a9b1dSJustin T. Gibbs nperiph->periph_name, 27068b8a9b1dSJustin T. Gibbs DEV_IDLEN); 27078b8a9b1dSJustin T. Gibbs cgdl->unit_number = nperiph->unit_number; 27088b8a9b1dSJustin T. Gibbs found = 1; 27098b8a9b1dSJustin T. Gibbs } 27108b8a9b1dSJustin T. Gibbs } 27118b8a9b1dSJustin T. Gibbs if (found == 0) { 27128b8a9b1dSJustin T. Gibbs cgdl->status = CAM_GDEVLIST_ERROR; 27138b8a9b1dSJustin T. Gibbs break; 27148b8a9b1dSJustin T. Gibbs } 27158b8a9b1dSJustin T. Gibbs 27168b8a9b1dSJustin T. Gibbs if (nperiph == NULL) 27178b8a9b1dSJustin T. Gibbs cgdl->status = CAM_GDEVLIST_LAST_DEVICE; 27188b8a9b1dSJustin T. Gibbs else 27198b8a9b1dSJustin T. Gibbs cgdl->status = CAM_GDEVLIST_MORE_DEVS; 27208b8a9b1dSJustin T. Gibbs 27218b8a9b1dSJustin T. Gibbs cgdl->index++; 27228b8a9b1dSJustin T. Gibbs cgdl->generation = device->generation; 27238b8a9b1dSJustin T. Gibbs 27248b8a9b1dSJustin T. Gibbs cgdl->ccb_h.status = CAM_REQ_CMP; 27258b8a9b1dSJustin T. Gibbs break; 27268b8a9b1dSJustin T. Gibbs } 27278b8a9b1dSJustin T. Gibbs case XPT_DEV_MATCH: 27288b8a9b1dSJustin T. Gibbs { 27298b8a9b1dSJustin T. Gibbs dev_pos_type position_type; 27308b8a9b1dSJustin T. Gibbs struct ccb_dev_match *cdm; 27318b8a9b1dSJustin T. Gibbs 27328b8a9b1dSJustin T. Gibbs cdm = &start_ccb->cdm; 27338b8a9b1dSJustin T. Gibbs 27348b8a9b1dSJustin T. Gibbs /* 27358b8a9b1dSJustin T. Gibbs * There are two ways of getting at information in the EDT. 27368b8a9b1dSJustin T. Gibbs * The first way is via the primary EDT tree. It starts 27378b8a9b1dSJustin T. Gibbs * with a list of busses, then a list of targets on a bus, 27388b8a9b1dSJustin T. Gibbs * then devices/luns on a target, and then peripherals on a 27398b8a9b1dSJustin T. Gibbs * device/lun. The "other" way is by the peripheral driver 27408b8a9b1dSJustin T. Gibbs * lists. The peripheral driver lists are organized by 27418b8a9b1dSJustin T. Gibbs * peripheral driver. (obviously) So it makes sense to 27428b8a9b1dSJustin T. Gibbs * use the peripheral driver list if the user is looking 27438b8a9b1dSJustin T. Gibbs * for something like "da1", or all "da" devices. If the 27448b8a9b1dSJustin T. Gibbs * user is looking for something on a particular bus/target 27458b8a9b1dSJustin T. Gibbs * or lun, it's generally better to go through the EDT tree. 27468b8a9b1dSJustin T. Gibbs */ 27478b8a9b1dSJustin T. Gibbs 27488b8a9b1dSJustin T. Gibbs if (cdm->pos.position_type != CAM_DEV_POS_NONE) 27498b8a9b1dSJustin T. Gibbs position_type = cdm->pos.position_type; 27508b8a9b1dSJustin T. Gibbs else { 27513393f8daSKenneth D. Merry u_int i; 27528b8a9b1dSJustin T. Gibbs 27538b8a9b1dSJustin T. Gibbs position_type = CAM_DEV_POS_NONE; 27548b8a9b1dSJustin T. Gibbs 27558b8a9b1dSJustin T. Gibbs for (i = 0; i < cdm->num_patterns; i++) { 27568b8a9b1dSJustin T. Gibbs if ((cdm->patterns[i].type == DEV_MATCH_BUS) 27578b8a9b1dSJustin T. Gibbs ||(cdm->patterns[i].type == DEV_MATCH_DEVICE)){ 27588b8a9b1dSJustin T. Gibbs position_type = CAM_DEV_POS_EDT; 27598b8a9b1dSJustin T. Gibbs break; 27608b8a9b1dSJustin T. Gibbs } 27618b8a9b1dSJustin T. Gibbs } 27628b8a9b1dSJustin T. Gibbs 27638b8a9b1dSJustin T. Gibbs if (cdm->num_patterns == 0) 27648b8a9b1dSJustin T. Gibbs position_type = CAM_DEV_POS_EDT; 27658b8a9b1dSJustin T. Gibbs else if (position_type == CAM_DEV_POS_NONE) 27668b8a9b1dSJustin T. Gibbs position_type = CAM_DEV_POS_PDRV; 27678b8a9b1dSJustin T. Gibbs } 27688b8a9b1dSJustin T. Gibbs 276992c40f40SAlexander Motin /* 277092c40f40SAlexander Motin * Note that we drop the SIM lock here, because the EDT 277192c40f40SAlexander Motin * traversal code needs to do its own locking. 277292c40f40SAlexander Motin */ 277392c40f40SAlexander Motin CAM_SIM_UNLOCK(xpt_path_sim(cdm->ccb_h.path)); 27748b8a9b1dSJustin T. Gibbs switch(position_type & CAM_DEV_POS_TYPEMASK) { 27758b8a9b1dSJustin T. Gibbs case CAM_DEV_POS_EDT: 277607c6eac9SPoul-Henning Kamp xptedtmatch(cdm); 27778b8a9b1dSJustin T. Gibbs break; 27788b8a9b1dSJustin T. Gibbs case CAM_DEV_POS_PDRV: 277907c6eac9SPoul-Henning Kamp xptperiphlistmatch(cdm); 27808b8a9b1dSJustin T. Gibbs break; 27818b8a9b1dSJustin T. Gibbs default: 27828b8a9b1dSJustin T. Gibbs cdm->status = CAM_DEV_MATCH_ERROR; 27838b8a9b1dSJustin T. Gibbs break; 27848b8a9b1dSJustin T. Gibbs } 278592c40f40SAlexander Motin CAM_SIM_LOCK(xpt_path_sim(cdm->ccb_h.path)); 27868b8a9b1dSJustin T. Gibbs 27878b8a9b1dSJustin T. Gibbs if (cdm->status == CAM_DEV_MATCH_ERROR) 27888b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.status = CAM_REQ_CMP_ERR; 27898b8a9b1dSJustin T. Gibbs else 27908b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.status = CAM_REQ_CMP; 27918b8a9b1dSJustin T. Gibbs 27928b8a9b1dSJustin T. Gibbs break; 27938b8a9b1dSJustin T. Gibbs } 27948b8a9b1dSJustin T. Gibbs case XPT_SASYNC_CB: 27958b8a9b1dSJustin T. Gibbs { 279684f82481SScott Long struct ccb_setasync *csa; 279784f82481SScott Long struct async_node *cur_entry; 279884f82481SScott Long struct async_list *async_head; 279984f82481SScott Long u_int32_t added; 280084f82481SScott Long 280184f82481SScott Long csa = &start_ccb->csa; 280284f82481SScott Long added = csa->event_enable; 2803da396db2SAlexander Motin async_head = &path->device->asyncs; 280484f82481SScott Long 280584f82481SScott Long /* 280684f82481SScott Long * If there is already an entry for us, simply 280784f82481SScott Long * update it. 280884f82481SScott Long */ 280984f82481SScott Long cur_entry = SLIST_FIRST(async_head); 281084f82481SScott Long while (cur_entry != NULL) { 281184f82481SScott Long if ((cur_entry->callback_arg == csa->callback_arg) 281284f82481SScott Long && (cur_entry->callback == csa->callback)) 281384f82481SScott Long break; 281484f82481SScott Long cur_entry = SLIST_NEXT(cur_entry, links); 281584f82481SScott Long } 281684f82481SScott Long 281784f82481SScott Long if (cur_entry != NULL) { 281884f82481SScott Long /* 281984f82481SScott Long * If the request has no flags set, 282084f82481SScott Long * remove the entry. 282184f82481SScott Long */ 282284f82481SScott Long added &= ~cur_entry->event_enable; 282384f82481SScott Long if (csa->event_enable == 0) { 282484f82481SScott Long SLIST_REMOVE(async_head, cur_entry, 282584f82481SScott Long async_node, links); 2826da396db2SAlexander Motin xpt_release_device(path->device); 282784f82481SScott Long free(cur_entry, M_CAMXPT); 282884f82481SScott Long } else { 282984f82481SScott Long cur_entry->event_enable = csa->event_enable; 283084f82481SScott Long } 28317685edecSAlexander Motin csa->event_enable = added; 283284f82481SScott Long } else { 283384f82481SScott Long cur_entry = malloc(sizeof(*cur_entry), M_CAMXPT, 283484f82481SScott Long M_NOWAIT); 283584f82481SScott Long if (cur_entry == NULL) { 283684f82481SScott Long csa->ccb_h.status = CAM_RESRC_UNAVAIL; 283784f82481SScott Long break; 283884f82481SScott Long } 283984f82481SScott Long cur_entry->event_enable = csa->event_enable; 284084f82481SScott Long cur_entry->callback_arg = csa->callback_arg; 284184f82481SScott Long cur_entry->callback = csa->callback; 284284f82481SScott Long SLIST_INSERT_HEAD(async_head, cur_entry, links); 2843da396db2SAlexander Motin xpt_acquire_device(path->device); 284484f82481SScott Long } 28458b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.status = CAM_REQ_CMP; 28468b8a9b1dSJustin T. Gibbs break; 28478b8a9b1dSJustin T. Gibbs } 28488b8a9b1dSJustin T. Gibbs case XPT_REL_SIMQ: 28498b8a9b1dSJustin T. Gibbs { 28508b8a9b1dSJustin T. Gibbs struct ccb_relsim *crs; 28518b8a9b1dSJustin T. Gibbs struct cam_ed *dev; 28528b8a9b1dSJustin T. Gibbs 28538b8a9b1dSJustin T. Gibbs crs = &start_ccb->crs; 2854da396db2SAlexander Motin dev = path->device; 28558b8a9b1dSJustin T. Gibbs if (dev == NULL) { 28568b8a9b1dSJustin T. Gibbs 28578b8a9b1dSJustin T. Gibbs crs->ccb_h.status = CAM_DEV_NOT_THERE; 28588b8a9b1dSJustin T. Gibbs break; 28598b8a9b1dSJustin T. Gibbs } 28608b8a9b1dSJustin T. Gibbs 28618b8a9b1dSJustin T. Gibbs if ((crs->release_flags & RELSIM_ADJUST_OPENINGS) != 0) { 28628b8a9b1dSJustin T. Gibbs 28638b8a9b1dSJustin T. Gibbs /* Don't ever go below one opening */ 28648b8a9b1dSJustin T. Gibbs if (crs->openings > 0) { 28657dc3213dSAlexander Motin xpt_dev_ccbq_resize(path, crs->openings); 286679ccc199SJordan K. Hubbard if (bootverbose) { 2867da396db2SAlexander Motin xpt_print(path, 28687dc3213dSAlexander Motin "number of openings is now %d\n", 28698b8a9b1dSJustin T. Gibbs crs->openings); 28708b8a9b1dSJustin T. Gibbs } 28718b8a9b1dSJustin T. Gibbs } 28728b8a9b1dSJustin T. Gibbs } 28738b8a9b1dSJustin T. Gibbs 28748b8a9b1dSJustin T. Gibbs if ((crs->release_flags & RELSIM_RELEASE_AFTER_TIMEOUT) != 0) { 28758b8a9b1dSJustin T. Gibbs 28768b8a9b1dSJustin T. Gibbs if ((dev->flags & CAM_DEV_REL_TIMEOUT_PENDING) != 0) { 28778b8a9b1dSJustin T. Gibbs 28788b8a9b1dSJustin T. Gibbs /* 28798b8a9b1dSJustin T. Gibbs * Just extend the old timeout and decrement 28808b8a9b1dSJustin T. Gibbs * the freeze count so that a single timeout 28818b8a9b1dSJustin T. Gibbs * is sufficient for releasing the queue. 28828b8a9b1dSJustin T. Gibbs */ 28838b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.flags &= ~CAM_DEV_QFREEZE; 28842b83592fSScott Long callout_stop(&dev->callout); 28858b8a9b1dSJustin T. Gibbs } else { 28868b8a9b1dSJustin T. Gibbs 28878b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.flags |= CAM_DEV_QFREEZE; 28888b8a9b1dSJustin T. Gibbs } 28898b8a9b1dSJustin T. Gibbs 28902b83592fSScott Long callout_reset(&dev->callout, 28912b83592fSScott Long (crs->release_timeout * hz) / 1000, 28922b83592fSScott Long xpt_release_devq_timeout, dev); 28938b8a9b1dSJustin T. Gibbs 28948b8a9b1dSJustin T. Gibbs dev->flags |= CAM_DEV_REL_TIMEOUT_PENDING; 28958b8a9b1dSJustin T. Gibbs 28968b8a9b1dSJustin T. Gibbs } 28978b8a9b1dSJustin T. Gibbs 28988b8a9b1dSJustin T. Gibbs if ((crs->release_flags & RELSIM_RELEASE_AFTER_CMDCMPLT) != 0) { 28998b8a9b1dSJustin T. Gibbs 29008b8a9b1dSJustin T. Gibbs if ((dev->flags & CAM_DEV_REL_ON_COMPLETE) != 0) { 29018b8a9b1dSJustin T. Gibbs /* 29028b8a9b1dSJustin T. Gibbs * Decrement the freeze count so that a single 29038b8a9b1dSJustin T. Gibbs * completion is still sufficient to unfreeze 29048b8a9b1dSJustin T. Gibbs * the queue. 29058b8a9b1dSJustin T. Gibbs */ 29068b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.flags &= ~CAM_DEV_QFREEZE; 29078b8a9b1dSJustin T. Gibbs } else { 29088b8a9b1dSJustin T. Gibbs 29098b8a9b1dSJustin T. Gibbs dev->flags |= CAM_DEV_REL_ON_COMPLETE; 29108b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.flags |= CAM_DEV_QFREEZE; 29118b8a9b1dSJustin T. Gibbs } 29128b8a9b1dSJustin T. Gibbs } 29138b8a9b1dSJustin T. Gibbs 29148b8a9b1dSJustin T. Gibbs if ((crs->release_flags & RELSIM_RELEASE_AFTER_QEMPTY) != 0) { 29158b8a9b1dSJustin T. Gibbs 29168b8a9b1dSJustin T. Gibbs if ((dev->flags & CAM_DEV_REL_ON_QUEUE_EMPTY) != 0 29178b8a9b1dSJustin T. Gibbs || (dev->ccbq.dev_active == 0)) { 29188b8a9b1dSJustin T. Gibbs 29198b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.flags &= ~CAM_DEV_QFREEZE; 29208b8a9b1dSJustin T. Gibbs } else { 29218b8a9b1dSJustin T. Gibbs 29228b8a9b1dSJustin T. Gibbs dev->flags |= CAM_DEV_REL_ON_QUEUE_EMPTY; 29238b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.flags |= CAM_DEV_QFREEZE; 29248b8a9b1dSJustin T. Gibbs } 29258b8a9b1dSJustin T. Gibbs } 29268b8a9b1dSJustin T. Gibbs 2927cccf4220SAlexander Motin if ((start_ccb->ccb_h.flags & CAM_DEV_QFREEZE) == 0) 2928cccf4220SAlexander Motin xpt_release_devq(path, /*count*/1, /*run_queue*/TRUE); 2929cccf4220SAlexander Motin start_ccb->crs.qfrozen_cnt = dev->ccbq.queue.qfrozen_cnt; 29308b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.status = CAM_REQ_CMP; 29318b8a9b1dSJustin T. Gibbs break; 29328b8a9b1dSJustin T. Gibbs } 29338b8a9b1dSJustin T. Gibbs case XPT_DEBUG: { 293480d6987cSAlexander Motin struct cam_path *oldpath; 293580d6987cSAlexander Motin struct cam_sim *oldsim; 293680d6987cSAlexander Motin 2937f0f25b9cSAlexander Motin /* Check that all request bits are supported. */ 293822c7d606SAlexander Motin if (start_ccb->cdbg.flags & ~(CAM_DEBUG_COMPILE)) { 2939f0f25b9cSAlexander Motin start_ccb->ccb_h.status = CAM_FUNC_NOTAVAIL; 2940f0f25b9cSAlexander Motin break; 2941f0f25b9cSAlexander Motin } 2942f0f25b9cSAlexander Motin 294380d6987cSAlexander Motin cam_dflags = CAM_DEBUG_NONE; 29448b8a9b1dSJustin T. Gibbs if (cam_dpath != NULL) { 294580d6987cSAlexander Motin /* To release the old path we must hold proper lock. */ 294680d6987cSAlexander Motin oldpath = cam_dpath; 29478b8a9b1dSJustin T. Gibbs cam_dpath = NULL; 294880d6987cSAlexander Motin oldsim = xpt_path_sim(oldpath); 294980d6987cSAlexander Motin CAM_SIM_UNLOCK(xpt_path_sim(start_ccb->ccb_h.path)); 295080d6987cSAlexander Motin CAM_SIM_LOCK(oldsim); 295180d6987cSAlexander Motin xpt_free_path(oldpath); 295280d6987cSAlexander Motin CAM_SIM_UNLOCK(oldsim); 295380d6987cSAlexander Motin CAM_SIM_LOCK(xpt_path_sim(start_ccb->ccb_h.path)); 29548b8a9b1dSJustin T. Gibbs } 295580d6987cSAlexander Motin if (start_ccb->cdbg.flags != CAM_DEBUG_NONE) { 2956e5dfa058SAlexander Motin if (xpt_create_path(&cam_dpath, NULL, 29578b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.path_id, 29588b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.target_id, 29598b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.target_lun) != 29608b8a9b1dSJustin T. Gibbs CAM_REQ_CMP) { 29618b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.status = CAM_RESRC_UNAVAIL; 2962aa872be6SMatt Jacob } else { 296380d6987cSAlexander Motin cam_dflags = start_ccb->cdbg.flags; 29648b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.status = CAM_REQ_CMP; 2965f0d9af51SMatt Jacob xpt_print(cam_dpath, "debugging flags now %x\n", 2966f0d9af51SMatt Jacob cam_dflags); 2967aa872be6SMatt Jacob } 296880d6987cSAlexander Motin } else 29698b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.status = CAM_REQ_CMP; 29708b8a9b1dSJustin T. Gibbs break; 29718b8a9b1dSJustin T. Gibbs } 29728b8a9b1dSJustin T. Gibbs case XPT_NOOP: 297387cfaf0eSJustin T. Gibbs if ((start_ccb->ccb_h.flags & CAM_DEV_QFREEZE) != 0) 2974da396db2SAlexander Motin xpt_freeze_devq(path, 1); 29758b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.status = CAM_REQ_CMP; 29768b8a9b1dSJustin T. Gibbs break; 29778b8a9b1dSJustin T. Gibbs default: 29788b8a9b1dSJustin T. Gibbs case XPT_SDEV_TYPE: 29798b8a9b1dSJustin T. Gibbs case XPT_TERM_IO: 29808b8a9b1dSJustin T. Gibbs case XPT_ENG_INQ: 29818b8a9b1dSJustin T. Gibbs /* XXX Implement */ 29823501942bSJustin T. Gibbs printf("%s: CCB type %#x not supported\n", __func__, 29833501942bSJustin T. Gibbs start_ccb->ccb_h.func_code); 29848b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.status = CAM_PROVIDE_FAIL; 2985b882a6d3SMatt Jacob if (start_ccb->ccb_h.func_code & XPT_FC_DEV_QUEUED) { 2986b882a6d3SMatt Jacob xpt_done(start_ccb); 2987b882a6d3SMatt Jacob } 29888b8a9b1dSJustin T. Gibbs break; 29898b8a9b1dSJustin T. Gibbs } 29908b8a9b1dSJustin T. Gibbs } 29918b8a9b1dSJustin T. Gibbs 29928b8a9b1dSJustin T. Gibbs void 29938b8a9b1dSJustin T. Gibbs xpt_polled_action(union ccb *start_ccb) 29948b8a9b1dSJustin T. Gibbs { 29958b8a9b1dSJustin T. Gibbs u_int32_t timeout; 29968b8a9b1dSJustin T. Gibbs struct cam_sim *sim; 29978b8a9b1dSJustin T. Gibbs struct cam_devq *devq; 29988b8a9b1dSJustin T. Gibbs struct cam_ed *dev; 29998b8a9b1dSJustin T. Gibbs 300068153f43SScott Long 30010069293bSAlexander Motin timeout = start_ccb->ccb_h.timeout * 10; 30028b8a9b1dSJustin T. Gibbs sim = start_ccb->ccb_h.path->bus->sim; 30038b8a9b1dSJustin T. Gibbs devq = sim->devq; 30048b8a9b1dSJustin T. Gibbs dev = start_ccb->ccb_h.path->device; 30058b8a9b1dSJustin T. Gibbs 30062b83592fSScott Long mtx_assert(sim->mtx, MA_OWNED); 30078b8a9b1dSJustin T. Gibbs 30084a612489SAlexander Motin /* Don't use ISR for this SIM while polling. */ 30094a612489SAlexander Motin sim->flags |= CAM_SIM_POLLED; 30104a612489SAlexander Motin 30118b8a9b1dSJustin T. Gibbs /* 30128b8a9b1dSJustin T. Gibbs * Steal an opening so that no other queued requests 30138b8a9b1dSJustin T. Gibbs * can get it before us while we simulate interrupts. 30148b8a9b1dSJustin T. Gibbs */ 30158b8a9b1dSJustin T. Gibbs dev->ccbq.devq_openings--; 30168b8a9b1dSJustin T. Gibbs dev->ccbq.dev_openings--; 30178b8a9b1dSJustin T. Gibbs 3018d3ef3454SIan Dowse while(((devq != NULL && devq->send_openings <= 0) || 3019d3ef3454SIan Dowse dev->ccbq.dev_openings < 0) && (--timeout > 0)) { 30200069293bSAlexander Motin DELAY(100); 30218b8a9b1dSJustin T. Gibbs (*(sim->sim_poll))(sim); 302239fe6d85SAlexander Motin camisr_runqueue(sim); 30238b8a9b1dSJustin T. Gibbs } 30248b8a9b1dSJustin T. Gibbs 30258b8a9b1dSJustin T. Gibbs dev->ccbq.devq_openings++; 30268b8a9b1dSJustin T. Gibbs dev->ccbq.dev_openings++; 30278b8a9b1dSJustin T. Gibbs 30288b8a9b1dSJustin T. Gibbs if (timeout != 0) { 30298b8a9b1dSJustin T. Gibbs xpt_action(start_ccb); 30308b8a9b1dSJustin T. Gibbs while(--timeout > 0) { 30318b8a9b1dSJustin T. Gibbs (*(sim->sim_poll))(sim); 303239fe6d85SAlexander Motin camisr_runqueue(sim); 30338b8a9b1dSJustin T. Gibbs if ((start_ccb->ccb_h.status & CAM_STATUS_MASK) 30348b8a9b1dSJustin T. Gibbs != CAM_REQ_INPROG) 30358b8a9b1dSJustin T. Gibbs break; 30360069293bSAlexander Motin DELAY(100); 30378b8a9b1dSJustin T. Gibbs } 30388b8a9b1dSJustin T. Gibbs if (timeout == 0) { 30398b8a9b1dSJustin T. Gibbs /* 30408b8a9b1dSJustin T. Gibbs * XXX Is it worth adding a sim_timeout entry 30418b8a9b1dSJustin T. Gibbs * point so we can attempt recovery? If 30428b8a9b1dSJustin T. Gibbs * this is only used for dumps, I don't think 30438b8a9b1dSJustin T. Gibbs * it is. 30448b8a9b1dSJustin T. Gibbs */ 30458b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.status = CAM_CMD_TIMEOUT; 30468b8a9b1dSJustin T. Gibbs } 30478b8a9b1dSJustin T. Gibbs } else { 30488b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.status = CAM_RESRC_UNAVAIL; 30498b8a9b1dSJustin T. Gibbs } 30504a612489SAlexander Motin 30514a612489SAlexander Motin /* We will use CAM ISR for this SIM again. */ 30524a612489SAlexander Motin sim->flags &= ~CAM_SIM_POLLED; 30538b8a9b1dSJustin T. Gibbs } 30548b8a9b1dSJustin T. Gibbs 30558b8a9b1dSJustin T. Gibbs /* 30568b8a9b1dSJustin T. Gibbs * Schedule a peripheral driver to receive a ccb when it's 30578b8a9b1dSJustin T. Gibbs * target device has space for more transactions. 30588b8a9b1dSJustin T. Gibbs */ 30598b8a9b1dSJustin T. Gibbs void 30608b8a9b1dSJustin T. Gibbs xpt_schedule(struct cam_periph *perph, u_int32_t new_priority) 30618b8a9b1dSJustin T. Gibbs { 30628b8a9b1dSJustin T. Gibbs struct cam_ed *device; 306383c5d981SAlexander Motin int runq = 0; 30648b8a9b1dSJustin T. Gibbs 30652b83592fSScott Long mtx_assert(perph->sim->mtx, MA_OWNED); 306668153f43SScott Long 30678b8a9b1dSJustin T. Gibbs CAM_DEBUG(perph->path, CAM_DEBUG_TRACE, ("xpt_schedule\n")); 30688b8a9b1dSJustin T. Gibbs device = perph->path->device; 30698b8a9b1dSJustin T. Gibbs if (periph_is_queued(perph)) { 30708b8a9b1dSJustin T. Gibbs /* Simply reorder based on new priority */ 30718b8a9b1dSJustin T. Gibbs CAM_DEBUG(perph->path, CAM_DEBUG_SUBTRACE, 30728b8a9b1dSJustin T. Gibbs (" change priority to %d\n", new_priority)); 30738b8a9b1dSJustin T. Gibbs if (new_priority < perph->pinfo.priority) { 30748b8a9b1dSJustin T. Gibbs camq_change_priority(&device->drvq, 30758b8a9b1dSJustin T. Gibbs perph->pinfo.index, 30768b8a9b1dSJustin T. Gibbs new_priority); 3077cccf4220SAlexander Motin runq = 1; 30788b8a9b1dSJustin T. Gibbs } 30798b8a9b1dSJustin T. Gibbs } else { 30808b8a9b1dSJustin T. Gibbs /* New entry on the queue */ 30818b8a9b1dSJustin T. Gibbs CAM_DEBUG(perph->path, CAM_DEBUG_SUBTRACE, 30828b8a9b1dSJustin T. Gibbs (" added periph to queue\n")); 30838b8a9b1dSJustin T. Gibbs perph->pinfo.priority = new_priority; 30848bad620dSJustin T. Gibbs perph->pinfo.generation = ++device->drvq.generation; 30858b8a9b1dSJustin T. Gibbs camq_insert(&device->drvq, &perph->pinfo); 3086cccf4220SAlexander Motin runq = 1; 30878b8a9b1dSJustin T. Gibbs } 30888b8a9b1dSJustin T. Gibbs if (runq != 0) { 30898b8a9b1dSJustin T. Gibbs CAM_DEBUG(perph->path, CAM_DEBUG_SUBTRACE, 3090cccf4220SAlexander Motin (" calling xpt_run_dev_allocq\n")); 3091cccf4220SAlexander Motin xpt_run_dev_allocq(device); 30928b8a9b1dSJustin T. Gibbs } 30938b8a9b1dSJustin T. Gibbs } 30948b8a9b1dSJustin T. Gibbs 30958b8a9b1dSJustin T. Gibbs 30968b8a9b1dSJustin T. Gibbs /* 30978b8a9b1dSJustin T. Gibbs * Schedule a device to run on a given queue. 30988b8a9b1dSJustin T. Gibbs * If the device was inserted as a new entry on the queue, 30998b8a9b1dSJustin T. Gibbs * return 1 meaning the device queue should be run. If we 31008b8a9b1dSJustin T. Gibbs * were already queued, implying someone else has already 31018b8a9b1dSJustin T. Gibbs * started the queue, return 0 so the caller doesn't attempt 310277dc25ccSScott Long * to run the queue. 31038b8a9b1dSJustin T. Gibbs */ 310452c9ce25SScott Long int 31058b8a9b1dSJustin T. Gibbs xpt_schedule_dev(struct camq *queue, cam_pinfo *pinfo, 31068b8a9b1dSJustin T. Gibbs u_int32_t new_priority) 31078b8a9b1dSJustin T. Gibbs { 31088b8a9b1dSJustin T. Gibbs int retval; 31098b8a9b1dSJustin T. Gibbs u_int32_t old_priority; 31108b8a9b1dSJustin T. Gibbs 3111aa872be6SMatt Jacob CAM_DEBUG_PRINT(CAM_DEBUG_XPT, ("xpt_schedule_dev\n")); 31128b8a9b1dSJustin T. Gibbs 31138b8a9b1dSJustin T. Gibbs old_priority = pinfo->priority; 31148b8a9b1dSJustin T. Gibbs 31158b8a9b1dSJustin T. Gibbs /* 31168b8a9b1dSJustin T. Gibbs * Are we already queued? 31178b8a9b1dSJustin T. Gibbs */ 31188b8a9b1dSJustin T. Gibbs if (pinfo->index != CAM_UNQUEUED_INDEX) { 31198b8a9b1dSJustin T. Gibbs /* Simply reorder based on new priority */ 31208b8a9b1dSJustin T. Gibbs if (new_priority < old_priority) { 31218b8a9b1dSJustin T. Gibbs camq_change_priority(queue, pinfo->index, 31228b8a9b1dSJustin T. Gibbs new_priority); 3123aa872be6SMatt Jacob CAM_DEBUG_PRINT(CAM_DEBUG_XPT, 31248b8a9b1dSJustin T. Gibbs ("changed priority to %d\n", 31258b8a9b1dSJustin T. Gibbs new_priority)); 312683c5d981SAlexander Motin retval = 1; 312783c5d981SAlexander Motin } else 31288b8a9b1dSJustin T. Gibbs retval = 0; 31298b8a9b1dSJustin T. Gibbs } else { 31308b8a9b1dSJustin T. Gibbs /* New entry on the queue */ 31318b8a9b1dSJustin T. Gibbs if (new_priority < old_priority) 31328b8a9b1dSJustin T. Gibbs pinfo->priority = new_priority; 31338b8a9b1dSJustin T. Gibbs 3134aa872be6SMatt Jacob CAM_DEBUG_PRINT(CAM_DEBUG_XPT, 31358b8a9b1dSJustin T. Gibbs ("Inserting onto queue\n")); 31368bad620dSJustin T. Gibbs pinfo->generation = ++queue->generation; 31378b8a9b1dSJustin T. Gibbs camq_insert(queue, pinfo); 31388b8a9b1dSJustin T. Gibbs retval = 1; 31398b8a9b1dSJustin T. Gibbs } 31408b8a9b1dSJustin T. Gibbs return (retval); 31418b8a9b1dSJustin T. Gibbs } 31428b8a9b1dSJustin T. Gibbs 31438b8a9b1dSJustin T. Gibbs static void 3144cccf4220SAlexander Motin xpt_run_dev_allocq(struct cam_ed *device) 31458b8a9b1dSJustin T. Gibbs { 31468b8a9b1dSJustin T. Gibbs struct camq *drvq; 31478b8a9b1dSJustin T. Gibbs 3148cccf4220SAlexander Motin if (device->ccbq.devq_allocating) 3149cccf4220SAlexander Motin return; 3150cccf4220SAlexander Motin device->ccbq.devq_allocating = 1; 3151cccf4220SAlexander Motin CAM_DEBUG_PRINT(CAM_DEBUG_XPT, ("xpt_run_dev_allocq(%p)\n", device)); 31528b8a9b1dSJustin T. Gibbs drvq = &device->drvq; 3153cccf4220SAlexander Motin while ((drvq->entries > 0) && 3154cccf4220SAlexander Motin (device->ccbq.devq_openings > 0 || 3155cccf4220SAlexander Motin CAMQ_GET_PRIO(drvq) <= CAM_PRIORITY_OOB) && 3156cccf4220SAlexander Motin (device->ccbq.queue.qfrozen_cnt == 0)) { 3157cccf4220SAlexander Motin union ccb *work_ccb; 3158cccf4220SAlexander Motin struct cam_periph *drv; 3159cccf4220SAlexander Motin 31602d89c125SAlexander Motin KASSERT(drvq->entries > 0, ("xpt_run_dev_allocq: " 31612d89c125SAlexander Motin "Device on queue without any work to do")); 31628b8a9b1dSJustin T. Gibbs if ((work_ccb = xpt_get_ccb(device)) != NULL) { 31635a526431SJustin T. Gibbs drv = (struct cam_periph*)camq_remove(drvq, CAMQ_HEAD); 31648b8a9b1dSJustin T. Gibbs xpt_setup_ccb(&work_ccb->ccb_h, drv->path, 31658b8a9b1dSJustin T. Gibbs drv->pinfo.priority); 3166aa872be6SMatt Jacob CAM_DEBUG_PRINT(CAM_DEBUG_XPT, 31678b8a9b1dSJustin T. Gibbs ("calling periph start\n")); 31688b8a9b1dSJustin T. Gibbs drv->periph_start(drv, work_ccb); 31698b8a9b1dSJustin T. Gibbs } else { 31708b8a9b1dSJustin T. Gibbs /* 31718b8a9b1dSJustin T. Gibbs * Malloc failure in alloc_ccb 31728b8a9b1dSJustin T. Gibbs */ 31738b8a9b1dSJustin T. Gibbs /* 31748b8a9b1dSJustin T. Gibbs * XXX add us to a list to be run from free_ccb 31758b8a9b1dSJustin T. Gibbs * if we don't have any ccbs active on this 31768b8a9b1dSJustin T. Gibbs * device queue otherwise we may never get run 31778b8a9b1dSJustin T. Gibbs * again. 31788b8a9b1dSJustin T. Gibbs */ 31798b8a9b1dSJustin T. Gibbs break; 31808b8a9b1dSJustin T. Gibbs } 31818b8a9b1dSJustin T. Gibbs } 3182cccf4220SAlexander Motin device->ccbq.devq_allocating = 0; 31838b8a9b1dSJustin T. Gibbs } 31848b8a9b1dSJustin T. Gibbs 318583c5d981SAlexander Motin static void 3186cccf4220SAlexander Motin xpt_run_devq(struct cam_devq *devq) 31878b8a9b1dSJustin T. Gibbs { 3188de9ebb68SAlexander Motin char cdb_str[(SCSI_MAX_CDBLEN * 3) + 1]; 31898b8a9b1dSJustin T. Gibbs 3190cccf4220SAlexander Motin CAM_DEBUG_PRINT(CAM_DEBUG_XPT, ("xpt_run_devq\n")); 31918b8a9b1dSJustin T. Gibbs 3192cccf4220SAlexander Motin devq->send_queue.qfrozen_cnt++; 31938b8a9b1dSJustin T. Gibbs while ((devq->send_queue.entries > 0) 3194ec700f26SAlexander Motin && (devq->send_openings > 0) 3195cccf4220SAlexander Motin && (devq->send_queue.qfrozen_cnt <= 1)) { 31968b8a9b1dSJustin T. Gibbs struct cam_ed_qinfo *qinfo; 31978b8a9b1dSJustin T. Gibbs struct cam_ed *device; 31988b8a9b1dSJustin T. Gibbs union ccb *work_ccb; 31998b8a9b1dSJustin T. Gibbs struct cam_sim *sim; 32008b8a9b1dSJustin T. Gibbs 32018b8a9b1dSJustin T. Gibbs qinfo = (struct cam_ed_qinfo *)camq_remove(&devq->send_queue, 32025a526431SJustin T. Gibbs CAMQ_HEAD); 32038b8a9b1dSJustin T. Gibbs device = qinfo->device; 3204aa872be6SMatt Jacob CAM_DEBUG_PRINT(CAM_DEBUG_XPT, 320550642f18SKenneth D. Merry ("running device %p\n", device)); 32068b8a9b1dSJustin T. Gibbs 32075a526431SJustin T. Gibbs work_ccb = cam_ccbq_peek_ccb(&device->ccbq, CAMQ_HEAD); 32088b8a9b1dSJustin T. Gibbs if (work_ccb == NULL) { 320957b89bbcSNate Lawson printf("device on run queue with no ccbs???\n"); 32108b8a9b1dSJustin T. Gibbs continue; 32118b8a9b1dSJustin T. Gibbs } 32128b8a9b1dSJustin T. Gibbs 32138b8a9b1dSJustin T. Gibbs if ((work_ccb->ccb_h.flags & CAM_HIGH_POWER) != 0) { 32148b8a9b1dSJustin T. Gibbs 32152b83592fSScott Long mtx_lock(&xsoftc.xpt_lock); 32162b83592fSScott Long if (xsoftc.num_highpower <= 0) { 32178b8a9b1dSJustin T. Gibbs /* 32188b8a9b1dSJustin T. Gibbs * We got a high power command, but we 32198b8a9b1dSJustin T. Gibbs * don't have any available slots. Freeze 32208b8a9b1dSJustin T. Gibbs * the device queue until we have a slot 32218b8a9b1dSJustin T. Gibbs * available. 32228b8a9b1dSJustin T. Gibbs */ 322383c5d981SAlexander Motin xpt_freeze_devq(work_ccb->ccb_h.path, 1); 32242b83592fSScott Long STAILQ_INSERT_TAIL(&xsoftc.highpowerq, 3225ea541bfdSAlexander Motin work_ccb->ccb_h.path->device, 3226ea541bfdSAlexander Motin highpowerq_entry); 32278b8a9b1dSJustin T. Gibbs 3228469f9f44SScott Long mtx_unlock(&xsoftc.xpt_lock); 32298b8a9b1dSJustin T. Gibbs continue; 32308b8a9b1dSJustin T. Gibbs } else { 32318b8a9b1dSJustin T. Gibbs /* 32328b8a9b1dSJustin T. Gibbs * Consume a high power slot while 32338b8a9b1dSJustin T. Gibbs * this ccb runs. 32348b8a9b1dSJustin T. Gibbs */ 32352b83592fSScott Long xsoftc.num_highpower--; 32368b8a9b1dSJustin T. Gibbs } 32372b83592fSScott Long mtx_unlock(&xsoftc.xpt_lock); 32388b8a9b1dSJustin T. Gibbs } 32398b8a9b1dSJustin T. Gibbs cam_ccbq_remove_ccb(&device->ccbq, work_ccb); 32408b8a9b1dSJustin T. Gibbs cam_ccbq_send_ccb(&device->ccbq, work_ccb); 32418b8a9b1dSJustin T. Gibbs 32428b8a9b1dSJustin T. Gibbs devq->send_openings--; 32438b8a9b1dSJustin T. Gibbs devq->send_active++; 32448b8a9b1dSJustin T. Gibbs 3245cccf4220SAlexander Motin xpt_schedule_devq(devq, device); 32468b8a9b1dSJustin T. Gibbs 3247cccf4220SAlexander Motin if ((work_ccb->ccb_h.flags & CAM_DEV_QFREEZE) != 0) { 32488b8a9b1dSJustin T. Gibbs /* 32498b8a9b1dSJustin T. Gibbs * The client wants to freeze the queue 32508b8a9b1dSJustin T. Gibbs * after this CCB is sent. 32518b8a9b1dSJustin T. Gibbs */ 325283c5d981SAlexander Motin xpt_freeze_devq(work_ccb->ccb_h.path, 1); 32538b8a9b1dSJustin T. Gibbs } 32548b8a9b1dSJustin T. Gibbs 3255a4eb4f16SMatt Jacob /* In Target mode, the peripheral driver knows best... */ 3256a4eb4f16SMatt Jacob if (work_ccb->ccb_h.func_code == XPT_SCSI_IO) { 3257a4eb4f16SMatt Jacob if ((device->inq_flags & SID_CmdQue) != 0 3258a4eb4f16SMatt Jacob && work_ccb->csio.tag_action != CAM_TAG_ACTION_NONE) 32598b8a9b1dSJustin T. Gibbs work_ccb->ccb_h.flags |= CAM_TAG_ACTION_VALID; 32608b8a9b1dSJustin T. Gibbs else 32618b8a9b1dSJustin T. Gibbs /* 3262a4eb4f16SMatt Jacob * Clear this in case of a retried CCB that 3263a4eb4f16SMatt Jacob * failed due to a rejected tag. 32648b8a9b1dSJustin T. Gibbs */ 32658b8a9b1dSJustin T. Gibbs work_ccb->ccb_h.flags &= ~CAM_TAG_ACTION_VALID; 3266a4eb4f16SMatt Jacob } 32678b8a9b1dSJustin T. Gibbs 3268de9ebb68SAlexander Motin switch (work_ccb->ccb_h.func_code) { 3269de9ebb68SAlexander Motin case XPT_SCSI_IO: 3270de9ebb68SAlexander Motin CAM_DEBUG(work_ccb->ccb_h.path, 3271de9ebb68SAlexander Motin CAM_DEBUG_CDB,("%s. CDB: %s\n", 3272de9ebb68SAlexander Motin scsi_op_desc(work_ccb->csio.cdb_io.cdb_bytes[0], 3273de9ebb68SAlexander Motin &device->inq_data), 3274de9ebb68SAlexander Motin scsi_cdb_string(work_ccb->csio.cdb_io.cdb_bytes, 3275de9ebb68SAlexander Motin cdb_str, sizeof(cdb_str)))); 3276de9ebb68SAlexander Motin break; 3277de9ebb68SAlexander Motin case XPT_ATA_IO: 3278de9ebb68SAlexander Motin CAM_DEBUG(work_ccb->ccb_h.path, 3279de9ebb68SAlexander Motin CAM_DEBUG_CDB,("%s. ACB: %s\n", 3280de9ebb68SAlexander Motin ata_op_string(&work_ccb->ataio.cmd), 3281de9ebb68SAlexander Motin ata_cmd_string(&work_ccb->ataio.cmd, 3282de9ebb68SAlexander Motin cdb_str, sizeof(cdb_str)))); 3283de9ebb68SAlexander Motin break; 3284de9ebb68SAlexander Motin default: 3285de9ebb68SAlexander Motin break; 3286de9ebb68SAlexander Motin } 3287de9ebb68SAlexander Motin 32888b8a9b1dSJustin T. Gibbs /* 32898b8a9b1dSJustin T. Gibbs * Device queues can be shared among multiple sim instances 32908b8a9b1dSJustin T. Gibbs * that reside on different busses. Use the SIM in the queue 32918b8a9b1dSJustin T. Gibbs * CCB's path, rather than the one in the bus that was passed 32928b8a9b1dSJustin T. Gibbs * into this function. 32938b8a9b1dSJustin T. Gibbs */ 32948b8a9b1dSJustin T. Gibbs sim = work_ccb->ccb_h.path->bus->sim; 32958b8a9b1dSJustin T. Gibbs (*(sim->sim_action))(sim, work_ccb); 32968b8a9b1dSJustin T. Gibbs } 3297cccf4220SAlexander Motin devq->send_queue.qfrozen_cnt--; 32988b8a9b1dSJustin T. Gibbs } 32998b8a9b1dSJustin T. Gibbs 33008b8a9b1dSJustin T. Gibbs /* 33018b8a9b1dSJustin T. Gibbs * This function merges stuff from the slave ccb into the master ccb, while 33028b8a9b1dSJustin T. Gibbs * keeping important fields in the master ccb constant. 33038b8a9b1dSJustin T. Gibbs */ 33048b8a9b1dSJustin T. Gibbs void 33058b8a9b1dSJustin T. Gibbs xpt_merge_ccb(union ccb *master_ccb, union ccb *slave_ccb) 33068b8a9b1dSJustin T. Gibbs { 330768153f43SScott Long 33088b8a9b1dSJustin T. Gibbs /* 33098b8a9b1dSJustin T. Gibbs * Pull fields that are valid for peripheral drivers to set 33108b8a9b1dSJustin T. Gibbs * into the master CCB along with the CCB "payload". 33118b8a9b1dSJustin T. Gibbs */ 33128b8a9b1dSJustin T. Gibbs master_ccb->ccb_h.retry_count = slave_ccb->ccb_h.retry_count; 33138b8a9b1dSJustin T. Gibbs master_ccb->ccb_h.func_code = slave_ccb->ccb_h.func_code; 33148b8a9b1dSJustin T. Gibbs master_ccb->ccb_h.timeout = slave_ccb->ccb_h.timeout; 33158b8a9b1dSJustin T. Gibbs master_ccb->ccb_h.flags = slave_ccb->ccb_h.flags; 33168b8a9b1dSJustin T. Gibbs bcopy(&(&slave_ccb->ccb_h)[1], &(&master_ccb->ccb_h)[1], 33178b8a9b1dSJustin T. Gibbs sizeof(union ccb) - sizeof(struct ccb_hdr)); 33188b8a9b1dSJustin T. Gibbs } 33198b8a9b1dSJustin T. Gibbs 33208b8a9b1dSJustin T. Gibbs void 33218b8a9b1dSJustin T. Gibbs xpt_setup_ccb(struct ccb_hdr *ccb_h, struct cam_path *path, u_int32_t priority) 33228b8a9b1dSJustin T. Gibbs { 332368153f43SScott Long 33248b8a9b1dSJustin T. Gibbs CAM_DEBUG(path, CAM_DEBUG_TRACE, ("xpt_setup_ccb\n")); 33258b8a9b1dSJustin T. Gibbs ccb_h->pinfo.priority = priority; 33268b8a9b1dSJustin T. Gibbs ccb_h->path = path; 33278b8a9b1dSJustin T. Gibbs ccb_h->path_id = path->bus->path_id; 33288b8a9b1dSJustin T. Gibbs if (path->target) 33298b8a9b1dSJustin T. Gibbs ccb_h->target_id = path->target->target_id; 33308b8a9b1dSJustin T. Gibbs else 33318b8a9b1dSJustin T. Gibbs ccb_h->target_id = CAM_TARGET_WILDCARD; 33328b8a9b1dSJustin T. Gibbs if (path->device) { 33338b8a9b1dSJustin T. Gibbs ccb_h->target_lun = path->device->lun_id; 33348bad620dSJustin T. Gibbs ccb_h->pinfo.generation = ++path->device->ccbq.queue.generation; 33358b8a9b1dSJustin T. Gibbs } else { 33368b8a9b1dSJustin T. Gibbs ccb_h->target_lun = CAM_TARGET_WILDCARD; 33378b8a9b1dSJustin T. Gibbs } 33388b8a9b1dSJustin T. Gibbs ccb_h->pinfo.index = CAM_UNQUEUED_INDEX; 33398b8a9b1dSJustin T. Gibbs ccb_h->flags = 0; 3340*b5595753SNathan Whitehorn ccb_h->xflags = 0; 33418b8a9b1dSJustin T. Gibbs } 33428b8a9b1dSJustin T. Gibbs 33438b8a9b1dSJustin T. Gibbs /* Path manipulation functions */ 33448b8a9b1dSJustin T. Gibbs cam_status 33458b8a9b1dSJustin T. Gibbs xpt_create_path(struct cam_path **new_path_ptr, struct cam_periph *perph, 33468b8a9b1dSJustin T. Gibbs path_id_t path_id, target_id_t target_id, lun_id_t lun_id) 33478b8a9b1dSJustin T. Gibbs { 33488b8a9b1dSJustin T. Gibbs struct cam_path *path; 33498b8a9b1dSJustin T. Gibbs cam_status status; 33508b8a9b1dSJustin T. Gibbs 3351596ee08fSAlexander Motin path = (struct cam_path *)malloc(sizeof(*path), M_CAMPATH, M_NOWAIT); 33528b8a9b1dSJustin T. Gibbs 33538b8a9b1dSJustin T. Gibbs if (path == NULL) { 33548b8a9b1dSJustin T. Gibbs status = CAM_RESRC_UNAVAIL; 33558b8a9b1dSJustin T. Gibbs return(status); 33568b8a9b1dSJustin T. Gibbs } 33578b8a9b1dSJustin T. Gibbs status = xpt_compile_path(path, perph, path_id, target_id, lun_id); 33588b8a9b1dSJustin T. Gibbs if (status != CAM_REQ_CMP) { 3359596ee08fSAlexander Motin free(path, M_CAMPATH); 33608b8a9b1dSJustin T. Gibbs path = NULL; 33618b8a9b1dSJustin T. Gibbs } 33628b8a9b1dSJustin T. Gibbs *new_path_ptr = path; 33638b8a9b1dSJustin T. Gibbs return (status); 33648b8a9b1dSJustin T. Gibbs } 33658b8a9b1dSJustin T. Gibbs 33662b83592fSScott Long cam_status 33672b83592fSScott Long xpt_create_path_unlocked(struct cam_path **new_path_ptr, 33682b83592fSScott Long struct cam_periph *periph, path_id_t path_id, 33692b83592fSScott Long target_id_t target_id, lun_id_t lun_id) 33702b83592fSScott Long { 33712b83592fSScott Long struct cam_path *path; 33722b83592fSScott Long struct cam_eb *bus = NULL; 33732b83592fSScott Long cam_status status; 33742b83592fSScott Long 3375596ee08fSAlexander Motin path = (struct cam_path *)malloc(sizeof(*path), M_CAMPATH, M_WAITOK); 33762b83592fSScott Long 33772b83592fSScott Long bus = xpt_find_bus(path_id); 33789bccc7a9SAlexander Motin if (bus != NULL) 337911e4faceSScott Long CAM_SIM_LOCK(bus->sim); 33802b83592fSScott Long status = xpt_compile_path(path, periph, path_id, target_id, lun_id); 33819bccc7a9SAlexander Motin if (bus != NULL) { 338211e4faceSScott Long CAM_SIM_UNLOCK(bus->sim); 338315975b7bSMatt Jacob xpt_release_bus(bus); 338415975b7bSMatt Jacob } 33852b83592fSScott Long if (status != CAM_REQ_CMP) { 3386596ee08fSAlexander Motin free(path, M_CAMPATH); 33872b83592fSScott Long path = NULL; 33882b83592fSScott Long } 33892b83592fSScott Long *new_path_ptr = path; 33902b83592fSScott Long return (status); 33912b83592fSScott Long } 33922b83592fSScott Long 339352c9ce25SScott Long cam_status 33948b8a9b1dSJustin T. Gibbs xpt_compile_path(struct cam_path *new_path, struct cam_periph *perph, 33958b8a9b1dSJustin T. Gibbs path_id_t path_id, target_id_t target_id, lun_id_t lun_id) 33968b8a9b1dSJustin T. Gibbs { 33978b8a9b1dSJustin T. Gibbs struct cam_eb *bus; 33988b8a9b1dSJustin T. Gibbs struct cam_et *target; 33998b8a9b1dSJustin T. Gibbs struct cam_ed *device; 34008b8a9b1dSJustin T. Gibbs cam_status status; 34018b8a9b1dSJustin T. Gibbs 34028b8a9b1dSJustin T. Gibbs status = CAM_REQ_CMP; /* Completed without error */ 34038b8a9b1dSJustin T. Gibbs target = NULL; /* Wildcarded */ 34048b8a9b1dSJustin T. Gibbs device = NULL; /* Wildcarded */ 3405a5479bc5SJustin T. Gibbs 3406a5479bc5SJustin T. Gibbs /* 3407a5479bc5SJustin T. Gibbs * We will potentially modify the EDT, so block interrupts 3408a5479bc5SJustin T. Gibbs * that may attempt to create cam paths. 3409a5479bc5SJustin T. Gibbs */ 34108b8a9b1dSJustin T. Gibbs bus = xpt_find_bus(path_id); 34118b8a9b1dSJustin T. Gibbs if (bus == NULL) { 34128b8a9b1dSJustin T. Gibbs status = CAM_PATH_INVALID; 3413c8bead2aSJustin T. Gibbs } else { 34148b8a9b1dSJustin T. Gibbs target = xpt_find_target(bus, target_id); 34158b8a9b1dSJustin T. Gibbs if (target == NULL) { 34168b8a9b1dSJustin T. Gibbs /* Create one */ 34178b8a9b1dSJustin T. Gibbs struct cam_et *new_target; 34188b8a9b1dSJustin T. Gibbs 34198b8a9b1dSJustin T. Gibbs new_target = xpt_alloc_target(bus, target_id); 34208b8a9b1dSJustin T. Gibbs if (new_target == NULL) { 34218b8a9b1dSJustin T. Gibbs status = CAM_RESRC_UNAVAIL; 34228b8a9b1dSJustin T. Gibbs } else { 34238b8a9b1dSJustin T. Gibbs target = new_target; 34248b8a9b1dSJustin T. Gibbs } 34258b8a9b1dSJustin T. Gibbs } 3426c8bead2aSJustin T. Gibbs if (target != NULL) { 34278b8a9b1dSJustin T. Gibbs device = xpt_find_device(target, lun_id); 34288b8a9b1dSJustin T. Gibbs if (device == NULL) { 34298b8a9b1dSJustin T. Gibbs /* Create one */ 34308b8a9b1dSJustin T. Gibbs struct cam_ed *new_device; 34318b8a9b1dSJustin T. Gibbs 343252c9ce25SScott Long new_device = 343352c9ce25SScott Long (*(bus->xport->alloc_device))(bus, 34348b8a9b1dSJustin T. Gibbs target, 34358b8a9b1dSJustin T. Gibbs lun_id); 34368b8a9b1dSJustin T. Gibbs if (new_device == NULL) { 34378b8a9b1dSJustin T. Gibbs status = CAM_RESRC_UNAVAIL; 34388b8a9b1dSJustin T. Gibbs } else { 34398b8a9b1dSJustin T. Gibbs device = new_device; 34408b8a9b1dSJustin T. Gibbs } 34418b8a9b1dSJustin T. Gibbs } 34428b8a9b1dSJustin T. Gibbs } 34438b8a9b1dSJustin T. Gibbs } 34448b8a9b1dSJustin T. Gibbs 34458b8a9b1dSJustin T. Gibbs /* 34468b8a9b1dSJustin T. Gibbs * Only touch the user's data if we are successful. 34478b8a9b1dSJustin T. Gibbs */ 34488b8a9b1dSJustin T. Gibbs if (status == CAM_REQ_CMP) { 34498b8a9b1dSJustin T. Gibbs new_path->periph = perph; 34508b8a9b1dSJustin T. Gibbs new_path->bus = bus; 34518b8a9b1dSJustin T. Gibbs new_path->target = target; 34528b8a9b1dSJustin T. Gibbs new_path->device = device; 34538b8a9b1dSJustin T. Gibbs CAM_DEBUG(new_path, CAM_DEBUG_TRACE, ("xpt_compile_path\n")); 34548b8a9b1dSJustin T. Gibbs } else { 34558b8a9b1dSJustin T. Gibbs if (device != NULL) 3456f98d7a47SAlexander Motin xpt_release_device(device); 34578b8a9b1dSJustin T. Gibbs if (target != NULL) 3458f98d7a47SAlexander Motin xpt_release_target(target); 3459a5479bc5SJustin T. Gibbs if (bus != NULL) 3460a5479bc5SJustin T. Gibbs xpt_release_bus(bus); 34618b8a9b1dSJustin T. Gibbs } 34628b8a9b1dSJustin T. Gibbs return (status); 34638b8a9b1dSJustin T. Gibbs } 34648b8a9b1dSJustin T. Gibbs 346552c9ce25SScott Long void 34668b8a9b1dSJustin T. Gibbs xpt_release_path(struct cam_path *path) 34678b8a9b1dSJustin T. Gibbs { 34688b8a9b1dSJustin T. Gibbs CAM_DEBUG(path, CAM_DEBUG_TRACE, ("xpt_release_path\n")); 34699dd03ecfSJustin T. Gibbs if (path->device != NULL) { 3470f98d7a47SAlexander Motin xpt_release_device(path->device); 34719dd03ecfSJustin T. Gibbs path->device = NULL; 34729dd03ecfSJustin T. Gibbs } 34739dd03ecfSJustin T. Gibbs if (path->target != NULL) { 3474f98d7a47SAlexander Motin xpt_release_target(path->target); 34759dd03ecfSJustin T. Gibbs path->target = NULL; 34769dd03ecfSJustin T. Gibbs } 34779dd03ecfSJustin T. Gibbs if (path->bus != NULL) { 34789dd03ecfSJustin T. Gibbs xpt_release_bus(path->bus); 34799dd03ecfSJustin T. Gibbs path->bus = NULL; 34809dd03ecfSJustin T. Gibbs } 34818b8a9b1dSJustin T. Gibbs } 34828b8a9b1dSJustin T. Gibbs 34838b8a9b1dSJustin T. Gibbs void 34848b8a9b1dSJustin T. Gibbs xpt_free_path(struct cam_path *path) 34858b8a9b1dSJustin T. Gibbs { 348668153f43SScott Long 34878b8a9b1dSJustin T. Gibbs CAM_DEBUG(path, CAM_DEBUG_TRACE, ("xpt_free_path\n")); 34888b8a9b1dSJustin T. Gibbs xpt_release_path(path); 3489596ee08fSAlexander Motin free(path, M_CAMPATH); 34908b8a9b1dSJustin T. Gibbs } 34918b8a9b1dSJustin T. Gibbs 349215975b7bSMatt Jacob void 349315975b7bSMatt Jacob xpt_path_counts(struct cam_path *path, uint32_t *bus_ref, 349415975b7bSMatt Jacob uint32_t *periph_ref, uint32_t *target_ref, uint32_t *device_ref) 349515975b7bSMatt Jacob { 349615975b7bSMatt Jacob 34979a7c2696SAlexander Motin xpt_lock_buses(); 349815975b7bSMatt Jacob if (bus_ref) { 349915975b7bSMatt Jacob if (path->bus) 350015975b7bSMatt Jacob *bus_ref = path->bus->refcount; 350115975b7bSMatt Jacob else 350215975b7bSMatt Jacob *bus_ref = 0; 350315975b7bSMatt Jacob } 350415975b7bSMatt Jacob if (periph_ref) { 350515975b7bSMatt Jacob if (path->periph) 350615975b7bSMatt Jacob *periph_ref = path->periph->refcount; 350715975b7bSMatt Jacob else 350815975b7bSMatt Jacob *periph_ref = 0; 350915975b7bSMatt Jacob } 3510dcdf6e74SAlexander Motin xpt_unlock_buses(); 351115975b7bSMatt Jacob if (target_ref) { 351215975b7bSMatt Jacob if (path->target) 351315975b7bSMatt Jacob *target_ref = path->target->refcount; 351415975b7bSMatt Jacob else 351515975b7bSMatt Jacob *target_ref = 0; 351615975b7bSMatt Jacob } 351715975b7bSMatt Jacob if (device_ref) { 351815975b7bSMatt Jacob if (path->device) 351915975b7bSMatt Jacob *device_ref = path->device->refcount; 352015975b7bSMatt Jacob else 352115975b7bSMatt Jacob *device_ref = 0; 352215975b7bSMatt Jacob } 352315975b7bSMatt Jacob } 35248b8a9b1dSJustin T. Gibbs 35258b8a9b1dSJustin T. Gibbs /* 35262cefde5fSJustin T. Gibbs * Return -1 for failure, 0 for exact match, 1 for match with wildcards 35272cefde5fSJustin T. Gibbs * in path1, 2 for match with wildcards in path2. 35288b8a9b1dSJustin T. Gibbs */ 35298b8a9b1dSJustin T. Gibbs int 35308b8a9b1dSJustin T. Gibbs xpt_path_comp(struct cam_path *path1, struct cam_path *path2) 35318b8a9b1dSJustin T. Gibbs { 35328b8a9b1dSJustin T. Gibbs int retval = 0; 35338b8a9b1dSJustin T. Gibbs 35348b8a9b1dSJustin T. Gibbs if (path1->bus != path2->bus) { 35352cefde5fSJustin T. Gibbs if (path1->bus->path_id == CAM_BUS_WILDCARD) 35368b8a9b1dSJustin T. Gibbs retval = 1; 35372cefde5fSJustin T. Gibbs else if (path2->bus->path_id == CAM_BUS_WILDCARD) 35382cefde5fSJustin T. Gibbs retval = 2; 35398b8a9b1dSJustin T. Gibbs else 35408b8a9b1dSJustin T. Gibbs return (-1); 35418b8a9b1dSJustin T. Gibbs } 35428b8a9b1dSJustin T. Gibbs if (path1->target != path2->target) { 35432cefde5fSJustin T. Gibbs if (path1->target->target_id == CAM_TARGET_WILDCARD) { 35442cefde5fSJustin T. Gibbs if (retval == 0) 35458b8a9b1dSJustin T. Gibbs retval = 1; 35462cefde5fSJustin T. Gibbs } else if (path2->target->target_id == CAM_TARGET_WILDCARD) 35472cefde5fSJustin T. Gibbs retval = 2; 35488b8a9b1dSJustin T. Gibbs else 35498b8a9b1dSJustin T. Gibbs return (-1); 35508b8a9b1dSJustin T. Gibbs } 35518b8a9b1dSJustin T. Gibbs if (path1->device != path2->device) { 35522cefde5fSJustin T. Gibbs if (path1->device->lun_id == CAM_LUN_WILDCARD) { 35532cefde5fSJustin T. Gibbs if (retval == 0) 35548b8a9b1dSJustin T. Gibbs retval = 1; 35552cefde5fSJustin T. Gibbs } else if (path2->device->lun_id == CAM_LUN_WILDCARD) 35562cefde5fSJustin T. Gibbs retval = 2; 35578b8a9b1dSJustin T. Gibbs else 35588b8a9b1dSJustin T. Gibbs return (-1); 35598b8a9b1dSJustin T. Gibbs } 35608b8a9b1dSJustin T. Gibbs return (retval); 35618b8a9b1dSJustin T. Gibbs } 35628b8a9b1dSJustin T. Gibbs 35630d4f3c31SAlexander Motin int 35640d4f3c31SAlexander Motin xpt_path_comp_dev(struct cam_path *path, struct cam_ed *dev) 35650d4f3c31SAlexander Motin { 35660d4f3c31SAlexander Motin int retval = 0; 35670d4f3c31SAlexander Motin 35680d4f3c31SAlexander Motin if (path->bus != dev->target->bus) { 35690d4f3c31SAlexander Motin if (path->bus->path_id == CAM_BUS_WILDCARD) 35700d4f3c31SAlexander Motin retval = 1; 35710d4f3c31SAlexander Motin else if (dev->target->bus->path_id == CAM_BUS_WILDCARD) 35720d4f3c31SAlexander Motin retval = 2; 35730d4f3c31SAlexander Motin else 35740d4f3c31SAlexander Motin return (-1); 35750d4f3c31SAlexander Motin } 35760d4f3c31SAlexander Motin if (path->target != dev->target) { 35770d4f3c31SAlexander Motin if (path->target->target_id == CAM_TARGET_WILDCARD) { 35780d4f3c31SAlexander Motin if (retval == 0) 35790d4f3c31SAlexander Motin retval = 1; 35800d4f3c31SAlexander Motin } else if (dev->target->target_id == CAM_TARGET_WILDCARD) 35810d4f3c31SAlexander Motin retval = 2; 35820d4f3c31SAlexander Motin else 35830d4f3c31SAlexander Motin return (-1); 35840d4f3c31SAlexander Motin } 35850d4f3c31SAlexander Motin if (path->device != dev) { 35860d4f3c31SAlexander Motin if (path->device->lun_id == CAM_LUN_WILDCARD) { 35870d4f3c31SAlexander Motin if (retval == 0) 35880d4f3c31SAlexander Motin retval = 1; 35890d4f3c31SAlexander Motin } else if (dev->lun_id == CAM_LUN_WILDCARD) 35900d4f3c31SAlexander Motin retval = 2; 35910d4f3c31SAlexander Motin else 35920d4f3c31SAlexander Motin return (-1); 35930d4f3c31SAlexander Motin } 35940d4f3c31SAlexander Motin return (retval); 35950d4f3c31SAlexander Motin } 35960d4f3c31SAlexander Motin 35978b8a9b1dSJustin T. Gibbs void 35988b8a9b1dSJustin T. Gibbs xpt_print_path(struct cam_path *path) 35998b8a9b1dSJustin T. Gibbs { 360068153f43SScott Long 36018b8a9b1dSJustin T. Gibbs if (path == NULL) 36028b8a9b1dSJustin T. Gibbs printf("(nopath): "); 36038b8a9b1dSJustin T. Gibbs else { 36048b8a9b1dSJustin T. Gibbs if (path->periph != NULL) 36058b8a9b1dSJustin T. Gibbs printf("(%s%d:", path->periph->periph_name, 36068b8a9b1dSJustin T. Gibbs path->periph->unit_number); 36078b8a9b1dSJustin T. Gibbs else 36088b8a9b1dSJustin T. Gibbs printf("(noperiph:"); 36098b8a9b1dSJustin T. Gibbs 36108b8a9b1dSJustin T. Gibbs if (path->bus != NULL) 36118b8a9b1dSJustin T. Gibbs printf("%s%d:%d:", path->bus->sim->sim_name, 36128b8a9b1dSJustin T. Gibbs path->bus->sim->unit_number, 36138b8a9b1dSJustin T. Gibbs path->bus->sim->bus_id); 36148b8a9b1dSJustin T. Gibbs else 36158b8a9b1dSJustin T. Gibbs printf("nobus:"); 36168b8a9b1dSJustin T. Gibbs 36178b8a9b1dSJustin T. Gibbs if (path->target != NULL) 36188b8a9b1dSJustin T. Gibbs printf("%d:", path->target->target_id); 36198b8a9b1dSJustin T. Gibbs else 36208b8a9b1dSJustin T. Gibbs printf("X:"); 36218b8a9b1dSJustin T. Gibbs 36228b8a9b1dSJustin T. Gibbs if (path->device != NULL) 36238b8a9b1dSJustin T. Gibbs printf("%d): ", path->device->lun_id); 36248b8a9b1dSJustin T. Gibbs else 36258b8a9b1dSJustin T. Gibbs printf("X): "); 36268b8a9b1dSJustin T. Gibbs } 36278b8a9b1dSJustin T. Gibbs } 36288b8a9b1dSJustin T. Gibbs 3629f0d9af51SMatt Jacob void 36300d4f3c31SAlexander Motin xpt_print_device(struct cam_ed *device) 36310d4f3c31SAlexander Motin { 36320d4f3c31SAlexander Motin 36330d4f3c31SAlexander Motin if (device == NULL) 36340d4f3c31SAlexander Motin printf("(nopath): "); 36350d4f3c31SAlexander Motin else { 36360d4f3c31SAlexander Motin printf("(noperiph:%s%d:%d:%d:%d): ", device->sim->sim_name, 36370d4f3c31SAlexander Motin device->sim->unit_number, 36380d4f3c31SAlexander Motin device->sim->bus_id, 36390d4f3c31SAlexander Motin device->target->target_id, 36400d4f3c31SAlexander Motin device->lun_id); 36410d4f3c31SAlexander Motin } 36420d4f3c31SAlexander Motin } 36430d4f3c31SAlexander Motin 36440d4f3c31SAlexander Motin void 3645f0d9af51SMatt Jacob xpt_print(struct cam_path *path, const char *fmt, ...) 3646f0d9af51SMatt Jacob { 3647f0d9af51SMatt Jacob va_list ap; 3648f0d9af51SMatt Jacob xpt_print_path(path); 3649f0d9af51SMatt Jacob va_start(ap, fmt); 3650f0d9af51SMatt Jacob vprintf(fmt, ap); 3651f0d9af51SMatt Jacob va_end(ap); 3652f0d9af51SMatt Jacob } 3653f0d9af51SMatt Jacob 36543393f8daSKenneth D. Merry int 36553393f8daSKenneth D. Merry xpt_path_string(struct cam_path *path, char *str, size_t str_len) 36563393f8daSKenneth D. Merry { 36573393f8daSKenneth D. Merry struct sbuf sb; 36583393f8daSKenneth D. Merry 3659ac37e649SEdward Tomasz Napierala #ifdef INVARIANTS 3660a8d4700dSEdward Tomasz Napierala if (path != NULL && path->bus != NULL) 36612b83592fSScott Long mtx_assert(path->bus->sim->mtx, MA_OWNED); 3662ac37e649SEdward Tomasz Napierala #endif 366368153f43SScott Long 36643393f8daSKenneth D. Merry sbuf_new(&sb, str, str_len, 0); 36653393f8daSKenneth D. Merry 36663393f8daSKenneth D. Merry if (path == NULL) 36673393f8daSKenneth D. Merry sbuf_printf(&sb, "(nopath): "); 36683393f8daSKenneth D. Merry else { 36693393f8daSKenneth D. Merry if (path->periph != NULL) 36703393f8daSKenneth D. Merry sbuf_printf(&sb, "(%s%d:", path->periph->periph_name, 36713393f8daSKenneth D. Merry path->periph->unit_number); 36723393f8daSKenneth D. Merry else 36733393f8daSKenneth D. Merry sbuf_printf(&sb, "(noperiph:"); 36743393f8daSKenneth D. Merry 36753393f8daSKenneth D. Merry if (path->bus != NULL) 36763393f8daSKenneth D. Merry sbuf_printf(&sb, "%s%d:%d:", path->bus->sim->sim_name, 36773393f8daSKenneth D. Merry path->bus->sim->unit_number, 36783393f8daSKenneth D. Merry path->bus->sim->bus_id); 36793393f8daSKenneth D. Merry else 36803393f8daSKenneth D. Merry sbuf_printf(&sb, "nobus:"); 36813393f8daSKenneth D. Merry 36823393f8daSKenneth D. Merry if (path->target != NULL) 36833393f8daSKenneth D. Merry sbuf_printf(&sb, "%d:", path->target->target_id); 36843393f8daSKenneth D. Merry else 36853393f8daSKenneth D. Merry sbuf_printf(&sb, "X:"); 36863393f8daSKenneth D. Merry 36873393f8daSKenneth D. Merry if (path->device != NULL) 36883393f8daSKenneth D. Merry sbuf_printf(&sb, "%d): ", path->device->lun_id); 36893393f8daSKenneth D. Merry else 36903393f8daSKenneth D. Merry sbuf_printf(&sb, "X): "); 36913393f8daSKenneth D. Merry } 36923393f8daSKenneth D. Merry sbuf_finish(&sb); 36933393f8daSKenneth D. Merry 36943393f8daSKenneth D. Merry return(sbuf_len(&sb)); 36953393f8daSKenneth D. Merry } 36963393f8daSKenneth D. Merry 36978b8a9b1dSJustin T. Gibbs path_id_t 36988b8a9b1dSJustin T. Gibbs xpt_path_path_id(struct cam_path *path) 36998b8a9b1dSJustin T. Gibbs { 37008b8a9b1dSJustin T. Gibbs return(path->bus->path_id); 37018b8a9b1dSJustin T. Gibbs } 37028b8a9b1dSJustin T. Gibbs 37038b8a9b1dSJustin T. Gibbs target_id_t 37048b8a9b1dSJustin T. Gibbs xpt_path_target_id(struct cam_path *path) 37058b8a9b1dSJustin T. Gibbs { 37068b8a9b1dSJustin T. Gibbs if (path->target != NULL) 37078b8a9b1dSJustin T. Gibbs return (path->target->target_id); 37088b8a9b1dSJustin T. Gibbs else 37098b8a9b1dSJustin T. Gibbs return (CAM_TARGET_WILDCARD); 37108b8a9b1dSJustin T. Gibbs } 37118b8a9b1dSJustin T. Gibbs 37128b8a9b1dSJustin T. Gibbs lun_id_t 37138b8a9b1dSJustin T. Gibbs xpt_path_lun_id(struct cam_path *path) 37148b8a9b1dSJustin T. Gibbs { 37158b8a9b1dSJustin T. Gibbs if (path->device != NULL) 37168b8a9b1dSJustin T. Gibbs return (path->device->lun_id); 37178b8a9b1dSJustin T. Gibbs else 37188b8a9b1dSJustin T. Gibbs return (CAM_LUN_WILDCARD); 37198b8a9b1dSJustin T. Gibbs } 37208b8a9b1dSJustin T. Gibbs 37218b8a9b1dSJustin T. Gibbs struct cam_sim * 37228b8a9b1dSJustin T. Gibbs xpt_path_sim(struct cam_path *path) 37238b8a9b1dSJustin T. Gibbs { 372468153f43SScott Long 37258b8a9b1dSJustin T. Gibbs return (path->bus->sim); 37268b8a9b1dSJustin T. Gibbs } 37278b8a9b1dSJustin T. Gibbs 37288b8a9b1dSJustin T. Gibbs struct cam_periph* 37298b8a9b1dSJustin T. Gibbs xpt_path_periph(struct cam_path *path) 37308b8a9b1dSJustin T. Gibbs { 37312b83592fSScott Long mtx_assert(path->bus->sim->mtx, MA_OWNED); 373268153f43SScott Long 37338b8a9b1dSJustin T. Gibbs return (path->periph); 37348b8a9b1dSJustin T. Gibbs } 37358b8a9b1dSJustin T. Gibbs 37360d307e09SAlexander Motin int 37370d307e09SAlexander Motin xpt_path_legacy_ata_id(struct cam_path *path) 37380d307e09SAlexander Motin { 37390d307e09SAlexander Motin struct cam_eb *bus; 37400d307e09SAlexander Motin int bus_id; 37410d307e09SAlexander Motin 37420d307e09SAlexander Motin if ((strcmp(path->bus->sim->sim_name, "ata") != 0) && 37430d307e09SAlexander Motin strcmp(path->bus->sim->sim_name, "ahcich") != 0 && 37440d307e09SAlexander Motin strcmp(path->bus->sim->sim_name, "mvsch") != 0 && 37450d307e09SAlexander Motin strcmp(path->bus->sim->sim_name, "siisch") != 0) 37460d307e09SAlexander Motin return (-1); 37470d307e09SAlexander Motin 37480d307e09SAlexander Motin if (strcmp(path->bus->sim->sim_name, "ata") == 0 && 37490d307e09SAlexander Motin path->bus->sim->unit_number < 2) { 37500d307e09SAlexander Motin bus_id = path->bus->sim->unit_number; 37510d307e09SAlexander Motin } else { 37520d307e09SAlexander Motin bus_id = 2; 37530d307e09SAlexander Motin xpt_lock_buses(); 37540d307e09SAlexander Motin TAILQ_FOREACH(bus, &xsoftc.xpt_busses, links) { 37550d307e09SAlexander Motin if (bus == path->bus) 37560d307e09SAlexander Motin break; 37570d307e09SAlexander Motin if ((strcmp(bus->sim->sim_name, "ata") == 0 && 37580d307e09SAlexander Motin bus->sim->unit_number >= 2) || 37590d307e09SAlexander Motin strcmp(bus->sim->sim_name, "ahcich") == 0 || 37600d307e09SAlexander Motin strcmp(bus->sim->sim_name, "mvsch") == 0 || 37610d307e09SAlexander Motin strcmp(bus->sim->sim_name, "siisch") == 0) 37620d307e09SAlexander Motin bus_id++; 37630d307e09SAlexander Motin } 37640d307e09SAlexander Motin xpt_unlock_buses(); 37650d307e09SAlexander Motin } 3766ce6cf987SAlexander Motin if (path->target != NULL) { 3767ce6cf987SAlexander Motin if (path->target->target_id < 2) 37680d307e09SAlexander Motin return (bus_id * 2 + path->target->target_id); 37690d307e09SAlexander Motin else 3770ce6cf987SAlexander Motin return (-1); 3771ce6cf987SAlexander Motin } else 37720d307e09SAlexander Motin return (bus_id * 2); 37730d307e09SAlexander Motin } 37740d307e09SAlexander Motin 37758b8a9b1dSJustin T. Gibbs /* 37768b8a9b1dSJustin T. Gibbs * Release a CAM control block for the caller. Remit the cost of the structure 37778b8a9b1dSJustin T. Gibbs * to the device referenced by the path. If the this device had no 'credits' 37788b8a9b1dSJustin T. Gibbs * and peripheral drivers have registered async callbacks for this notification 37798b8a9b1dSJustin T. Gibbs * call them now. 37808b8a9b1dSJustin T. Gibbs */ 37818b8a9b1dSJustin T. Gibbs void 37828b8a9b1dSJustin T. Gibbs xpt_release_ccb(union ccb *free_ccb) 37838b8a9b1dSJustin T. Gibbs { 37848b8a9b1dSJustin T. Gibbs struct cam_path *path; 37858b8a9b1dSJustin T. Gibbs struct cam_ed *device; 37868b8a9b1dSJustin T. Gibbs struct cam_eb *bus; 37872b83592fSScott Long struct cam_sim *sim; 378868153f43SScott Long 3789aa872be6SMatt Jacob CAM_DEBUG_PRINT(CAM_DEBUG_XPT, ("xpt_release_ccb\n")); 37908b8a9b1dSJustin T. Gibbs path = free_ccb->ccb_h.path; 37918b8a9b1dSJustin T. Gibbs device = path->device; 37928b8a9b1dSJustin T. Gibbs bus = path->bus; 37932b83592fSScott Long sim = bus->sim; 37942b83592fSScott Long 37952b83592fSScott Long mtx_assert(sim->mtx, MA_OWNED); 37962b83592fSScott Long 37978b8a9b1dSJustin T. Gibbs cam_ccbq_release_opening(&device->ccbq); 37982b83592fSScott Long if (sim->ccb_count > sim->max_ccbs) { 37998b8a9b1dSJustin T. Gibbs xpt_free_ccb(free_ccb); 38002b83592fSScott Long sim->ccb_count--; 38018b8a9b1dSJustin T. Gibbs } else { 38022b83592fSScott Long SLIST_INSERT_HEAD(&sim->ccb_freeq, &free_ccb->ccb_h, 38032b83592fSScott Long xpt_links.sle); 38048b8a9b1dSJustin T. Gibbs } 3805cccf4220SAlexander Motin xpt_run_dev_allocq(device); 38068b8a9b1dSJustin T. Gibbs } 38078b8a9b1dSJustin T. Gibbs 38088b8a9b1dSJustin T. Gibbs /* Functions accessed by SIM drivers */ 38098b8a9b1dSJustin T. Gibbs 381052c9ce25SScott Long static struct xpt_xport xport_default = { 381152c9ce25SScott Long .alloc_device = xpt_alloc_device_default, 381252c9ce25SScott Long .action = xpt_action_default, 381352c9ce25SScott Long .async = xpt_dev_async_default, 381452c9ce25SScott Long }; 381552c9ce25SScott Long 38168b8a9b1dSJustin T. Gibbs /* 38178b8a9b1dSJustin T. Gibbs * A sim structure, listing the SIM entry points and instance 38188b8a9b1dSJustin T. Gibbs * identification info is passed to xpt_bus_register to hook the SIM 38198b8a9b1dSJustin T. Gibbs * into the CAM framework. xpt_bus_register creates a cam_eb entry 38208b8a9b1dSJustin T. Gibbs * for this new bus and places it in the array of busses and assigns 38218b8a9b1dSJustin T. Gibbs * it a path_id. The path_id may be influenced by "hard wiring" 38228b8a9b1dSJustin T. Gibbs * information specified by the user. Once interrupt services are 382302caf36eSEdward Tomasz Napierala * available, the bus will be probed. 38248b8a9b1dSJustin T. Gibbs */ 38258b8a9b1dSJustin T. Gibbs int32_t 3826b50569b7SScott Long xpt_bus_register(struct cam_sim *sim, device_t parent, u_int32_t bus) 38278b8a9b1dSJustin T. Gibbs { 38288b8a9b1dSJustin T. Gibbs struct cam_eb *new_bus; 3829434bbf6eSJustin T. Gibbs struct cam_eb *old_bus; 38308b8a9b1dSJustin T. Gibbs struct ccb_pathinq cpi; 383183c5d981SAlexander Motin struct cam_path *path; 383252c9ce25SScott Long cam_status status; 38338b8a9b1dSJustin T. Gibbs 38342b83592fSScott Long mtx_assert(sim->mtx, MA_OWNED); 383568153f43SScott Long 38368b8a9b1dSJustin T. Gibbs sim->bus_id = bus; 38378b8a9b1dSJustin T. Gibbs new_bus = (struct cam_eb *)malloc(sizeof(*new_bus), 3838362abc44STai-hwa Liang M_CAMXPT, M_NOWAIT); 38398b8a9b1dSJustin T. Gibbs if (new_bus == NULL) { 38408b8a9b1dSJustin T. Gibbs /* Couldn't satisfy request */ 38418b8a9b1dSJustin T. Gibbs return (CAM_RESRC_UNAVAIL); 38428b8a9b1dSJustin T. Gibbs } 38438b8a9b1dSJustin T. Gibbs if (strcmp(sim->sim_name, "xpt") != 0) { 3844434bbf6eSJustin T. Gibbs sim->path_id = 3845434bbf6eSJustin T. Gibbs xptpathid(sim->sim_name, sim->unit_number, sim->bus_id); 38468b8a9b1dSJustin T. Gibbs } 38478b8a9b1dSJustin T. Gibbs 3848434bbf6eSJustin T. Gibbs TAILQ_INIT(&new_bus->et_entries); 38498b8a9b1dSJustin T. Gibbs new_bus->path_id = sim->path_id; 3850fa6099fdSEdward Tomasz Napierala cam_sim_hold(sim); 38518b8a9b1dSJustin T. Gibbs new_bus->sim = sim; 385287cfaf0eSJustin T. Gibbs timevalclear(&new_bus->last_reset); 3853434bbf6eSJustin T. Gibbs new_bus->flags = 0; 3854a5479bc5SJustin T. Gibbs new_bus->refcount = 1; /* Held until a bus_deregister event */ 3855434bbf6eSJustin T. Gibbs new_bus->generation = 0; 385652c9ce25SScott Long 38579a7c2696SAlexander Motin xpt_lock_buses(); 38582b83592fSScott Long old_bus = TAILQ_FIRST(&xsoftc.xpt_busses); 3859434bbf6eSJustin T. Gibbs while (old_bus != NULL 3860434bbf6eSJustin T. Gibbs && old_bus->path_id < new_bus->path_id) 3861434bbf6eSJustin T. Gibbs old_bus = TAILQ_NEXT(old_bus, links); 3862434bbf6eSJustin T. Gibbs if (old_bus != NULL) 3863434bbf6eSJustin T. Gibbs TAILQ_INSERT_BEFORE(old_bus, new_bus, links); 3864434bbf6eSJustin T. Gibbs else 38652b83592fSScott Long TAILQ_INSERT_TAIL(&xsoftc.xpt_busses, new_bus, links); 38662b83592fSScott Long xsoftc.bus_generation++; 38679a7c2696SAlexander Motin xpt_unlock_buses(); 38688b8a9b1dSJustin T. Gibbs 386952c9ce25SScott Long /* 387052c9ce25SScott Long * Set a default transport so that a PATH_INQ can be issued to 387152c9ce25SScott Long * the SIM. This will then allow for probing and attaching of 387252c9ce25SScott Long * a more appropriate transport. 387352c9ce25SScott Long */ 387452c9ce25SScott Long new_bus->xport = &xport_default; 38758b8a9b1dSJustin T. Gibbs 387632aa80a6SAlexander Motin status = xpt_create_path(&path, /*periph*/NULL, sim->path_id, 38778b8a9b1dSJustin T. Gibbs CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD); 3878627995dcSAlexander Motin if (status != CAM_REQ_CMP) { 3879627995dcSAlexander Motin xpt_release_bus(new_bus); 3880627995dcSAlexander Motin free(path, M_CAMXPT); 3881627995dcSAlexander Motin return (CAM_RESRC_UNAVAIL); 3882627995dcSAlexander Motin } 388352c9ce25SScott Long 388483c5d981SAlexander Motin xpt_setup_ccb(&cpi.ccb_h, path, CAM_PRIORITY_NORMAL); 38858b8a9b1dSJustin T. Gibbs cpi.ccb_h.func_code = XPT_PATH_INQ; 38868b8a9b1dSJustin T. Gibbs xpt_action((union ccb *)&cpi); 388752c9ce25SScott Long 388852c9ce25SScott Long if (cpi.ccb_h.status == CAM_REQ_CMP) { 388952c9ce25SScott Long switch (cpi.transport) { 389052c9ce25SScott Long case XPORT_SPI: 389152c9ce25SScott Long case XPORT_SAS: 389252c9ce25SScott Long case XPORT_FC: 389352c9ce25SScott Long case XPORT_USB: 389433ea30feSAlexander Motin case XPORT_ISCSI: 3895*b5595753SNathan Whitehorn case XPORT_SRP: 389633ea30feSAlexander Motin case XPORT_PPB: 389752c9ce25SScott Long new_bus->xport = scsi_get_xport(); 389852c9ce25SScott Long break; 389952c9ce25SScott Long case XPORT_ATA: 390052c9ce25SScott Long case XPORT_SATA: 390152c9ce25SScott Long new_bus->xport = ata_get_xport(); 390252c9ce25SScott Long break; 390352c9ce25SScott Long default: 390452c9ce25SScott Long new_bus->xport = &xport_default; 390552c9ce25SScott Long break; 39068b8a9b1dSJustin T. Gibbs } 390752c9ce25SScott Long } 390852c9ce25SScott Long 390952c9ce25SScott Long /* Notify interested parties */ 391052c9ce25SScott Long if (sim->path_id != CAM_XPT_PATH_ID) { 391183c5d981SAlexander Motin 391283c5d981SAlexander Motin xpt_async(AC_PATH_REGISTERED, path, &cpi); 3913b01773b0SKenneth D. Merry if ((cpi.hba_misc & PIM_NOSCAN) == 0) { 3914b01773b0SKenneth D. Merry union ccb *scan_ccb; 3915b01773b0SKenneth D. Merry 391683c5d981SAlexander Motin /* Initiate bus rescan. */ 391783c5d981SAlexander Motin scan_ccb = xpt_alloc_ccb_nowait(); 3918e5736ac8SAlexander Motin if (scan_ccb != NULL) { 391983c5d981SAlexander Motin scan_ccb->ccb_h.path = path; 392083c5d981SAlexander Motin scan_ccb->ccb_h.func_code = XPT_SCAN_BUS; 392183c5d981SAlexander Motin scan_ccb->crcn.flags = 0; 392283c5d981SAlexander Motin xpt_rescan(scan_ccb); 392383c5d981SAlexander Motin } else 3924b01773b0SKenneth D. Merry xpt_print(path, 3925b01773b0SKenneth D. Merry "Can't allocate CCB to scan bus\n"); 3926b01773b0SKenneth D. Merry } else 3927b01773b0SKenneth D. Merry xpt_free_path(path); 3928e5736ac8SAlexander Motin } else 392983c5d981SAlexander Motin xpt_free_path(path); 39308b8a9b1dSJustin T. Gibbs return (CAM_SUCCESS); 39318b8a9b1dSJustin T. Gibbs } 39328b8a9b1dSJustin T. Gibbs 3933434bbf6eSJustin T. Gibbs int32_t 3934434bbf6eSJustin T. Gibbs xpt_bus_deregister(path_id_t pathid) 39358b8a9b1dSJustin T. Gibbs { 3936434bbf6eSJustin T. Gibbs struct cam_path bus_path; 3937434bbf6eSJustin T. Gibbs cam_status status; 3938434bbf6eSJustin T. Gibbs 3939434bbf6eSJustin T. Gibbs status = xpt_compile_path(&bus_path, NULL, pathid, 3940434bbf6eSJustin T. Gibbs CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD); 3941434bbf6eSJustin T. Gibbs if (status != CAM_REQ_CMP) 3942434bbf6eSJustin T. Gibbs return (status); 3943434bbf6eSJustin T. Gibbs 3944434bbf6eSJustin T. Gibbs xpt_async(AC_LOST_DEVICE, &bus_path, NULL); 3945434bbf6eSJustin T. Gibbs xpt_async(AC_PATH_DEREGISTERED, &bus_path, NULL); 3946434bbf6eSJustin T. Gibbs 3947434bbf6eSJustin T. Gibbs /* Release the reference count held while registered. */ 3948434bbf6eSJustin T. Gibbs xpt_release_bus(bus_path.bus); 3949434bbf6eSJustin T. Gibbs xpt_release_path(&bus_path); 3950434bbf6eSJustin T. Gibbs 3951434bbf6eSJustin T. Gibbs return (CAM_REQ_CMP); 3952434bbf6eSJustin T. Gibbs } 3953434bbf6eSJustin T. Gibbs 3954434bbf6eSJustin T. Gibbs static path_id_t 3955434bbf6eSJustin T. Gibbs xptnextfreepathid(void) 3956434bbf6eSJustin T. Gibbs { 3957434bbf6eSJustin T. Gibbs struct cam_eb *bus; 3958434bbf6eSJustin T. Gibbs path_id_t pathid; 39592398f0cdSPeter Wemm const char *strval; 39608b8a9b1dSJustin T. Gibbs 3961434bbf6eSJustin T. Gibbs pathid = 0; 39629a7c2696SAlexander Motin xpt_lock_buses(); 39632b83592fSScott Long bus = TAILQ_FIRST(&xsoftc.xpt_busses); 3964434bbf6eSJustin T. Gibbs retry: 3965434bbf6eSJustin T. Gibbs /* Find an unoccupied pathid */ 39669e6461a2SMatt Jacob while (bus != NULL && bus->path_id <= pathid) { 3967434bbf6eSJustin T. Gibbs if (bus->path_id == pathid) 3968434bbf6eSJustin T. Gibbs pathid++; 3969434bbf6eSJustin T. Gibbs bus = TAILQ_NEXT(bus, links); 3970434bbf6eSJustin T. Gibbs } 39719a7c2696SAlexander Motin xpt_unlock_buses(); 3972434bbf6eSJustin T. Gibbs 3973434bbf6eSJustin T. Gibbs /* 3974434bbf6eSJustin T. Gibbs * Ensure that this pathid is not reserved for 3975434bbf6eSJustin T. Gibbs * a bus that may be registered in the future. 3976434bbf6eSJustin T. Gibbs */ 397775f51904SPeter Wemm if (resource_string_value("scbus", pathid, "at", &strval) == 0) { 3978434bbf6eSJustin T. Gibbs ++pathid; 39798b8a9b1dSJustin T. Gibbs /* Start the search over */ 39809a7c2696SAlexander Motin xpt_lock_buses(); 3981434bbf6eSJustin T. Gibbs goto retry; 39828b8a9b1dSJustin T. Gibbs } 3983434bbf6eSJustin T. Gibbs return (pathid); 39848b8a9b1dSJustin T. Gibbs } 39858b8a9b1dSJustin T. Gibbs 3986434bbf6eSJustin T. Gibbs static path_id_t 3987434bbf6eSJustin T. Gibbs xptpathid(const char *sim_name, int sim_unit, int sim_bus) 39888b8a9b1dSJustin T. Gibbs { 39898b8a9b1dSJustin T. Gibbs path_id_t pathid; 399075f51904SPeter Wemm int i, dunit, val; 3991642f0c46SPeter Wemm char buf[32]; 39922398f0cdSPeter Wemm const char *dname; 39938b8a9b1dSJustin T. Gibbs 39948b8a9b1dSJustin T. Gibbs pathid = CAM_XPT_PATH_ID; 399575f51904SPeter Wemm snprintf(buf, sizeof(buf), "%s%d", sim_name, sim_unit); 39962398f0cdSPeter Wemm i = 0; 39972398f0cdSPeter Wemm while ((resource_find_match(&i, &dname, &dunit, "at", buf)) == 0) { 39982398f0cdSPeter Wemm if (strcmp(dname, "scbus")) { 3999642f0c46SPeter Wemm /* Avoid a bit of foot shooting. */ 4000642f0c46SPeter Wemm continue; 4001642f0c46SPeter Wemm } 400275f51904SPeter Wemm if (dunit < 0) /* unwired?! */ 40038b8a9b1dSJustin T. Gibbs continue; 400475f51904SPeter Wemm if (resource_int_value("scbus", dunit, "bus", &val) == 0) { 400575f51904SPeter Wemm if (sim_bus == val) { 400675f51904SPeter Wemm pathid = dunit; 40078b8a9b1dSJustin T. Gibbs break; 40088b8a9b1dSJustin T. Gibbs } 40098b8a9b1dSJustin T. Gibbs } else if (sim_bus == 0) { 40108b8a9b1dSJustin T. Gibbs /* Unspecified matches bus 0 */ 401175f51904SPeter Wemm pathid = dunit; 40128b8a9b1dSJustin T. Gibbs break; 40138b8a9b1dSJustin T. Gibbs } else { 40148b8a9b1dSJustin T. Gibbs printf("Ambiguous scbus configuration for %s%d " 40158b8a9b1dSJustin T. Gibbs "bus %d, cannot wire down. The kernel " 40168b8a9b1dSJustin T. Gibbs "config entry for scbus%d should " 40178b8a9b1dSJustin T. Gibbs "specify a controller bus.\n" 40188b8a9b1dSJustin T. Gibbs "Scbus will be assigned dynamically.\n", 401975f51904SPeter Wemm sim_name, sim_unit, sim_bus, dunit); 40208b8a9b1dSJustin T. Gibbs break; 40218b8a9b1dSJustin T. Gibbs } 40228b8a9b1dSJustin T. Gibbs } 40238b8a9b1dSJustin T. Gibbs 4024434bbf6eSJustin T. Gibbs if (pathid == CAM_XPT_PATH_ID) 4025434bbf6eSJustin T. Gibbs pathid = xptnextfreepathid(); 40268b8a9b1dSJustin T. Gibbs return (pathid); 40278b8a9b1dSJustin T. Gibbs } 40288b8a9b1dSJustin T. Gibbs 402922c7d606SAlexander Motin static const char * 403022c7d606SAlexander Motin xpt_async_string(u_int32_t async_code) 403122c7d606SAlexander Motin { 403222c7d606SAlexander Motin 403322c7d606SAlexander Motin switch (async_code) { 403422c7d606SAlexander Motin case AC_BUS_RESET: return ("AC_BUS_RESET"); 403522c7d606SAlexander Motin case AC_UNSOL_RESEL: return ("AC_UNSOL_RESEL"); 403622c7d606SAlexander Motin case AC_SCSI_AEN: return ("AC_SCSI_AEN"); 403722c7d606SAlexander Motin case AC_SENT_BDR: return ("AC_SENT_BDR"); 403822c7d606SAlexander Motin case AC_PATH_REGISTERED: return ("AC_PATH_REGISTERED"); 403922c7d606SAlexander Motin case AC_PATH_DEREGISTERED: return ("AC_PATH_DEREGISTERED"); 404022c7d606SAlexander Motin case AC_FOUND_DEVICE: return ("AC_FOUND_DEVICE"); 404122c7d606SAlexander Motin case AC_LOST_DEVICE: return ("AC_LOST_DEVICE"); 404222c7d606SAlexander Motin case AC_TRANSFER_NEG: return ("AC_TRANSFER_NEG"); 404322c7d606SAlexander Motin case AC_INQ_CHANGED: return ("AC_INQ_CHANGED"); 404422c7d606SAlexander Motin case AC_GETDEV_CHANGED: return ("AC_GETDEV_CHANGED"); 404522c7d606SAlexander Motin case AC_CONTRACT: return ("AC_CONTRACT"); 404622c7d606SAlexander Motin case AC_ADVINFO_CHANGED: return ("AC_ADVINFO_CHANGED"); 40473631c638SAlexander Motin case AC_UNIT_ATTENTION: return ("AC_UNIT_ATTENTION"); 404822c7d606SAlexander Motin } 404922c7d606SAlexander Motin return ("AC_UNKNOWN"); 405022c7d606SAlexander Motin } 405122c7d606SAlexander Motin 40528b8a9b1dSJustin T. Gibbs void 40538b8a9b1dSJustin T. Gibbs xpt_async(u_int32_t async_code, struct cam_path *path, void *async_arg) 40548b8a9b1dSJustin T. Gibbs { 40558b8a9b1dSJustin T. Gibbs struct cam_eb *bus; 40568b8a9b1dSJustin T. Gibbs struct cam_et *target, *next_target; 40578b8a9b1dSJustin T. Gibbs struct cam_ed *device, *next_device; 40588b8a9b1dSJustin T. Gibbs 40592b83592fSScott Long mtx_assert(path->bus->sim->mtx, MA_OWNED); 406022c7d606SAlexander Motin CAM_DEBUG(path, CAM_DEBUG_TRACE | CAM_DEBUG_INFO, 406122c7d606SAlexander Motin ("xpt_async(%s)\n", xpt_async_string(async_code))); 40628b8a9b1dSJustin T. Gibbs 4063a5479bc5SJustin T. Gibbs /* 4064a5479bc5SJustin T. Gibbs * Most async events come from a CAM interrupt context. In 4065a5479bc5SJustin T. Gibbs * a few cases, the error recovery code at the peripheral layer, 4066a5479bc5SJustin T. Gibbs * which may run from our SWI or a process context, may signal 406777dc25ccSScott Long * deferred events with a call to xpt_async. 4068a5479bc5SJustin T. Gibbs */ 40698b8a9b1dSJustin T. Gibbs 40708b8a9b1dSJustin T. Gibbs bus = path->bus; 40718b8a9b1dSJustin T. Gibbs 40728b8a9b1dSJustin T. Gibbs if (async_code == AC_BUS_RESET) { 407387cfaf0eSJustin T. Gibbs /* Update our notion of when the last reset occurred */ 407487cfaf0eSJustin T. Gibbs microtime(&bus->last_reset); 40758b8a9b1dSJustin T. Gibbs } 40768b8a9b1dSJustin T. Gibbs 40778b8a9b1dSJustin T. Gibbs for (target = TAILQ_FIRST(&bus->et_entries); 40788b8a9b1dSJustin T. Gibbs target != NULL; 40798b8a9b1dSJustin T. Gibbs target = next_target) { 40808b8a9b1dSJustin T. Gibbs 40818b8a9b1dSJustin T. Gibbs next_target = TAILQ_NEXT(target, links); 40828b8a9b1dSJustin T. Gibbs 40838b8a9b1dSJustin T. Gibbs if (path->target != target 40842f22d08dSJustin T. Gibbs && path->target->target_id != CAM_TARGET_WILDCARD 40852f22d08dSJustin T. Gibbs && target->target_id != CAM_TARGET_WILDCARD) 40868b8a9b1dSJustin T. Gibbs continue; 40878b8a9b1dSJustin T. Gibbs 408887cfaf0eSJustin T. Gibbs if (async_code == AC_SENT_BDR) { 408987cfaf0eSJustin T. Gibbs /* Update our notion of when the last reset occurred */ 409087cfaf0eSJustin T. Gibbs microtime(&path->target->last_reset); 409187cfaf0eSJustin T. Gibbs } 409287cfaf0eSJustin T. Gibbs 40938b8a9b1dSJustin T. Gibbs for (device = TAILQ_FIRST(&target->ed_entries); 40948b8a9b1dSJustin T. Gibbs device != NULL; 40958b8a9b1dSJustin T. Gibbs device = next_device) { 40968b8a9b1dSJustin T. Gibbs 40978b8a9b1dSJustin T. Gibbs next_device = TAILQ_NEXT(device, links); 40988b8a9b1dSJustin T. Gibbs 40998b8a9b1dSJustin T. Gibbs if (path->device != device 41002f22d08dSJustin T. Gibbs && path->device->lun_id != CAM_LUN_WILDCARD 41012f22d08dSJustin T. Gibbs && device->lun_id != CAM_LUN_WILDCARD) 41028b8a9b1dSJustin T. Gibbs continue; 41039efda2c9SAlexander Motin /* 41049efda2c9SAlexander Motin * The async callback could free the device. 41059efda2c9SAlexander Motin * If it is a broadcast async, it doesn't hold 41069efda2c9SAlexander Motin * device reference, so take our own reference. 41079efda2c9SAlexander Motin */ 41089efda2c9SAlexander Motin xpt_acquire_device(device); 410952c9ce25SScott Long (*(bus->xport->async))(async_code, bus, 411052c9ce25SScott Long target, device, 411152c9ce25SScott Long async_arg); 41128b8a9b1dSJustin T. Gibbs 41132f22d08dSJustin T. Gibbs xpt_async_bcast(&device->asyncs, async_code, 41142f22d08dSJustin T. Gibbs path, async_arg); 41159efda2c9SAlexander Motin xpt_release_device(device); 41168b8a9b1dSJustin T. Gibbs } 41178b8a9b1dSJustin T. Gibbs } 4118c8bead2aSJustin T. Gibbs 4119c8bead2aSJustin T. Gibbs /* 4120c8bead2aSJustin T. Gibbs * If this wasn't a fully wildcarded async, tell all 4121c8bead2aSJustin T. Gibbs * clients that want all async events. 4122c8bead2aSJustin T. Gibbs */ 4123c8bead2aSJustin T. Gibbs if (bus != xpt_periph->path->bus) 4124c8bead2aSJustin T. Gibbs xpt_async_bcast(&xpt_periph->path->device->asyncs, async_code, 41258b8a9b1dSJustin T. Gibbs path, async_arg); 41268b8a9b1dSJustin T. Gibbs } 41278b8a9b1dSJustin T. Gibbs 41288b8a9b1dSJustin T. Gibbs static void 41298b8a9b1dSJustin T. Gibbs xpt_async_bcast(struct async_list *async_head, 41308b8a9b1dSJustin T. Gibbs u_int32_t async_code, 41318b8a9b1dSJustin T. Gibbs struct cam_path *path, void *async_arg) 41328b8a9b1dSJustin T. Gibbs { 41338b8a9b1dSJustin T. Gibbs struct async_node *cur_entry; 41348b8a9b1dSJustin T. Gibbs 41358b8a9b1dSJustin T. Gibbs cur_entry = SLIST_FIRST(async_head); 41368b8a9b1dSJustin T. Gibbs while (cur_entry != NULL) { 41378b8a9b1dSJustin T. Gibbs struct async_node *next_entry; 41388b8a9b1dSJustin T. Gibbs /* 41398b8a9b1dSJustin T. Gibbs * Grab the next list entry before we call the current 41408b8a9b1dSJustin T. Gibbs * entry's callback. This is because the callback function 41418b8a9b1dSJustin T. Gibbs * can delete its async callback entry. 41428b8a9b1dSJustin T. Gibbs */ 41438b8a9b1dSJustin T. Gibbs next_entry = SLIST_NEXT(cur_entry, links); 41448b8a9b1dSJustin T. Gibbs if ((cur_entry->event_enable & async_code) != 0) 41458b8a9b1dSJustin T. Gibbs cur_entry->callback(cur_entry->callback_arg, 41468b8a9b1dSJustin T. Gibbs async_code, path, 41478b8a9b1dSJustin T. Gibbs async_arg); 41488b8a9b1dSJustin T. Gibbs cur_entry = next_entry; 41498b8a9b1dSJustin T. Gibbs } 41508b8a9b1dSJustin T. Gibbs } 41518b8a9b1dSJustin T. Gibbs 41522f22d08dSJustin T. Gibbs static void 415352c9ce25SScott Long xpt_dev_async_default(u_int32_t async_code, struct cam_eb *bus, 415452c9ce25SScott Long struct cam_et *target, struct cam_ed *device, 415552c9ce25SScott Long void *async_arg) 41562f22d08dSJustin T. Gibbs { 4157b882a6d3SMatt Jacob printf("%s called\n", __func__); 41582f22d08dSJustin T. Gibbs } 41592f22d08dSJustin T. Gibbs 41608b8a9b1dSJustin T. Gibbs u_int32_t 4161cccf4220SAlexander Motin xpt_freeze_devq(struct cam_path *path, u_int count) 416283c5d981SAlexander Motin { 416383c5d981SAlexander Motin struct cam_ed *dev = path->device; 416483c5d981SAlexander Motin 416583c5d981SAlexander Motin mtx_assert(path->bus->sim->mtx, MA_OWNED); 41660d4f3c31SAlexander Motin CAM_DEBUG(path, CAM_DEBUG_TRACE, ("xpt_freeze_devq() %u->%u\n", 41670d4f3c31SAlexander Motin dev->ccbq.queue.qfrozen_cnt, dev->ccbq.queue.qfrozen_cnt + count)); 4168cccf4220SAlexander Motin dev->ccbq.queue.qfrozen_cnt += count; 416983c5d981SAlexander Motin /* Remove frozen device from sendq. */ 4170cccf4220SAlexander Motin if (device_is_queued(dev)) { 417183c5d981SAlexander Motin camq_remove(&dev->sim->devq->send_queue, 4172cccf4220SAlexander Motin dev->devq_entry.pinfo.index); 417383c5d981SAlexander Motin } 4174cccf4220SAlexander Motin return (dev->ccbq.queue.qfrozen_cnt); 41758b8a9b1dSJustin T. Gibbs } 41768b8a9b1dSJustin T. Gibbs 41778b8a9b1dSJustin T. Gibbs u_int32_t 41788b8a9b1dSJustin T. Gibbs xpt_freeze_simq(struct cam_sim *sim, u_int count) 41798b8a9b1dSJustin T. Gibbs { 4180ec700f26SAlexander Motin 41812b83592fSScott Long mtx_assert(sim->mtx, MA_OWNED); 4182cccf4220SAlexander Motin sim->devq->send_queue.qfrozen_cnt += count; 4183cccf4220SAlexander Motin return (sim->devq->send_queue.qfrozen_cnt); 41848b8a9b1dSJustin T. Gibbs } 41858b8a9b1dSJustin T. Gibbs 41868b8a9b1dSJustin T. Gibbs static void 41878b8a9b1dSJustin T. Gibbs xpt_release_devq_timeout(void *arg) 41888b8a9b1dSJustin T. Gibbs { 41898b8a9b1dSJustin T. Gibbs struct cam_ed *device; 41908b8a9b1dSJustin T. Gibbs 41918b8a9b1dSJustin T. Gibbs device = (struct cam_ed *)arg; 41920d4f3c31SAlexander Motin CAM_DEBUG_DEV(device, CAM_DEBUG_TRACE, ("xpt_release_devq_timeout\n")); 4193cccf4220SAlexander Motin xpt_release_devq_device(device, /*count*/1, /*run_queue*/TRUE); 41948b8a9b1dSJustin T. Gibbs } 41958b8a9b1dSJustin T. Gibbs 41968b8a9b1dSJustin T. Gibbs void 41972cefde5fSJustin T. Gibbs xpt_release_devq(struct cam_path *path, u_int count, int run_queue) 41982cefde5fSJustin T. Gibbs { 419968153f43SScott Long 4200cccf4220SAlexander Motin mtx_assert(path->bus->sim->mtx, MA_OWNED); 42010d4f3c31SAlexander Motin CAM_DEBUG(path, CAM_DEBUG_TRACE, ("xpt_release_devq(%d, %d)\n", 42020d4f3c31SAlexander Motin count, run_queue)); 4203cccf4220SAlexander Motin xpt_release_devq_device(path->device, count, run_queue); 420483c5d981SAlexander Motin } 420583c5d981SAlexander Motin 420683c5d981SAlexander Motin void 4207cccf4220SAlexander Motin xpt_release_devq_device(struct cam_ed *dev, u_int count, int run_queue) 42088b8a9b1dSJustin T. Gibbs { 42098b8a9b1dSJustin T. Gibbs 42100d4f3c31SAlexander Motin CAM_DEBUG_DEV(dev, CAM_DEBUG_TRACE, 42110d4f3c31SAlexander Motin ("xpt_release_devq_device(%d, %d) %u->%u\n", count, run_queue, 42120d4f3c31SAlexander Motin dev->ccbq.queue.qfrozen_cnt, dev->ccbq.queue.qfrozen_cnt - count)); 4213cccf4220SAlexander Motin if (count > dev->ccbq.queue.qfrozen_cnt) { 421483c5d981SAlexander Motin #ifdef INVARIANTS 4215cccf4220SAlexander Motin printf("xpt_release_devq(): requested %u > present %u\n", 4216cccf4220SAlexander Motin count, dev->ccbq.queue.qfrozen_cnt); 421783c5d981SAlexander Motin #endif 4218cccf4220SAlexander Motin count = dev->ccbq.queue.qfrozen_cnt; 421983c5d981SAlexander Motin } 4220cccf4220SAlexander Motin dev->ccbq.queue.qfrozen_cnt -= count; 4221cccf4220SAlexander Motin if (dev->ccbq.queue.qfrozen_cnt == 0) { 42228b8a9b1dSJustin T. Gibbs /* 42238b8a9b1dSJustin T. Gibbs * No longer need to wait for a successful 42248b8a9b1dSJustin T. Gibbs * command completion. 42258b8a9b1dSJustin T. Gibbs */ 42268b8a9b1dSJustin T. Gibbs dev->flags &= ~CAM_DEV_REL_ON_COMPLETE; 42278b8a9b1dSJustin T. Gibbs /* 42288b8a9b1dSJustin T. Gibbs * Remove any timeouts that might be scheduled 42298b8a9b1dSJustin T. Gibbs * to release this queue. 42308b8a9b1dSJustin T. Gibbs */ 42318b8a9b1dSJustin T. Gibbs if ((dev->flags & CAM_DEV_REL_TIMEOUT_PENDING) != 0) { 42322b83592fSScott Long callout_stop(&dev->callout); 42338b8a9b1dSJustin T. Gibbs dev->flags &= ~CAM_DEV_REL_TIMEOUT_PENDING; 42348b8a9b1dSJustin T. Gibbs } 4235cccf4220SAlexander Motin xpt_run_dev_allocq(dev); 423683c5d981SAlexander Motin if (run_queue == 0) 423783c5d981SAlexander Motin return; 42388b8a9b1dSJustin T. Gibbs /* 42398b8a9b1dSJustin T. Gibbs * Now that we are unfrozen schedule the 42408b8a9b1dSJustin T. Gibbs * device so any pending transactions are 42418b8a9b1dSJustin T. Gibbs * run. 42428b8a9b1dSJustin T. Gibbs */ 4243cccf4220SAlexander Motin if (xpt_schedule_devq(dev->sim->devq, dev)) 4244cccf4220SAlexander Motin xpt_run_devq(dev->sim->devq); 42458b8a9b1dSJustin T. Gibbs } 424683c5d981SAlexander Motin } 42478b8a9b1dSJustin T. Gibbs 42488b8a9b1dSJustin T. Gibbs void 42498b8a9b1dSJustin T. Gibbs xpt_release_simq(struct cam_sim *sim, int run_queue) 42508b8a9b1dSJustin T. Gibbs { 42518b8a9b1dSJustin T. Gibbs struct camq *sendq; 42528b8a9b1dSJustin T. Gibbs 42532b83592fSScott Long mtx_assert(sim->mtx, MA_OWNED); 42548b8a9b1dSJustin T. Gibbs sendq = &(sim->devq->send_queue); 4255cccf4220SAlexander Motin if (sendq->qfrozen_cnt <= 0) { 425683c5d981SAlexander Motin #ifdef INVARIANTS 425783c5d981SAlexander Motin printf("xpt_release_simq: requested 1 > present %u\n", 4258cccf4220SAlexander Motin sendq->qfrozen_cnt); 425983c5d981SAlexander Motin #endif 426083c5d981SAlexander Motin } else 4261cccf4220SAlexander Motin sendq->qfrozen_cnt--; 4262cccf4220SAlexander Motin if (sendq->qfrozen_cnt == 0) { 42638b8a9b1dSJustin T. Gibbs /* 42648b8a9b1dSJustin T. Gibbs * If there is a timeout scheduled to release this 42658b8a9b1dSJustin T. Gibbs * sim queue, remove it. The queue frozen count is 42668b8a9b1dSJustin T. Gibbs * already at 0. 42678b8a9b1dSJustin T. Gibbs */ 42688b8a9b1dSJustin T. Gibbs if ((sim->flags & CAM_SIM_REL_TIMEOUT_PENDING) != 0){ 42692b83592fSScott Long callout_stop(&sim->callout); 42708b8a9b1dSJustin T. Gibbs sim->flags &= ~CAM_SIM_REL_TIMEOUT_PENDING; 42718b8a9b1dSJustin T. Gibbs } 42728b8a9b1dSJustin T. Gibbs if (run_queue) { 42738b8a9b1dSJustin T. Gibbs /* 42748b8a9b1dSJustin T. Gibbs * Now that we are unfrozen run the send queue. 42758b8a9b1dSJustin T. Gibbs */ 4276cccf4220SAlexander Motin xpt_run_devq(sim->devq); 427777dc25ccSScott Long } 427877dc25ccSScott Long } 42798b8a9b1dSJustin T. Gibbs } 42808b8a9b1dSJustin T. Gibbs 42812b83592fSScott Long /* 42822b83592fSScott Long * XXX Appears to be unused. 42832b83592fSScott Long */ 42848b8a9b1dSJustin T. Gibbs static void 42858b8a9b1dSJustin T. Gibbs xpt_release_simq_timeout(void *arg) 42868b8a9b1dSJustin T. Gibbs { 42878b8a9b1dSJustin T. Gibbs struct cam_sim *sim; 42888b8a9b1dSJustin T. Gibbs 42898b8a9b1dSJustin T. Gibbs sim = (struct cam_sim *)arg; 42908b8a9b1dSJustin T. Gibbs xpt_release_simq(sim, /* run_queue */ TRUE); 42918b8a9b1dSJustin T. Gibbs } 42928b8a9b1dSJustin T. Gibbs 42938b8a9b1dSJustin T. Gibbs void 4294a5479bc5SJustin T. Gibbs xpt_done(union ccb *done_ccb) 42958b8a9b1dSJustin T. Gibbs { 42969758cc83SScott Long struct cam_sim *sim; 4297efa575b6SAlexander Motin int first; 42988b8a9b1dSJustin T. Gibbs 42998b8a9b1dSJustin T. Gibbs CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_TRACE, ("xpt_done\n")); 43009deea857SKenneth D. Merry if ((done_ccb->ccb_h.func_code & XPT_FC_QUEUED) != 0) { 43018b8a9b1dSJustin T. Gibbs /* 43028b8a9b1dSJustin T. Gibbs * Queue up the request for handling by our SWI handler 43038b8a9b1dSJustin T. Gibbs * any of the "non-immediate" type of ccbs. 43048b8a9b1dSJustin T. Gibbs */ 43059758cc83SScott Long sim = done_ccb->ccb_h.path->bus->sim; 43069758cc83SScott Long TAILQ_INSERT_TAIL(&sim->sim_doneq, &done_ccb->ccb_h, 43078b8a9b1dSJustin T. Gibbs sim_links.tqe); 43088b8a9b1dSJustin T. Gibbs done_ccb->ccb_h.pinfo.index = CAM_DONEQ_INDEX; 4309711f6613SAlexander Motin if ((sim->flags & (CAM_SIM_ON_DONEQ | CAM_SIM_POLLED | 4310711f6613SAlexander Motin CAM_SIM_BATCH)) == 0) { 43119758cc83SScott Long mtx_lock(&cam_simq_lock); 4312efa575b6SAlexander Motin first = TAILQ_EMPTY(&cam_simq); 4313efa575b6SAlexander Motin TAILQ_INSERT_TAIL(&cam_simq, sim, links); 43149758cc83SScott Long mtx_unlock(&cam_simq_lock); 4315788fb376SAlexander Motin sim->flags |= CAM_SIM_ON_DONEQ; 4316efa575b6SAlexander Motin if (first) 4317c86b6ff5SJohn Baldwin swi_sched(cambio_ih, 0); 4318788fb376SAlexander Motin } 43198b8a9b1dSJustin T. Gibbs } 43208b8a9b1dSJustin T. Gibbs } 43218b8a9b1dSJustin T. Gibbs 4322711f6613SAlexander Motin void 4323711f6613SAlexander Motin xpt_batch_start(struct cam_sim *sim) 4324711f6613SAlexander Motin { 4325711f6613SAlexander Motin 4326711f6613SAlexander Motin KASSERT((sim->flags & CAM_SIM_BATCH) == 0, ("Batch flag already set")); 4327711f6613SAlexander Motin sim->flags |= CAM_SIM_BATCH; 4328711f6613SAlexander Motin } 4329711f6613SAlexander Motin 4330711f6613SAlexander Motin void 4331711f6613SAlexander Motin xpt_batch_done(struct cam_sim *sim) 4332711f6613SAlexander Motin { 4333711f6613SAlexander Motin 4334711f6613SAlexander Motin KASSERT((sim->flags & CAM_SIM_BATCH) != 0, ("Batch flag was not set")); 4335711f6613SAlexander Motin sim->flags &= ~CAM_SIM_BATCH; 4336711f6613SAlexander Motin if (!TAILQ_EMPTY(&sim->sim_doneq) && 4337711f6613SAlexander Motin (sim->flags & CAM_SIM_ON_DONEQ) == 0) 433839fe6d85SAlexander Motin camisr_runqueue(sim); 4339711f6613SAlexander Motin } 4340711f6613SAlexander Motin 43418b8a9b1dSJustin T. Gibbs union ccb * 43428008a935SScott Long xpt_alloc_ccb() 43438b8a9b1dSJustin T. Gibbs { 43448b8a9b1dSJustin T. Gibbs union ccb *new_ccb; 43458b8a9b1dSJustin T. Gibbs 4346596ee08fSAlexander Motin new_ccb = malloc(sizeof(*new_ccb), M_CAMCCB, M_ZERO|M_WAITOK); 4347362abc44STai-hwa Liang return (new_ccb); 4348362abc44STai-hwa Liang } 4349362abc44STai-hwa Liang 4350362abc44STai-hwa Liang union ccb * 43518008a935SScott Long xpt_alloc_ccb_nowait() 4352362abc44STai-hwa Liang { 4353362abc44STai-hwa Liang union ccb *new_ccb; 4354362abc44STai-hwa Liang 4355596ee08fSAlexander Motin new_ccb = malloc(sizeof(*new_ccb), M_CAMCCB, M_ZERO|M_NOWAIT); 43568b8a9b1dSJustin T. Gibbs return (new_ccb); 43578b8a9b1dSJustin T. Gibbs } 43588b8a9b1dSJustin T. Gibbs 43598b8a9b1dSJustin T. Gibbs void 43608b8a9b1dSJustin T. Gibbs xpt_free_ccb(union ccb *free_ccb) 43618b8a9b1dSJustin T. Gibbs { 4362596ee08fSAlexander Motin free(free_ccb, M_CAMCCB); 43638b8a9b1dSJustin T. Gibbs } 43648b8a9b1dSJustin T. Gibbs 43658b8a9b1dSJustin T. Gibbs 43668b8a9b1dSJustin T. Gibbs 43678b8a9b1dSJustin T. Gibbs /* Private XPT functions */ 43688b8a9b1dSJustin T. Gibbs 43698b8a9b1dSJustin T. Gibbs /* 43708b8a9b1dSJustin T. Gibbs * Get a CAM control block for the caller. Charge the structure to the device 43718b8a9b1dSJustin T. Gibbs * referenced by the path. If the this device has no 'credits' then the 43728b8a9b1dSJustin T. Gibbs * device already has the maximum number of outstanding operations under way 43738b8a9b1dSJustin T. Gibbs * and we return NULL. If we don't have sufficient resources to allocate more 43748b8a9b1dSJustin T. Gibbs * ccbs, we also return NULL. 43758b8a9b1dSJustin T. Gibbs */ 43768b8a9b1dSJustin T. Gibbs static union ccb * 43778b8a9b1dSJustin T. Gibbs xpt_get_ccb(struct cam_ed *device) 43788b8a9b1dSJustin T. Gibbs { 43798b8a9b1dSJustin T. Gibbs union ccb *new_ccb; 43802b83592fSScott Long struct cam_sim *sim; 43818b8a9b1dSJustin T. Gibbs 43822b83592fSScott Long sim = device->sim; 43832b83592fSScott Long if ((new_ccb = (union ccb *)SLIST_FIRST(&sim->ccb_freeq)) == NULL) { 43848008a935SScott Long new_ccb = xpt_alloc_ccb_nowait(); 43858b8a9b1dSJustin T. Gibbs if (new_ccb == NULL) { 43868b8a9b1dSJustin T. Gibbs return (NULL); 43878b8a9b1dSJustin T. Gibbs } 43882b83592fSScott Long SLIST_INSERT_HEAD(&sim->ccb_freeq, &new_ccb->ccb_h, 43898b8a9b1dSJustin T. Gibbs xpt_links.sle); 43902b83592fSScott Long sim->ccb_count++; 43918b8a9b1dSJustin T. Gibbs } 43928b8a9b1dSJustin T. Gibbs cam_ccbq_take_opening(&device->ccbq); 43932b83592fSScott Long SLIST_REMOVE_HEAD(&sim->ccb_freeq, xpt_links.sle); 43948b8a9b1dSJustin T. Gibbs return (new_ccb); 43958b8a9b1dSJustin T. Gibbs } 43968b8a9b1dSJustin T. Gibbs 4397a5479bc5SJustin T. Gibbs static void 4398a5479bc5SJustin T. Gibbs xpt_release_bus(struct cam_eb *bus) 4399a5479bc5SJustin T. Gibbs { 4400a5479bc5SJustin T. Gibbs 44019a7c2696SAlexander Motin xpt_lock_buses(); 440215975b7bSMatt Jacob KASSERT(bus->refcount >= 1, ("bus->refcount >= 1")); 4403dcdf6e74SAlexander Motin if (--bus->refcount > 0) { 4404dcdf6e74SAlexander Motin xpt_unlock_buses(); 4405dcdf6e74SAlexander Motin return; 4406dcdf6e74SAlexander Motin } 4407dcdf6e74SAlexander Motin KASSERT(TAILQ_EMPTY(&bus->et_entries), 4408dcdf6e74SAlexander Motin ("refcount is zero, but target list is not empty")); 44092b83592fSScott Long TAILQ_REMOVE(&xsoftc.xpt_busses, bus, links); 44102b83592fSScott Long xsoftc.bus_generation++; 44119a7c2696SAlexander Motin xpt_unlock_buses(); 4412fa6099fdSEdward Tomasz Napierala cam_sim_release(bus->sim); 4413362abc44STai-hwa Liang free(bus, M_CAMXPT); 4414a5479bc5SJustin T. Gibbs } 44158b8a9b1dSJustin T. Gibbs 44168b8a9b1dSJustin T. Gibbs static struct cam_et * 44178b8a9b1dSJustin T. Gibbs xpt_alloc_target(struct cam_eb *bus, target_id_t target_id) 44188b8a9b1dSJustin T. Gibbs { 4419dcdf6e74SAlexander Motin struct cam_et *cur_target, *target; 44208b8a9b1dSJustin T. Gibbs 4421dcdf6e74SAlexander Motin mtx_assert(bus->sim->mtx, MA_OWNED); 44223501942bSJustin T. Gibbs target = (struct cam_et *)malloc(sizeof(*target), M_CAMXPT, 44233501942bSJustin T. Gibbs M_NOWAIT|M_ZERO); 4424dcdf6e74SAlexander Motin if (target == NULL) 4425dcdf6e74SAlexander Motin return (NULL); 44268b8a9b1dSJustin T. Gibbs 4427434bbf6eSJustin T. Gibbs TAILQ_INIT(&target->ed_entries); 44288b8a9b1dSJustin T. Gibbs target->bus = bus; 44298b8a9b1dSJustin T. Gibbs target->target_id = target_id; 44308b8a9b1dSJustin T. Gibbs target->refcount = 1; 4431434bbf6eSJustin T. Gibbs target->generation = 0; 443282b361b1SMatt Jacob target->luns = NULL; 4433434bbf6eSJustin T. Gibbs timevalclear(&target->last_reset); 4434a5479bc5SJustin T. Gibbs /* 4435a5479bc5SJustin T. Gibbs * Hold a reference to our parent bus so it 4436a5479bc5SJustin T. Gibbs * will not go away before we do. 4437a5479bc5SJustin T. Gibbs */ 44389a7c2696SAlexander Motin xpt_lock_buses(); 4439a5479bc5SJustin T. Gibbs bus->refcount++; 44409a7c2696SAlexander Motin xpt_unlock_buses(); 44418b8a9b1dSJustin T. Gibbs 44428b8a9b1dSJustin T. Gibbs /* Insertion sort into our bus's target list */ 44438b8a9b1dSJustin T. Gibbs cur_target = TAILQ_FIRST(&bus->et_entries); 44448b8a9b1dSJustin T. Gibbs while (cur_target != NULL && cur_target->target_id < target_id) 44458b8a9b1dSJustin T. Gibbs cur_target = TAILQ_NEXT(cur_target, links); 44468b8a9b1dSJustin T. Gibbs if (cur_target != NULL) { 44478b8a9b1dSJustin T. Gibbs TAILQ_INSERT_BEFORE(cur_target, target, links); 44488b8a9b1dSJustin T. Gibbs } else { 44498b8a9b1dSJustin T. Gibbs TAILQ_INSERT_TAIL(&bus->et_entries, target, links); 44508b8a9b1dSJustin T. Gibbs } 4451a5479bc5SJustin T. Gibbs bus->generation++; 44528b8a9b1dSJustin T. Gibbs return (target); 44538b8a9b1dSJustin T. Gibbs } 44548b8a9b1dSJustin T. Gibbs 4455a5479bc5SJustin T. Gibbs static void 4456f98d7a47SAlexander Motin xpt_release_target(struct cam_et *target) 44578b8a9b1dSJustin T. Gibbs { 4458a5479bc5SJustin T. Gibbs 4459dcdf6e74SAlexander Motin mtx_assert(target->bus->sim->mtx, MA_OWNED); 4460dcdf6e74SAlexander Motin if (--target->refcount > 0) 4461dcdf6e74SAlexander Motin return; 4462dcdf6e74SAlexander Motin KASSERT(TAILQ_EMPTY(&target->ed_entries), 4463dcdf6e74SAlexander Motin ("refcount is zero, but device list is not empty")); 4464f98d7a47SAlexander Motin TAILQ_REMOVE(&target->bus->et_entries, target, links); 4465f98d7a47SAlexander Motin target->bus->generation++; 4466f98d7a47SAlexander Motin xpt_release_bus(target->bus); 446782b361b1SMatt Jacob if (target->luns) 446882b361b1SMatt Jacob free(target->luns, M_CAMXPT); 4469362abc44STai-hwa Liang free(target, M_CAMXPT); 447077dc25ccSScott Long } 44718b8a9b1dSJustin T. Gibbs 44728b8a9b1dSJustin T. Gibbs static struct cam_ed * 447352c9ce25SScott Long xpt_alloc_device_default(struct cam_eb *bus, struct cam_et *target, 447452c9ce25SScott Long lun_id_t lun_id) 447552c9ce25SScott Long { 4476dcdf6e74SAlexander Motin struct cam_ed *device; 447752c9ce25SScott Long 447852c9ce25SScott Long device = xpt_alloc_device(bus, target, lun_id); 447952c9ce25SScott Long if (device == NULL) 448052c9ce25SScott Long return (NULL); 448152c9ce25SScott Long 448252c9ce25SScott Long device->mintags = 1; 448352c9ce25SScott Long device->maxtags = 1; 448483c5d981SAlexander Motin bus->sim->max_ccbs += device->ccbq.devq_openings; 448552c9ce25SScott Long return (device); 448652c9ce25SScott Long } 448752c9ce25SScott Long 448852c9ce25SScott Long struct cam_ed * 44898b8a9b1dSJustin T. Gibbs xpt_alloc_device(struct cam_eb *bus, struct cam_et *target, lun_id_t lun_id) 44908b8a9b1dSJustin T. Gibbs { 4491dcdf6e74SAlexander Motin struct cam_ed *cur_device, *device; 44928b8a9b1dSJustin T. Gibbs struct cam_devq *devq; 4493a5479bc5SJustin T. Gibbs cam_status status; 44948b8a9b1dSJustin T. Gibbs 4495dcdf6e74SAlexander Motin mtx_assert(target->bus->sim->mtx, MA_OWNED); 44968b8a9b1dSJustin T. Gibbs /* Make space for us in the device queue on our bus */ 44978b8a9b1dSJustin T. Gibbs devq = bus->sim->devq; 4498cccf4220SAlexander Motin status = cam_devq_resize(devq, devq->send_queue.array_size + 1); 4499dcdf6e74SAlexander Motin if (status != CAM_REQ_CMP) 4500dcdf6e74SAlexander Motin return (NULL); 45018b8a9b1dSJustin T. Gibbs 45028b8a9b1dSJustin T. Gibbs device = (struct cam_ed *)malloc(sizeof(*device), 4503596ee08fSAlexander Motin M_CAMDEV, M_NOWAIT|M_ZERO); 4504dcdf6e74SAlexander Motin if (device == NULL) 4505dcdf6e74SAlexander Motin return (NULL); 45068b8a9b1dSJustin T. Gibbs 4507cccf4220SAlexander Motin cam_init_pinfo(&device->devq_entry.pinfo); 4508cccf4220SAlexander Motin device->devq_entry.device = device; 45098b8a9b1dSJustin T. Gibbs device->target = target; 45108b8a9b1dSJustin T. Gibbs device->lun_id = lun_id; 45112b83592fSScott Long device->sim = bus->sim; 45128b8a9b1dSJustin T. Gibbs /* Initialize our queues */ 45138b8a9b1dSJustin T. Gibbs if (camq_init(&device->drvq, 0) != 0) { 4514596ee08fSAlexander Motin free(device, M_CAMDEV); 45158b8a9b1dSJustin T. Gibbs return (NULL); 45168b8a9b1dSJustin T. Gibbs } 45178b8a9b1dSJustin T. Gibbs if (cam_ccbq_init(&device->ccbq, 45188b8a9b1dSJustin T. Gibbs bus->sim->max_dev_openings) != 0) { 45198b8a9b1dSJustin T. Gibbs camq_fini(&device->drvq); 4520596ee08fSAlexander Motin free(device, M_CAMDEV); 45218b8a9b1dSJustin T. Gibbs return (NULL); 45228b8a9b1dSJustin T. Gibbs } 4523434bbf6eSJustin T. Gibbs SLIST_INIT(&device->asyncs); 4524434bbf6eSJustin T. Gibbs SLIST_INIT(&device->periphs); 4525434bbf6eSJustin T. Gibbs device->generation = 0; 4526434bbf6eSJustin T. Gibbs device->flags = CAM_DEV_UNCONFIGURED; 4527434bbf6eSJustin T. Gibbs device->tag_delay_count = 0; 4528df8f9080SJustin T. Gibbs device->tag_saved_openings = 0; 4529434bbf6eSJustin T. Gibbs device->refcount = 1; 45302b83592fSScott Long callout_init_mtx(&device->callout, bus->sim->mtx, 0); 4531434bbf6eSJustin T. Gibbs 4532dcdf6e74SAlexander Motin cur_device = TAILQ_FIRST(&target->ed_entries); 4533dcdf6e74SAlexander Motin while (cur_device != NULL && cur_device->lun_id < lun_id) 4534dcdf6e74SAlexander Motin cur_device = TAILQ_NEXT(cur_device, links); 4535dcdf6e74SAlexander Motin if (cur_device != NULL) 4536dcdf6e74SAlexander Motin TAILQ_INSERT_BEFORE(cur_device, device, links); 4537dcdf6e74SAlexander Motin else 4538dcdf6e74SAlexander Motin TAILQ_INSERT_TAIL(&target->ed_entries, device, links); 4539434bbf6eSJustin T. Gibbs target->refcount++; 4540dcdf6e74SAlexander Motin target->generation++; 45418b8a9b1dSJustin T. Gibbs return (device); 45428b8a9b1dSJustin T. Gibbs } 45438b8a9b1dSJustin T. Gibbs 4544f98d7a47SAlexander Motin void 4545f98d7a47SAlexander Motin xpt_acquire_device(struct cam_ed *device) 45468b8a9b1dSJustin T. Gibbs { 45478b8a9b1dSJustin T. Gibbs 4548dcdf6e74SAlexander Motin mtx_assert(device->sim->mtx, MA_OWNED); 4549f98d7a47SAlexander Motin device->refcount++; 4550f98d7a47SAlexander Motin } 4551f98d7a47SAlexander Motin 4552f98d7a47SAlexander Motin void 4553f98d7a47SAlexander Motin xpt_release_device(struct cam_ed *device) 4554f98d7a47SAlexander Motin { 45558b8a9b1dSJustin T. Gibbs struct cam_devq *devq; 45568b8a9b1dSJustin T. Gibbs 4557dcdf6e74SAlexander Motin mtx_assert(device->sim->mtx, MA_OWNED); 4558dcdf6e74SAlexander Motin if (--device->refcount > 0) 4559dcdf6e74SAlexander Motin return; 4560dcdf6e74SAlexander Motin 4561dcdf6e74SAlexander Motin KASSERT(SLIST_EMPTY(&device->periphs), 4562dcdf6e74SAlexander Motin ("refcount is zero, but periphs list is not empty")); 4563cccf4220SAlexander Motin if (device->devq_entry.pinfo.index != CAM_UNQUEUED_INDEX) 4564a5479bc5SJustin T. Gibbs panic("Removing device while still queued for ccbs"); 45652cefde5fSJustin T. Gibbs 45662cefde5fSJustin T. Gibbs if ((device->flags & CAM_DEV_REL_TIMEOUT_PENDING) != 0) 45672b83592fSScott Long callout_stop(&device->callout); 45682cefde5fSJustin T. Gibbs 4569f98d7a47SAlexander Motin TAILQ_REMOVE(&device->target->ed_entries, device,links); 4570f98d7a47SAlexander Motin device->target->generation++; 4571f98d7a47SAlexander Motin device->target->bus->sim->max_ccbs -= device->ccbq.devq_openings; 45728b8a9b1dSJustin T. Gibbs /* Release our slot in the devq */ 4573f98d7a47SAlexander Motin devq = device->target->bus->sim->devq; 4574cccf4220SAlexander Motin cam_devq_resize(devq, devq->send_queue.array_size - 1); 45757c20d5d7STai-hwa Liang camq_fini(&device->drvq); 457620a7933fSAlexander Motin cam_ccbq_fini(&device->ccbq); 4577e6bd5983SKenneth D. Merry /* 4578e6bd5983SKenneth D. Merry * Free allocated memory. free(9) does nothing if the 4579e6bd5983SKenneth D. Merry * supplied pointer is NULL, so it is safe to call without 4580e6bd5983SKenneth D. Merry * checking. 4581e6bd5983SKenneth D. Merry */ 4582e6bd5983SKenneth D. Merry free(device->supported_vpds, M_CAMXPT); 4583e6bd5983SKenneth D. Merry free(device->device_id, M_CAMXPT); 4584e6bd5983SKenneth D. Merry free(device->physpath, M_CAMXPT); 4585e6bd5983SKenneth D. Merry free(device->rcap_buf, M_CAMXPT); 4586e6bd5983SKenneth D. Merry free(device->serial_num, M_CAMXPT); 4587e6bd5983SKenneth D. Merry 4588f98d7a47SAlexander Motin xpt_release_target(device->target); 4589596ee08fSAlexander Motin free(device, M_CAMDEV); 45908b8a9b1dSJustin T. Gibbs } 45918b8a9b1dSJustin T. Gibbs 459252c9ce25SScott Long u_int32_t 45938b8a9b1dSJustin T. Gibbs xpt_dev_ccbq_resize(struct cam_path *path, int newopenings) 45948b8a9b1dSJustin T. Gibbs { 45958b8a9b1dSJustin T. Gibbs int diff; 45968b8a9b1dSJustin T. Gibbs int result; 45978b8a9b1dSJustin T. Gibbs struct cam_ed *dev; 45988b8a9b1dSJustin T. Gibbs 45998b8a9b1dSJustin T. Gibbs dev = path->device; 46008b8a9b1dSJustin T. Gibbs 46018b8a9b1dSJustin T. Gibbs diff = newopenings - (dev->ccbq.dev_active + dev->ccbq.dev_openings); 46028b8a9b1dSJustin T. Gibbs result = cam_ccbq_resize(&dev->ccbq, newopenings); 4603df8f9080SJustin T. Gibbs if ((dev->flags & CAM_DEV_TAG_AFTER_COUNT) != 0 4604df8f9080SJustin T. Gibbs || (dev->inq_flags & SID_CmdQue) != 0) 4605df8f9080SJustin T. Gibbs dev->tag_saved_openings = newopenings; 46068b8a9b1dSJustin T. Gibbs /* Adjust the global limit */ 46072b83592fSScott Long dev->sim->max_ccbs += diff; 46088b8a9b1dSJustin T. Gibbs return (result); 46098b8a9b1dSJustin T. Gibbs } 46108b8a9b1dSJustin T. Gibbs 46118b8a9b1dSJustin T. Gibbs static struct cam_eb * 46128b8a9b1dSJustin T. Gibbs xpt_find_bus(path_id_t path_id) 46138b8a9b1dSJustin T. Gibbs { 46148b8a9b1dSJustin T. Gibbs struct cam_eb *bus; 46158b8a9b1dSJustin T. Gibbs 46169a7c2696SAlexander Motin xpt_lock_buses(); 46172b83592fSScott Long for (bus = TAILQ_FIRST(&xsoftc.xpt_busses); 46188b8a9b1dSJustin T. Gibbs bus != NULL; 46198b8a9b1dSJustin T. Gibbs bus = TAILQ_NEXT(bus, links)) { 4620a5479bc5SJustin T. Gibbs if (bus->path_id == path_id) { 4621a5479bc5SJustin T. Gibbs bus->refcount++; 46228b8a9b1dSJustin T. Gibbs break; 46238b8a9b1dSJustin T. Gibbs } 4624a5479bc5SJustin T. Gibbs } 46259a7c2696SAlexander Motin xpt_unlock_buses(); 46268b8a9b1dSJustin T. Gibbs return (bus); 46278b8a9b1dSJustin T. Gibbs } 46288b8a9b1dSJustin T. Gibbs 46298b8a9b1dSJustin T. Gibbs static struct cam_et * 46308b8a9b1dSJustin T. Gibbs xpt_find_target(struct cam_eb *bus, target_id_t target_id) 46318b8a9b1dSJustin T. Gibbs { 46328b8a9b1dSJustin T. Gibbs struct cam_et *target; 46338b8a9b1dSJustin T. Gibbs 4634dcdf6e74SAlexander Motin mtx_assert(bus->sim->mtx, MA_OWNED); 46358b8a9b1dSJustin T. Gibbs for (target = TAILQ_FIRST(&bus->et_entries); 46368b8a9b1dSJustin T. Gibbs target != NULL; 46378b8a9b1dSJustin T. Gibbs target = TAILQ_NEXT(target, links)) { 46388b8a9b1dSJustin T. Gibbs if (target->target_id == target_id) { 46398b8a9b1dSJustin T. Gibbs target->refcount++; 46408b8a9b1dSJustin T. Gibbs break; 46418b8a9b1dSJustin T. Gibbs } 46428b8a9b1dSJustin T. Gibbs } 46438b8a9b1dSJustin T. Gibbs return (target); 46448b8a9b1dSJustin T. Gibbs } 46458b8a9b1dSJustin T. Gibbs 46468b8a9b1dSJustin T. Gibbs static struct cam_ed * 46478b8a9b1dSJustin T. Gibbs xpt_find_device(struct cam_et *target, lun_id_t lun_id) 46488b8a9b1dSJustin T. Gibbs { 46498b8a9b1dSJustin T. Gibbs struct cam_ed *device; 46508b8a9b1dSJustin T. Gibbs 4651dcdf6e74SAlexander Motin mtx_assert(target->bus->sim->mtx, MA_OWNED); 46528b8a9b1dSJustin T. Gibbs for (device = TAILQ_FIRST(&target->ed_entries); 46538b8a9b1dSJustin T. Gibbs device != NULL; 46548b8a9b1dSJustin T. Gibbs device = TAILQ_NEXT(device, links)) { 46558b8a9b1dSJustin T. Gibbs if (device->lun_id == lun_id) { 46568b8a9b1dSJustin T. Gibbs device->refcount++; 46578b8a9b1dSJustin T. Gibbs break; 46588b8a9b1dSJustin T. Gibbs } 46598b8a9b1dSJustin T. Gibbs } 46608b8a9b1dSJustin T. Gibbs return (device); 46618b8a9b1dSJustin T. Gibbs } 46628b8a9b1dSJustin T. Gibbs 466330a4094fSAlexander Motin void 4664f0adc790SJustin T. Gibbs xpt_start_tags(struct cam_path *path) 4665f0adc790SJustin T. Gibbs { 4666fd21cc5eSJustin T. Gibbs struct ccb_relsim crs; 4667fd21cc5eSJustin T. Gibbs struct cam_ed *device; 4668fd21cc5eSJustin T. Gibbs struct cam_sim *sim; 4669fd21cc5eSJustin T. Gibbs int newopenings; 4670fd21cc5eSJustin T. Gibbs 4671fd21cc5eSJustin T. Gibbs device = path->device; 4672fd21cc5eSJustin T. Gibbs sim = path->bus->sim; 4673fd21cc5eSJustin T. Gibbs device->flags &= ~CAM_DEV_TAG_AFTER_COUNT; 4674fd21cc5eSJustin T. Gibbs xpt_freeze_devq(path, /*count*/1); 4675fd21cc5eSJustin T. Gibbs device->inq_flags |= SID_CmdQue; 4676df8f9080SJustin T. Gibbs if (device->tag_saved_openings != 0) 4677df8f9080SJustin T. Gibbs newopenings = device->tag_saved_openings; 4678df8f9080SJustin T. Gibbs else 467952c9ce25SScott Long newopenings = min(device->maxtags, 4680df8f9080SJustin T. Gibbs sim->max_tagged_dev_openings); 4681f0adc790SJustin T. Gibbs xpt_dev_ccbq_resize(path, newopenings); 4682581b2e78SAlexander Motin xpt_async(AC_GETDEV_CHANGED, path, NULL); 4683bbfa4aa1SAlexander Motin xpt_setup_ccb(&crs.ccb_h, path, CAM_PRIORITY_NORMAL); 4684fd21cc5eSJustin T. Gibbs crs.ccb_h.func_code = XPT_REL_SIMQ; 4685fd21cc5eSJustin T. Gibbs crs.release_flags = RELSIM_RELEASE_AFTER_QEMPTY; 4686fd21cc5eSJustin T. Gibbs crs.openings 4687fd21cc5eSJustin T. Gibbs = crs.release_timeout 4688fd21cc5eSJustin T. Gibbs = crs.qfrozen_cnt 4689fd21cc5eSJustin T. Gibbs = 0; 4690fd21cc5eSJustin T. Gibbs xpt_action((union ccb *)&crs); 4691fd21cc5eSJustin T. Gibbs } 4692fd21cc5eSJustin T. Gibbs 469330a4094fSAlexander Motin void 469430a4094fSAlexander Motin xpt_stop_tags(struct cam_path *path) 469530a4094fSAlexander Motin { 469630a4094fSAlexander Motin struct ccb_relsim crs; 469730a4094fSAlexander Motin struct cam_ed *device; 469830a4094fSAlexander Motin struct cam_sim *sim; 469930a4094fSAlexander Motin 470030a4094fSAlexander Motin device = path->device; 470130a4094fSAlexander Motin sim = path->bus->sim; 470230a4094fSAlexander Motin device->flags &= ~CAM_DEV_TAG_AFTER_COUNT; 470330a4094fSAlexander Motin device->tag_delay_count = 0; 470430a4094fSAlexander Motin xpt_freeze_devq(path, /*count*/1); 470530a4094fSAlexander Motin device->inq_flags &= ~SID_CmdQue; 470630a4094fSAlexander Motin xpt_dev_ccbq_resize(path, sim->max_dev_openings); 4707581b2e78SAlexander Motin xpt_async(AC_GETDEV_CHANGED, path, NULL); 470830a4094fSAlexander Motin xpt_setup_ccb(&crs.ccb_h, path, CAM_PRIORITY_NORMAL); 470930a4094fSAlexander Motin crs.ccb_h.func_code = XPT_REL_SIMQ; 471030a4094fSAlexander Motin crs.release_flags = RELSIM_RELEASE_AFTER_QEMPTY; 471130a4094fSAlexander Motin crs.openings 471230a4094fSAlexander Motin = crs.release_timeout 471330a4094fSAlexander Motin = crs.qfrozen_cnt 471430a4094fSAlexander Motin = 0; 471530a4094fSAlexander Motin xpt_action((union ccb *)&crs); 471630a4094fSAlexander Motin } 471730a4094fSAlexander Motin 471883c5d981SAlexander Motin static void 471983c5d981SAlexander Motin xpt_boot_delay(void *arg) 47208b8a9b1dSJustin T. Gibbs { 47212b83592fSScott Long 472283c5d981SAlexander Motin xpt_release_boot(); 47238b8a9b1dSJustin T. Gibbs } 47248b8a9b1dSJustin T. Gibbs 47258b8a9b1dSJustin T. Gibbs static void 47268b8a9b1dSJustin T. Gibbs xpt_config(void *arg) 47278b8a9b1dSJustin T. Gibbs { 47283393f8daSKenneth D. Merry /* 47293393f8daSKenneth D. Merry * Now that interrupts are enabled, go find our devices 47303393f8daSKenneth D. Merry */ 47318b8a9b1dSJustin T. Gibbs 4732f0f25b9cSAlexander Motin /* Setup debugging path */ 47338b8a9b1dSJustin T. Gibbs if (cam_dflags != CAM_DEBUG_NONE) { 4734e5dfa058SAlexander Motin if (xpt_create_path_unlocked(&cam_dpath, NULL, 47358b8a9b1dSJustin T. Gibbs CAM_DEBUG_BUS, CAM_DEBUG_TARGET, 47368b8a9b1dSJustin T. Gibbs CAM_DEBUG_LUN) != CAM_REQ_CMP) { 47378b8a9b1dSJustin T. Gibbs printf("xpt_config: xpt_create_path() failed for debug" 47388b8a9b1dSJustin T. Gibbs " target %d:%d:%d, debugging disabled\n", 47398b8a9b1dSJustin T. Gibbs CAM_DEBUG_BUS, CAM_DEBUG_TARGET, CAM_DEBUG_LUN); 47408b8a9b1dSJustin T. Gibbs cam_dflags = CAM_DEBUG_NONE; 47418b8a9b1dSJustin T. Gibbs } 47428b8a9b1dSJustin T. Gibbs } else 47438b8a9b1dSJustin T. Gibbs cam_dpath = NULL; 47448b8a9b1dSJustin T. Gibbs 474583c5d981SAlexander Motin periphdriver_init(1); 474683c5d981SAlexander Motin xpt_hold_boot(); 474783c5d981SAlexander Motin callout_init(&xsoftc.boot_callout, 1); 474883c5d981SAlexander Motin callout_reset(&xsoftc.boot_callout, hz * xsoftc.boot_delay / 1000, 474983c5d981SAlexander Motin xpt_boot_delay, NULL); 475083c5d981SAlexander Motin /* Fire up rescan thread. */ 475183c5d981SAlexander Motin if (kproc_create(xpt_scanner_thread, NULL, NULL, 0, 0, "xpt_thrd")) { 47526f15a274SAlexander Motin printf("xpt_config: failed to create rescan thread.\n"); 47531e637ba6SAlexander Motin } 475483c5d981SAlexander Motin } 47558b8a9b1dSJustin T. Gibbs 475683c5d981SAlexander Motin void 475783c5d981SAlexander Motin xpt_hold_boot(void) 475883c5d981SAlexander Motin { 475983c5d981SAlexander Motin xpt_lock_buses(); 476083c5d981SAlexander Motin xsoftc.buses_to_config++; 476183c5d981SAlexander Motin xpt_unlock_buses(); 476283c5d981SAlexander Motin } 476383c5d981SAlexander Motin 476483c5d981SAlexander Motin void 476583c5d981SAlexander Motin xpt_release_boot(void) 476683c5d981SAlexander Motin { 476783c5d981SAlexander Motin xpt_lock_buses(); 476883c5d981SAlexander Motin xsoftc.buses_to_config--; 476983c5d981SAlexander Motin if (xsoftc.buses_to_config == 0 && xsoftc.buses_config_done == 0) { 477083c5d981SAlexander Motin struct xpt_task *task; 477183c5d981SAlexander Motin 477283c5d981SAlexander Motin xsoftc.buses_config_done = 1; 477383c5d981SAlexander Motin xpt_unlock_buses(); 4774ecdf1113SJustin T. Gibbs /* Call manually because we don't have any busses */ 477583c5d981SAlexander Motin task = malloc(sizeof(struct xpt_task), M_CAMXPT, M_NOWAIT); 477683c5d981SAlexander Motin if (task != NULL) { 477783c5d981SAlexander Motin TASK_INIT(&task->task, 0, xpt_finishconfig_task, task); 477883c5d981SAlexander Motin taskqueue_enqueue(taskqueue_thread, &task->task); 47792863f7b1SJustin T. Gibbs } 478083c5d981SAlexander Motin } else 478183c5d981SAlexander Motin xpt_unlock_buses(); 47822863f7b1SJustin T. Gibbs } 47838b8a9b1dSJustin T. Gibbs 47848b8a9b1dSJustin T. Gibbs /* 47858b8a9b1dSJustin T. Gibbs * If the given device only has one peripheral attached to it, and if that 47868b8a9b1dSJustin T. Gibbs * peripheral is the passthrough driver, announce it. This insures that the 47878b8a9b1dSJustin T. Gibbs * user sees some sort of announcement for every peripheral in their system. 47888b8a9b1dSJustin T. Gibbs */ 47898b8a9b1dSJustin T. Gibbs static int 47908b8a9b1dSJustin T. Gibbs xptpassannouncefunc(struct cam_ed *device, void *arg) 47918b8a9b1dSJustin T. Gibbs { 47928b8a9b1dSJustin T. Gibbs struct cam_periph *periph; 47938b8a9b1dSJustin T. Gibbs int i; 47948b8a9b1dSJustin T. Gibbs 47958b8a9b1dSJustin T. Gibbs for (periph = SLIST_FIRST(&device->periphs), i = 0; periph != NULL; 47968b8a9b1dSJustin T. Gibbs periph = SLIST_NEXT(periph, periph_links), i++); 47978b8a9b1dSJustin T. Gibbs 47988b8a9b1dSJustin T. Gibbs periph = SLIST_FIRST(&device->periphs); 47998b8a9b1dSJustin T. Gibbs if ((i == 1) 48008b8a9b1dSJustin T. Gibbs && (strncmp(periph->periph_name, "pass", 4) == 0)) 48018b8a9b1dSJustin T. Gibbs xpt_announce_periph(periph, NULL); 48028b8a9b1dSJustin T. Gibbs 48038b8a9b1dSJustin T. Gibbs return(1); 48048b8a9b1dSJustin T. Gibbs } 48058b8a9b1dSJustin T. Gibbs 48068b8a9b1dSJustin T. Gibbs static void 48072b83592fSScott Long xpt_finishconfig_task(void *context, int pending) 48088b8a9b1dSJustin T. Gibbs { 48098b8a9b1dSJustin T. Gibbs 481083c5d981SAlexander Motin periphdriver_init(2); 48112b83592fSScott Long /* 48122b83592fSScott Long * Check for devices with no "standard" peripheral driver 48132b83592fSScott Long * attached. For any devices like that, announce the 48142b83592fSScott Long * passthrough driver so the user will see something. 48152b83592fSScott Long */ 48163089bb2eSAlexander Motin if (!bootverbose) 48172b83592fSScott Long xpt_for_all_devices(xptpassannouncefunc, NULL); 48182b83592fSScott Long 48192b83592fSScott Long /* Release our hook so that the boot can continue. */ 48202b83592fSScott Long config_intrhook_disestablish(xsoftc.xpt_config_hook); 48210dd50e9bSScott Long free(xsoftc.xpt_config_hook, M_CAMXPT); 48222b83592fSScott Long xsoftc.xpt_config_hook = NULL; 48232b83592fSScott Long 48242b83592fSScott Long free(context, M_CAMXPT); 48252b83592fSScott Long } 48262b83592fSScott Long 482785d92640SScott Long cam_status 482885d92640SScott Long xpt_register_async(int event, ac_callback_t *cbfunc, void *cbarg, 482985d92640SScott Long struct cam_path *path) 483085d92640SScott Long { 483185d92640SScott Long struct ccb_setasync csa; 483285d92640SScott Long cam_status status; 483385d92640SScott Long int xptpath = 0; 483485d92640SScott Long 483585d92640SScott Long if (path == NULL) { 483685d92640SScott Long mtx_lock(&xsoftc.xpt_lock); 483785d92640SScott Long status = xpt_create_path(&path, /*periph*/NULL, CAM_XPT_PATH_ID, 483885d92640SScott Long CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD); 483985d92640SScott Long if (status != CAM_REQ_CMP) { 484085d92640SScott Long mtx_unlock(&xsoftc.xpt_lock); 484185d92640SScott Long return (status); 484285d92640SScott Long } 484385d92640SScott Long xptpath = 1; 484485d92640SScott Long } 484585d92640SScott Long 484683c5d981SAlexander Motin xpt_setup_ccb(&csa.ccb_h, path, CAM_PRIORITY_NORMAL); 484785d92640SScott Long csa.ccb_h.func_code = XPT_SASYNC_CB; 484885d92640SScott Long csa.event_enable = event; 484985d92640SScott Long csa.callback = cbfunc; 485085d92640SScott Long csa.callback_arg = cbarg; 485185d92640SScott Long xpt_action((union ccb *)&csa); 485285d92640SScott Long status = csa.ccb_h.status; 48533501942bSJustin T. Gibbs 485485d92640SScott Long if (xptpath) { 485585d92640SScott Long xpt_free_path(path); 485685d92640SScott Long mtx_unlock(&xsoftc.xpt_lock); 48573501942bSJustin T. Gibbs } 48587685edecSAlexander Motin 48597685edecSAlexander Motin if ((status == CAM_REQ_CMP) && 48607685edecSAlexander Motin (csa.event_enable & AC_FOUND_DEVICE)) { 48617685edecSAlexander Motin /* 48627685edecSAlexander Motin * Get this peripheral up to date with all 48637685edecSAlexander Motin * the currently existing devices. 48647685edecSAlexander Motin */ 48657685edecSAlexander Motin xpt_for_all_devices(xptsetasyncfunc, &csa); 48667685edecSAlexander Motin } 48677685edecSAlexander Motin if ((status == CAM_REQ_CMP) && 48687685edecSAlexander Motin (csa.event_enable & AC_PATH_REGISTERED)) { 48697685edecSAlexander Motin /* 48707685edecSAlexander Motin * Get this peripheral up to date with all 48717685edecSAlexander Motin * the currently existing busses. 48727685edecSAlexander Motin */ 48737685edecSAlexander Motin xpt_for_all_busses(xptsetasyncbusfunc, &csa); 48747685edecSAlexander Motin } 48753501942bSJustin T. Gibbs 487685d92640SScott Long return (status); 487785d92640SScott Long } 487885d92640SScott Long 48798b8a9b1dSJustin T. Gibbs static void 48808b8a9b1dSJustin T. Gibbs xptaction(struct cam_sim *sim, union ccb *work_ccb) 48818b8a9b1dSJustin T. Gibbs { 48828b8a9b1dSJustin T. Gibbs CAM_DEBUG(work_ccb->ccb_h.path, CAM_DEBUG_TRACE, ("xptaction\n")); 48838b8a9b1dSJustin T. Gibbs 48848b8a9b1dSJustin T. Gibbs switch (work_ccb->ccb_h.func_code) { 48858b8a9b1dSJustin T. Gibbs /* Common cases first */ 48868b8a9b1dSJustin T. Gibbs case XPT_PATH_INQ: /* Path routing inquiry */ 48878b8a9b1dSJustin T. Gibbs { 48888b8a9b1dSJustin T. Gibbs struct ccb_pathinq *cpi; 48898b8a9b1dSJustin T. Gibbs 48908b8a9b1dSJustin T. Gibbs cpi = &work_ccb->cpi; 48918b8a9b1dSJustin T. Gibbs cpi->version_num = 1; /* XXX??? */ 48928b8a9b1dSJustin T. Gibbs cpi->hba_inquiry = 0; 48938b8a9b1dSJustin T. Gibbs cpi->target_sprt = 0; 48948b8a9b1dSJustin T. Gibbs cpi->hba_misc = 0; 48958b8a9b1dSJustin T. Gibbs cpi->hba_eng_cnt = 0; 48968b8a9b1dSJustin T. Gibbs cpi->max_target = 0; 48978b8a9b1dSJustin T. Gibbs cpi->max_lun = 0; 48988b8a9b1dSJustin T. Gibbs cpi->initiator_id = 0; 48998b8a9b1dSJustin T. Gibbs strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN); 49008b8a9b1dSJustin T. Gibbs strncpy(cpi->hba_vid, "", HBA_IDLEN); 49018b8a9b1dSJustin T. Gibbs strncpy(cpi->dev_name, sim->sim_name, DEV_IDLEN); 49028b8a9b1dSJustin T. Gibbs cpi->unit_number = sim->unit_number; 49038b8a9b1dSJustin T. Gibbs cpi->bus_id = sim->bus_id; 49049deea857SKenneth D. Merry cpi->base_transfer_speed = 0; 49053393f8daSKenneth D. Merry cpi->protocol = PROTO_UNSPECIFIED; 49063393f8daSKenneth D. Merry cpi->protocol_version = PROTO_VERSION_UNSPECIFIED; 49073393f8daSKenneth D. Merry cpi->transport = XPORT_UNSPECIFIED; 49083393f8daSKenneth D. Merry cpi->transport_version = XPORT_VERSION_UNSPECIFIED; 49098b8a9b1dSJustin T. Gibbs cpi->ccb_h.status = CAM_REQ_CMP; 49108b8a9b1dSJustin T. Gibbs xpt_done(work_ccb); 49118b8a9b1dSJustin T. Gibbs break; 49128b8a9b1dSJustin T. Gibbs } 49138b8a9b1dSJustin T. Gibbs default: 49148b8a9b1dSJustin T. Gibbs work_ccb->ccb_h.status = CAM_REQ_INVALID; 49158b8a9b1dSJustin T. Gibbs xpt_done(work_ccb); 49168b8a9b1dSJustin T. Gibbs break; 49178b8a9b1dSJustin T. Gibbs } 49188b8a9b1dSJustin T. Gibbs } 49198b8a9b1dSJustin T. Gibbs 49208b8a9b1dSJustin T. Gibbs /* 4921434bbf6eSJustin T. Gibbs * The xpt as a "controller" has no interrupt sources, so polling 4922434bbf6eSJustin T. Gibbs * is a no-op. 4923434bbf6eSJustin T. Gibbs */ 4924434bbf6eSJustin T. Gibbs static void 4925434bbf6eSJustin T. Gibbs xptpoll(struct cam_sim *sim) 4926434bbf6eSJustin T. Gibbs { 4927434bbf6eSJustin T. Gibbs } 4928434bbf6eSJustin T. Gibbs 49292b83592fSScott Long void 49302b83592fSScott Long xpt_lock_buses(void) 49312b83592fSScott Long { 49322b83592fSScott Long mtx_lock(&xsoftc.xpt_topo_lock); 49332b83592fSScott Long } 49342b83592fSScott Long 49352b83592fSScott Long void 49362b83592fSScott Long xpt_unlock_buses(void) 49372b83592fSScott Long { 49382b83592fSScott Long mtx_unlock(&xsoftc.xpt_topo_lock); 49392b83592fSScott Long } 49402b83592fSScott Long 49415d754af7SMatt Jacob static void 49429758cc83SScott Long camisr(void *dummy) 49438b8a9b1dSJustin T. Gibbs { 49449758cc83SScott Long cam_simq_t queue; 49452b83592fSScott Long struct cam_sim *sim; 49468b8a9b1dSJustin T. Gibbs 49479758cc83SScott Long mtx_lock(&cam_simq_lock); 4948ef3cf714SScott Long TAILQ_INIT(&queue); 4949788fb376SAlexander Motin while (!TAILQ_EMPTY(&cam_simq)) { 49509758cc83SScott Long TAILQ_CONCAT(&queue, &cam_simq, links); 49519758cc83SScott Long mtx_unlock(&cam_simq_lock); 4952ef3cf714SScott Long 49539758cc83SScott Long while ((sim = TAILQ_FIRST(&queue)) != NULL) { 49549758cc83SScott Long TAILQ_REMOVE(&queue, sim, links); 495511e4faceSScott Long CAM_SIM_LOCK(sim); 495639fe6d85SAlexander Motin camisr_runqueue(sim); 495710284c8bSAlexander Motin sim->flags &= ~CAM_SIM_ON_DONEQ; 495811e4faceSScott Long CAM_SIM_UNLOCK(sim); 49599758cc83SScott Long } 4960788fb376SAlexander Motin mtx_lock(&cam_simq_lock); 4961788fb376SAlexander Motin } 4962788fb376SAlexander Motin mtx_unlock(&cam_simq_lock); 49639758cc83SScott Long } 49649758cc83SScott Long 49659758cc83SScott Long static void 496639fe6d85SAlexander Motin camisr_runqueue(struct cam_sim *sim) 49679758cc83SScott Long { 49689758cc83SScott Long struct ccb_hdr *ccb_h; 49699758cc83SScott Long 497039fe6d85SAlexander Motin while ((ccb_h = TAILQ_FIRST(&sim->sim_doneq)) != NULL) { 49718b8a9b1dSJustin T. Gibbs int runq; 49728b8a9b1dSJustin T. Gibbs 497339fe6d85SAlexander Motin TAILQ_REMOVE(&sim->sim_doneq, ccb_h, sim_links.tqe); 49748b8a9b1dSJustin T. Gibbs ccb_h->pinfo.index = CAM_UNQUEUED_INDEX; 49758b8a9b1dSJustin T. Gibbs 49768b8a9b1dSJustin T. Gibbs CAM_DEBUG(ccb_h->path, CAM_DEBUG_TRACE, 497757b89bbcSNate Lawson ("camisr\n")); 49788b8a9b1dSJustin T. Gibbs 49798b8a9b1dSJustin T. Gibbs runq = FALSE; 49808b8a9b1dSJustin T. Gibbs 49818b8a9b1dSJustin T. Gibbs if (ccb_h->flags & CAM_HIGH_POWER) { 49828b8a9b1dSJustin T. Gibbs struct highpowerlist *hphead; 4983ea541bfdSAlexander Motin struct cam_ed *device; 49848b8a9b1dSJustin T. Gibbs 49852b83592fSScott Long mtx_lock(&xsoftc.xpt_lock); 49862b83592fSScott Long hphead = &xsoftc.highpowerq; 49878b8a9b1dSJustin T. Gibbs 4988ea541bfdSAlexander Motin device = STAILQ_FIRST(hphead); 49898b8a9b1dSJustin T. Gibbs 49908b8a9b1dSJustin T. Gibbs /* 49918b8a9b1dSJustin T. Gibbs * Increment the count since this command is done. 49928b8a9b1dSJustin T. Gibbs */ 49932b83592fSScott Long xsoftc.num_highpower++; 49948b8a9b1dSJustin T. Gibbs 49958b8a9b1dSJustin T. Gibbs /* 49968b8a9b1dSJustin T. Gibbs * Any high powered commands queued up? 49978b8a9b1dSJustin T. Gibbs */ 4998ea541bfdSAlexander Motin if (device != NULL) { 49998b8a9b1dSJustin T. Gibbs 5000ea541bfdSAlexander Motin STAILQ_REMOVE_HEAD(hphead, highpowerq_entry); 50012b83592fSScott Long mtx_unlock(&xsoftc.xpt_lock); 50028b8a9b1dSJustin T. Gibbs 5003ea541bfdSAlexander Motin xpt_release_devq_device(device, 50042cefde5fSJustin T. Gibbs /*count*/1, /*runqueue*/TRUE); 50052b83592fSScott Long } else 50062b83592fSScott Long mtx_unlock(&xsoftc.xpt_lock); 50078b8a9b1dSJustin T. Gibbs } 50082b83592fSScott Long 50099deea857SKenneth D. Merry if ((ccb_h->func_code & XPT_FC_USER_CCB) == 0) { 50108b8a9b1dSJustin T. Gibbs struct cam_ed *dev; 50118b8a9b1dSJustin T. Gibbs 50128b8a9b1dSJustin T. Gibbs dev = ccb_h->path->device; 50138b8a9b1dSJustin T. Gibbs 50148b8a9b1dSJustin T. Gibbs cam_ccbq_ccb_done(&dev->ccbq, (union ccb *)ccb_h); 501539fe6d85SAlexander Motin sim->devq->send_active--; 501639fe6d85SAlexander Motin sim->devq->send_openings++; 501783c5d981SAlexander Motin runq = TRUE; 50188b8a9b1dSJustin T. Gibbs 5019b9c473b2SAlexander Motin if (((dev->flags & CAM_DEV_REL_ON_QUEUE_EMPTY) != 0 50208b8a9b1dSJustin T. Gibbs && (dev->ccbq.dev_active == 0))) { 5021b9c473b2SAlexander Motin dev->flags &= ~CAM_DEV_REL_ON_QUEUE_EMPTY; 5022b9c473b2SAlexander Motin xpt_release_devq(ccb_h->path, /*count*/1, 5023b9c473b2SAlexander Motin /*run_queue*/FALSE); 5024b9c473b2SAlexander Motin } 5025b9c473b2SAlexander Motin 5026b9c473b2SAlexander Motin if (((dev->flags & CAM_DEV_REL_ON_COMPLETE) != 0 5027b9c473b2SAlexander Motin && (ccb_h->status&CAM_STATUS_MASK) != CAM_REQUEUE_REQ)) { 5028b9c473b2SAlexander Motin dev->flags &= ~CAM_DEV_REL_ON_COMPLETE; 50292cefde5fSJustin T. Gibbs xpt_release_devq(ccb_h->path, /*count*/1, 503083c5d981SAlexander Motin /*run_queue*/FALSE); 50318b8a9b1dSJustin T. Gibbs } 50328b8a9b1dSJustin T. Gibbs 5033fd21cc5eSJustin T. Gibbs if ((dev->flags & CAM_DEV_TAG_AFTER_COUNT) != 0 5034fd21cc5eSJustin T. Gibbs && (--dev->tag_delay_count == 0)) 5035fd21cc5eSJustin T. Gibbs xpt_start_tags(ccb_h->path); 5036cccf4220SAlexander Motin if (!device_is_queued(dev)) { 503739fe6d85SAlexander Motin (void)xpt_schedule_devq(sim->devq, dev); 50383501942bSJustin T. Gibbs } 50398b8a9b1dSJustin T. Gibbs } 50408b8a9b1dSJustin T. Gibbs 50418b8a9b1dSJustin T. Gibbs if (ccb_h->status & CAM_RELEASE_SIMQ) { 504239fe6d85SAlexander Motin xpt_release_simq(sim, /*run_queue*/TRUE); 5043434bbf6eSJustin T. Gibbs ccb_h->status &= ~CAM_RELEASE_SIMQ; 5044434bbf6eSJustin T. Gibbs runq = FALSE; 5045434bbf6eSJustin T. Gibbs } 5046434bbf6eSJustin T. Gibbs 5047434bbf6eSJustin T. Gibbs if ((ccb_h->flags & CAM_DEV_QFRZDIS) 50488b8a9b1dSJustin T. Gibbs && (ccb_h->status & CAM_DEV_QFRZN)) { 50492cefde5fSJustin T. Gibbs xpt_release_devq(ccb_h->path, /*count*/1, 50508b8a9b1dSJustin T. Gibbs /*run_queue*/TRUE); 50518b8a9b1dSJustin T. Gibbs ccb_h->status &= ~CAM_DEV_QFRZN; 50528b8a9b1dSJustin T. Gibbs } else if (runq) { 505339fe6d85SAlexander Motin xpt_run_devq(sim->devq); 50548b8a9b1dSJustin T. Gibbs } 50558b8a9b1dSJustin T. Gibbs 50568b8a9b1dSJustin T. Gibbs /* Call the peripheral driver's callback */ 5057434bbf6eSJustin T. Gibbs (*ccb_h->cbfcnp)(ccb_h->path->periph, (union ccb *)ccb_h); 50588b8a9b1dSJustin T. Gibbs } 50598b8a9b1dSJustin T. Gibbs } 5060