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> 43227d67aaSAlexander Motin #include <sys/proc.h> 443393f8daSKenneth D. Merry #include <sys/sbuf.h> 45227d67aaSAlexander Motin #include <sys/smp.h> 462b83592fSScott Long #include <sys/taskqueue.h> 478b8a9b1dSJustin T. Gibbs 48ef3cf714SScott Long #include <sys/lock.h> 49ef3cf714SScott Long #include <sys/mutex.h> 503b87a552SMatt Jacob #include <sys/sysctl.h> 519e6461a2SMatt Jacob #include <sys/kthread.h> 52ef3cf714SScott Long 538b8a9b1dSJustin T. Gibbs #include <cam/cam.h> 548b8a9b1dSJustin T. Gibbs #include <cam/cam_ccb.h> 558b8a9b1dSJustin T. Gibbs #include <cam/cam_periph.h> 5652c9ce25SScott Long #include <cam/cam_queue.h> 578b8a9b1dSJustin T. Gibbs #include <cam/cam_sim.h> 588b8a9b1dSJustin T. Gibbs #include <cam/cam_xpt.h> 598b8a9b1dSJustin T. Gibbs #include <cam/cam_xpt_sim.h> 608b8a9b1dSJustin T. Gibbs #include <cam/cam_xpt_periph.h> 6152c9ce25SScott Long #include <cam/cam_xpt_internal.h> 628b8a9b1dSJustin T. Gibbs #include <cam/cam_debug.h> 6325a2902cSScott Long #include <cam/cam_compat.h> 648b8a9b1dSJustin T. Gibbs 658b8a9b1dSJustin T. Gibbs #include <cam/scsi/scsi_all.h> 668b8a9b1dSJustin T. Gibbs #include <cam/scsi/scsi_message.h> 678b8a9b1dSJustin T. Gibbs #include <cam/scsi/scsi_pass.h> 68abef0e67SMarius Strobl 69abef0e67SMarius Strobl #include <machine/md_var.h> /* geometry translation */ 70f0d9af51SMatt Jacob #include <machine/stdarg.h> /* for xpt_print below */ 71abef0e67SMarius Strobl 728b8a9b1dSJustin T. Gibbs #include "opt_cam.h" 738b8a9b1dSJustin T. Gibbs 7452c9ce25SScott Long /* 7552c9ce25SScott Long * This is the maximum number of high powered commands (e.g. start unit) 7652c9ce25SScott Long * that can be outstanding at a particular time. 7752c9ce25SScott Long */ 7852c9ce25SScott Long #ifndef CAM_MAX_HIGHPOWER 7952c9ce25SScott Long #define CAM_MAX_HIGHPOWER 4 8052c9ce25SScott Long #endif 8152c9ce25SScott Long 828b8a9b1dSJustin T. Gibbs /* Datastructures internal to the xpt layer */ 83362abc44STai-hwa Liang MALLOC_DEFINE(M_CAMXPT, "CAM XPT", "CAM XPT buffers"); 84596ee08fSAlexander Motin MALLOC_DEFINE(M_CAMDEV, "CAM DEV", "CAM devices"); 85596ee08fSAlexander Motin MALLOC_DEFINE(M_CAMCCB, "CAM CCB", "CAM CCBs"); 86596ee08fSAlexander Motin MALLOC_DEFINE(M_CAMPATH, "CAM path", "CAM paths"); 878b8a9b1dSJustin T. Gibbs 882b83592fSScott Long /* Object for defering XPT actions to a taskqueue */ 892b83592fSScott Long struct xpt_task { 902b83592fSScott Long struct task task; 9184f82481SScott Long void *data1; 9284f82481SScott Long uintptr_t data2; 932b83592fSScott Long }; 942b83592fSScott Long 958b8a9b1dSJustin T. Gibbs struct xpt_softc { 962b83592fSScott Long /* number of high powered commands that can go through right now */ 97daa5487fSAlexander Motin struct mtx xpt_highpower_lock; 98ea541bfdSAlexander Motin STAILQ_HEAD(highpowerlist, cam_ed) highpowerq; 992b83592fSScott Long int num_highpower; 1002b83592fSScott Long 1012b83592fSScott Long /* queue for handling async rescan requests. */ 1022b83592fSScott Long TAILQ_HEAD(, ccb_hdr) ccb_scanq; 10383c5d981SAlexander Motin int buses_to_config; 10483c5d981SAlexander Motin int buses_config_done; 1052b83592fSScott Long 1062b83592fSScott Long /* Registered busses */ 1072b83592fSScott Long TAILQ_HEAD(,cam_eb) xpt_busses; 1082b83592fSScott Long u_int bus_generation; 1092b83592fSScott Long 1102b83592fSScott Long struct intr_config_hook *xpt_config_hook; 1112b83592fSScott Long 11283c5d981SAlexander Motin int boot_delay; 11383c5d981SAlexander Motin struct callout boot_callout; 11483c5d981SAlexander Motin 1152b83592fSScott Long struct mtx xpt_topo_lock; 1162b83592fSScott Long struct mtx xpt_lock; 117227d67aaSAlexander Motin struct taskqueue *xpt_taskq; 1188b8a9b1dSJustin T. Gibbs }; 1198b8a9b1dSJustin T. Gibbs 1208b8a9b1dSJustin T. Gibbs typedef enum { 1218b8a9b1dSJustin T. Gibbs DM_RET_COPY = 0x01, 1228b8a9b1dSJustin T. Gibbs DM_RET_FLAG_MASK = 0x0f, 1238b8a9b1dSJustin T. Gibbs DM_RET_NONE = 0x00, 1248b8a9b1dSJustin T. Gibbs DM_RET_STOP = 0x10, 1258b8a9b1dSJustin T. Gibbs DM_RET_DESCEND = 0x20, 1268b8a9b1dSJustin T. Gibbs DM_RET_ERROR = 0x30, 1278b8a9b1dSJustin T. Gibbs DM_RET_ACTION_MASK = 0xf0 1288b8a9b1dSJustin T. Gibbs } dev_match_ret; 1298b8a9b1dSJustin T. Gibbs 1308b8a9b1dSJustin T. Gibbs typedef enum { 1318b8a9b1dSJustin T. Gibbs XPT_DEPTH_BUS, 1328b8a9b1dSJustin T. Gibbs XPT_DEPTH_TARGET, 1338b8a9b1dSJustin T. Gibbs XPT_DEPTH_DEVICE, 1348b8a9b1dSJustin T. Gibbs XPT_DEPTH_PERIPH 1358b8a9b1dSJustin T. Gibbs } xpt_traverse_depth; 1368b8a9b1dSJustin T. Gibbs 1378b8a9b1dSJustin T. Gibbs struct xpt_traverse_config { 1388b8a9b1dSJustin T. Gibbs xpt_traverse_depth depth; 1398b8a9b1dSJustin T. Gibbs void *tr_func; 1408b8a9b1dSJustin T. Gibbs void *tr_arg; 1418b8a9b1dSJustin T. Gibbs }; 1428b8a9b1dSJustin T. Gibbs 1438b8a9b1dSJustin T. Gibbs typedef int xpt_busfunc_t (struct cam_eb *bus, void *arg); 1448b8a9b1dSJustin T. Gibbs typedef int xpt_targetfunc_t (struct cam_et *target, void *arg); 1458b8a9b1dSJustin T. Gibbs typedef int xpt_devicefunc_t (struct cam_ed *device, void *arg); 1468b8a9b1dSJustin T. Gibbs typedef int xpt_periphfunc_t (struct cam_periph *periph, void *arg); 1478b8a9b1dSJustin T. Gibbs typedef int xpt_pdrvfunc_t (struct periph_driver **pdrv, void *arg); 1488b8a9b1dSJustin T. Gibbs 1498b8a9b1dSJustin T. Gibbs /* Transport layer configuration information */ 1508b8a9b1dSJustin T. Gibbs static struct xpt_softc xsoftc; 1518b8a9b1dSJustin T. Gibbs 15283c5d981SAlexander Motin TUNABLE_INT("kern.cam.boot_delay", &xsoftc.boot_delay); 15383c5d981SAlexander Motin SYSCTL_INT(_kern_cam, OID_AUTO, boot_delay, CTLFLAG_RDTUN, 15483c5d981SAlexander Motin &xsoftc.boot_delay, 0, "Bus registration wait time"); 15583c5d981SAlexander Motin 156227d67aaSAlexander Motin struct cam_doneq { 157227d67aaSAlexander Motin struct mtx_padalign cam_doneq_mtx; 158227d67aaSAlexander Motin STAILQ_HEAD(, ccb_hdr) cam_doneq; 159227d67aaSAlexander Motin int cam_doneq_sleep; 160227d67aaSAlexander Motin }; 1618b8a9b1dSJustin T. Gibbs 162227d67aaSAlexander Motin static struct cam_doneq cam_doneqs[MAXCPU]; 163227d67aaSAlexander Motin static int cam_num_doneqs; 164227d67aaSAlexander Motin static struct proc *cam_proc; 165227d67aaSAlexander Motin 166227d67aaSAlexander Motin TUNABLE_INT("kern.cam.num_doneqs", &cam_num_doneqs); 167227d67aaSAlexander Motin SYSCTL_INT(_kern_cam, OID_AUTO, num_doneqs, CTLFLAG_RDTUN, 168227d67aaSAlexander Motin &cam_num_doneqs, 0, "Number of completion queues/threads"); 1698b8a9b1dSJustin T. Gibbs 1709a1c8571SNick Hibma struct cam_periph *xpt_periph; 1719a1c8571SNick Hibma 1728b8a9b1dSJustin T. Gibbs static periph_init_t xpt_periph_init; 1738b8a9b1dSJustin T. Gibbs 1748b8a9b1dSJustin T. Gibbs static struct periph_driver xpt_driver = 1758b8a9b1dSJustin T. Gibbs { 1768b8a9b1dSJustin T. Gibbs xpt_periph_init, "xpt", 1771e637ba6SAlexander Motin TAILQ_HEAD_INITIALIZER(xpt_driver.units), /* generation */ 0, 1781e637ba6SAlexander Motin CAM_PERIPH_DRV_EARLY 1798b8a9b1dSJustin T. Gibbs }; 1808b8a9b1dSJustin T. Gibbs 1810b7c27b9SPeter Wemm PERIPHDRIVER_DECLARE(xpt, xpt_driver); 1828b8a9b1dSJustin T. Gibbs 1838b8a9b1dSJustin T. Gibbs static d_open_t xptopen; 1848b8a9b1dSJustin T. Gibbs static d_close_t xptclose; 1858b8a9b1dSJustin T. Gibbs static d_ioctl_t xptioctl; 18625a2902cSScott Long static d_ioctl_t xptdoioctl; 1878b8a9b1dSJustin T. Gibbs 1884e2f199eSPoul-Henning Kamp static struct cdevsw xpt_cdevsw = { 189dc08ffecSPoul-Henning Kamp .d_version = D_VERSION, 1902b83592fSScott Long .d_flags = 0, 1917ac40f5fSPoul-Henning Kamp .d_open = xptopen, 1927ac40f5fSPoul-Henning Kamp .d_close = xptclose, 1937ac40f5fSPoul-Henning Kamp .d_ioctl = xptioctl, 1947ac40f5fSPoul-Henning Kamp .d_name = "xpt", 1958b8a9b1dSJustin T. Gibbs }; 1968b8a9b1dSJustin T. Gibbs 1978b8a9b1dSJustin T. Gibbs /* Storage for debugging datastructures */ 1988b8a9b1dSJustin T. Gibbs struct cam_path *cam_dpath; 19982b361b1SMatt Jacob u_int32_t cam_dflags = CAM_DEBUG_FLAGS; 20082b361b1SMatt Jacob TUNABLE_INT("kern.cam.dflags", &cam_dflags); 201240577c2SMatthew D Fleming SYSCTL_UINT(_kern_cam, OID_AUTO, dflags, CTLFLAG_RW, 202f0f25b9cSAlexander Motin &cam_dflags, 0, "Enabled debug flags"); 203f0f25b9cSAlexander Motin u_int32_t cam_debug_delay = CAM_DEBUG_DELAY; 20482b361b1SMatt Jacob TUNABLE_INT("kern.cam.debug_delay", &cam_debug_delay); 205240577c2SMatthew D Fleming SYSCTL_UINT(_kern_cam, OID_AUTO, debug_delay, CTLFLAG_RW, 206f0f25b9cSAlexander Motin &cam_debug_delay, 0, "Delay in us after each debug message"); 2078b8a9b1dSJustin T. Gibbs 2086d2a8f1cSPeter Wemm /* Our boot-time initialization hook */ 20974bd1c10SNick Hibma static int cam_module_event_handler(module_t, int /*modeventtype_t*/, void *); 21074bd1c10SNick Hibma 21174bd1c10SNick Hibma static moduledata_t cam_moduledata = { 21274bd1c10SNick Hibma "cam", 21374bd1c10SNick Hibma cam_module_event_handler, 21474bd1c10SNick Hibma NULL 21574bd1c10SNick Hibma }; 21674bd1c10SNick Hibma 2172b83592fSScott Long static int xpt_init(void *); 21874bd1c10SNick Hibma 21974bd1c10SNick Hibma DECLARE_MODULE(cam, cam_moduledata, SI_SUB_CONFIGURE, SI_ORDER_SECOND); 22074bd1c10SNick Hibma MODULE_VERSION(cam, 1); 22174bd1c10SNick Hibma 2228b8a9b1dSJustin T. Gibbs 2238b8a9b1dSJustin T. Gibbs static void xpt_async_bcast(struct async_list *async_head, 2248b8a9b1dSJustin T. Gibbs u_int32_t async_code, 2258b8a9b1dSJustin T. Gibbs struct cam_path *path, 2268b8a9b1dSJustin T. Gibbs void *async_arg); 227434bbf6eSJustin T. Gibbs static path_id_t xptnextfreepathid(void); 228434bbf6eSJustin T. Gibbs static path_id_t xptpathid(const char *sim_name, int sim_unit, int sim_bus); 229227d67aaSAlexander Motin static union ccb *xpt_get_ccb(struct cam_periph *periph); 230227d67aaSAlexander Motin static union ccb *xpt_get_ccb_nowait(struct cam_periph *periph); 231227d67aaSAlexander Motin static void xpt_run_allocq(struct cam_periph *periph, int sleep); 232227d67aaSAlexander Motin static void xpt_run_allocq_task(void *context, int pending); 233cccf4220SAlexander Motin static void xpt_run_devq(struct cam_devq *devq); 2348b8a9b1dSJustin T. Gibbs static timeout_t xpt_release_devq_timeout; 2352b83592fSScott Long static void xpt_release_simq_timeout(void *arg) __unused; 236227d67aaSAlexander Motin static void xpt_acquire_bus(struct cam_eb *bus); 237a5479bc5SJustin T. Gibbs static void xpt_release_bus(struct cam_eb *bus); 238daa5487fSAlexander Motin static uint32_t xpt_freeze_devq_device(struct cam_ed *dev, u_int count); 239227d67aaSAlexander Motin static int xpt_release_devq_device(struct cam_ed *dev, u_int count, 240cccf4220SAlexander Motin int run_queue); 2418b8a9b1dSJustin T. Gibbs static struct cam_et* 2428b8a9b1dSJustin T. Gibbs xpt_alloc_target(struct cam_eb *bus, target_id_t target_id); 243227d67aaSAlexander Motin static void xpt_acquire_target(struct cam_et *target); 244f98d7a47SAlexander Motin static void xpt_release_target(struct cam_et *target); 2458b8a9b1dSJustin T. Gibbs static struct cam_eb* 2468b8a9b1dSJustin T. Gibbs xpt_find_bus(path_id_t path_id); 2478b8a9b1dSJustin T. Gibbs static struct cam_et* 2488b8a9b1dSJustin T. Gibbs xpt_find_target(struct cam_eb *bus, target_id_t target_id); 2498b8a9b1dSJustin T. Gibbs static struct cam_ed* 2508b8a9b1dSJustin T. Gibbs xpt_find_device(struct cam_et *target, lun_id_t lun_id); 2518b8a9b1dSJustin T. Gibbs static void xpt_config(void *arg); 252227d67aaSAlexander Motin static int xpt_schedule_dev(struct camq *queue, cam_pinfo *dev_pinfo, 253227d67aaSAlexander Motin u_int32_t new_priority); 2548b8a9b1dSJustin T. Gibbs static xpt_devicefunc_t xptpassannouncefunc; 2558b8a9b1dSJustin T. Gibbs static void xptaction(struct cam_sim *sim, union ccb *work_ccb); 256434bbf6eSJustin T. Gibbs static void xptpoll(struct cam_sim *sim); 257227d67aaSAlexander Motin static void camisr_runqueue(void); 258227d67aaSAlexander Motin static void xpt_done_process(struct ccb_hdr *ccb_h); 259227d67aaSAlexander Motin static void xpt_done_td(void *); 2608b8a9b1dSJustin T. Gibbs static dev_match_ret xptbusmatch(struct dev_match_pattern *patterns, 2613393f8daSKenneth D. Merry u_int num_patterns, struct cam_eb *bus); 2628b8a9b1dSJustin T. Gibbs static dev_match_ret xptdevicematch(struct dev_match_pattern *patterns, 2633393f8daSKenneth D. Merry u_int num_patterns, 2643393f8daSKenneth D. Merry struct cam_ed *device); 2658b8a9b1dSJustin T. Gibbs static dev_match_ret xptperiphmatch(struct dev_match_pattern *patterns, 2663393f8daSKenneth D. Merry u_int num_patterns, 2678b8a9b1dSJustin T. Gibbs struct cam_periph *periph); 2688b8a9b1dSJustin T. Gibbs static xpt_busfunc_t xptedtbusfunc; 2698b8a9b1dSJustin T. Gibbs static xpt_targetfunc_t xptedttargetfunc; 2708b8a9b1dSJustin T. Gibbs static xpt_devicefunc_t xptedtdevicefunc; 2718b8a9b1dSJustin T. Gibbs static xpt_periphfunc_t xptedtperiphfunc; 2728b8a9b1dSJustin T. Gibbs static xpt_pdrvfunc_t xptplistpdrvfunc; 2738b8a9b1dSJustin T. Gibbs static xpt_periphfunc_t xptplistperiphfunc; 2748b8a9b1dSJustin T. Gibbs static int xptedtmatch(struct ccb_dev_match *cdm); 2758b8a9b1dSJustin T. Gibbs static int xptperiphlistmatch(struct ccb_dev_match *cdm); 2768b8a9b1dSJustin T. Gibbs static int xptbustraverse(struct cam_eb *start_bus, 2778b8a9b1dSJustin T. Gibbs xpt_busfunc_t *tr_func, void *arg); 2788b8a9b1dSJustin T. Gibbs static int xpttargettraverse(struct cam_eb *bus, 2798b8a9b1dSJustin T. Gibbs struct cam_et *start_target, 2808b8a9b1dSJustin T. Gibbs xpt_targetfunc_t *tr_func, void *arg); 2818b8a9b1dSJustin T. Gibbs static int xptdevicetraverse(struct cam_et *target, 2828b8a9b1dSJustin T. Gibbs struct cam_ed *start_device, 2838b8a9b1dSJustin T. Gibbs xpt_devicefunc_t *tr_func, void *arg); 2848b8a9b1dSJustin T. Gibbs static int xptperiphtraverse(struct cam_ed *device, 2858b8a9b1dSJustin T. Gibbs struct cam_periph *start_periph, 2868b8a9b1dSJustin T. Gibbs xpt_periphfunc_t *tr_func, void *arg); 2878b8a9b1dSJustin T. Gibbs static int xptpdrvtraverse(struct periph_driver **start_pdrv, 2888b8a9b1dSJustin T. Gibbs xpt_pdrvfunc_t *tr_func, void *arg); 2898b8a9b1dSJustin T. Gibbs static int xptpdperiphtraverse(struct periph_driver **pdrv, 2908b8a9b1dSJustin T. Gibbs struct cam_periph *start_periph, 2918b8a9b1dSJustin T. Gibbs xpt_periphfunc_t *tr_func, 2928b8a9b1dSJustin T. Gibbs void *arg); 2938b8a9b1dSJustin T. Gibbs static xpt_busfunc_t xptdefbusfunc; 2948b8a9b1dSJustin T. Gibbs static xpt_targetfunc_t xptdeftargetfunc; 2958b8a9b1dSJustin T. Gibbs static xpt_devicefunc_t xptdefdevicefunc; 2968b8a9b1dSJustin T. Gibbs static xpt_periphfunc_t xptdefperiphfunc; 29783c5d981SAlexander Motin static void xpt_finishconfig_task(void *context, int pending); 29852c9ce25SScott Long static void xpt_dev_async_default(u_int32_t async_code, 29952c9ce25SScott Long struct cam_eb *bus, 30052c9ce25SScott Long struct cam_et *target, 30152c9ce25SScott Long struct cam_ed *device, 30252c9ce25SScott Long void *async_arg); 30352c9ce25SScott Long static struct cam_ed * xpt_alloc_device_default(struct cam_eb *bus, 30452c9ce25SScott Long struct cam_et *target, 30552c9ce25SScott Long lun_id_t lun_id); 3068b8a9b1dSJustin T. Gibbs static xpt_devicefunc_t xptsetasyncfunc; 3078b8a9b1dSJustin T. Gibbs static xpt_busfunc_t xptsetasyncbusfunc; 3088b8a9b1dSJustin T. Gibbs static cam_status xptregister(struct cam_periph *periph, 3098b8a9b1dSJustin T. Gibbs void *arg); 310cccf4220SAlexander Motin static __inline int device_is_queued(struct cam_ed *device); 3118b8a9b1dSJustin T. Gibbs 3128b8a9b1dSJustin T. Gibbs static __inline int 313cccf4220SAlexander Motin xpt_schedule_devq(struct cam_devq *devq, struct cam_ed *dev) 31430a4094fSAlexander Motin { 31530a4094fSAlexander Motin int retval; 31630a4094fSAlexander Motin 317227d67aaSAlexander Motin mtx_assert(&devq->send_mtx, MA_OWNED); 31883c5d981SAlexander Motin if ((dev->ccbq.queue.entries > 0) && 31983c5d981SAlexander Motin (dev->ccbq.dev_openings > 0) && 320cccf4220SAlexander Motin (dev->ccbq.queue.qfrozen_cnt == 0)) { 32130a4094fSAlexander Motin /* 32230a4094fSAlexander Motin * The priority of a device waiting for controller 3236bccea7cSRebecca Cran * resources is that of the highest priority CCB 32430a4094fSAlexander Motin * enqueued. 32530a4094fSAlexander Motin */ 32630a4094fSAlexander Motin retval = 327cccf4220SAlexander Motin xpt_schedule_dev(&devq->send_queue, 328227d67aaSAlexander Motin &dev->devq_entry, 32983c5d981SAlexander Motin CAMQ_GET_PRIO(&dev->ccbq.queue)); 33030a4094fSAlexander Motin } else { 33130a4094fSAlexander Motin retval = 0; 33230a4094fSAlexander Motin } 33330a4094fSAlexander Motin return (retval); 33430a4094fSAlexander Motin } 33530a4094fSAlexander Motin 33630a4094fSAlexander Motin static __inline int 337cccf4220SAlexander Motin device_is_queued(struct cam_ed *device) 3388b8a9b1dSJustin T. Gibbs { 339227d67aaSAlexander Motin return (device->devq_entry.index != CAM_UNQUEUED_INDEX); 3408b8a9b1dSJustin T. Gibbs } 3418b8a9b1dSJustin T. Gibbs 3428b8a9b1dSJustin T. Gibbs static void 3438b8a9b1dSJustin T. Gibbs xpt_periph_init() 3448b8a9b1dSJustin T. Gibbs { 34573d26919SKenneth D. Merry make_dev(&xpt_cdevsw, 0, UID_ROOT, GID_OPERATOR, 0600, "xpt0"); 3468b8a9b1dSJustin T. Gibbs } 3478b8a9b1dSJustin T. Gibbs 3488b8a9b1dSJustin T. Gibbs static int 34989c9c53dSPoul-Henning Kamp xptopen(struct cdev *dev, int flags, int fmt, struct thread *td) 3508b8a9b1dSJustin T. Gibbs { 3518b8a9b1dSJustin T. Gibbs 3528b8a9b1dSJustin T. Gibbs /* 35366a0780eSKenneth D. Merry * Only allow read-write access. 35466a0780eSKenneth D. Merry */ 35566a0780eSKenneth D. Merry if (((flags & FWRITE) == 0) || ((flags & FREAD) == 0)) 35666a0780eSKenneth D. Merry return(EPERM); 35766a0780eSKenneth D. Merry 35866a0780eSKenneth D. Merry /* 3598b8a9b1dSJustin T. Gibbs * We don't allow nonblocking access. 3608b8a9b1dSJustin T. Gibbs */ 3618b8a9b1dSJustin T. Gibbs if ((flags & O_NONBLOCK) != 0) { 3622b83592fSScott Long printf("%s: can't do nonblocking access\n", devtoname(dev)); 3638b8a9b1dSJustin T. Gibbs return(ENODEV); 3648b8a9b1dSJustin T. Gibbs } 3658b8a9b1dSJustin T. Gibbs 3668b8a9b1dSJustin T. Gibbs return(0); 3678b8a9b1dSJustin T. Gibbs } 3688b8a9b1dSJustin T. Gibbs 3698b8a9b1dSJustin T. Gibbs static int 37089c9c53dSPoul-Henning Kamp xptclose(struct cdev *dev, int flag, int fmt, struct thread *td) 3718b8a9b1dSJustin T. Gibbs { 3728b8a9b1dSJustin T. Gibbs 3738b8a9b1dSJustin T. Gibbs return(0); 3748b8a9b1dSJustin T. Gibbs } 3758b8a9b1dSJustin T. Gibbs 3762b83592fSScott Long /* 3772b83592fSScott Long * Don't automatically grab the xpt softc lock here even though this is going 3782b83592fSScott Long * through the xpt device. The xpt device is really just a back door for 3792b83592fSScott Long * accessing other devices and SIMs, so the right thing to do is to grab 3802b83592fSScott Long * the appropriate SIM lock once the bus/SIM is located. 3812b83592fSScott Long */ 3828b8a9b1dSJustin T. Gibbs static int 38389c9c53dSPoul-Henning Kamp xptioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, struct thread *td) 3848b8a9b1dSJustin T. Gibbs { 3852b83592fSScott Long int error; 3868b8a9b1dSJustin T. Gibbs 38725a2902cSScott Long if ((error = xptdoioctl(dev, cmd, addr, flag, td)) == ENOTTY) { 388f564de00SScott Long error = cam_compat_ioctl(dev, cmd, addr, flag, td, xptdoioctl); 38925a2902cSScott Long } 39025a2902cSScott Long return (error); 39125a2902cSScott Long } 39225a2902cSScott Long 39325a2902cSScott Long static int 39425a2902cSScott Long xptdoioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, struct thread *td) 39525a2902cSScott Long { 39625a2902cSScott Long int error; 39725a2902cSScott Long 3988b8a9b1dSJustin T. Gibbs error = 0; 3998b8a9b1dSJustin T. Gibbs 4008b8a9b1dSJustin T. Gibbs switch(cmd) { 4018b8a9b1dSJustin T. Gibbs /* 4028b8a9b1dSJustin T. Gibbs * For the transport layer CAMIOCOMMAND ioctl, we really only want 4038b8a9b1dSJustin T. Gibbs * to accept CCB types that don't quite make sense to send through a 4048c7a96c5SScott Long * passthrough driver. XPT_PATH_INQ is an exception to this, as stated 4058c7a96c5SScott Long * in the CAM spec. 4068b8a9b1dSJustin T. Gibbs */ 4078b8a9b1dSJustin T. Gibbs case CAMIOCOMMAND: { 4088b8a9b1dSJustin T. Gibbs union ccb *ccb; 4098b8a9b1dSJustin T. Gibbs union ccb *inccb; 4102b83592fSScott Long struct cam_eb *bus; 4118b8a9b1dSJustin T. Gibbs 4128b8a9b1dSJustin T. Gibbs inccb = (union ccb *)addr; 4138b8a9b1dSJustin T. Gibbs 4142b83592fSScott Long bus = xpt_find_bus(inccb->ccb_h.path_id); 4150e85f214SMatt Jacob if (bus == NULL) 4160e85f214SMatt Jacob return (EINVAL); 4170e85f214SMatt Jacob 4180e85f214SMatt Jacob switch (inccb->ccb_h.func_code) { 4190e85f214SMatt Jacob case XPT_SCAN_BUS: 4200e85f214SMatt Jacob case XPT_RESET_BUS: 4210e85f214SMatt Jacob if (inccb->ccb_h.target_id != CAM_TARGET_WILDCARD || 4220e85f214SMatt Jacob inccb->ccb_h.target_lun != CAM_LUN_WILDCARD) { 4230e85f214SMatt Jacob xpt_release_bus(bus); 4240e85f214SMatt Jacob return (EINVAL); 4250e85f214SMatt Jacob } 4260e85f214SMatt Jacob break; 4270e85f214SMatt Jacob case XPT_SCAN_TGT: 4280e85f214SMatt Jacob if (inccb->ccb_h.target_id == CAM_TARGET_WILDCARD || 4290e85f214SMatt Jacob inccb->ccb_h.target_lun != CAM_LUN_WILDCARD) { 4300e85f214SMatt Jacob xpt_release_bus(bus); 4310e85f214SMatt Jacob return (EINVAL); 4320e85f214SMatt Jacob } 4330e85f214SMatt Jacob break; 4340e85f214SMatt Jacob default: 4352b83592fSScott Long break; 4362b83592fSScott Long } 4372b83592fSScott Long 4388b8a9b1dSJustin T. Gibbs switch(inccb->ccb_h.func_code) { 4398b8a9b1dSJustin T. Gibbs case XPT_SCAN_BUS: 4408b8a9b1dSJustin T. Gibbs case XPT_RESET_BUS: 4418c7a96c5SScott Long case XPT_PATH_INQ: 4428fcf57f5SJustin T. Gibbs case XPT_ENG_INQ: 4438b8a9b1dSJustin T. Gibbs case XPT_SCAN_LUN: 4440e85f214SMatt Jacob case XPT_SCAN_TGT: 4458b8a9b1dSJustin T. Gibbs 4468008a935SScott Long ccb = xpt_alloc_ccb(); 4472b83592fSScott Long 4488b8a9b1dSJustin T. Gibbs /* 4498b8a9b1dSJustin T. Gibbs * Create a path using the bus, target, and lun the 4508b8a9b1dSJustin T. Gibbs * user passed in. 4518b8a9b1dSJustin T. Gibbs */ 452e5dfa058SAlexander Motin if (xpt_create_path(&ccb->ccb_h.path, NULL, 4538b8a9b1dSJustin T. Gibbs inccb->ccb_h.path_id, 4548b8a9b1dSJustin T. Gibbs inccb->ccb_h.target_id, 4558b8a9b1dSJustin T. Gibbs inccb->ccb_h.target_lun) != 4568b8a9b1dSJustin T. Gibbs CAM_REQ_CMP){ 4578b8a9b1dSJustin T. Gibbs error = EINVAL; 4588b8a9b1dSJustin T. Gibbs xpt_free_ccb(ccb); 4598b8a9b1dSJustin T. Gibbs break; 4608b8a9b1dSJustin T. Gibbs } 4618b8a9b1dSJustin T. Gibbs /* Ensure all of our fields are correct */ 4628b8a9b1dSJustin T. Gibbs xpt_setup_ccb(&ccb->ccb_h, ccb->ccb_h.path, 4638b8a9b1dSJustin T. Gibbs inccb->ccb_h.pinfo.priority); 4648b8a9b1dSJustin T. Gibbs xpt_merge_ccb(ccb, inccb); 465227d67aaSAlexander Motin xpt_path_lock(ccb->ccb_h.path); 4668b8a9b1dSJustin T. Gibbs cam_periph_runccb(ccb, NULL, 0, 0, NULL); 467227d67aaSAlexander Motin xpt_path_unlock(ccb->ccb_h.path); 4688b8a9b1dSJustin T. Gibbs bcopy(ccb, inccb, sizeof(union ccb)); 4698b8a9b1dSJustin T. Gibbs xpt_free_path(ccb->ccb_h.path); 4708b8a9b1dSJustin T. Gibbs xpt_free_ccb(ccb); 4718b8a9b1dSJustin T. Gibbs break; 4728b8a9b1dSJustin T. Gibbs 4738b8a9b1dSJustin T. Gibbs case XPT_DEBUG: { 4748b8a9b1dSJustin T. Gibbs union ccb ccb; 4758b8a9b1dSJustin T. Gibbs 4768b8a9b1dSJustin T. Gibbs /* 477aa872be6SMatt Jacob * This is an immediate CCB, so it's okay to 4788b8a9b1dSJustin T. Gibbs * allocate it on the stack. 4798b8a9b1dSJustin T. Gibbs */ 4808b8a9b1dSJustin T. Gibbs 4818b8a9b1dSJustin T. Gibbs /* 4828b8a9b1dSJustin T. Gibbs * Create a path using the bus, target, and lun the 4838b8a9b1dSJustin T. Gibbs * user passed in. 4848b8a9b1dSJustin T. Gibbs */ 485e5dfa058SAlexander Motin if (xpt_create_path(&ccb.ccb_h.path, NULL, 4868b8a9b1dSJustin T. Gibbs inccb->ccb_h.path_id, 4878b8a9b1dSJustin T. Gibbs inccb->ccb_h.target_id, 4888b8a9b1dSJustin T. Gibbs inccb->ccb_h.target_lun) != 4898b8a9b1dSJustin T. Gibbs CAM_REQ_CMP){ 4908b8a9b1dSJustin T. Gibbs error = EINVAL; 4918b8a9b1dSJustin T. Gibbs break; 4928b8a9b1dSJustin T. Gibbs } 4938b8a9b1dSJustin T. Gibbs /* Ensure all of our fields are correct */ 4948b8a9b1dSJustin T. Gibbs xpt_setup_ccb(&ccb.ccb_h, ccb.ccb_h.path, 4958b8a9b1dSJustin T. Gibbs inccb->ccb_h.pinfo.priority); 4968b8a9b1dSJustin T. Gibbs xpt_merge_ccb(&ccb, inccb); 4978b8a9b1dSJustin T. Gibbs xpt_action(&ccb); 4988b8a9b1dSJustin T. Gibbs bcopy(&ccb, inccb, sizeof(union ccb)); 4998b8a9b1dSJustin T. Gibbs xpt_free_path(ccb.ccb_h.path); 5008b8a9b1dSJustin T. Gibbs break; 5018b8a9b1dSJustin T. Gibbs 5028b8a9b1dSJustin T. Gibbs } 5038b8a9b1dSJustin T. Gibbs case XPT_DEV_MATCH: { 5048b8a9b1dSJustin T. Gibbs struct cam_periph_map_info mapinfo; 50559190eaaSKenneth D. Merry struct cam_path *old_path; 5068b8a9b1dSJustin T. Gibbs 5078b8a9b1dSJustin T. Gibbs /* 5088b8a9b1dSJustin T. Gibbs * We can't deal with physical addresses for this 5098b8a9b1dSJustin T. Gibbs * type of transaction. 5108b8a9b1dSJustin T. Gibbs */ 511dd0b4fb6SKonstantin Belousov if ((inccb->ccb_h.flags & CAM_DATA_MASK) != 512dd0b4fb6SKonstantin Belousov CAM_DATA_VADDR) { 5138b8a9b1dSJustin T. Gibbs error = EINVAL; 5148b8a9b1dSJustin T. Gibbs break; 5158b8a9b1dSJustin T. Gibbs } 51659190eaaSKenneth D. Merry 51759190eaaSKenneth D. Merry /* 51859190eaaSKenneth D. Merry * Save this in case the caller had it set to 51959190eaaSKenneth D. Merry * something in particular. 52059190eaaSKenneth D. Merry */ 52159190eaaSKenneth D. Merry old_path = inccb->ccb_h.path; 52259190eaaSKenneth D. Merry 52359190eaaSKenneth D. Merry /* 52459190eaaSKenneth D. Merry * We really don't need a path for the matching 52559190eaaSKenneth D. Merry * code. The path is needed because of the 52659190eaaSKenneth D. Merry * debugging statements in xpt_action(). They 52759190eaaSKenneth D. Merry * assume that the CCB has a valid path. 52859190eaaSKenneth D. Merry */ 52959190eaaSKenneth D. Merry inccb->ccb_h.path = xpt_periph->path; 53059190eaaSKenneth D. Merry 5318b8a9b1dSJustin T. Gibbs bzero(&mapinfo, sizeof(mapinfo)); 5328b8a9b1dSJustin T. Gibbs 5338b8a9b1dSJustin T. Gibbs /* 5348b8a9b1dSJustin T. Gibbs * Map the pattern and match buffers into kernel 5358b8a9b1dSJustin T. Gibbs * virtual address space. 5368b8a9b1dSJustin T. Gibbs */ 5378b8a9b1dSJustin T. Gibbs error = cam_periph_mapmem(inccb, &mapinfo); 5388b8a9b1dSJustin T. Gibbs 53959190eaaSKenneth D. Merry if (error) { 54059190eaaSKenneth D. Merry inccb->ccb_h.path = old_path; 5418b8a9b1dSJustin T. Gibbs break; 54259190eaaSKenneth D. Merry } 5438b8a9b1dSJustin T. Gibbs 5448b8a9b1dSJustin T. Gibbs /* 5458b8a9b1dSJustin T. Gibbs * This is an immediate CCB, we can send it on directly. 5468b8a9b1dSJustin T. Gibbs */ 5478b8a9b1dSJustin T. Gibbs xpt_action(inccb); 5488b8a9b1dSJustin T. Gibbs 5498b8a9b1dSJustin T. Gibbs /* 5508b8a9b1dSJustin T. Gibbs * Map the buffers back into user space. 5518b8a9b1dSJustin T. Gibbs */ 5528b8a9b1dSJustin T. Gibbs cam_periph_unmapmem(inccb, &mapinfo); 5538b8a9b1dSJustin T. Gibbs 55459190eaaSKenneth D. Merry inccb->ccb_h.path = old_path; 55559190eaaSKenneth D. Merry 5568b8a9b1dSJustin T. Gibbs error = 0; 5578b8a9b1dSJustin T. Gibbs break; 5588b8a9b1dSJustin T. Gibbs } 5598b8a9b1dSJustin T. Gibbs default: 5608fcf57f5SJustin T. Gibbs error = ENOTSUP; 5618b8a9b1dSJustin T. Gibbs break; 5628b8a9b1dSJustin T. Gibbs } 563daddc001SScott Long xpt_release_bus(bus); 5648b8a9b1dSJustin T. Gibbs break; 5658b8a9b1dSJustin T. Gibbs } 5668b8a9b1dSJustin T. Gibbs /* 5678b8a9b1dSJustin T. Gibbs * This is the getpassthru ioctl. It takes a XPT_GDEVLIST ccb as input, 5688b8a9b1dSJustin T. Gibbs * with the periphal driver name and unit name filled in. The other 5698b8a9b1dSJustin T. Gibbs * fields don't really matter as input. The passthrough driver name 5708b8a9b1dSJustin T. Gibbs * ("pass"), and unit number are passed back in the ccb. The current 5718b8a9b1dSJustin T. Gibbs * device generation number, and the index into the device peripheral 5728b8a9b1dSJustin T. Gibbs * driver list, and the status are also passed back. Note that 5738b8a9b1dSJustin T. Gibbs * since we do everything in one pass, unlike the XPT_GDEVLIST ccb, 5748b8a9b1dSJustin T. Gibbs * we never return a status of CAM_GDEVLIST_LIST_CHANGED. It is 5758b8a9b1dSJustin T. Gibbs * (or rather should be) impossible for the device peripheral driver 5768b8a9b1dSJustin T. Gibbs * list to change since we look at the whole thing in one pass, and 57777dc25ccSScott Long * we do it with lock protection. 5788b8a9b1dSJustin T. Gibbs * 5798b8a9b1dSJustin T. Gibbs */ 5808b8a9b1dSJustin T. Gibbs case CAMGETPASSTHRU: { 5818b8a9b1dSJustin T. Gibbs union ccb *ccb; 5828b8a9b1dSJustin T. Gibbs struct cam_periph *periph; 5838b8a9b1dSJustin T. Gibbs struct periph_driver **p_drv; 5848b8a9b1dSJustin T. Gibbs char *name; 5853393f8daSKenneth D. Merry u_int unit; 586621a60d4SKenneth D. Merry int base_periph_found; 5878b8a9b1dSJustin T. Gibbs 5888b8a9b1dSJustin T. Gibbs ccb = (union ccb *)addr; 5898b8a9b1dSJustin T. Gibbs unit = ccb->cgdl.unit_number; 5908b8a9b1dSJustin T. Gibbs name = ccb->cgdl.periph_name; 591621a60d4SKenneth D. Merry base_periph_found = 0; 592621a60d4SKenneth D. Merry 5938b8a9b1dSJustin T. Gibbs /* 5948b8a9b1dSJustin T. Gibbs * Sanity check -- make sure we don't get a null peripheral 5958b8a9b1dSJustin T. Gibbs * driver name. 5968b8a9b1dSJustin T. Gibbs */ 5978b8a9b1dSJustin T. Gibbs if (*ccb->cgdl.periph_name == '\0') { 5988b8a9b1dSJustin T. Gibbs error = EINVAL; 5998b8a9b1dSJustin T. Gibbs break; 6008b8a9b1dSJustin T. Gibbs } 6018b8a9b1dSJustin T. Gibbs 6028b8a9b1dSJustin T. Gibbs /* Keep the list from changing while we traverse it */ 6039a7c2696SAlexander Motin xpt_lock_buses(); 6048b8a9b1dSJustin T. Gibbs 6058b8a9b1dSJustin T. Gibbs /* first find our driver in the list of drivers */ 6060b7c27b9SPeter Wemm for (p_drv = periph_drivers; *p_drv != NULL; p_drv++) 6078b8a9b1dSJustin T. Gibbs if (strcmp((*p_drv)->driver_name, name) == 0) 6088b8a9b1dSJustin T. Gibbs break; 6098b8a9b1dSJustin T. Gibbs 6108b8a9b1dSJustin T. Gibbs if (*p_drv == NULL) { 6119a7c2696SAlexander Motin xpt_unlock_buses(); 6128b8a9b1dSJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_CMP_ERR; 6138b8a9b1dSJustin T. Gibbs ccb->cgdl.status = CAM_GDEVLIST_ERROR; 6148b8a9b1dSJustin T. Gibbs *ccb->cgdl.periph_name = '\0'; 6158b8a9b1dSJustin T. Gibbs ccb->cgdl.unit_number = 0; 6168b8a9b1dSJustin T. Gibbs error = ENOENT; 6178b8a9b1dSJustin T. Gibbs break; 6188b8a9b1dSJustin T. Gibbs } 6198b8a9b1dSJustin T. Gibbs 6208b8a9b1dSJustin T. Gibbs /* 6218b8a9b1dSJustin T. Gibbs * Run through every peripheral instance of this driver 6228b8a9b1dSJustin T. Gibbs * and check to see whether it matches the unit passed 6238b8a9b1dSJustin T. Gibbs * in by the user. If it does, get out of the loops and 6248b8a9b1dSJustin T. Gibbs * find the passthrough driver associated with that 6258b8a9b1dSJustin T. Gibbs * peripheral driver. 6268b8a9b1dSJustin T. Gibbs */ 6278b8a9b1dSJustin T. Gibbs for (periph = TAILQ_FIRST(&(*p_drv)->units); periph != NULL; 6288b8a9b1dSJustin T. Gibbs periph = TAILQ_NEXT(periph, unit_links)) { 6298b8a9b1dSJustin T. Gibbs 630a29779e8SAlexander Motin if (periph->unit_number == unit) 6318b8a9b1dSJustin T. Gibbs break; 6328b8a9b1dSJustin T. Gibbs } 6338b8a9b1dSJustin T. Gibbs /* 6348b8a9b1dSJustin T. Gibbs * If we found the peripheral driver that the user passed 6358b8a9b1dSJustin T. Gibbs * in, go through all of the peripheral drivers for that 6368b8a9b1dSJustin T. Gibbs * particular device and look for a passthrough driver. 6378b8a9b1dSJustin T. Gibbs */ 6388b8a9b1dSJustin T. Gibbs if (periph != NULL) { 6398b8a9b1dSJustin T. Gibbs struct cam_ed *device; 6408b8a9b1dSJustin T. Gibbs int i; 6418b8a9b1dSJustin T. Gibbs 642621a60d4SKenneth D. Merry base_periph_found = 1; 6438b8a9b1dSJustin T. Gibbs device = periph->path->device; 644fc2ffbe6SPoul-Henning Kamp for (i = 0, periph = SLIST_FIRST(&device->periphs); 6458b8a9b1dSJustin T. Gibbs periph != NULL; 646fc2ffbe6SPoul-Henning Kamp periph = SLIST_NEXT(periph, periph_links), i++) { 6478b8a9b1dSJustin T. Gibbs /* 6488b8a9b1dSJustin T. Gibbs * Check to see whether we have a 6498b8a9b1dSJustin T. Gibbs * passthrough device or not. 6508b8a9b1dSJustin T. Gibbs */ 6518b8a9b1dSJustin T. Gibbs if (strcmp(periph->periph_name, "pass") == 0) { 6528b8a9b1dSJustin T. Gibbs /* 6538b8a9b1dSJustin T. Gibbs * Fill in the getdevlist fields. 6548b8a9b1dSJustin T. Gibbs */ 6558b8a9b1dSJustin T. Gibbs strcpy(ccb->cgdl.periph_name, 6568b8a9b1dSJustin T. Gibbs periph->periph_name); 6578b8a9b1dSJustin T. Gibbs ccb->cgdl.unit_number = 6588b8a9b1dSJustin T. Gibbs periph->unit_number; 659fc2ffbe6SPoul-Henning Kamp if (SLIST_NEXT(periph, periph_links)) 6608b8a9b1dSJustin T. Gibbs ccb->cgdl.status = 6618b8a9b1dSJustin T. Gibbs CAM_GDEVLIST_MORE_DEVS; 6628b8a9b1dSJustin T. Gibbs else 6638b8a9b1dSJustin T. Gibbs ccb->cgdl.status = 6648b8a9b1dSJustin T. Gibbs CAM_GDEVLIST_LAST_DEVICE; 6658b8a9b1dSJustin T. Gibbs ccb->cgdl.generation = 6668b8a9b1dSJustin T. Gibbs device->generation; 6678b8a9b1dSJustin T. Gibbs ccb->cgdl.index = i; 6688b8a9b1dSJustin T. Gibbs /* 6698b8a9b1dSJustin T. Gibbs * Fill in some CCB header fields 6708b8a9b1dSJustin T. Gibbs * that the user may want. 6718b8a9b1dSJustin T. Gibbs */ 6728b8a9b1dSJustin T. Gibbs ccb->ccb_h.path_id = 6738b8a9b1dSJustin T. Gibbs periph->path->bus->path_id; 6748b8a9b1dSJustin T. Gibbs ccb->ccb_h.target_id = 6758b8a9b1dSJustin T. Gibbs periph->path->target->target_id; 6768b8a9b1dSJustin T. Gibbs ccb->ccb_h.target_lun = 6778b8a9b1dSJustin T. Gibbs periph->path->device->lun_id; 6788b8a9b1dSJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_CMP; 6798b8a9b1dSJustin T. Gibbs break; 6808b8a9b1dSJustin T. Gibbs } 6818b8a9b1dSJustin T. Gibbs } 6828b8a9b1dSJustin T. Gibbs } 6838b8a9b1dSJustin T. Gibbs 6848b8a9b1dSJustin T. Gibbs /* 6858b8a9b1dSJustin T. Gibbs * If the periph is null here, one of two things has 6868b8a9b1dSJustin T. Gibbs * happened. The first possibility is that we couldn't 6878b8a9b1dSJustin T. Gibbs * find the unit number of the particular peripheral driver 6888b8a9b1dSJustin T. Gibbs * that the user is asking about. e.g. the user asks for 6898b8a9b1dSJustin T. Gibbs * the passthrough driver for "da11". We find the list of 6908b8a9b1dSJustin T. Gibbs * "da" peripherals all right, but there is no unit 11. 6918b8a9b1dSJustin T. Gibbs * The other possibility is that we went through the list 6928b8a9b1dSJustin T. Gibbs * of peripheral drivers attached to the device structure, 6938b8a9b1dSJustin T. Gibbs * but didn't find one with the name "pass". Either way, 6948b8a9b1dSJustin T. Gibbs * we return ENOENT, since we couldn't find something. 6958b8a9b1dSJustin T. Gibbs */ 6968b8a9b1dSJustin T. Gibbs if (periph == NULL) { 6978b8a9b1dSJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_CMP_ERR; 6988b8a9b1dSJustin T. Gibbs ccb->cgdl.status = CAM_GDEVLIST_ERROR; 6998b8a9b1dSJustin T. Gibbs *ccb->cgdl.periph_name = '\0'; 7008b8a9b1dSJustin T. Gibbs ccb->cgdl.unit_number = 0; 7018b8a9b1dSJustin T. Gibbs error = ENOENT; 702621a60d4SKenneth D. Merry /* 703621a60d4SKenneth D. Merry * It is unfortunate that this is even necessary, 704621a60d4SKenneth D. Merry * but there are many, many clueless users out there. 705621a60d4SKenneth D. Merry * If this is true, the user is looking for the 706621a60d4SKenneth D. Merry * passthrough driver, but doesn't have one in his 707621a60d4SKenneth D. Merry * kernel. 708621a60d4SKenneth D. Merry */ 709621a60d4SKenneth D. Merry if (base_periph_found == 1) { 710621a60d4SKenneth D. Merry printf("xptioctl: pass driver is not in the " 711621a60d4SKenneth D. Merry "kernel\n"); 712935c968aSChristian Brueffer printf("xptioctl: put \"device pass\" in " 713621a60d4SKenneth D. Merry "your kernel config file\n"); 714621a60d4SKenneth D. Merry } 7158b8a9b1dSJustin T. Gibbs } 7169a7c2696SAlexander Motin xpt_unlock_buses(); 7178b8a9b1dSJustin T. Gibbs break; 7188b8a9b1dSJustin T. Gibbs } 7198b8a9b1dSJustin T. Gibbs default: 7208b8a9b1dSJustin T. Gibbs error = ENOTTY; 7218b8a9b1dSJustin T. Gibbs break; 7228b8a9b1dSJustin T. Gibbs } 7238b8a9b1dSJustin T. Gibbs 7248b8a9b1dSJustin T. Gibbs return(error); 7258b8a9b1dSJustin T. Gibbs } 7268b8a9b1dSJustin T. Gibbs 72774bd1c10SNick Hibma static int 72874bd1c10SNick Hibma cam_module_event_handler(module_t mod, int what, void *arg) 72974bd1c10SNick Hibma { 7302b83592fSScott Long int error; 7312b83592fSScott Long 7322b83592fSScott Long switch (what) { 7332b83592fSScott Long case MOD_LOAD: 7342b83592fSScott Long if ((error = xpt_init(NULL)) != 0) 7352b83592fSScott Long return (error); 7362b83592fSScott Long break; 7372b83592fSScott Long case MOD_UNLOAD: 73874bd1c10SNick Hibma return EBUSY; 7392b83592fSScott Long default: 7403e019deaSPoul-Henning Kamp return EOPNOTSUPP; 74174bd1c10SNick Hibma } 74274bd1c10SNick Hibma 74374bd1c10SNick Hibma return 0; 74474bd1c10SNick Hibma } 74574bd1c10SNick Hibma 74683c5d981SAlexander Motin static void 74783c5d981SAlexander Motin xpt_rescan_done(struct cam_periph *periph, union ccb *done_ccb) 74883c5d981SAlexander Motin { 74983c5d981SAlexander Motin 75083c5d981SAlexander Motin if (done_ccb->ccb_h.ppriv_ptr1 == NULL) { 75183c5d981SAlexander Motin xpt_free_path(done_ccb->ccb_h.path); 75283c5d981SAlexander Motin xpt_free_ccb(done_ccb); 75383c5d981SAlexander Motin } else { 75483c5d981SAlexander Motin done_ccb->ccb_h.cbfcnp = done_ccb->ccb_h.ppriv_ptr1; 75583c5d981SAlexander Motin (*done_ccb->ccb_h.cbfcnp)(periph, done_ccb); 75683c5d981SAlexander Motin } 75783c5d981SAlexander Motin xpt_release_boot(); 75883c5d981SAlexander Motin } 75983c5d981SAlexander Motin 7609e6461a2SMatt Jacob /* thread to handle bus rescans */ 7619e6461a2SMatt Jacob static void 7629e6461a2SMatt Jacob xpt_scanner_thread(void *dummy) 7639e6461a2SMatt Jacob { 7649e6461a2SMatt Jacob union ccb *ccb; 765227d67aaSAlexander Motin struct cam_path path; 7662b83592fSScott Long 7672b83592fSScott Long xpt_lock_buses(); 76883c5d981SAlexander Motin for (;;) { 7695a73cc12SKenneth D. Merry if (TAILQ_EMPTY(&xsoftc.ccb_scanq)) 7702b83592fSScott Long msleep(&xsoftc.ccb_scanq, &xsoftc.xpt_topo_lock, PRIBIO, 7712b83592fSScott Long "ccb_scanq", 0); 77283c5d981SAlexander Motin if ((ccb = (union ccb *)TAILQ_FIRST(&xsoftc.ccb_scanq)) != NULL) { 77383c5d981SAlexander Motin TAILQ_REMOVE(&xsoftc.ccb_scanq, &ccb->ccb_h, sim_links.tqe); 7742b83592fSScott Long xpt_unlock_buses(); 7752b83592fSScott Long 776227d67aaSAlexander Motin /* 777227d67aaSAlexander Motin * Since lock can be dropped inside and path freed 778227d67aaSAlexander Motin * by completion callback even before return here, 779227d67aaSAlexander Motin * take our own path copy for reference. 780227d67aaSAlexander Motin */ 781227d67aaSAlexander Motin xpt_copy_path(&path, ccb->ccb_h.path); 782227d67aaSAlexander Motin xpt_path_lock(&path); 78383c5d981SAlexander Motin xpt_action(ccb); 784227d67aaSAlexander Motin xpt_path_unlock(&path); 785227d67aaSAlexander Motin xpt_release_path(&path); 78683c5d981SAlexander Motin 78783c5d981SAlexander Motin xpt_lock_buses(); 7889e6461a2SMatt Jacob } 7899e6461a2SMatt Jacob } 7909e6461a2SMatt Jacob } 7919e6461a2SMatt Jacob 7929e6461a2SMatt Jacob void 7939e6461a2SMatt Jacob xpt_rescan(union ccb *ccb) 7949e6461a2SMatt Jacob { 7959e6461a2SMatt Jacob struct ccb_hdr *hdr; 7962b83592fSScott Long 79783c5d981SAlexander Motin /* Prepare request */ 7980e85f214SMatt Jacob if (ccb->ccb_h.path->target->target_id == CAM_TARGET_WILDCARD && 799411cadaeSAlexander Motin ccb->ccb_h.path->device->lun_id == CAM_LUN_WILDCARD) 80083c5d981SAlexander Motin ccb->ccb_h.func_code = XPT_SCAN_BUS; 8010e85f214SMatt Jacob else if (ccb->ccb_h.path->target->target_id != CAM_TARGET_WILDCARD && 8020e85f214SMatt Jacob ccb->ccb_h.path->device->lun_id == CAM_LUN_WILDCARD) 8030e85f214SMatt Jacob ccb->ccb_h.func_code = XPT_SCAN_TGT; 8040e85f214SMatt Jacob else if (ccb->ccb_h.path->target->target_id != CAM_TARGET_WILDCARD && 8050e85f214SMatt Jacob ccb->ccb_h.path->device->lun_id != CAM_LUN_WILDCARD) 80683c5d981SAlexander Motin ccb->ccb_h.func_code = XPT_SCAN_LUN; 8070e85f214SMatt Jacob else { 8080e85f214SMatt Jacob xpt_print(ccb->ccb_h.path, "illegal scan path\n"); 8090e85f214SMatt Jacob xpt_free_path(ccb->ccb_h.path); 8100e85f214SMatt Jacob xpt_free_ccb(ccb); 8110e85f214SMatt Jacob return; 8120e85f214SMatt Jacob } 81383c5d981SAlexander Motin ccb->ccb_h.ppriv_ptr1 = ccb->ccb_h.cbfcnp; 81483c5d981SAlexander Motin ccb->ccb_h.cbfcnp = xpt_rescan_done; 81583c5d981SAlexander Motin xpt_setup_ccb(&ccb->ccb_h, ccb->ccb_h.path, CAM_PRIORITY_XPT); 81683c5d981SAlexander Motin /* Don't make duplicate entries for the same paths. */ 8172b83592fSScott Long xpt_lock_buses(); 81883c5d981SAlexander Motin if (ccb->ccb_h.ppriv_ptr1 == NULL) { 8192b83592fSScott Long TAILQ_FOREACH(hdr, &xsoftc.ccb_scanq, sim_links.tqe) { 8209e6461a2SMatt Jacob if (xpt_path_comp(hdr->path, ccb->ccb_h.path) == 0) { 8215a73cc12SKenneth D. Merry wakeup(&xsoftc.ccb_scanq); 8222b83592fSScott Long xpt_unlock_buses(); 8239e6461a2SMatt Jacob xpt_print(ccb->ccb_h.path, "rescan already queued\n"); 8249e6461a2SMatt Jacob xpt_free_path(ccb->ccb_h.path); 8259e6461a2SMatt Jacob xpt_free_ccb(ccb); 8269e6461a2SMatt Jacob return; 8279e6461a2SMatt Jacob } 8289e6461a2SMatt Jacob } 82983c5d981SAlexander Motin } 8302b83592fSScott Long TAILQ_INSERT_TAIL(&xsoftc.ccb_scanq, &ccb->ccb_h, sim_links.tqe); 83183c5d981SAlexander Motin xsoftc.buses_to_config++; 8322b83592fSScott Long wakeup(&xsoftc.ccb_scanq); 8332b83592fSScott Long xpt_unlock_buses(); 8349e6461a2SMatt Jacob } 8359e6461a2SMatt Jacob 8368b8a9b1dSJustin T. Gibbs /* Functions accessed by the peripheral drivers */ 8372b83592fSScott Long static int 8389e6461a2SMatt Jacob xpt_init(void *dummy) 8398b8a9b1dSJustin T. Gibbs { 8408b8a9b1dSJustin T. Gibbs struct cam_sim *xpt_sim; 8418b8a9b1dSJustin T. Gibbs struct cam_path *path; 842434bbf6eSJustin T. Gibbs struct cam_devq *devq; 8438b8a9b1dSJustin T. Gibbs cam_status status; 844227d67aaSAlexander Motin int error, i; 8458b8a9b1dSJustin T. Gibbs 8462b83592fSScott Long TAILQ_INIT(&xsoftc.xpt_busses); 8472b83592fSScott Long TAILQ_INIT(&xsoftc.ccb_scanq); 8482b83592fSScott Long STAILQ_INIT(&xsoftc.highpowerq); 8492b83592fSScott Long xsoftc.num_highpower = CAM_MAX_HIGHPOWER; 8508b8a9b1dSJustin T. Gibbs 8512b83592fSScott Long mtx_init(&xsoftc.xpt_lock, "XPT lock", NULL, MTX_DEF); 852daa5487fSAlexander Motin mtx_init(&xsoftc.xpt_highpower_lock, "XPT highpower lock", NULL, MTX_DEF); 8532b83592fSScott Long mtx_init(&xsoftc.xpt_topo_lock, "XPT topology lock", NULL, MTX_DEF); 854227d67aaSAlexander Motin xsoftc.xpt_taskq = taskqueue_create("CAM XPT task", M_WAITOK, 855227d67aaSAlexander Motin taskqueue_thread_enqueue, /*context*/&xsoftc.xpt_taskq); 856ef3cf714SScott Long 8576b156f61SSean Bruno #ifdef CAM_BOOT_DELAY 8586b156f61SSean Bruno /* 8596b156f61SSean Bruno * Override this value at compile time to assist our users 8606b156f61SSean Bruno * who don't use loader to boot a kernel. 8616b156f61SSean Bruno */ 8626b156f61SSean Bruno xsoftc.boot_delay = CAM_BOOT_DELAY; 8636b156f61SSean Bruno #endif 8648b8a9b1dSJustin T. Gibbs /* 8658b8a9b1dSJustin T. Gibbs * The xpt layer is, itself, the equivelent of a SIM. 8668b8a9b1dSJustin T. Gibbs * Allow 16 ccbs in the ccb pool for it. This should 8678b8a9b1dSJustin T. Gibbs * give decent parallelism when we probe busses and 8688b8a9b1dSJustin T. Gibbs * perform other XPT functions. 8698b8a9b1dSJustin T. Gibbs */ 870434bbf6eSJustin T. Gibbs devq = cam_simq_alloc(16); 871434bbf6eSJustin T. Gibbs xpt_sim = cam_sim_alloc(xptaction, 872434bbf6eSJustin T. Gibbs xptpoll, 873434bbf6eSJustin T. Gibbs "xpt", 874434bbf6eSJustin T. Gibbs /*softc*/NULL, 875434bbf6eSJustin T. Gibbs /*unit*/0, 8762b83592fSScott Long /*mtx*/&xsoftc.xpt_lock, 877434bbf6eSJustin T. Gibbs /*max_dev_transactions*/0, 878434bbf6eSJustin T. Gibbs /*max_tagged_dev_transactions*/0, 879434bbf6eSJustin T. Gibbs devq); 8802b83592fSScott Long if (xpt_sim == NULL) 8812b83592fSScott Long return (ENOMEM); 8828b8a9b1dSJustin T. Gibbs 8832b83592fSScott Long mtx_lock(&xsoftc.xpt_lock); 884b50569b7SScott Long if ((status = xpt_bus_register(xpt_sim, NULL, 0)) != CAM_SUCCESS) { 88583c5d981SAlexander Motin mtx_unlock(&xsoftc.xpt_lock); 886a2821e04SMatt Jacob printf("xpt_init: xpt_bus_register failed with status %#x," 887df826980SMatt Jacob " failing attach\n", status); 8882b83592fSScott Long return (EINVAL); 889df826980SMatt Jacob } 890daa5487fSAlexander Motin mtx_unlock(&xsoftc.xpt_lock); 8918b8a9b1dSJustin T. Gibbs 8928b8a9b1dSJustin T. Gibbs /* 8938b8a9b1dSJustin T. Gibbs * Looking at the XPT from the SIM layer, the XPT is 8948b8a9b1dSJustin T. Gibbs * the equivelent of a peripheral driver. Allocate 8958b8a9b1dSJustin T. Gibbs * a peripheral driver entry for us. 8968b8a9b1dSJustin T. Gibbs */ 8978b8a9b1dSJustin T. Gibbs if ((status = xpt_create_path(&path, NULL, CAM_XPT_PATH_ID, 8988b8a9b1dSJustin T. Gibbs CAM_TARGET_WILDCARD, 8998b8a9b1dSJustin T. Gibbs CAM_LUN_WILDCARD)) != CAM_REQ_CMP) { 90083c5d981SAlexander Motin mtx_unlock(&xsoftc.xpt_lock); 9018b8a9b1dSJustin T. Gibbs printf("xpt_init: xpt_create_path failed with status %#x," 9028b8a9b1dSJustin T. Gibbs " failing attach\n", status); 9032b83592fSScott Long return (EINVAL); 9048b8a9b1dSJustin T. Gibbs } 905daa5487fSAlexander Motin xpt_path_lock(path); 906ee9c90c7SKenneth D. Merry cam_periph_alloc(xptregister, NULL, NULL, NULL, "xpt", CAM_PERIPH_BIO, 9072b83592fSScott Long path, NULL, 0, xpt_sim); 908daa5487fSAlexander Motin xpt_path_unlock(path); 9098b8a9b1dSJustin T. Gibbs xpt_free_path(path); 910daa5487fSAlexander Motin 911227d67aaSAlexander Motin if (cam_num_doneqs < 1) 912227d67aaSAlexander Motin cam_num_doneqs = 1 + mp_ncpus / 6; 913227d67aaSAlexander Motin else if (cam_num_doneqs > MAXCPU) 914227d67aaSAlexander Motin cam_num_doneqs = MAXCPU; 915227d67aaSAlexander Motin for (i = 0; i < cam_num_doneqs; i++) { 916227d67aaSAlexander Motin mtx_init(&cam_doneqs[i].cam_doneq_mtx, "CAM doneq", NULL, 917227d67aaSAlexander Motin MTX_DEF); 918227d67aaSAlexander Motin STAILQ_INIT(&cam_doneqs[i].cam_doneq); 919227d67aaSAlexander Motin error = kproc_kthread_add(xpt_done_td, &cam_doneqs[i], 920227d67aaSAlexander Motin &cam_proc, NULL, 0, 0, "cam", "doneq%d", i); 921227d67aaSAlexander Motin if (error != 0) { 922227d67aaSAlexander Motin cam_num_doneqs = i; 923227d67aaSAlexander Motin break; 924227d67aaSAlexander Motin } 925227d67aaSAlexander Motin } 926227d67aaSAlexander Motin if (cam_num_doneqs < 1) { 927227d67aaSAlexander Motin printf("xpt_init: Cannot init completion queues " 928227d67aaSAlexander Motin "- failing attach\n"); 929227d67aaSAlexander Motin return (ENOMEM); 930227d67aaSAlexander Motin } 9318b8a9b1dSJustin T. Gibbs /* 9328b8a9b1dSJustin T. Gibbs * Register a callback for when interrupts are enabled. 9338b8a9b1dSJustin T. Gibbs */ 9342b83592fSScott Long xsoftc.xpt_config_hook = 9358b8a9b1dSJustin T. Gibbs (struct intr_config_hook *)malloc(sizeof(struct intr_config_hook), 9360dd50e9bSScott Long M_CAMXPT, M_NOWAIT | M_ZERO); 9372b83592fSScott Long if (xsoftc.xpt_config_hook == NULL) { 9388b8a9b1dSJustin T. Gibbs printf("xpt_init: Cannot malloc config hook " 9398b8a9b1dSJustin T. Gibbs "- failing attach\n"); 9402b83592fSScott Long return (ENOMEM); 9418b8a9b1dSJustin T. Gibbs } 9422b83592fSScott Long xsoftc.xpt_config_hook->ich_func = xpt_config; 9432b83592fSScott Long if (config_intrhook_establish(xsoftc.xpt_config_hook) != 0) { 9440dd50e9bSScott Long free (xsoftc.xpt_config_hook, M_CAMXPT); 9458b8a9b1dSJustin T. Gibbs printf("xpt_init: config_intrhook_establish failed " 9468b8a9b1dSJustin T. Gibbs "- failing attach\n"); 9478b8a9b1dSJustin T. Gibbs } 9488b8a9b1dSJustin T. Gibbs 9492b83592fSScott Long return (0); 9508b8a9b1dSJustin T. Gibbs } 9518b8a9b1dSJustin T. Gibbs 9528b8a9b1dSJustin T. Gibbs static cam_status 9538b8a9b1dSJustin T. Gibbs xptregister(struct cam_periph *periph, void *arg) 9548b8a9b1dSJustin T. Gibbs { 9552b83592fSScott Long struct cam_sim *xpt_sim; 9562b83592fSScott Long 9578b8a9b1dSJustin T. Gibbs if (periph == NULL) { 9588b8a9b1dSJustin T. Gibbs printf("xptregister: periph was NULL!!\n"); 9598b8a9b1dSJustin T. Gibbs return(CAM_REQ_CMP_ERR); 9608b8a9b1dSJustin T. Gibbs } 9618b8a9b1dSJustin T. Gibbs 9622b83592fSScott Long xpt_sim = (struct cam_sim *)arg; 9632b83592fSScott Long xpt_sim->softc = periph; 9648b8a9b1dSJustin T. Gibbs xpt_periph = periph; 9652b83592fSScott Long periph->softc = NULL; 9668b8a9b1dSJustin T. Gibbs 9678b8a9b1dSJustin T. Gibbs return(CAM_REQ_CMP); 9688b8a9b1dSJustin T. Gibbs } 9698b8a9b1dSJustin T. Gibbs 9708b8a9b1dSJustin T. Gibbs int32_t 9718b8a9b1dSJustin T. Gibbs xpt_add_periph(struct cam_periph *periph) 9728b8a9b1dSJustin T. Gibbs { 9738b8a9b1dSJustin T. Gibbs struct cam_ed *device; 9748b8a9b1dSJustin T. Gibbs int32_t status; 9758b8a9b1dSJustin T. Gibbs 976227d67aaSAlexander Motin TASK_INIT(&periph->periph_run_task, 0, xpt_run_allocq_task, periph); 9778b8a9b1dSJustin T. Gibbs device = periph->path->device; 9788b8a9b1dSJustin T. Gibbs status = CAM_REQ_CMP; 9798b8a9b1dSJustin T. Gibbs if (device != NULL) { 980227d67aaSAlexander Motin mtx_lock(&device->target->bus->eb_mtx); 9818b8a9b1dSJustin T. Gibbs device->generation++; 982227d67aaSAlexander Motin SLIST_INSERT_HEAD(&device->periphs, periph, periph_links); 983227d67aaSAlexander Motin mtx_unlock(&device->target->bus->eb_mtx); 9848b8a9b1dSJustin T. Gibbs } 9858b8a9b1dSJustin T. Gibbs 9868b8a9b1dSJustin T. Gibbs return (status); 9878b8a9b1dSJustin T. Gibbs } 9888b8a9b1dSJustin T. Gibbs 9898b8a9b1dSJustin T. Gibbs void 990a29779e8SAlexander Motin xpt_remove_periph(struct cam_periph *periph) 9918b8a9b1dSJustin T. Gibbs { 9928b8a9b1dSJustin T. Gibbs struct cam_ed *device; 9938b8a9b1dSJustin T. Gibbs 9948b8a9b1dSJustin T. Gibbs device = periph->path->device; 9958b8a9b1dSJustin T. Gibbs if (device != NULL) { 996227d67aaSAlexander Motin mtx_lock(&device->target->bus->eb_mtx); 9978b8a9b1dSJustin T. Gibbs device->generation++; 998227d67aaSAlexander Motin SLIST_REMOVE(&device->periphs, periph, cam_periph, periph_links); 999227d67aaSAlexander Motin mtx_unlock(&device->target->bus->eb_mtx); 10008b8a9b1dSJustin T. Gibbs } 10018b8a9b1dSJustin T. Gibbs } 10028b8a9b1dSJustin T. Gibbs 10033393f8daSKenneth D. Merry 10043393f8daSKenneth D. Merry void 10053393f8daSKenneth D. Merry xpt_announce_periph(struct cam_periph *periph, char *announce_string) 10063393f8daSKenneth D. Merry { 100757079b17SAlexander Motin struct cam_path *path = periph->path; 10083393f8daSKenneth D. Merry 1009227d67aaSAlexander Motin cam_periph_assert(periph, MA_OWNED); 10108d36a71bSAlexander Motin periph->flags |= CAM_PERIPH_ANNOUNCED; 101168153f43SScott Long 1012abe83505SNathan Whitehorn printf("%s%d at %s%d bus %d scbus%d target %d lun %jx\n", 10133393f8daSKenneth D. Merry periph->periph_name, periph->unit_number, 10143393f8daSKenneth D. Merry path->bus->sim->sim_name, 10153393f8daSKenneth D. Merry path->bus->sim->unit_number, 10163393f8daSKenneth D. Merry path->bus->sim->bus_id, 1017ad413009SAlexander Motin path->bus->path_id, 10183393f8daSKenneth D. Merry path->target->target_id, 1019abe83505SNathan Whitehorn (uintmax_t)path->device->lun_id); 10203393f8daSKenneth D. Merry printf("%s%d: ", periph->periph_name, periph->unit_number); 102152c9ce25SScott Long if (path->device->protocol == PROTO_SCSI) 10223393f8daSKenneth D. Merry scsi_print_inquiry(&path->device->inq_data); 102352c9ce25SScott Long else if (path->device->protocol == PROTO_ATA || 102452c9ce25SScott Long path->device->protocol == PROTO_SATAPM) 102552c9ce25SScott Long ata_print_ident(&path->device->ident_data); 10263089bb2eSAlexander Motin else if (path->device->protocol == PROTO_SEMB) 10273089bb2eSAlexander Motin semb_print_ident( 10283089bb2eSAlexander Motin (struct sep_identify_data *)&path->device->ident_data); 102952c9ce25SScott Long else 103052c9ce25SScott Long printf("Unknown protocol device\n"); 1031aa93041dSAlexander Motin if (path->device->serial_num_len > 0) { 10323393f8daSKenneth D. Merry /* Don't wrap the screen - print only the first 60 chars */ 10333393f8daSKenneth D. Merry printf("%s%d: Serial Number %.60s\n", periph->periph_name, 10343393f8daSKenneth D. Merry periph->unit_number, path->device->serial_num); 10353393f8daSKenneth D. Merry } 103657079b17SAlexander Motin /* Announce transport details. */ 103757079b17SAlexander Motin (*(path->bus->xport->announce))(periph); 103857079b17SAlexander Motin /* Announce command queueing. */ 10393393f8daSKenneth D. Merry if (path->device->inq_flags & SID_CmdQue 10403393f8daSKenneth D. Merry || path->device->flags & CAM_DEV_TAG_AFTER_COUNT) { 10410aacc535SAlexander Motin printf("%s%d: Command Queueing enabled\n", 10423393f8daSKenneth D. Merry periph->periph_name, periph->unit_number); 10433393f8daSKenneth D. Merry } 104457079b17SAlexander Motin /* Announce caller's details if they've passed in. */ 10453393f8daSKenneth D. Merry if (announce_string != NULL) 10463393f8daSKenneth D. Merry printf("%s%d: %s\n", periph->periph_name, 10473393f8daSKenneth D. Merry periph->unit_number, announce_string); 10483393f8daSKenneth D. Merry } 10498b8a9b1dSJustin T. Gibbs 10506fb5c84eSSteven Hartland void 10516fb5c84eSSteven Hartland xpt_announce_quirks(struct cam_periph *periph, int quirks, char *bit_string) 10526fb5c84eSSteven Hartland { 10536fb5c84eSSteven Hartland if (quirks != 0) { 10546fb5c84eSSteven Hartland printf("%s%d: quirks=0x%b\n", periph->periph_name, 10556fb5c84eSSteven Hartland periph->unit_number, quirks, bit_string); 10566fb5c84eSSteven Hartland } 10576fb5c84eSSteven Hartland } 10586fb5c84eSSteven Hartland 10598d36a71bSAlexander Motin void 10608d36a71bSAlexander Motin xpt_denounce_periph(struct cam_periph *periph) 10618d36a71bSAlexander Motin { 10628d36a71bSAlexander Motin struct cam_path *path = periph->path; 10638d36a71bSAlexander Motin 1064227d67aaSAlexander Motin cam_periph_assert(periph, MA_OWNED); 1065abe83505SNathan Whitehorn printf("%s%d at %s%d bus %d scbus%d target %d lun %jx\n", 10668d36a71bSAlexander Motin periph->periph_name, periph->unit_number, 10678d36a71bSAlexander Motin path->bus->sim->sim_name, 10688d36a71bSAlexander Motin path->bus->sim->unit_number, 10698d36a71bSAlexander Motin path->bus->sim->bus_id, 10708d36a71bSAlexander Motin path->bus->path_id, 10718d36a71bSAlexander Motin path->target->target_id, 1072abe83505SNathan Whitehorn (uintmax_t)path->device->lun_id); 10738d36a71bSAlexander Motin printf("%s%d: ", periph->periph_name, periph->unit_number); 10748d36a71bSAlexander Motin if (path->device->protocol == PROTO_SCSI) 10758d36a71bSAlexander Motin scsi_print_inquiry_short(&path->device->inq_data); 10768d36a71bSAlexander Motin else if (path->device->protocol == PROTO_ATA || 10778d36a71bSAlexander Motin path->device->protocol == PROTO_SATAPM) 10788d36a71bSAlexander Motin ata_print_ident_short(&path->device->ident_data); 10798d36a71bSAlexander Motin else if (path->device->protocol == PROTO_SEMB) 10808d36a71bSAlexander Motin semb_print_ident_short( 10818d36a71bSAlexander Motin (struct sep_identify_data *)&path->device->ident_data); 10828d36a71bSAlexander Motin else 10838d36a71bSAlexander Motin printf("Unknown protocol device"); 10848d36a71bSAlexander Motin if (path->device->serial_num_len > 0) 10858d36a71bSAlexander Motin printf(" s/n %.60s", path->device->serial_num); 10868d36a71bSAlexander Motin printf(" detached\n"); 10878d36a71bSAlexander Motin } 10888d36a71bSAlexander Motin 10898d36a71bSAlexander Motin 10903501942bSJustin T. Gibbs int 10913501942bSJustin T. Gibbs xpt_getattr(char *buf, size_t len, const char *attr, struct cam_path *path) 10923501942bSJustin T. Gibbs { 1093ccba7102SAlexander Motin int ret = -1, l; 10943501942bSJustin T. Gibbs struct ccb_dev_advinfo cdai; 1095ccba7102SAlexander Motin struct scsi_vpd_id_descriptor *idd; 10963501942bSJustin T. Gibbs 1097227d67aaSAlexander Motin xpt_path_assert(path, MA_OWNED); 10986884b662SAlexander Motin 10993501942bSJustin T. Gibbs memset(&cdai, 0, sizeof(cdai)); 11003501942bSJustin T. Gibbs xpt_setup_ccb(&cdai.ccb_h, path, CAM_PRIORITY_NORMAL); 11013501942bSJustin T. Gibbs cdai.ccb_h.func_code = XPT_DEV_ADVINFO; 11023501942bSJustin T. Gibbs cdai.bufsiz = len; 11033501942bSJustin T. Gibbs 11043501942bSJustin T. Gibbs if (!strcmp(attr, "GEOM::ident")) 11053501942bSJustin T. Gibbs cdai.buftype = CDAI_TYPE_SERIAL_NUM; 11063501942bSJustin T. Gibbs else if (!strcmp(attr, "GEOM::physpath")) 11073501942bSJustin T. Gibbs cdai.buftype = CDAI_TYPE_PHYS_PATH; 110840f27d7cSAlexander Motin else if (strcmp(attr, "GEOM::lunid") == 0 || 110940f27d7cSAlexander Motin strcmp(attr, "GEOM::lunname") == 0) { 1110ccba7102SAlexander Motin cdai.buftype = CDAI_TYPE_SCSI_DEVID; 1111ccba7102SAlexander Motin cdai.bufsiz = CAM_SCSI_DEVID_MAXLEN; 1112ccba7102SAlexander Motin } else 11133501942bSJustin T. Gibbs goto out; 11143501942bSJustin T. Gibbs 11153501942bSJustin T. Gibbs cdai.buf = malloc(cdai.bufsiz, M_CAMXPT, M_NOWAIT|M_ZERO); 11163501942bSJustin T. Gibbs if (cdai.buf == NULL) { 11173501942bSJustin T. Gibbs ret = ENOMEM; 11183501942bSJustin T. Gibbs goto out; 11193501942bSJustin T. Gibbs } 11203501942bSJustin T. Gibbs xpt_action((union ccb *)&cdai); /* can only be synchronous */ 11213501942bSJustin T. Gibbs if ((cdai.ccb_h.status & CAM_DEV_QFRZN) != 0) 11223501942bSJustin T. Gibbs cam_release_devq(cdai.ccb_h.path, 0, 0, 0, FALSE); 11233501942bSJustin T. Gibbs if (cdai.provsiz == 0) 11243501942bSJustin T. Gibbs goto out; 1125ccba7102SAlexander Motin if (cdai.buftype == CDAI_TYPE_SCSI_DEVID) { 112640f27d7cSAlexander Motin if (strcmp(attr, "GEOM::lunid") == 0) { 1127ccba7102SAlexander Motin idd = scsi_get_devid((struct scsi_vpd_device_id *)cdai.buf, 1128ccba7102SAlexander Motin cdai.provsiz, scsi_devid_is_lun_naa); 1129ccba7102SAlexander Motin if (idd == NULL) 1130ccba7102SAlexander Motin idd = scsi_get_devid((struct scsi_vpd_device_id *)cdai.buf, 1131ccba7102SAlexander Motin cdai.provsiz, scsi_devid_is_lun_eui64); 113240f27d7cSAlexander Motin } else 113340f27d7cSAlexander Motin idd = NULL; 1134ccba7102SAlexander Motin if (idd == NULL) 1135ccba7102SAlexander Motin idd = scsi_get_devid((struct scsi_vpd_device_id *)cdai.buf, 1136ccba7102SAlexander Motin cdai.provsiz, scsi_devid_is_lun_t10); 1137ccba7102SAlexander Motin if (idd == NULL) 1138ccba7102SAlexander Motin idd = scsi_get_devid((struct scsi_vpd_device_id *)cdai.buf, 1139ccba7102SAlexander Motin cdai.provsiz, scsi_devid_is_lun_name); 1140ccba7102SAlexander Motin if (idd == NULL) 1141ccba7102SAlexander Motin goto out; 1142ccba7102SAlexander Motin ret = 0; 1143ccba7102SAlexander Motin if ((idd->proto_codeset & SVPD_ID_CODESET_MASK) == SVPD_ID_CODESET_ASCII || 1144ccba7102SAlexander Motin (idd->proto_codeset & SVPD_ID_CODESET_MASK) == SVPD_ID_CODESET_UTF8) { 1145ccba7102SAlexander Motin l = strnlen(idd->identifier, idd->length); 1146ccba7102SAlexander Motin if (l < len) { 1147ccba7102SAlexander Motin bcopy(idd->identifier, buf, l); 1148ccba7102SAlexander Motin buf[l] = 0; 1149ccba7102SAlexander Motin } else 1150ccba7102SAlexander Motin ret = EFAULT; 1151ccba7102SAlexander Motin } else { 1152ccba7102SAlexander Motin if (idd->length * 2 < len) { 1153ccba7102SAlexander Motin for (l = 0; l < idd->length; l++) 1154ccba7102SAlexander Motin sprintf(buf + l * 2, "%02x", 1155ccba7102SAlexander Motin idd->identifier[l]); 1156ccba7102SAlexander Motin } else 1157ccba7102SAlexander Motin ret = EFAULT; 1158ccba7102SAlexander Motin } 1159ccba7102SAlexander Motin } else { 11603501942bSJustin T. Gibbs ret = 0; 11613501942bSJustin T. Gibbs if (strlcpy(buf, cdai.buf, len) >= len) 11623501942bSJustin T. Gibbs ret = EFAULT; 1163ccba7102SAlexander Motin } 11643501942bSJustin T. Gibbs 11653501942bSJustin T. Gibbs out: 11663501942bSJustin T. Gibbs if (cdai.buf != NULL) 11673501942bSJustin T. Gibbs free(cdai.buf, M_CAMXPT); 11683501942bSJustin T. Gibbs return ret; 11693501942bSJustin T. Gibbs } 11703501942bSJustin T. Gibbs 11718b8a9b1dSJustin T. Gibbs static dev_match_ret 11723393f8daSKenneth D. Merry xptbusmatch(struct dev_match_pattern *patterns, u_int num_patterns, 11738b8a9b1dSJustin T. Gibbs struct cam_eb *bus) 11748b8a9b1dSJustin T. Gibbs { 11758b8a9b1dSJustin T. Gibbs dev_match_ret retval; 11768b8a9b1dSJustin T. Gibbs int i; 11778b8a9b1dSJustin T. Gibbs 11788b8a9b1dSJustin T. Gibbs retval = DM_RET_NONE; 11798b8a9b1dSJustin T. Gibbs 11808b8a9b1dSJustin T. Gibbs /* 11818b8a9b1dSJustin T. Gibbs * If we aren't given something to match against, that's an error. 11828b8a9b1dSJustin T. Gibbs */ 11838b8a9b1dSJustin T. Gibbs if (bus == NULL) 11848b8a9b1dSJustin T. Gibbs return(DM_RET_ERROR); 11858b8a9b1dSJustin T. Gibbs 11868b8a9b1dSJustin T. Gibbs /* 11878b8a9b1dSJustin T. Gibbs * If there are no match entries, then this bus matches no 11888b8a9b1dSJustin T. Gibbs * matter what. 11898b8a9b1dSJustin T. Gibbs */ 11908b8a9b1dSJustin T. Gibbs if ((patterns == NULL) || (num_patterns == 0)) 11918b8a9b1dSJustin T. Gibbs return(DM_RET_DESCEND | DM_RET_COPY); 11928b8a9b1dSJustin T. Gibbs 11938b8a9b1dSJustin T. Gibbs for (i = 0; i < num_patterns; i++) { 11948b8a9b1dSJustin T. Gibbs struct bus_match_pattern *cur_pattern; 11958b8a9b1dSJustin T. Gibbs 11968b8a9b1dSJustin T. Gibbs /* 11978b8a9b1dSJustin T. Gibbs * If the pattern in question isn't for a bus node, we 11988b8a9b1dSJustin T. Gibbs * aren't interested. However, we do indicate to the 11998b8a9b1dSJustin T. Gibbs * calling routine that we should continue descending the 12008b8a9b1dSJustin T. Gibbs * tree, since the user wants to match against lower-level 12018b8a9b1dSJustin T. Gibbs * EDT elements. 12028b8a9b1dSJustin T. Gibbs */ 12038b8a9b1dSJustin T. Gibbs if (patterns[i].type != DEV_MATCH_BUS) { 12048b8a9b1dSJustin T. Gibbs if ((retval & DM_RET_ACTION_MASK) == DM_RET_NONE) 12058b8a9b1dSJustin T. Gibbs retval |= DM_RET_DESCEND; 12068b8a9b1dSJustin T. Gibbs continue; 12078b8a9b1dSJustin T. Gibbs } 12088b8a9b1dSJustin T. Gibbs 12098b8a9b1dSJustin T. Gibbs cur_pattern = &patterns[i].pattern.bus_pattern; 12108b8a9b1dSJustin T. Gibbs 12118b8a9b1dSJustin T. Gibbs /* 12128b8a9b1dSJustin T. Gibbs * If they want to match any bus node, we give them any 12138b8a9b1dSJustin T. Gibbs * device node. 12148b8a9b1dSJustin T. Gibbs */ 12158b8a9b1dSJustin T. Gibbs if (cur_pattern->flags == BUS_MATCH_ANY) { 12168b8a9b1dSJustin T. Gibbs /* set the copy flag */ 12178b8a9b1dSJustin T. Gibbs retval |= DM_RET_COPY; 12188b8a9b1dSJustin T. Gibbs 12198b8a9b1dSJustin T. Gibbs /* 12208b8a9b1dSJustin T. Gibbs * If we've already decided on an action, go ahead 12218b8a9b1dSJustin T. Gibbs * and return. 12228b8a9b1dSJustin T. Gibbs */ 12238b8a9b1dSJustin T. Gibbs if ((retval & DM_RET_ACTION_MASK) != DM_RET_NONE) 12248b8a9b1dSJustin T. Gibbs return(retval); 12258b8a9b1dSJustin T. Gibbs } 12268b8a9b1dSJustin T. Gibbs 12278b8a9b1dSJustin T. Gibbs /* 12288b8a9b1dSJustin T. Gibbs * Not sure why someone would do this... 12298b8a9b1dSJustin T. Gibbs */ 12308b8a9b1dSJustin T. Gibbs if (cur_pattern->flags == BUS_MATCH_NONE) 12318b8a9b1dSJustin T. Gibbs continue; 12328b8a9b1dSJustin T. Gibbs 12338b8a9b1dSJustin T. Gibbs if (((cur_pattern->flags & BUS_MATCH_PATH) != 0) 12348b8a9b1dSJustin T. Gibbs && (cur_pattern->path_id != bus->path_id)) 12358b8a9b1dSJustin T. Gibbs continue; 12368b8a9b1dSJustin T. Gibbs 12378b8a9b1dSJustin T. Gibbs if (((cur_pattern->flags & BUS_MATCH_BUS_ID) != 0) 12388b8a9b1dSJustin T. Gibbs && (cur_pattern->bus_id != bus->sim->bus_id)) 12398b8a9b1dSJustin T. Gibbs continue; 12408b8a9b1dSJustin T. Gibbs 12418b8a9b1dSJustin T. Gibbs if (((cur_pattern->flags & BUS_MATCH_UNIT) != 0) 12428b8a9b1dSJustin T. Gibbs && (cur_pattern->unit_number != bus->sim->unit_number)) 12438b8a9b1dSJustin T. Gibbs continue; 12448b8a9b1dSJustin T. Gibbs 12458b8a9b1dSJustin T. Gibbs if (((cur_pattern->flags & BUS_MATCH_NAME) != 0) 12468b8a9b1dSJustin T. Gibbs && (strncmp(cur_pattern->dev_name, bus->sim->sim_name, 12478b8a9b1dSJustin T. Gibbs DEV_IDLEN) != 0)) 12488b8a9b1dSJustin T. Gibbs continue; 12498b8a9b1dSJustin T. Gibbs 12508b8a9b1dSJustin T. Gibbs /* 12518b8a9b1dSJustin T. Gibbs * If we get to this point, the user definitely wants 12528b8a9b1dSJustin T. Gibbs * information on this bus. So tell the caller to copy the 12538b8a9b1dSJustin T. Gibbs * data out. 12548b8a9b1dSJustin T. Gibbs */ 12558b8a9b1dSJustin T. Gibbs retval |= DM_RET_COPY; 12568b8a9b1dSJustin T. Gibbs 12578b8a9b1dSJustin T. Gibbs /* 12588b8a9b1dSJustin T. Gibbs * If the return action has been set to descend, then we 12598b8a9b1dSJustin T. Gibbs * know that we've already seen a non-bus matching 12608b8a9b1dSJustin T. Gibbs * expression, therefore we need to further descend the tree. 12618b8a9b1dSJustin T. Gibbs * This won't change by continuing around the loop, so we 12628b8a9b1dSJustin T. Gibbs * go ahead and return. If we haven't seen a non-bus 12638b8a9b1dSJustin T. Gibbs * matching expression, we keep going around the loop until 12648b8a9b1dSJustin T. Gibbs * we exhaust the matching expressions. We'll set the stop 12658b8a9b1dSJustin T. Gibbs * flag once we fall out of the loop. 12668b8a9b1dSJustin T. Gibbs */ 12678b8a9b1dSJustin T. Gibbs if ((retval & DM_RET_ACTION_MASK) == DM_RET_DESCEND) 12688b8a9b1dSJustin T. Gibbs return(retval); 12698b8a9b1dSJustin T. Gibbs } 12708b8a9b1dSJustin T. Gibbs 12718b8a9b1dSJustin T. Gibbs /* 12728b8a9b1dSJustin T. Gibbs * If the return action hasn't been set to descend yet, that means 12738b8a9b1dSJustin T. Gibbs * we haven't seen anything other than bus matching patterns. So 12748b8a9b1dSJustin T. Gibbs * tell the caller to stop descending the tree -- the user doesn't 12758b8a9b1dSJustin T. Gibbs * want to match against lower level tree elements. 12768b8a9b1dSJustin T. Gibbs */ 12778b8a9b1dSJustin T. Gibbs if ((retval & DM_RET_ACTION_MASK) == DM_RET_NONE) 12788b8a9b1dSJustin T. Gibbs retval |= DM_RET_STOP; 12798b8a9b1dSJustin T. Gibbs 12808b8a9b1dSJustin T. Gibbs return(retval); 12818b8a9b1dSJustin T. Gibbs } 12828b8a9b1dSJustin T. Gibbs 12838b8a9b1dSJustin T. Gibbs static dev_match_ret 12843393f8daSKenneth D. Merry xptdevicematch(struct dev_match_pattern *patterns, u_int num_patterns, 12858b8a9b1dSJustin T. Gibbs struct cam_ed *device) 12868b8a9b1dSJustin T. Gibbs { 12878b8a9b1dSJustin T. Gibbs dev_match_ret retval; 12888b8a9b1dSJustin T. Gibbs int i; 12898b8a9b1dSJustin T. Gibbs 12908b8a9b1dSJustin T. Gibbs retval = DM_RET_NONE; 12918b8a9b1dSJustin T. Gibbs 12928b8a9b1dSJustin T. Gibbs /* 12938b8a9b1dSJustin T. Gibbs * If we aren't given something to match against, that's an error. 12948b8a9b1dSJustin T. Gibbs */ 12958b8a9b1dSJustin T. Gibbs if (device == NULL) 12968b8a9b1dSJustin T. Gibbs return(DM_RET_ERROR); 12978b8a9b1dSJustin T. Gibbs 12988b8a9b1dSJustin T. Gibbs /* 12998b8a9b1dSJustin T. Gibbs * If there are no match entries, then this device matches no 13008b8a9b1dSJustin T. Gibbs * matter what. 13018b8a9b1dSJustin T. Gibbs */ 130259e75884SColin Percival if ((patterns == NULL) || (num_patterns == 0)) 13038b8a9b1dSJustin T. Gibbs return(DM_RET_DESCEND | DM_RET_COPY); 13048b8a9b1dSJustin T. Gibbs 13058b8a9b1dSJustin T. Gibbs for (i = 0; i < num_patterns; i++) { 13068b8a9b1dSJustin T. Gibbs struct device_match_pattern *cur_pattern; 13073501942bSJustin T. Gibbs struct scsi_vpd_device_id *device_id_page; 13088b8a9b1dSJustin T. Gibbs 13098b8a9b1dSJustin T. Gibbs /* 13108b8a9b1dSJustin T. Gibbs * If the pattern in question isn't for a device node, we 13118b8a9b1dSJustin T. Gibbs * aren't interested. 13128b8a9b1dSJustin T. Gibbs */ 13138b8a9b1dSJustin T. Gibbs if (patterns[i].type != DEV_MATCH_DEVICE) { 13148b8a9b1dSJustin T. Gibbs if ((patterns[i].type == DEV_MATCH_PERIPH) 13158b8a9b1dSJustin T. Gibbs && ((retval & DM_RET_ACTION_MASK) == DM_RET_NONE)) 13168b8a9b1dSJustin T. Gibbs retval |= DM_RET_DESCEND; 13178b8a9b1dSJustin T. Gibbs continue; 13188b8a9b1dSJustin T. Gibbs } 13198b8a9b1dSJustin T. Gibbs 13208b8a9b1dSJustin T. Gibbs cur_pattern = &patterns[i].pattern.device_pattern; 13218b8a9b1dSJustin T. Gibbs 13223501942bSJustin T. Gibbs /* Error out if mutually exclusive options are specified. */ 13233501942bSJustin T. Gibbs if ((cur_pattern->flags & (DEV_MATCH_INQUIRY|DEV_MATCH_DEVID)) 13243501942bSJustin T. Gibbs == (DEV_MATCH_INQUIRY|DEV_MATCH_DEVID)) 13253501942bSJustin T. Gibbs return(DM_RET_ERROR); 13263501942bSJustin T. Gibbs 13278b8a9b1dSJustin T. Gibbs /* 13288b8a9b1dSJustin T. Gibbs * If they want to match any device node, we give them any 13298b8a9b1dSJustin T. Gibbs * device node. 13308b8a9b1dSJustin T. Gibbs */ 13313501942bSJustin T. Gibbs if (cur_pattern->flags == DEV_MATCH_ANY) 13323501942bSJustin T. Gibbs goto copy_dev_node; 13338b8a9b1dSJustin T. Gibbs 13348b8a9b1dSJustin T. Gibbs /* 13358b8a9b1dSJustin T. Gibbs * Not sure why someone would do this... 13368b8a9b1dSJustin T. Gibbs */ 13378b8a9b1dSJustin T. Gibbs if (cur_pattern->flags == DEV_MATCH_NONE) 13388b8a9b1dSJustin T. Gibbs continue; 13398b8a9b1dSJustin T. Gibbs 13408b8a9b1dSJustin T. Gibbs if (((cur_pattern->flags & DEV_MATCH_PATH) != 0) 13418b8a9b1dSJustin T. Gibbs && (cur_pattern->path_id != device->target->bus->path_id)) 13428b8a9b1dSJustin T. Gibbs continue; 13438b8a9b1dSJustin T. Gibbs 13448b8a9b1dSJustin T. Gibbs if (((cur_pattern->flags & DEV_MATCH_TARGET) != 0) 13458b8a9b1dSJustin T. Gibbs && (cur_pattern->target_id != device->target->target_id)) 13468b8a9b1dSJustin T. Gibbs continue; 13478b8a9b1dSJustin T. Gibbs 13488b8a9b1dSJustin T. Gibbs if (((cur_pattern->flags & DEV_MATCH_LUN) != 0) 13498b8a9b1dSJustin T. Gibbs && (cur_pattern->target_lun != device->lun_id)) 13508b8a9b1dSJustin T. Gibbs continue; 13518b8a9b1dSJustin T. Gibbs 13528b8a9b1dSJustin T. Gibbs if (((cur_pattern->flags & DEV_MATCH_INQUIRY) != 0) 13538b8a9b1dSJustin T. Gibbs && (cam_quirkmatch((caddr_t)&device->inq_data, 13543501942bSJustin T. Gibbs (caddr_t)&cur_pattern->data.inq_pat, 13553501942bSJustin T. Gibbs 1, sizeof(cur_pattern->data.inq_pat), 13568b8a9b1dSJustin T. Gibbs scsi_static_inquiry_match) == NULL)) 13578b8a9b1dSJustin T. Gibbs continue; 13588b8a9b1dSJustin T. Gibbs 13593501942bSJustin T. Gibbs device_id_page = (struct scsi_vpd_device_id *)device->device_id; 13603501942bSJustin T. Gibbs if (((cur_pattern->flags & DEV_MATCH_DEVID) != 0) 13613501942bSJustin T. Gibbs && (device->device_id_len < SVPD_DEVICE_ID_HDR_LEN 13623501942bSJustin T. Gibbs || scsi_devid_match((uint8_t *)device_id_page->desc_list, 13633501942bSJustin T. Gibbs device->device_id_len 13643501942bSJustin T. Gibbs - SVPD_DEVICE_ID_HDR_LEN, 13653501942bSJustin T. Gibbs cur_pattern->data.devid_pat.id, 13663501942bSJustin T. Gibbs cur_pattern->data.devid_pat.id_len) != 0)) 13673501942bSJustin T. Gibbs continue; 13683501942bSJustin T. Gibbs 13693501942bSJustin T. Gibbs copy_dev_node: 13708b8a9b1dSJustin T. Gibbs /* 13718b8a9b1dSJustin T. Gibbs * If we get to this point, the user definitely wants 13728b8a9b1dSJustin T. Gibbs * information on this device. So tell the caller to copy 13738b8a9b1dSJustin T. Gibbs * the data out. 13748b8a9b1dSJustin T. Gibbs */ 13758b8a9b1dSJustin T. Gibbs retval |= DM_RET_COPY; 13768b8a9b1dSJustin T. Gibbs 13778b8a9b1dSJustin T. Gibbs /* 13788b8a9b1dSJustin T. Gibbs * If the return action has been set to descend, then we 13798b8a9b1dSJustin T. Gibbs * know that we've already seen a peripheral matching 13808b8a9b1dSJustin T. Gibbs * expression, therefore we need to further descend the tree. 13818b8a9b1dSJustin T. Gibbs * This won't change by continuing around the loop, so we 13828b8a9b1dSJustin T. Gibbs * go ahead and return. If we haven't seen a peripheral 13838b8a9b1dSJustin T. Gibbs * matching expression, we keep going around the loop until 13848b8a9b1dSJustin T. Gibbs * we exhaust the matching expressions. We'll set the stop 13858b8a9b1dSJustin T. Gibbs * flag once we fall out of the loop. 13868b8a9b1dSJustin T. Gibbs */ 13878b8a9b1dSJustin T. Gibbs if ((retval & DM_RET_ACTION_MASK) == DM_RET_DESCEND) 13888b8a9b1dSJustin T. Gibbs return(retval); 13898b8a9b1dSJustin T. Gibbs } 13908b8a9b1dSJustin T. Gibbs 13918b8a9b1dSJustin T. Gibbs /* 13928b8a9b1dSJustin T. Gibbs * If the return action hasn't been set to descend yet, that means 13938b8a9b1dSJustin T. Gibbs * we haven't seen any peripheral matching patterns. So tell the 13948b8a9b1dSJustin T. Gibbs * caller to stop descending the tree -- the user doesn't want to 13958b8a9b1dSJustin T. Gibbs * match against lower level tree elements. 13968b8a9b1dSJustin T. Gibbs */ 13978b8a9b1dSJustin T. Gibbs if ((retval & DM_RET_ACTION_MASK) == DM_RET_NONE) 13988b8a9b1dSJustin T. Gibbs retval |= DM_RET_STOP; 13998b8a9b1dSJustin T. Gibbs 14008b8a9b1dSJustin T. Gibbs return(retval); 14018b8a9b1dSJustin T. Gibbs } 14028b8a9b1dSJustin T. Gibbs 14038b8a9b1dSJustin T. Gibbs /* 14048b8a9b1dSJustin T. Gibbs * Match a single peripheral against any number of match patterns. 14058b8a9b1dSJustin T. Gibbs */ 14068b8a9b1dSJustin T. Gibbs static dev_match_ret 14073393f8daSKenneth D. Merry xptperiphmatch(struct dev_match_pattern *patterns, u_int num_patterns, 14088b8a9b1dSJustin T. Gibbs struct cam_periph *periph) 14098b8a9b1dSJustin T. Gibbs { 14108b8a9b1dSJustin T. Gibbs dev_match_ret retval; 14118b8a9b1dSJustin T. Gibbs int i; 14128b8a9b1dSJustin T. Gibbs 14138b8a9b1dSJustin T. Gibbs /* 14148b8a9b1dSJustin T. Gibbs * If we aren't given something to match against, that's an error. 14158b8a9b1dSJustin T. Gibbs */ 14168b8a9b1dSJustin T. Gibbs if (periph == NULL) 14178b8a9b1dSJustin T. Gibbs return(DM_RET_ERROR); 14188b8a9b1dSJustin T. Gibbs 14198b8a9b1dSJustin T. Gibbs /* 14208b8a9b1dSJustin T. Gibbs * If there are no match entries, then this peripheral matches no 14218b8a9b1dSJustin T. Gibbs * matter what. 14228b8a9b1dSJustin T. Gibbs */ 14238b8a9b1dSJustin T. Gibbs if ((patterns == NULL) || (num_patterns == 0)) 14248b8a9b1dSJustin T. Gibbs return(DM_RET_STOP | DM_RET_COPY); 14258b8a9b1dSJustin T. Gibbs 14268b8a9b1dSJustin T. Gibbs /* 14278b8a9b1dSJustin T. Gibbs * There aren't any nodes below a peripheral node, so there's no 14288b8a9b1dSJustin T. Gibbs * reason to descend the tree any further. 14298b8a9b1dSJustin T. Gibbs */ 14308b8a9b1dSJustin T. Gibbs retval = DM_RET_STOP; 14318b8a9b1dSJustin T. Gibbs 14328b8a9b1dSJustin T. Gibbs for (i = 0; i < num_patterns; i++) { 14338b8a9b1dSJustin T. Gibbs struct periph_match_pattern *cur_pattern; 14348b8a9b1dSJustin T. Gibbs 14358b8a9b1dSJustin T. Gibbs /* 14368b8a9b1dSJustin T. Gibbs * If the pattern in question isn't for a peripheral, we 14378b8a9b1dSJustin T. Gibbs * aren't interested. 14388b8a9b1dSJustin T. Gibbs */ 14398b8a9b1dSJustin T. Gibbs if (patterns[i].type != DEV_MATCH_PERIPH) 14408b8a9b1dSJustin T. Gibbs continue; 14418b8a9b1dSJustin T. Gibbs 14428b8a9b1dSJustin T. Gibbs cur_pattern = &patterns[i].pattern.periph_pattern; 14438b8a9b1dSJustin T. Gibbs 14448b8a9b1dSJustin T. Gibbs /* 14458b8a9b1dSJustin T. Gibbs * If they want to match on anything, then we will do so. 14468b8a9b1dSJustin T. Gibbs */ 14478b8a9b1dSJustin T. Gibbs if (cur_pattern->flags == PERIPH_MATCH_ANY) { 14488b8a9b1dSJustin T. Gibbs /* set the copy flag */ 14498b8a9b1dSJustin T. Gibbs retval |= DM_RET_COPY; 14508b8a9b1dSJustin T. Gibbs 14518b8a9b1dSJustin T. Gibbs /* 14528b8a9b1dSJustin T. Gibbs * We've already set the return action to stop, 14538b8a9b1dSJustin T. Gibbs * since there are no nodes below peripherals in 14548b8a9b1dSJustin T. Gibbs * the tree. 14558b8a9b1dSJustin T. Gibbs */ 14568b8a9b1dSJustin T. Gibbs return(retval); 14578b8a9b1dSJustin T. Gibbs } 14588b8a9b1dSJustin T. Gibbs 14598b8a9b1dSJustin T. Gibbs /* 14608b8a9b1dSJustin T. Gibbs * Not sure why someone would do this... 14618b8a9b1dSJustin T. Gibbs */ 14628b8a9b1dSJustin T. Gibbs if (cur_pattern->flags == PERIPH_MATCH_NONE) 14638b8a9b1dSJustin T. Gibbs continue; 14648b8a9b1dSJustin T. Gibbs 14658b8a9b1dSJustin T. Gibbs if (((cur_pattern->flags & PERIPH_MATCH_PATH) != 0) 14668b8a9b1dSJustin T. Gibbs && (cur_pattern->path_id != periph->path->bus->path_id)) 14678b8a9b1dSJustin T. Gibbs continue; 14688b8a9b1dSJustin T. Gibbs 14698b8a9b1dSJustin T. Gibbs /* 14708b8a9b1dSJustin T. Gibbs * For the target and lun id's, we have to make sure the 14718b8a9b1dSJustin T. Gibbs * target and lun pointers aren't NULL. The xpt peripheral 14728b8a9b1dSJustin T. Gibbs * has a wildcard target and device. 14738b8a9b1dSJustin T. Gibbs */ 14748b8a9b1dSJustin T. Gibbs if (((cur_pattern->flags & PERIPH_MATCH_TARGET) != 0) 14758b8a9b1dSJustin T. Gibbs && ((periph->path->target == NULL) 14768b8a9b1dSJustin T. Gibbs ||(cur_pattern->target_id != periph->path->target->target_id))) 14778b8a9b1dSJustin T. Gibbs continue; 14788b8a9b1dSJustin T. Gibbs 14798b8a9b1dSJustin T. Gibbs if (((cur_pattern->flags & PERIPH_MATCH_LUN) != 0) 14808b8a9b1dSJustin T. Gibbs && ((periph->path->device == NULL) 14818b8a9b1dSJustin T. Gibbs || (cur_pattern->target_lun != periph->path->device->lun_id))) 14828b8a9b1dSJustin T. Gibbs continue; 14838b8a9b1dSJustin T. Gibbs 14848b8a9b1dSJustin T. Gibbs if (((cur_pattern->flags & PERIPH_MATCH_UNIT) != 0) 14858b8a9b1dSJustin T. Gibbs && (cur_pattern->unit_number != periph->unit_number)) 14868b8a9b1dSJustin T. Gibbs continue; 14878b8a9b1dSJustin T. Gibbs 14888b8a9b1dSJustin T. Gibbs if (((cur_pattern->flags & PERIPH_MATCH_NAME) != 0) 14898b8a9b1dSJustin T. Gibbs && (strncmp(cur_pattern->periph_name, periph->periph_name, 14908b8a9b1dSJustin T. Gibbs DEV_IDLEN) != 0)) 14918b8a9b1dSJustin T. Gibbs continue; 14928b8a9b1dSJustin T. Gibbs 14938b8a9b1dSJustin T. Gibbs /* 14948b8a9b1dSJustin T. Gibbs * If we get to this point, the user definitely wants 14958b8a9b1dSJustin T. Gibbs * information on this peripheral. So tell the caller to 14968b8a9b1dSJustin T. Gibbs * copy the data out. 14978b8a9b1dSJustin T. Gibbs */ 14988b8a9b1dSJustin T. Gibbs retval |= DM_RET_COPY; 14998b8a9b1dSJustin T. Gibbs 15008b8a9b1dSJustin T. Gibbs /* 15018b8a9b1dSJustin T. Gibbs * The return action has already been set to stop, since 15028b8a9b1dSJustin T. Gibbs * peripherals don't have any nodes below them in the EDT. 15038b8a9b1dSJustin T. Gibbs */ 15048b8a9b1dSJustin T. Gibbs return(retval); 15058b8a9b1dSJustin T. Gibbs } 15068b8a9b1dSJustin T. Gibbs 15078b8a9b1dSJustin T. Gibbs /* 15088b8a9b1dSJustin T. Gibbs * If we get to this point, the peripheral that was passed in 15098b8a9b1dSJustin T. Gibbs * doesn't match any of the patterns. 15108b8a9b1dSJustin T. Gibbs */ 15118b8a9b1dSJustin T. Gibbs return(retval); 15128b8a9b1dSJustin T. Gibbs } 15138b8a9b1dSJustin T. Gibbs 15148b8a9b1dSJustin T. Gibbs static int 15158b8a9b1dSJustin T. Gibbs xptedtbusfunc(struct cam_eb *bus, void *arg) 15168b8a9b1dSJustin T. Gibbs { 15178b8a9b1dSJustin T. Gibbs struct ccb_dev_match *cdm; 1518227d67aaSAlexander Motin struct cam_et *target; 15198b8a9b1dSJustin T. Gibbs dev_match_ret retval; 15208b8a9b1dSJustin T. Gibbs 15218b8a9b1dSJustin T. Gibbs cdm = (struct ccb_dev_match *)arg; 15228b8a9b1dSJustin T. Gibbs 15238b8a9b1dSJustin T. Gibbs /* 15248b8a9b1dSJustin T. Gibbs * If our position is for something deeper in the tree, that means 15258b8a9b1dSJustin T. Gibbs * that we've already seen this node. So, we keep going down. 15268b8a9b1dSJustin T. Gibbs */ 15278b8a9b1dSJustin T. Gibbs if ((cdm->pos.position_type & CAM_DEV_POS_BUS) 15288b8a9b1dSJustin T. Gibbs && (cdm->pos.cookie.bus == bus) 15298b8a9b1dSJustin T. Gibbs && (cdm->pos.position_type & CAM_DEV_POS_TARGET) 15308b8a9b1dSJustin T. Gibbs && (cdm->pos.cookie.target != NULL)) 15318b8a9b1dSJustin T. Gibbs retval = DM_RET_DESCEND; 15328b8a9b1dSJustin T. Gibbs else 15338b8a9b1dSJustin T. Gibbs retval = xptbusmatch(cdm->patterns, cdm->num_patterns, bus); 15348b8a9b1dSJustin T. Gibbs 15358b8a9b1dSJustin T. Gibbs /* 15368b8a9b1dSJustin T. Gibbs * If we got an error, bail out of the search. 15378b8a9b1dSJustin T. Gibbs */ 15388b8a9b1dSJustin T. Gibbs if ((retval & DM_RET_ACTION_MASK) == DM_RET_ERROR) { 15398b8a9b1dSJustin T. Gibbs cdm->status = CAM_DEV_MATCH_ERROR; 15408b8a9b1dSJustin T. Gibbs return(0); 15418b8a9b1dSJustin T. Gibbs } 15428b8a9b1dSJustin T. Gibbs 15438b8a9b1dSJustin T. Gibbs /* 15448b8a9b1dSJustin T. Gibbs * If the copy flag is set, copy this bus out. 15458b8a9b1dSJustin T. Gibbs */ 15468b8a9b1dSJustin T. Gibbs if (retval & DM_RET_COPY) { 15478b8a9b1dSJustin T. Gibbs int spaceleft, j; 15488b8a9b1dSJustin T. Gibbs 15498b8a9b1dSJustin T. Gibbs spaceleft = cdm->match_buf_len - (cdm->num_matches * 15508b8a9b1dSJustin T. Gibbs sizeof(struct dev_match_result)); 15518b8a9b1dSJustin T. Gibbs 15528b8a9b1dSJustin T. Gibbs /* 15538b8a9b1dSJustin T. Gibbs * If we don't have enough space to put in another 15548b8a9b1dSJustin T. Gibbs * match result, save our position and tell the 15558b8a9b1dSJustin T. Gibbs * user there are more devices to check. 15568b8a9b1dSJustin T. Gibbs */ 15578b8a9b1dSJustin T. Gibbs if (spaceleft < sizeof(struct dev_match_result)) { 15588b8a9b1dSJustin T. Gibbs bzero(&cdm->pos, sizeof(cdm->pos)); 15598b8a9b1dSJustin T. Gibbs cdm->pos.position_type = 15608b8a9b1dSJustin T. Gibbs CAM_DEV_POS_EDT | CAM_DEV_POS_BUS; 15618b8a9b1dSJustin T. Gibbs 15628b8a9b1dSJustin T. Gibbs cdm->pos.cookie.bus = bus; 15638b8a9b1dSJustin T. Gibbs cdm->pos.generations[CAM_BUS_GENERATION]= 15642b83592fSScott Long xsoftc.bus_generation; 15658b8a9b1dSJustin T. Gibbs cdm->status = CAM_DEV_MATCH_MORE; 15668b8a9b1dSJustin T. Gibbs return(0); 15678b8a9b1dSJustin T. Gibbs } 15688b8a9b1dSJustin T. Gibbs j = cdm->num_matches; 15698b8a9b1dSJustin T. Gibbs cdm->num_matches++; 15708b8a9b1dSJustin T. Gibbs cdm->matches[j].type = DEV_MATCH_BUS; 15718b8a9b1dSJustin T. Gibbs cdm->matches[j].result.bus_result.path_id = bus->path_id; 15728b8a9b1dSJustin T. Gibbs cdm->matches[j].result.bus_result.bus_id = bus->sim->bus_id; 15738b8a9b1dSJustin T. Gibbs cdm->matches[j].result.bus_result.unit_number = 15748b8a9b1dSJustin T. Gibbs bus->sim->unit_number; 15758b8a9b1dSJustin T. Gibbs strncpy(cdm->matches[j].result.bus_result.dev_name, 15768b8a9b1dSJustin T. Gibbs bus->sim->sim_name, DEV_IDLEN); 15778b8a9b1dSJustin T. Gibbs } 15788b8a9b1dSJustin T. Gibbs 15798b8a9b1dSJustin T. Gibbs /* 15808b8a9b1dSJustin T. Gibbs * If the user is only interested in busses, there's no 15818b8a9b1dSJustin T. Gibbs * reason to descend to the next level in the tree. 15828b8a9b1dSJustin T. Gibbs */ 15838b8a9b1dSJustin T. Gibbs if ((retval & DM_RET_ACTION_MASK) == DM_RET_STOP) 15848b8a9b1dSJustin T. Gibbs return(1); 15858b8a9b1dSJustin T. Gibbs 15868b8a9b1dSJustin T. Gibbs /* 15878b8a9b1dSJustin T. Gibbs * If there is a target generation recorded, check it to 15888b8a9b1dSJustin T. Gibbs * make sure the target list hasn't changed. 15898b8a9b1dSJustin T. Gibbs */ 1590227d67aaSAlexander Motin mtx_lock(&bus->eb_mtx); 15918b8a9b1dSJustin T. Gibbs if ((cdm->pos.position_type & CAM_DEV_POS_BUS) 15928b8a9b1dSJustin T. Gibbs && (cdm->pos.cookie.bus == bus) 15938b8a9b1dSJustin T. Gibbs && (cdm->pos.position_type & CAM_DEV_POS_TARGET) 1594227d67aaSAlexander Motin && (cdm->pos.cookie.target != NULL)) { 1595227d67aaSAlexander Motin if ((cdm->pos.generations[CAM_TARGET_GENERATION] != 1596227d67aaSAlexander Motin bus->generation)) { 1597227d67aaSAlexander Motin mtx_unlock(&bus->eb_mtx); 1598227d67aaSAlexander Motin cdm->status = CAM_DEV_MATCH_LIST_CHANGED; 1599227d67aaSAlexander Motin return (0); 1600227d67aaSAlexander Motin } 1601227d67aaSAlexander Motin target = (struct cam_et *)cdm->pos.cookie.target; 1602227d67aaSAlexander Motin target->refcount++; 1603227d67aaSAlexander Motin } else 1604227d67aaSAlexander Motin target = NULL; 1605227d67aaSAlexander Motin mtx_unlock(&bus->eb_mtx); 1606227d67aaSAlexander Motin 1607227d67aaSAlexander Motin return (xpttargettraverse(bus, target, xptedttargetfunc, arg)); 16088b8a9b1dSJustin T. Gibbs } 16098b8a9b1dSJustin T. Gibbs 16108b8a9b1dSJustin T. Gibbs static int 16118b8a9b1dSJustin T. Gibbs xptedttargetfunc(struct cam_et *target, void *arg) 16128b8a9b1dSJustin T. Gibbs { 16138b8a9b1dSJustin T. Gibbs struct ccb_dev_match *cdm; 1614227d67aaSAlexander Motin struct cam_eb *bus; 1615227d67aaSAlexander Motin struct cam_ed *device; 16168b8a9b1dSJustin T. Gibbs 16178b8a9b1dSJustin T. Gibbs cdm = (struct ccb_dev_match *)arg; 1618227d67aaSAlexander Motin bus = target->bus; 16198b8a9b1dSJustin T. Gibbs 16208b8a9b1dSJustin T. Gibbs /* 16218b8a9b1dSJustin T. Gibbs * If there is a device list generation recorded, check it to 16228b8a9b1dSJustin T. Gibbs * make sure the device list hasn't changed. 16238b8a9b1dSJustin T. Gibbs */ 1624227d67aaSAlexander Motin mtx_lock(&bus->eb_mtx); 16258b8a9b1dSJustin T. Gibbs if ((cdm->pos.position_type & CAM_DEV_POS_BUS) 1626227d67aaSAlexander Motin && (cdm->pos.cookie.bus == bus) 16278b8a9b1dSJustin T. Gibbs && (cdm->pos.position_type & CAM_DEV_POS_TARGET) 16288b8a9b1dSJustin T. Gibbs && (cdm->pos.cookie.target == target) 16298b8a9b1dSJustin T. Gibbs && (cdm->pos.position_type & CAM_DEV_POS_DEVICE) 1630227d67aaSAlexander Motin && (cdm->pos.cookie.device != NULL)) { 1631227d67aaSAlexander Motin if (cdm->pos.generations[CAM_DEV_GENERATION] != 1632227d67aaSAlexander Motin target->generation) { 1633227d67aaSAlexander Motin mtx_unlock(&bus->eb_mtx); 16348b8a9b1dSJustin T. Gibbs cdm->status = CAM_DEV_MATCH_LIST_CHANGED; 16358b8a9b1dSJustin T. Gibbs return(0); 16368b8a9b1dSJustin T. Gibbs } 1637227d67aaSAlexander Motin device = (struct cam_ed *)cdm->pos.cookie.device; 1638227d67aaSAlexander Motin device->refcount++; 1639227d67aaSAlexander Motin } else 1640227d67aaSAlexander Motin device = NULL; 1641227d67aaSAlexander Motin mtx_unlock(&bus->eb_mtx); 16428b8a9b1dSJustin T. Gibbs 1643227d67aaSAlexander Motin return (xptdevicetraverse(target, device, xptedtdevicefunc, arg)); 16448b8a9b1dSJustin T. Gibbs } 16458b8a9b1dSJustin T. Gibbs 16468b8a9b1dSJustin T. Gibbs static int 16478b8a9b1dSJustin T. Gibbs xptedtdevicefunc(struct cam_ed *device, void *arg) 16488b8a9b1dSJustin T. Gibbs { 1649227d67aaSAlexander Motin struct cam_eb *bus; 1650227d67aaSAlexander Motin struct cam_periph *periph; 16518b8a9b1dSJustin T. Gibbs struct ccb_dev_match *cdm; 16528b8a9b1dSJustin T. Gibbs dev_match_ret retval; 16538b8a9b1dSJustin T. Gibbs 16548b8a9b1dSJustin T. Gibbs cdm = (struct ccb_dev_match *)arg; 1655227d67aaSAlexander Motin bus = device->target->bus; 16568b8a9b1dSJustin T. Gibbs 16578b8a9b1dSJustin T. Gibbs /* 16588b8a9b1dSJustin T. Gibbs * If our position is for something deeper in the tree, that means 16598b8a9b1dSJustin T. Gibbs * that we've already seen this node. So, we keep going down. 16608b8a9b1dSJustin T. Gibbs */ 16618b8a9b1dSJustin T. Gibbs if ((cdm->pos.position_type & CAM_DEV_POS_DEVICE) 16628b8a9b1dSJustin T. Gibbs && (cdm->pos.cookie.device == device) 16638b8a9b1dSJustin T. Gibbs && (cdm->pos.position_type & CAM_DEV_POS_PERIPH) 16648b8a9b1dSJustin T. Gibbs && (cdm->pos.cookie.periph != NULL)) 16658b8a9b1dSJustin T. Gibbs retval = DM_RET_DESCEND; 16668b8a9b1dSJustin T. Gibbs else 16678b8a9b1dSJustin T. Gibbs retval = xptdevicematch(cdm->patterns, cdm->num_patterns, 16688b8a9b1dSJustin T. Gibbs device); 16698b8a9b1dSJustin T. Gibbs 16708b8a9b1dSJustin T. Gibbs if ((retval & DM_RET_ACTION_MASK) == DM_RET_ERROR) { 16718b8a9b1dSJustin T. Gibbs cdm->status = CAM_DEV_MATCH_ERROR; 16728b8a9b1dSJustin T. Gibbs return(0); 16738b8a9b1dSJustin T. Gibbs } 16748b8a9b1dSJustin T. Gibbs 16758b8a9b1dSJustin T. Gibbs /* 16768b8a9b1dSJustin T. Gibbs * If the copy flag is set, copy this device out. 16778b8a9b1dSJustin T. Gibbs */ 16788b8a9b1dSJustin T. Gibbs if (retval & DM_RET_COPY) { 16798b8a9b1dSJustin T. Gibbs int spaceleft, j; 16808b8a9b1dSJustin T. Gibbs 16818b8a9b1dSJustin T. Gibbs spaceleft = cdm->match_buf_len - (cdm->num_matches * 16828b8a9b1dSJustin T. Gibbs sizeof(struct dev_match_result)); 16838b8a9b1dSJustin T. Gibbs 16848b8a9b1dSJustin T. Gibbs /* 16858b8a9b1dSJustin T. Gibbs * If we don't have enough space to put in another 16868b8a9b1dSJustin T. Gibbs * match result, save our position and tell the 16878b8a9b1dSJustin T. Gibbs * user there are more devices to check. 16888b8a9b1dSJustin T. Gibbs */ 16898b8a9b1dSJustin T. Gibbs if (spaceleft < sizeof(struct dev_match_result)) { 16908b8a9b1dSJustin T. Gibbs bzero(&cdm->pos, sizeof(cdm->pos)); 16918b8a9b1dSJustin T. Gibbs cdm->pos.position_type = 16928b8a9b1dSJustin T. Gibbs CAM_DEV_POS_EDT | CAM_DEV_POS_BUS | 16938b8a9b1dSJustin T. Gibbs CAM_DEV_POS_TARGET | CAM_DEV_POS_DEVICE; 16948b8a9b1dSJustin T. Gibbs 16958b8a9b1dSJustin T. Gibbs cdm->pos.cookie.bus = device->target->bus; 16968b8a9b1dSJustin T. Gibbs cdm->pos.generations[CAM_BUS_GENERATION]= 16972b83592fSScott Long xsoftc.bus_generation; 16988b8a9b1dSJustin T. Gibbs cdm->pos.cookie.target = device->target; 16998b8a9b1dSJustin T. Gibbs cdm->pos.generations[CAM_TARGET_GENERATION] = 17008b8a9b1dSJustin T. Gibbs device->target->bus->generation; 17018b8a9b1dSJustin T. Gibbs cdm->pos.cookie.device = device; 17028b8a9b1dSJustin T. Gibbs cdm->pos.generations[CAM_DEV_GENERATION] = 17038b8a9b1dSJustin T. Gibbs device->target->generation; 17048b8a9b1dSJustin T. Gibbs cdm->status = CAM_DEV_MATCH_MORE; 17058b8a9b1dSJustin T. Gibbs return(0); 17068b8a9b1dSJustin T. Gibbs } 17078b8a9b1dSJustin T. Gibbs j = cdm->num_matches; 17088b8a9b1dSJustin T. Gibbs cdm->num_matches++; 17098b8a9b1dSJustin T. Gibbs cdm->matches[j].type = DEV_MATCH_DEVICE; 17108b8a9b1dSJustin T. Gibbs cdm->matches[j].result.device_result.path_id = 17118b8a9b1dSJustin T. Gibbs device->target->bus->path_id; 17128b8a9b1dSJustin T. Gibbs cdm->matches[j].result.device_result.target_id = 17138b8a9b1dSJustin T. Gibbs device->target->target_id; 17148b8a9b1dSJustin T. Gibbs cdm->matches[j].result.device_result.target_lun = 17158b8a9b1dSJustin T. Gibbs device->lun_id; 171652c9ce25SScott Long cdm->matches[j].result.device_result.protocol = 171752c9ce25SScott Long device->protocol; 17188b8a9b1dSJustin T. Gibbs bcopy(&device->inq_data, 17198b8a9b1dSJustin T. Gibbs &cdm->matches[j].result.device_result.inq_data, 17208b8a9b1dSJustin T. Gibbs sizeof(struct scsi_inquiry_data)); 172152c9ce25SScott Long bcopy(&device->ident_data, 172252c9ce25SScott Long &cdm->matches[j].result.device_result.ident_data, 172352c9ce25SScott Long sizeof(struct ata_params)); 17249deea857SKenneth D. Merry 17259deea857SKenneth D. Merry /* Let the user know whether this device is unconfigured */ 17269deea857SKenneth D. Merry if (device->flags & CAM_DEV_UNCONFIGURED) 17279deea857SKenneth D. Merry cdm->matches[j].result.device_result.flags = 17289deea857SKenneth D. Merry DEV_RESULT_UNCONFIGURED; 17299deea857SKenneth D. Merry else 17309deea857SKenneth D. Merry cdm->matches[j].result.device_result.flags = 17319deea857SKenneth D. Merry DEV_RESULT_NOFLAG; 17328b8a9b1dSJustin T. Gibbs } 17338b8a9b1dSJustin T. Gibbs 17348b8a9b1dSJustin T. Gibbs /* 17358b8a9b1dSJustin T. Gibbs * If the user isn't interested in peripherals, don't descend 17368b8a9b1dSJustin T. Gibbs * the tree any further. 17378b8a9b1dSJustin T. Gibbs */ 17388b8a9b1dSJustin T. Gibbs if ((retval & DM_RET_ACTION_MASK) == DM_RET_STOP) 17398b8a9b1dSJustin T. Gibbs return(1); 17408b8a9b1dSJustin T. Gibbs 17418b8a9b1dSJustin T. Gibbs /* 17428b8a9b1dSJustin T. Gibbs * If there is a peripheral list generation recorded, make sure 17438b8a9b1dSJustin T. Gibbs * it hasn't changed. 17448b8a9b1dSJustin T. Gibbs */ 1745227d67aaSAlexander Motin xpt_lock_buses(); 1746227d67aaSAlexander Motin mtx_lock(&bus->eb_mtx); 17478b8a9b1dSJustin T. Gibbs if ((cdm->pos.position_type & CAM_DEV_POS_BUS) 1748227d67aaSAlexander Motin && (cdm->pos.cookie.bus == bus) 17498b8a9b1dSJustin T. Gibbs && (cdm->pos.position_type & CAM_DEV_POS_TARGET) 17508b8a9b1dSJustin T. Gibbs && (cdm->pos.cookie.target == device->target) 17518b8a9b1dSJustin T. Gibbs && (cdm->pos.position_type & CAM_DEV_POS_DEVICE) 17528b8a9b1dSJustin T. Gibbs && (cdm->pos.cookie.device == device) 17538b8a9b1dSJustin T. Gibbs && (cdm->pos.position_type & CAM_DEV_POS_PERIPH) 1754227d67aaSAlexander Motin && (cdm->pos.cookie.periph != NULL)) { 1755227d67aaSAlexander Motin if (cdm->pos.generations[CAM_PERIPH_GENERATION] != 1756227d67aaSAlexander Motin device->generation) { 1757227d67aaSAlexander Motin mtx_unlock(&bus->eb_mtx); 1758227d67aaSAlexander Motin xpt_unlock_buses(); 1759227d67aaSAlexander Motin cdm->status = CAM_DEV_MATCH_LIST_CHANGED; 1760227d67aaSAlexander Motin return(0); 1761227d67aaSAlexander Motin } 1762227d67aaSAlexander Motin periph = (struct cam_periph *)cdm->pos.cookie.periph; 1763227d67aaSAlexander Motin periph->refcount++; 1764227d67aaSAlexander Motin } else 1765227d67aaSAlexander Motin periph = NULL; 1766227d67aaSAlexander Motin mtx_unlock(&bus->eb_mtx); 1767227d67aaSAlexander Motin xpt_unlock_buses(); 1768227d67aaSAlexander Motin 1769227d67aaSAlexander Motin return (xptperiphtraverse(device, periph, xptedtperiphfunc, arg)); 17708b8a9b1dSJustin T. Gibbs } 17718b8a9b1dSJustin T. Gibbs 17728b8a9b1dSJustin T. Gibbs static int 17738b8a9b1dSJustin T. Gibbs xptedtperiphfunc(struct cam_periph *periph, void *arg) 17748b8a9b1dSJustin T. Gibbs { 17758b8a9b1dSJustin T. Gibbs struct ccb_dev_match *cdm; 17768b8a9b1dSJustin T. Gibbs dev_match_ret retval; 17778b8a9b1dSJustin T. Gibbs 17788b8a9b1dSJustin T. Gibbs cdm = (struct ccb_dev_match *)arg; 17798b8a9b1dSJustin T. Gibbs 17808b8a9b1dSJustin T. Gibbs retval = xptperiphmatch(cdm->patterns, cdm->num_patterns, periph); 17818b8a9b1dSJustin T. Gibbs 17828b8a9b1dSJustin T. Gibbs if ((retval & DM_RET_ACTION_MASK) == DM_RET_ERROR) { 17838b8a9b1dSJustin T. Gibbs cdm->status = CAM_DEV_MATCH_ERROR; 17848b8a9b1dSJustin T. Gibbs return(0); 17858b8a9b1dSJustin T. Gibbs } 17868b8a9b1dSJustin T. Gibbs 17878b8a9b1dSJustin T. Gibbs /* 17888b8a9b1dSJustin T. Gibbs * If the copy flag is set, copy this peripheral out. 17898b8a9b1dSJustin T. Gibbs */ 17908b8a9b1dSJustin T. Gibbs if (retval & DM_RET_COPY) { 17918b8a9b1dSJustin T. Gibbs int spaceleft, j; 17928b8a9b1dSJustin T. Gibbs 17938b8a9b1dSJustin T. Gibbs spaceleft = cdm->match_buf_len - (cdm->num_matches * 17948b8a9b1dSJustin T. Gibbs sizeof(struct dev_match_result)); 17958b8a9b1dSJustin T. Gibbs 17968b8a9b1dSJustin T. Gibbs /* 17978b8a9b1dSJustin T. Gibbs * If we don't have enough space to put in another 17988b8a9b1dSJustin T. Gibbs * match result, save our position and tell the 17998b8a9b1dSJustin T. Gibbs * user there are more devices to check. 18008b8a9b1dSJustin T. Gibbs */ 18018b8a9b1dSJustin T. Gibbs if (spaceleft < sizeof(struct dev_match_result)) { 18028b8a9b1dSJustin T. Gibbs bzero(&cdm->pos, sizeof(cdm->pos)); 18038b8a9b1dSJustin T. Gibbs cdm->pos.position_type = 18048b8a9b1dSJustin T. Gibbs CAM_DEV_POS_EDT | CAM_DEV_POS_BUS | 18058b8a9b1dSJustin T. Gibbs CAM_DEV_POS_TARGET | CAM_DEV_POS_DEVICE | 18068b8a9b1dSJustin T. Gibbs CAM_DEV_POS_PERIPH; 18078b8a9b1dSJustin T. Gibbs 18088b8a9b1dSJustin T. Gibbs cdm->pos.cookie.bus = periph->path->bus; 18098b8a9b1dSJustin T. Gibbs cdm->pos.generations[CAM_BUS_GENERATION]= 18102b83592fSScott Long xsoftc.bus_generation; 18118b8a9b1dSJustin T. Gibbs cdm->pos.cookie.target = periph->path->target; 18128b8a9b1dSJustin T. Gibbs cdm->pos.generations[CAM_TARGET_GENERATION] = 18138b8a9b1dSJustin T. Gibbs periph->path->bus->generation; 18148b8a9b1dSJustin T. Gibbs cdm->pos.cookie.device = periph->path->device; 18158b8a9b1dSJustin T. Gibbs cdm->pos.generations[CAM_DEV_GENERATION] = 18168b8a9b1dSJustin T. Gibbs periph->path->target->generation; 18178b8a9b1dSJustin T. Gibbs cdm->pos.cookie.periph = periph; 18188b8a9b1dSJustin T. Gibbs cdm->pos.generations[CAM_PERIPH_GENERATION] = 18198b8a9b1dSJustin T. Gibbs periph->path->device->generation; 18208b8a9b1dSJustin T. Gibbs cdm->status = CAM_DEV_MATCH_MORE; 18218b8a9b1dSJustin T. Gibbs return(0); 18228b8a9b1dSJustin T. Gibbs } 18238b8a9b1dSJustin T. Gibbs 18248b8a9b1dSJustin T. Gibbs j = cdm->num_matches; 18258b8a9b1dSJustin T. Gibbs cdm->num_matches++; 18268b8a9b1dSJustin T. Gibbs cdm->matches[j].type = DEV_MATCH_PERIPH; 18278b8a9b1dSJustin T. Gibbs cdm->matches[j].result.periph_result.path_id = 18288b8a9b1dSJustin T. Gibbs periph->path->bus->path_id; 18298b8a9b1dSJustin T. Gibbs cdm->matches[j].result.periph_result.target_id = 18308b8a9b1dSJustin T. Gibbs periph->path->target->target_id; 18318b8a9b1dSJustin T. Gibbs cdm->matches[j].result.periph_result.target_lun = 18328b8a9b1dSJustin T. Gibbs periph->path->device->lun_id; 18338b8a9b1dSJustin T. Gibbs cdm->matches[j].result.periph_result.unit_number = 18348b8a9b1dSJustin T. Gibbs periph->unit_number; 18358b8a9b1dSJustin T. Gibbs strncpy(cdm->matches[j].result.periph_result.periph_name, 18368b8a9b1dSJustin T. Gibbs periph->periph_name, DEV_IDLEN); 18378b8a9b1dSJustin T. Gibbs } 18388b8a9b1dSJustin T. Gibbs 18398b8a9b1dSJustin T. Gibbs return(1); 18408b8a9b1dSJustin T. Gibbs } 18418b8a9b1dSJustin T. Gibbs 18428b8a9b1dSJustin T. Gibbs static int 18438b8a9b1dSJustin T. Gibbs xptedtmatch(struct ccb_dev_match *cdm) 18448b8a9b1dSJustin T. Gibbs { 1845227d67aaSAlexander Motin struct cam_eb *bus; 18468b8a9b1dSJustin T. Gibbs int ret; 18478b8a9b1dSJustin T. Gibbs 18488b8a9b1dSJustin T. Gibbs cdm->num_matches = 0; 18498b8a9b1dSJustin T. Gibbs 18508b8a9b1dSJustin T. Gibbs /* 18518b8a9b1dSJustin T. Gibbs * Check the bus list generation. If it has changed, the user 18528b8a9b1dSJustin T. Gibbs * needs to reset everything and start over. 18538b8a9b1dSJustin T. Gibbs */ 1854227d67aaSAlexander Motin xpt_lock_buses(); 18558b8a9b1dSJustin T. Gibbs if ((cdm->pos.position_type & CAM_DEV_POS_BUS) 1856227d67aaSAlexander Motin && (cdm->pos.cookie.bus != NULL)) { 1857227d67aaSAlexander Motin if (cdm->pos.generations[CAM_BUS_GENERATION] != 1858227d67aaSAlexander Motin xsoftc.bus_generation) { 1859227d67aaSAlexander Motin xpt_unlock_buses(); 18608b8a9b1dSJustin T. Gibbs cdm->status = CAM_DEV_MATCH_LIST_CHANGED; 18618b8a9b1dSJustin T. Gibbs return(0); 18628b8a9b1dSJustin T. Gibbs } 1863227d67aaSAlexander Motin bus = (struct cam_eb *)cdm->pos.cookie.bus; 1864227d67aaSAlexander Motin bus->refcount++; 1865227d67aaSAlexander Motin } else 1866227d67aaSAlexander Motin bus = NULL; 1867227d67aaSAlexander Motin xpt_unlock_buses(); 18688b8a9b1dSJustin T. Gibbs 1869227d67aaSAlexander Motin ret = xptbustraverse(bus, xptedtbusfunc, cdm); 18708b8a9b1dSJustin T. Gibbs 18718b8a9b1dSJustin T. Gibbs /* 18728b8a9b1dSJustin T. Gibbs * If we get back 0, that means that we had to stop before fully 18738b8a9b1dSJustin T. Gibbs * traversing the EDT. It also means that one of the subroutines 18748b8a9b1dSJustin T. Gibbs * has set the status field to the proper value. If we get back 1, 18758b8a9b1dSJustin T. Gibbs * we've fully traversed the EDT and copied out any matching entries. 18768b8a9b1dSJustin T. Gibbs */ 18778b8a9b1dSJustin T. Gibbs if (ret == 1) 18788b8a9b1dSJustin T. Gibbs cdm->status = CAM_DEV_MATCH_LAST; 18798b8a9b1dSJustin T. Gibbs 18808b8a9b1dSJustin T. Gibbs return(ret); 18818b8a9b1dSJustin T. Gibbs } 18828b8a9b1dSJustin T. Gibbs 18838b8a9b1dSJustin T. Gibbs static int 18848b8a9b1dSJustin T. Gibbs xptplistpdrvfunc(struct periph_driver **pdrv, void *arg) 18858b8a9b1dSJustin T. Gibbs { 1886227d67aaSAlexander Motin struct cam_periph *periph; 18878b8a9b1dSJustin T. Gibbs struct ccb_dev_match *cdm; 18888b8a9b1dSJustin T. Gibbs 18898b8a9b1dSJustin T. Gibbs cdm = (struct ccb_dev_match *)arg; 18908b8a9b1dSJustin T. Gibbs 1891227d67aaSAlexander Motin xpt_lock_buses(); 18928b8a9b1dSJustin T. Gibbs if ((cdm->pos.position_type & CAM_DEV_POS_PDPTR) 18938b8a9b1dSJustin T. Gibbs && (cdm->pos.cookie.pdrv == pdrv) 18948b8a9b1dSJustin T. Gibbs && (cdm->pos.position_type & CAM_DEV_POS_PERIPH) 1895227d67aaSAlexander Motin && (cdm->pos.cookie.periph != NULL)) { 1896227d67aaSAlexander Motin if (cdm->pos.generations[CAM_PERIPH_GENERATION] != 1897227d67aaSAlexander Motin (*pdrv)->generation) { 1898227d67aaSAlexander Motin xpt_unlock_buses(); 18998b8a9b1dSJustin T. Gibbs cdm->status = CAM_DEV_MATCH_LIST_CHANGED; 19008b8a9b1dSJustin T. Gibbs return(0); 19018b8a9b1dSJustin T. Gibbs } 1902227d67aaSAlexander Motin periph = (struct cam_periph *)cdm->pos.cookie.periph; 1903227d67aaSAlexander Motin periph->refcount++; 1904227d67aaSAlexander Motin } else 1905227d67aaSAlexander Motin periph = NULL; 1906227d67aaSAlexander Motin xpt_unlock_buses(); 19078b8a9b1dSJustin T. Gibbs 1908227d67aaSAlexander Motin return (xptpdperiphtraverse(pdrv, periph, xptplistperiphfunc, arg)); 19098b8a9b1dSJustin T. Gibbs } 19108b8a9b1dSJustin T. Gibbs 19118b8a9b1dSJustin T. Gibbs static int 19128b8a9b1dSJustin T. Gibbs xptplistperiphfunc(struct cam_periph *periph, void *arg) 19138b8a9b1dSJustin T. Gibbs { 19148b8a9b1dSJustin T. Gibbs struct ccb_dev_match *cdm; 19158b8a9b1dSJustin T. Gibbs dev_match_ret retval; 19168b8a9b1dSJustin T. Gibbs 19178b8a9b1dSJustin T. Gibbs cdm = (struct ccb_dev_match *)arg; 19188b8a9b1dSJustin T. Gibbs 19198b8a9b1dSJustin T. Gibbs retval = xptperiphmatch(cdm->patterns, cdm->num_patterns, periph); 19208b8a9b1dSJustin T. Gibbs 19218b8a9b1dSJustin T. Gibbs if ((retval & DM_RET_ACTION_MASK) == DM_RET_ERROR) { 19228b8a9b1dSJustin T. Gibbs cdm->status = CAM_DEV_MATCH_ERROR; 19238b8a9b1dSJustin T. Gibbs return(0); 19248b8a9b1dSJustin T. Gibbs } 19258b8a9b1dSJustin T. Gibbs 19268b8a9b1dSJustin T. Gibbs /* 19278b8a9b1dSJustin T. Gibbs * If the copy flag is set, copy this peripheral out. 19288b8a9b1dSJustin T. Gibbs */ 19298b8a9b1dSJustin T. Gibbs if (retval & DM_RET_COPY) { 19308b8a9b1dSJustin T. Gibbs int spaceleft, j; 19318b8a9b1dSJustin T. Gibbs 19328b8a9b1dSJustin T. Gibbs spaceleft = cdm->match_buf_len - (cdm->num_matches * 19338b8a9b1dSJustin T. Gibbs sizeof(struct dev_match_result)); 19348b8a9b1dSJustin T. Gibbs 19358b8a9b1dSJustin T. Gibbs /* 19368b8a9b1dSJustin T. Gibbs * If we don't have enough space to put in another 19378b8a9b1dSJustin T. Gibbs * match result, save our position and tell the 19388b8a9b1dSJustin T. Gibbs * user there are more devices to check. 19398b8a9b1dSJustin T. Gibbs */ 19408b8a9b1dSJustin T. Gibbs if (spaceleft < sizeof(struct dev_match_result)) { 19418b8a9b1dSJustin T. Gibbs struct periph_driver **pdrv; 19428b8a9b1dSJustin T. Gibbs 19438b8a9b1dSJustin T. Gibbs pdrv = NULL; 19448b8a9b1dSJustin T. Gibbs bzero(&cdm->pos, sizeof(cdm->pos)); 19458b8a9b1dSJustin T. Gibbs cdm->pos.position_type = 19468b8a9b1dSJustin T. Gibbs CAM_DEV_POS_PDRV | CAM_DEV_POS_PDPTR | 19478b8a9b1dSJustin T. Gibbs CAM_DEV_POS_PERIPH; 19488b8a9b1dSJustin T. Gibbs 19498b8a9b1dSJustin T. Gibbs /* 19508b8a9b1dSJustin T. Gibbs * This may look a bit non-sensical, but it is 19518b8a9b1dSJustin T. Gibbs * actually quite logical. There are very few 19528b8a9b1dSJustin T. Gibbs * peripheral drivers, and bloating every peripheral 19538b8a9b1dSJustin T. Gibbs * structure with a pointer back to its parent 19548b8a9b1dSJustin T. Gibbs * peripheral driver linker set entry would cost 19558b8a9b1dSJustin T. Gibbs * more in the long run than doing this quick lookup. 19568b8a9b1dSJustin T. Gibbs */ 19570b7c27b9SPeter Wemm for (pdrv = periph_drivers; *pdrv != NULL; pdrv++) { 19588b8a9b1dSJustin T. Gibbs if (strcmp((*pdrv)->driver_name, 19598b8a9b1dSJustin T. Gibbs periph->periph_name) == 0) 19608b8a9b1dSJustin T. Gibbs break; 19618b8a9b1dSJustin T. Gibbs } 19628b8a9b1dSJustin T. Gibbs 196301910babSScott Long if (*pdrv == NULL) { 19648b8a9b1dSJustin T. Gibbs cdm->status = CAM_DEV_MATCH_ERROR; 19658b8a9b1dSJustin T. Gibbs return(0); 19668b8a9b1dSJustin T. Gibbs } 19678b8a9b1dSJustin T. Gibbs 19688b8a9b1dSJustin T. Gibbs cdm->pos.cookie.pdrv = pdrv; 19698b8a9b1dSJustin T. Gibbs /* 19708b8a9b1dSJustin T. Gibbs * The periph generation slot does double duty, as 19718b8a9b1dSJustin T. Gibbs * does the periph pointer slot. They are used for 19728b8a9b1dSJustin T. Gibbs * both edt and pdrv lookups and positioning. 19738b8a9b1dSJustin T. Gibbs */ 19748b8a9b1dSJustin T. Gibbs cdm->pos.cookie.periph = periph; 19758b8a9b1dSJustin T. Gibbs cdm->pos.generations[CAM_PERIPH_GENERATION] = 19768b8a9b1dSJustin T. Gibbs (*pdrv)->generation; 19778b8a9b1dSJustin T. Gibbs cdm->status = CAM_DEV_MATCH_MORE; 19788b8a9b1dSJustin T. Gibbs return(0); 19798b8a9b1dSJustin T. Gibbs } 19808b8a9b1dSJustin T. Gibbs 19818b8a9b1dSJustin T. Gibbs j = cdm->num_matches; 19828b8a9b1dSJustin T. Gibbs cdm->num_matches++; 19838b8a9b1dSJustin T. Gibbs cdm->matches[j].type = DEV_MATCH_PERIPH; 19848b8a9b1dSJustin T. Gibbs cdm->matches[j].result.periph_result.path_id = 19858b8a9b1dSJustin T. Gibbs periph->path->bus->path_id; 19868b8a9b1dSJustin T. Gibbs 19878b8a9b1dSJustin T. Gibbs /* 19888b8a9b1dSJustin T. Gibbs * The transport layer peripheral doesn't have a target or 19898b8a9b1dSJustin T. Gibbs * lun. 19908b8a9b1dSJustin T. Gibbs */ 19918b8a9b1dSJustin T. Gibbs if (periph->path->target) 19928b8a9b1dSJustin T. Gibbs cdm->matches[j].result.periph_result.target_id = 19938b8a9b1dSJustin T. Gibbs periph->path->target->target_id; 19948b8a9b1dSJustin T. Gibbs else 1995431d3a5bSAlexander Motin cdm->matches[j].result.periph_result.target_id = 1996431d3a5bSAlexander Motin CAM_TARGET_WILDCARD; 19978b8a9b1dSJustin T. Gibbs 19988b8a9b1dSJustin T. Gibbs if (periph->path->device) 19998b8a9b1dSJustin T. Gibbs cdm->matches[j].result.periph_result.target_lun = 20008b8a9b1dSJustin T. Gibbs periph->path->device->lun_id; 20018b8a9b1dSJustin T. Gibbs else 2002431d3a5bSAlexander Motin cdm->matches[j].result.periph_result.target_lun = 2003431d3a5bSAlexander Motin CAM_LUN_WILDCARD; 20048b8a9b1dSJustin T. Gibbs 20058b8a9b1dSJustin T. Gibbs cdm->matches[j].result.periph_result.unit_number = 20068b8a9b1dSJustin T. Gibbs periph->unit_number; 20078b8a9b1dSJustin T. Gibbs strncpy(cdm->matches[j].result.periph_result.periph_name, 20088b8a9b1dSJustin T. Gibbs periph->periph_name, DEV_IDLEN); 20098b8a9b1dSJustin T. Gibbs } 20108b8a9b1dSJustin T. Gibbs 20118b8a9b1dSJustin T. Gibbs return(1); 20128b8a9b1dSJustin T. Gibbs } 20138b8a9b1dSJustin T. Gibbs 20148b8a9b1dSJustin T. Gibbs static int 20158b8a9b1dSJustin T. Gibbs xptperiphlistmatch(struct ccb_dev_match *cdm) 20168b8a9b1dSJustin T. Gibbs { 20178b8a9b1dSJustin T. Gibbs int ret; 20188b8a9b1dSJustin T. Gibbs 20198b8a9b1dSJustin T. Gibbs cdm->num_matches = 0; 20208b8a9b1dSJustin T. Gibbs 20218b8a9b1dSJustin T. Gibbs /* 20228b8a9b1dSJustin T. Gibbs * At this point in the edt traversal function, we check the bus 20238b8a9b1dSJustin T. Gibbs * list generation to make sure that no busses have been added or 20248b8a9b1dSJustin T. Gibbs * removed since the user last sent a XPT_DEV_MATCH ccb through. 20258b8a9b1dSJustin T. Gibbs * For the peripheral driver list traversal function, however, we 20268b8a9b1dSJustin T. Gibbs * don't have to worry about new peripheral driver types coming or 20278b8a9b1dSJustin T. Gibbs * going; they're in a linker set, and therefore can't change 20288b8a9b1dSJustin T. Gibbs * without a recompile. 20298b8a9b1dSJustin T. Gibbs */ 20308b8a9b1dSJustin T. Gibbs 20318b8a9b1dSJustin T. Gibbs if ((cdm->pos.position_type & CAM_DEV_POS_PDPTR) 20328b8a9b1dSJustin T. Gibbs && (cdm->pos.cookie.pdrv != NULL)) 20338b8a9b1dSJustin T. Gibbs ret = xptpdrvtraverse( 20348b8a9b1dSJustin T. Gibbs (struct periph_driver **)cdm->pos.cookie.pdrv, 20358b8a9b1dSJustin T. Gibbs xptplistpdrvfunc, cdm); 20368b8a9b1dSJustin T. Gibbs else 20378b8a9b1dSJustin T. Gibbs ret = xptpdrvtraverse(NULL, xptplistpdrvfunc, cdm); 20388b8a9b1dSJustin T. Gibbs 20398b8a9b1dSJustin T. Gibbs /* 20408b8a9b1dSJustin T. Gibbs * If we get back 0, that means that we had to stop before fully 20418b8a9b1dSJustin T. Gibbs * traversing the peripheral driver tree. It also means that one of 20428b8a9b1dSJustin T. Gibbs * the subroutines has set the status field to the proper value. If 20438b8a9b1dSJustin T. Gibbs * we get back 1, we've fully traversed the EDT and copied out any 20448b8a9b1dSJustin T. Gibbs * matching entries. 20458b8a9b1dSJustin T. Gibbs */ 20468b8a9b1dSJustin T. Gibbs if (ret == 1) 20478b8a9b1dSJustin T. Gibbs cdm->status = CAM_DEV_MATCH_LAST; 20488b8a9b1dSJustin T. Gibbs 20498b8a9b1dSJustin T. Gibbs return(ret); 20508b8a9b1dSJustin T. Gibbs } 20518b8a9b1dSJustin T. Gibbs 20528b8a9b1dSJustin T. Gibbs static int 20538b8a9b1dSJustin T. Gibbs xptbustraverse(struct cam_eb *start_bus, xpt_busfunc_t *tr_func, void *arg) 20548b8a9b1dSJustin T. Gibbs { 20558b8a9b1dSJustin T. Gibbs struct cam_eb *bus, *next_bus; 20568b8a9b1dSJustin T. Gibbs int retval; 20578b8a9b1dSJustin T. Gibbs 20588b8a9b1dSJustin T. Gibbs retval = 1; 2059227d67aaSAlexander Motin if (start_bus) 2060227d67aaSAlexander Motin bus = start_bus; 2061227d67aaSAlexander Motin else { 20629a7c2696SAlexander Motin xpt_lock_buses(); 2063227d67aaSAlexander Motin bus = TAILQ_FIRST(&xsoftc.xpt_busses); 2064227d67aaSAlexander Motin if (bus == NULL) { 20659a7c2696SAlexander Motin xpt_unlock_buses(); 2066227d67aaSAlexander Motin return (retval); 2067227d67aaSAlexander Motin } 2068227d67aaSAlexander Motin bus->refcount++; 2069227d67aaSAlexander Motin xpt_unlock_buses(); 2070227d67aaSAlexander Motin } 2071227d67aaSAlexander Motin for (; bus != NULL; bus = next_bus) { 20728b8a9b1dSJustin T. Gibbs retval = tr_func(bus, arg); 2073227d67aaSAlexander Motin if (retval == 0) { 2074227d67aaSAlexander Motin xpt_release_bus(bus); 2075227d67aaSAlexander Motin break; 2076227d67aaSAlexander Motin } 20779a7c2696SAlexander Motin xpt_lock_buses(); 20788900f4b8SKenneth D. Merry next_bus = TAILQ_NEXT(bus, links); 2079227d67aaSAlexander Motin if (next_bus) 2080227d67aaSAlexander Motin next_bus->refcount++; 20819a7c2696SAlexander Motin xpt_unlock_buses(); 20828900f4b8SKenneth D. Merry xpt_release_bus(bus); 20838b8a9b1dSJustin T. Gibbs } 20848b8a9b1dSJustin T. Gibbs return(retval); 20858b8a9b1dSJustin T. Gibbs } 20868b8a9b1dSJustin T. Gibbs 20878b8a9b1dSJustin T. Gibbs static int 20888b8a9b1dSJustin T. Gibbs xpttargettraverse(struct cam_eb *bus, struct cam_et *start_target, 20898b8a9b1dSJustin T. Gibbs xpt_targetfunc_t *tr_func, void *arg) 20908b8a9b1dSJustin T. Gibbs { 20918b8a9b1dSJustin T. Gibbs struct cam_et *target, *next_target; 20928b8a9b1dSJustin T. Gibbs int retval; 20938b8a9b1dSJustin T. Gibbs 20948b8a9b1dSJustin T. Gibbs retval = 1; 2095227d67aaSAlexander Motin if (start_target) 2096227d67aaSAlexander Motin target = start_target; 2097227d67aaSAlexander Motin else { 2098227d67aaSAlexander Motin mtx_lock(&bus->eb_mtx); 2099227d67aaSAlexander Motin target = TAILQ_FIRST(&bus->et_entries); 2100227d67aaSAlexander Motin if (target == NULL) { 2101227d67aaSAlexander Motin mtx_unlock(&bus->eb_mtx); 21028b8a9b1dSJustin T. Gibbs return (retval); 21038b8a9b1dSJustin T. Gibbs } 2104227d67aaSAlexander Motin target->refcount++; 2105227d67aaSAlexander Motin mtx_unlock(&bus->eb_mtx); 2106227d67aaSAlexander Motin } 2107227d67aaSAlexander Motin for (; target != NULL; target = next_target) { 2108227d67aaSAlexander Motin retval = tr_func(target, arg); 2109227d67aaSAlexander Motin if (retval == 0) { 2110227d67aaSAlexander Motin xpt_release_target(target); 2111227d67aaSAlexander Motin break; 2112227d67aaSAlexander Motin } 2113227d67aaSAlexander Motin mtx_lock(&bus->eb_mtx); 2114227d67aaSAlexander Motin next_target = TAILQ_NEXT(target, links); 2115227d67aaSAlexander Motin if (next_target) 2116227d67aaSAlexander Motin next_target->refcount++; 2117227d67aaSAlexander Motin mtx_unlock(&bus->eb_mtx); 2118227d67aaSAlexander Motin xpt_release_target(target); 2119227d67aaSAlexander Motin } 21208b8a9b1dSJustin T. Gibbs return(retval); 21218b8a9b1dSJustin T. Gibbs } 21228b8a9b1dSJustin T. Gibbs 21238b8a9b1dSJustin T. Gibbs static int 21248b8a9b1dSJustin T. Gibbs xptdevicetraverse(struct cam_et *target, struct cam_ed *start_device, 21258b8a9b1dSJustin T. Gibbs xpt_devicefunc_t *tr_func, void *arg) 21268b8a9b1dSJustin T. Gibbs { 2127227d67aaSAlexander Motin struct cam_eb *bus; 21288b8a9b1dSJustin T. Gibbs struct cam_ed *device, *next_device; 21298b8a9b1dSJustin T. Gibbs int retval; 21308b8a9b1dSJustin T. Gibbs 21318b8a9b1dSJustin T. Gibbs retval = 1; 2132227d67aaSAlexander Motin bus = target->bus; 2133227d67aaSAlexander Motin if (start_device) 2134227d67aaSAlexander Motin device = start_device; 2135227d67aaSAlexander Motin else { 2136227d67aaSAlexander Motin mtx_lock(&bus->eb_mtx); 2137227d67aaSAlexander Motin device = TAILQ_FIRST(&target->ed_entries); 2138227d67aaSAlexander Motin if (device == NULL) { 2139227d67aaSAlexander Motin mtx_unlock(&bus->eb_mtx); 21408b8a9b1dSJustin T. Gibbs return (retval); 21418b8a9b1dSJustin T. Gibbs } 2142227d67aaSAlexander Motin device->refcount++; 2143227d67aaSAlexander Motin mtx_unlock(&bus->eb_mtx); 2144227d67aaSAlexander Motin } 2145227d67aaSAlexander Motin for (; device != NULL; device = next_device) { 2146227d67aaSAlexander Motin mtx_lock(&device->device_mtx); 2147227d67aaSAlexander Motin retval = tr_func(device, arg); 2148227d67aaSAlexander Motin mtx_unlock(&device->device_mtx); 2149227d67aaSAlexander Motin if (retval == 0) { 2150227d67aaSAlexander Motin xpt_release_device(device); 2151227d67aaSAlexander Motin break; 2152227d67aaSAlexander Motin } 2153227d67aaSAlexander Motin mtx_lock(&bus->eb_mtx); 2154227d67aaSAlexander Motin next_device = TAILQ_NEXT(device, links); 2155227d67aaSAlexander Motin if (next_device) 2156227d67aaSAlexander Motin next_device->refcount++; 2157227d67aaSAlexander Motin mtx_unlock(&bus->eb_mtx); 2158227d67aaSAlexander Motin xpt_release_device(device); 2159227d67aaSAlexander Motin } 21608b8a9b1dSJustin T. Gibbs return(retval); 21618b8a9b1dSJustin T. Gibbs } 21628b8a9b1dSJustin T. Gibbs 21638b8a9b1dSJustin T. Gibbs static int 21648b8a9b1dSJustin T. Gibbs xptperiphtraverse(struct cam_ed *device, struct cam_periph *start_periph, 21658b8a9b1dSJustin T. Gibbs xpt_periphfunc_t *tr_func, void *arg) 21668b8a9b1dSJustin T. Gibbs { 2167227d67aaSAlexander Motin struct cam_eb *bus; 21688b8a9b1dSJustin T. Gibbs struct cam_periph *periph, *next_periph; 21698b8a9b1dSJustin T. Gibbs int retval; 21708b8a9b1dSJustin T. Gibbs 21718b8a9b1dSJustin T. Gibbs retval = 1; 21728b8a9b1dSJustin T. Gibbs 2173227d67aaSAlexander Motin bus = device->target->bus; 2174227d67aaSAlexander Motin if (start_periph) 2175227d67aaSAlexander Motin periph = start_periph; 2176227d67aaSAlexander Motin else { 21778900f4b8SKenneth D. Merry xpt_lock_buses(); 2178227d67aaSAlexander Motin mtx_lock(&bus->eb_mtx); 2179227d67aaSAlexander Motin periph = SLIST_FIRST(&device->periphs); 2180227d67aaSAlexander Motin while (periph != NULL && (periph->flags & CAM_PERIPH_FREE) != 0) 2181227d67aaSAlexander Motin periph = SLIST_NEXT(periph, periph_links); 2182227d67aaSAlexander Motin if (periph == NULL) { 2183227d67aaSAlexander Motin mtx_unlock(&bus->eb_mtx); 21848900f4b8SKenneth D. Merry xpt_unlock_buses(); 2185227d67aaSAlexander Motin return (retval); 2186227d67aaSAlexander Motin } 2187227d67aaSAlexander Motin periph->refcount++; 2188227d67aaSAlexander Motin mtx_unlock(&bus->eb_mtx); 2189227d67aaSAlexander Motin xpt_unlock_buses(); 2190227d67aaSAlexander Motin } 2191227d67aaSAlexander Motin for (; periph != NULL; periph = next_periph) { 2192227d67aaSAlexander Motin retval = tr_func(periph, arg); 2193227d67aaSAlexander Motin if (retval == 0) { 21949813c936SAlexander Motin cam_periph_release_locked(periph); 2195227d67aaSAlexander Motin break; 2196227d67aaSAlexander Motin } 2197227d67aaSAlexander Motin xpt_lock_buses(); 2198227d67aaSAlexander Motin mtx_lock(&bus->eb_mtx); 2199227d67aaSAlexander Motin next_periph = SLIST_NEXT(periph, periph_links); 2200227d67aaSAlexander Motin while (next_periph != NULL && 2201227d67aaSAlexander Motin (next_periph->flags & CAM_PERIPH_FREE) != 0) 2202227d67aaSAlexander Motin next_periph = SLIST_NEXT(periph, periph_links); 2203227d67aaSAlexander Motin if (next_periph) 2204227d67aaSAlexander Motin next_periph->refcount++; 2205227d67aaSAlexander Motin mtx_unlock(&bus->eb_mtx); 2206227d67aaSAlexander Motin xpt_unlock_buses(); 2207227d67aaSAlexander Motin cam_periph_release_locked(periph); 2208227d67aaSAlexander Motin } 22098b8a9b1dSJustin T. Gibbs return(retval); 22108b8a9b1dSJustin T. Gibbs } 22118b8a9b1dSJustin T. Gibbs 22128b8a9b1dSJustin T. Gibbs static int 22138b8a9b1dSJustin T. Gibbs xptpdrvtraverse(struct periph_driver **start_pdrv, 22148b8a9b1dSJustin T. Gibbs xpt_pdrvfunc_t *tr_func, void *arg) 22158b8a9b1dSJustin T. Gibbs { 22168b8a9b1dSJustin T. Gibbs struct periph_driver **pdrv; 22178b8a9b1dSJustin T. Gibbs int retval; 22188b8a9b1dSJustin T. Gibbs 22198b8a9b1dSJustin T. Gibbs retval = 1; 22208b8a9b1dSJustin T. Gibbs 22218b8a9b1dSJustin T. Gibbs /* 22228b8a9b1dSJustin T. Gibbs * We don't traverse the peripheral driver list like we do the 22238b8a9b1dSJustin T. Gibbs * other lists, because it is a linker set, and therefore cannot be 22248b8a9b1dSJustin T. Gibbs * changed during runtime. If the peripheral driver list is ever 22258b8a9b1dSJustin T. Gibbs * re-done to be something other than a linker set (i.e. it can 22268b8a9b1dSJustin T. Gibbs * change while the system is running), the list traversal should 22278b8a9b1dSJustin T. Gibbs * be modified to work like the other traversal functions. 22288b8a9b1dSJustin T. Gibbs */ 22290b7c27b9SPeter Wemm for (pdrv = (start_pdrv ? start_pdrv : periph_drivers); 22308b8a9b1dSJustin T. Gibbs *pdrv != NULL; pdrv++) { 22318b8a9b1dSJustin T. Gibbs retval = tr_func(pdrv, arg); 22328b8a9b1dSJustin T. Gibbs 22338b8a9b1dSJustin T. Gibbs if (retval == 0) 22348b8a9b1dSJustin T. Gibbs return(retval); 22358b8a9b1dSJustin T. Gibbs } 22368b8a9b1dSJustin T. Gibbs 22378b8a9b1dSJustin T. Gibbs return(retval); 22388b8a9b1dSJustin T. Gibbs } 22398b8a9b1dSJustin T. Gibbs 22408b8a9b1dSJustin T. Gibbs static int 22418b8a9b1dSJustin T. Gibbs xptpdperiphtraverse(struct periph_driver **pdrv, 22428b8a9b1dSJustin T. Gibbs struct cam_periph *start_periph, 22438b8a9b1dSJustin T. Gibbs xpt_periphfunc_t *tr_func, void *arg) 22448b8a9b1dSJustin T. Gibbs { 22458b8a9b1dSJustin T. Gibbs struct cam_periph *periph, *next_periph; 22468b8a9b1dSJustin T. Gibbs int retval; 22478b8a9b1dSJustin T. Gibbs 22488b8a9b1dSJustin T. Gibbs retval = 1; 22498b8a9b1dSJustin T. Gibbs 2250227d67aaSAlexander Motin if (start_periph) 2251227d67aaSAlexander Motin periph = start_periph; 2252227d67aaSAlexander Motin else { 2253f1e2546aSMatt Jacob xpt_lock_buses(); 2254227d67aaSAlexander Motin periph = TAILQ_FIRST(&(*pdrv)->units); 2255227d67aaSAlexander Motin while (periph != NULL && (periph->flags & CAM_PERIPH_FREE) != 0) 2256227d67aaSAlexander Motin periph = TAILQ_NEXT(periph, unit_links); 2257227d67aaSAlexander Motin if (periph == NULL) { 2258227d67aaSAlexander Motin xpt_unlock_buses(); 2259227d67aaSAlexander Motin return (retval); 22608900f4b8SKenneth D. Merry } 22618900f4b8SKenneth D. Merry periph->refcount++; 2262dcdf6e74SAlexander Motin xpt_unlock_buses(); 22638b8a9b1dSJustin T. Gibbs } 2264227d67aaSAlexander Motin for (; periph != NULL; periph = next_periph) { 2265227d67aaSAlexander Motin cam_periph_lock(periph); 2266227d67aaSAlexander Motin retval = tr_func(periph, arg); 2267227d67aaSAlexander Motin cam_periph_unlock(periph); 2268227d67aaSAlexander Motin if (retval == 0) { 2269227d67aaSAlexander Motin cam_periph_release(periph); 2270227d67aaSAlexander Motin break; 2271227d67aaSAlexander Motin } 2272227d67aaSAlexander Motin xpt_lock_buses(); 2273227d67aaSAlexander Motin next_periph = TAILQ_NEXT(periph, unit_links); 2274227d67aaSAlexander Motin while (next_periph != NULL && 2275227d67aaSAlexander Motin (next_periph->flags & CAM_PERIPH_FREE) != 0) 2276227d67aaSAlexander Motin next_periph = TAILQ_NEXT(periph, unit_links); 2277227d67aaSAlexander Motin if (next_periph) 2278227d67aaSAlexander Motin next_periph->refcount++; 2279f1e2546aSMatt Jacob xpt_unlock_buses(); 2280227d67aaSAlexander Motin cam_periph_release(periph); 2281227d67aaSAlexander Motin } 22828b8a9b1dSJustin T. Gibbs return(retval); 22838b8a9b1dSJustin T. Gibbs } 22848b8a9b1dSJustin T. Gibbs 22858b8a9b1dSJustin T. Gibbs static int 22868b8a9b1dSJustin T. Gibbs xptdefbusfunc(struct cam_eb *bus, void *arg) 22878b8a9b1dSJustin T. Gibbs { 22888b8a9b1dSJustin T. Gibbs struct xpt_traverse_config *tr_config; 22898b8a9b1dSJustin T. Gibbs 22908b8a9b1dSJustin T. Gibbs tr_config = (struct xpt_traverse_config *)arg; 22918b8a9b1dSJustin T. Gibbs 22928b8a9b1dSJustin T. Gibbs if (tr_config->depth == XPT_DEPTH_BUS) { 22938b8a9b1dSJustin T. Gibbs xpt_busfunc_t *tr_func; 22948b8a9b1dSJustin T. Gibbs 22958b8a9b1dSJustin T. Gibbs tr_func = (xpt_busfunc_t *)tr_config->tr_func; 22968b8a9b1dSJustin T. Gibbs 22978b8a9b1dSJustin T. Gibbs return(tr_func(bus, tr_config->tr_arg)); 22988b8a9b1dSJustin T. Gibbs } else 22998b8a9b1dSJustin T. Gibbs return(xpttargettraverse(bus, NULL, xptdeftargetfunc, arg)); 23008b8a9b1dSJustin T. Gibbs } 23018b8a9b1dSJustin T. Gibbs 23028b8a9b1dSJustin T. Gibbs static int 23038b8a9b1dSJustin T. Gibbs xptdeftargetfunc(struct cam_et *target, void *arg) 23048b8a9b1dSJustin T. Gibbs { 23058b8a9b1dSJustin T. Gibbs struct xpt_traverse_config *tr_config; 23068b8a9b1dSJustin T. Gibbs 23078b8a9b1dSJustin T. Gibbs tr_config = (struct xpt_traverse_config *)arg; 23088b8a9b1dSJustin T. Gibbs 23098b8a9b1dSJustin T. Gibbs if (tr_config->depth == XPT_DEPTH_TARGET) { 23108b8a9b1dSJustin T. Gibbs xpt_targetfunc_t *tr_func; 23118b8a9b1dSJustin T. Gibbs 23128b8a9b1dSJustin T. Gibbs tr_func = (xpt_targetfunc_t *)tr_config->tr_func; 23138b8a9b1dSJustin T. Gibbs 23148b8a9b1dSJustin T. Gibbs return(tr_func(target, tr_config->tr_arg)); 23158b8a9b1dSJustin T. Gibbs } else 23168b8a9b1dSJustin T. Gibbs return(xptdevicetraverse(target, NULL, xptdefdevicefunc, arg)); 23178b8a9b1dSJustin T. Gibbs } 23188b8a9b1dSJustin T. Gibbs 23198b8a9b1dSJustin T. Gibbs static int 23208b8a9b1dSJustin T. Gibbs xptdefdevicefunc(struct cam_ed *device, void *arg) 23218b8a9b1dSJustin T. Gibbs { 23228b8a9b1dSJustin T. Gibbs struct xpt_traverse_config *tr_config; 23238b8a9b1dSJustin T. Gibbs 23248b8a9b1dSJustin T. Gibbs tr_config = (struct xpt_traverse_config *)arg; 23258b8a9b1dSJustin T. Gibbs 23268b8a9b1dSJustin T. Gibbs if (tr_config->depth == XPT_DEPTH_DEVICE) { 23278b8a9b1dSJustin T. Gibbs xpt_devicefunc_t *tr_func; 23288b8a9b1dSJustin T. Gibbs 23298b8a9b1dSJustin T. Gibbs tr_func = (xpt_devicefunc_t *)tr_config->tr_func; 23308b8a9b1dSJustin T. Gibbs 23318b8a9b1dSJustin T. Gibbs return(tr_func(device, tr_config->tr_arg)); 23328b8a9b1dSJustin T. Gibbs } else 23338b8a9b1dSJustin T. Gibbs return(xptperiphtraverse(device, NULL, xptdefperiphfunc, arg)); 23348b8a9b1dSJustin T. Gibbs } 23358b8a9b1dSJustin T. Gibbs 23368b8a9b1dSJustin T. Gibbs static int 23378b8a9b1dSJustin T. Gibbs xptdefperiphfunc(struct cam_periph *periph, void *arg) 23388b8a9b1dSJustin T. Gibbs { 23398b8a9b1dSJustin T. Gibbs struct xpt_traverse_config *tr_config; 23408b8a9b1dSJustin T. Gibbs xpt_periphfunc_t *tr_func; 23418b8a9b1dSJustin T. Gibbs 23428b8a9b1dSJustin T. Gibbs tr_config = (struct xpt_traverse_config *)arg; 23438b8a9b1dSJustin T. Gibbs 23448b8a9b1dSJustin T. Gibbs tr_func = (xpt_periphfunc_t *)tr_config->tr_func; 23458b8a9b1dSJustin T. Gibbs 23468b8a9b1dSJustin T. Gibbs /* 23478b8a9b1dSJustin T. Gibbs * Unlike the other default functions, we don't check for depth 23488b8a9b1dSJustin T. Gibbs * here. The peripheral driver level is the last level in the EDT, 23498b8a9b1dSJustin T. Gibbs * so if we're here, we should execute the function in question. 23508b8a9b1dSJustin T. Gibbs */ 23518b8a9b1dSJustin T. Gibbs return(tr_func(periph, tr_config->tr_arg)); 23528b8a9b1dSJustin T. Gibbs } 23538b8a9b1dSJustin T. Gibbs 23548b8a9b1dSJustin T. Gibbs /* 23558b8a9b1dSJustin T. Gibbs * Execute the given function for every bus in the EDT. 23568b8a9b1dSJustin T. Gibbs */ 23578b8a9b1dSJustin T. Gibbs static int 23588b8a9b1dSJustin T. Gibbs xpt_for_all_busses(xpt_busfunc_t *tr_func, void *arg) 23598b8a9b1dSJustin T. Gibbs { 23608b8a9b1dSJustin T. Gibbs struct xpt_traverse_config tr_config; 23618b8a9b1dSJustin T. Gibbs 23628b8a9b1dSJustin T. Gibbs tr_config.depth = XPT_DEPTH_BUS; 23638b8a9b1dSJustin T. Gibbs tr_config.tr_func = tr_func; 23648b8a9b1dSJustin T. Gibbs tr_config.tr_arg = arg; 23658b8a9b1dSJustin T. Gibbs 23668b8a9b1dSJustin T. Gibbs return(xptbustraverse(NULL, xptdefbusfunc, &tr_config)); 23678b8a9b1dSJustin T. Gibbs } 23688b8a9b1dSJustin T. Gibbs 23698b8a9b1dSJustin T. Gibbs /* 23708b8a9b1dSJustin T. Gibbs * Execute the given function for every device in the EDT. 23718b8a9b1dSJustin T. Gibbs */ 23728b8a9b1dSJustin T. Gibbs static int 23738b8a9b1dSJustin T. Gibbs xpt_for_all_devices(xpt_devicefunc_t *tr_func, void *arg) 23748b8a9b1dSJustin T. Gibbs { 23758b8a9b1dSJustin T. Gibbs struct xpt_traverse_config tr_config; 23768b8a9b1dSJustin T. Gibbs 23778b8a9b1dSJustin T. Gibbs tr_config.depth = XPT_DEPTH_DEVICE; 23788b8a9b1dSJustin T. Gibbs tr_config.tr_func = tr_func; 23798b8a9b1dSJustin T. Gibbs tr_config.tr_arg = arg; 23808b8a9b1dSJustin T. Gibbs 23818b8a9b1dSJustin T. Gibbs return(xptbustraverse(NULL, xptdefbusfunc, &tr_config)); 23828b8a9b1dSJustin T. Gibbs } 23838b8a9b1dSJustin T. Gibbs 23848b8a9b1dSJustin T. Gibbs static int 23858b8a9b1dSJustin T. Gibbs xptsetasyncfunc(struct cam_ed *device, void *arg) 23868b8a9b1dSJustin T. Gibbs { 23878b8a9b1dSJustin T. Gibbs struct cam_path path; 23888b8a9b1dSJustin T. Gibbs struct ccb_getdev cgd; 23897685edecSAlexander Motin struct ccb_setasync *csa = (struct ccb_setasync *)arg; 23908b8a9b1dSJustin T. Gibbs 2391c8bead2aSJustin T. Gibbs /* 2392c8bead2aSJustin T. Gibbs * Don't report unconfigured devices (Wildcard devs, 2393c8bead2aSJustin T. Gibbs * devices only for target mode, device instances 2394c8bead2aSJustin T. Gibbs * that have been invalidated but are waiting for 2395c8bead2aSJustin T. Gibbs * their last reference count to be released). 2396c8bead2aSJustin T. Gibbs */ 2397c8bead2aSJustin T. Gibbs if ((device->flags & CAM_DEV_UNCONFIGURED) != 0) 2398c8bead2aSJustin T. Gibbs return (1); 2399c8bead2aSJustin T. Gibbs 24008b8a9b1dSJustin T. Gibbs xpt_compile_path(&path, 24018b8a9b1dSJustin T. Gibbs NULL, 24028b8a9b1dSJustin T. Gibbs device->target->bus->path_id, 24038b8a9b1dSJustin T. Gibbs device->target->target_id, 24048b8a9b1dSJustin T. Gibbs device->lun_id); 2405bbfa4aa1SAlexander Motin xpt_setup_ccb(&cgd.ccb_h, &path, CAM_PRIORITY_NORMAL); 24068b8a9b1dSJustin T. Gibbs cgd.ccb_h.func_code = XPT_GDEV_TYPE; 24078b8a9b1dSJustin T. Gibbs xpt_action((union ccb *)&cgd); 24087685edecSAlexander Motin csa->callback(csa->callback_arg, 24098b8a9b1dSJustin T. Gibbs AC_FOUND_DEVICE, 24108b8a9b1dSJustin T. Gibbs &path, &cgd); 24118b8a9b1dSJustin T. Gibbs xpt_release_path(&path); 24128b8a9b1dSJustin T. Gibbs 24138b8a9b1dSJustin T. Gibbs return(1); 24148b8a9b1dSJustin T. Gibbs } 2415c8bead2aSJustin T. Gibbs 24168b8a9b1dSJustin T. Gibbs static int 24178b8a9b1dSJustin T. Gibbs xptsetasyncbusfunc(struct cam_eb *bus, void *arg) 24188b8a9b1dSJustin T. Gibbs { 24198b8a9b1dSJustin T. Gibbs struct cam_path path; 24208b8a9b1dSJustin T. Gibbs struct ccb_pathinq cpi; 24217685edecSAlexander Motin struct ccb_setasync *csa = (struct ccb_setasync *)arg; 24228b8a9b1dSJustin T. Gibbs 24238b8a9b1dSJustin T. Gibbs xpt_compile_path(&path, /*periph*/NULL, 24246dfc67e3SAlexander Motin bus->path_id, 24258b8a9b1dSJustin T. Gibbs CAM_TARGET_WILDCARD, 24268b8a9b1dSJustin T. Gibbs CAM_LUN_WILDCARD); 2427227d67aaSAlexander Motin xpt_path_lock(&path); 2428bbfa4aa1SAlexander Motin xpt_setup_ccb(&cpi.ccb_h, &path, CAM_PRIORITY_NORMAL); 24298b8a9b1dSJustin T. Gibbs cpi.ccb_h.func_code = XPT_PATH_INQ; 24308b8a9b1dSJustin T. Gibbs xpt_action((union ccb *)&cpi); 24317685edecSAlexander Motin csa->callback(csa->callback_arg, 24328b8a9b1dSJustin T. Gibbs AC_PATH_REGISTERED, 24338b8a9b1dSJustin T. Gibbs &path, &cpi); 2434227d67aaSAlexander Motin xpt_path_unlock(&path); 24358b8a9b1dSJustin T. Gibbs xpt_release_path(&path); 24368b8a9b1dSJustin T. Gibbs 24378b8a9b1dSJustin T. Gibbs return(1); 24388b8a9b1dSJustin T. Gibbs } 24398b8a9b1dSJustin T. Gibbs 24408b8a9b1dSJustin T. Gibbs void 24418b8a9b1dSJustin T. Gibbs xpt_action(union ccb *start_ccb) 24428b8a9b1dSJustin T. Gibbs { 24439911ecf9SJustin T. Gibbs 24448b8a9b1dSJustin T. Gibbs CAM_DEBUG(start_ccb->ccb_h.path, CAM_DEBUG_TRACE, ("xpt_action\n")); 24458b8a9b1dSJustin T. Gibbs 24468b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.status = CAM_REQ_INPROG; 244752c9ce25SScott Long (*(start_ccb->ccb_h.path->bus->xport->action))(start_ccb); 244852c9ce25SScott Long } 244952c9ce25SScott Long 245052c9ce25SScott Long void 245152c9ce25SScott Long xpt_action_default(union ccb *start_ccb) 245252c9ce25SScott Long { 2453da396db2SAlexander Motin struct cam_path *path; 2454227d67aaSAlexander Motin struct cam_sim *sim; 2455227d67aaSAlexander Motin int lock; 245652c9ce25SScott Long 2457da396db2SAlexander Motin path = start_ccb->ccb_h.path; 2458da396db2SAlexander Motin CAM_DEBUG(path, CAM_DEBUG_TRACE, ("xpt_action_default\n")); 245952c9ce25SScott Long 24608b8a9b1dSJustin T. Gibbs switch (start_ccb->ccb_h.func_code) { 24618b8a9b1dSJustin T. Gibbs case XPT_SCSI_IO: 2462d05caa00SKenneth D. Merry { 24633393f8daSKenneth D. Merry struct cam_ed *device; 2464d05caa00SKenneth D. Merry 24658b8a9b1dSJustin T. Gibbs /* 24668b8a9b1dSJustin T. Gibbs * For the sake of compatibility with SCSI-1 24678b8a9b1dSJustin T. Gibbs * devices that may not understand the identify 24688b8a9b1dSJustin T. Gibbs * message, we include lun information in the 24698b8a9b1dSJustin T. Gibbs * second byte of all commands. SCSI-1 specifies 24708b8a9b1dSJustin T. Gibbs * that luns are a 3 bit value and reserves only 3 24718b8a9b1dSJustin T. Gibbs * bits for lun information in the CDB. Later 24728b8a9b1dSJustin T. Gibbs * revisions of the SCSI spec allow for more than 8 24738b8a9b1dSJustin T. Gibbs * luns, but have deprecated lun information in the 24748b8a9b1dSJustin T. Gibbs * CDB. So, if the lun won't fit, we must omit. 24758b8a9b1dSJustin T. Gibbs * 24768b8a9b1dSJustin T. Gibbs * Also be aware that during initial probing for devices, 24778b8a9b1dSJustin T. Gibbs * the inquiry information is unknown but initialized to 0. 24788b8a9b1dSJustin T. Gibbs * This means that this code will be exercised while probing 24798b8a9b1dSJustin T. Gibbs * devices with an ANSI revision greater than 2. 24808b8a9b1dSJustin T. Gibbs */ 2481da396db2SAlexander Motin device = path->device; 24823393f8daSKenneth D. Merry if (device->protocol_version <= SCSI_REV_2 24838b8a9b1dSJustin T. Gibbs && start_ccb->ccb_h.target_lun < 8 24848b8a9b1dSJustin T. Gibbs && (start_ccb->ccb_h.flags & CAM_CDB_POINTER) == 0) { 24858b8a9b1dSJustin T. Gibbs 24868b8a9b1dSJustin T. Gibbs start_ccb->csio.cdb_io.cdb_bytes[1] |= 24878b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.target_lun << 5; 24888b8a9b1dSJustin T. Gibbs } 24898b8a9b1dSJustin T. Gibbs start_ccb->csio.scsi_status = SCSI_STATUS_OK; 2490d05caa00SKenneth D. Merry } 249107c6eac9SPoul-Henning Kamp /* FALLTHROUGH */ 24928b8a9b1dSJustin T. Gibbs case XPT_TARGET_IO: 24938b8a9b1dSJustin T. Gibbs case XPT_CONT_TARGET_IO: 24942cefde5fSJustin T. Gibbs start_ccb->csio.sense_resid = 0; 24952cefde5fSJustin T. Gibbs start_ccb->csio.resid = 0; 24962cefde5fSJustin T. Gibbs /* FALLTHROUGH */ 249752c9ce25SScott Long case XPT_ATA_IO: 2498de9ebb68SAlexander Motin if (start_ccb->ccb_h.func_code == XPT_ATA_IO) 249952c9ce25SScott Long start_ccb->ataio.resid = 0; 2500b882a6d3SMatt Jacob /* FALLTHROUGH */ 250110e1cf63SKenneth D. Merry case XPT_RESET_DEV: 25028b8a9b1dSJustin T. Gibbs case XPT_ENG_EXEC: 250306e79492SKenneth D. Merry case XPT_SMP_IO: 25042cefde5fSJustin T. Gibbs { 2505227d67aaSAlexander Motin struct cam_devq *devq; 25062cefde5fSJustin T. Gibbs 2507227d67aaSAlexander Motin devq = path->bus->sim->devq; 2508227d67aaSAlexander Motin mtx_lock(&devq->send_mtx); 2509227d67aaSAlexander Motin cam_ccbq_insert_ccb(&path->device->ccbq, start_ccb); 2510227d67aaSAlexander Motin if (xpt_schedule_devq(devq, path->device) != 0) 2511227d67aaSAlexander Motin xpt_run_devq(devq); 2512227d67aaSAlexander Motin mtx_unlock(&devq->send_mtx); 2513227d67aaSAlexander Motin break; 2514227d67aaSAlexander Motin } 2515227d67aaSAlexander Motin case XPT_CALC_GEOMETRY: 25168b8a9b1dSJustin T. Gibbs /* Filter out garbage */ 25178b8a9b1dSJustin T. Gibbs if (start_ccb->ccg.block_size == 0 25188b8a9b1dSJustin T. Gibbs || start_ccb->ccg.volume_size == 0) { 25198b8a9b1dSJustin T. Gibbs start_ccb->ccg.cylinders = 0; 25208b8a9b1dSJustin T. Gibbs start_ccb->ccg.heads = 0; 25218b8a9b1dSJustin T. Gibbs start_ccb->ccg.secs_per_track = 0; 25228b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.status = CAM_REQ_CMP; 25238b8a9b1dSJustin T. Gibbs break; 25248b8a9b1dSJustin T. Gibbs } 2525abef0e67SMarius Strobl #if defined(PC98) || defined(__sparc64__) 25268b8a9b1dSJustin T. Gibbs /* 25278b8a9b1dSJustin T. Gibbs * In a PC-98 system, geometry translation depens on 25288b8a9b1dSJustin T. Gibbs * the "real" device geometry obtained from mode page 4. 25298b8a9b1dSJustin T. Gibbs * SCSI geometry translation is performed in the 25308b8a9b1dSJustin T. Gibbs * initialization routine of the SCSI BIOS and the result 25318b8a9b1dSJustin T. Gibbs * stored in host memory. If the translation is available 25328b8a9b1dSJustin T. Gibbs * in host memory, use it. If not, rely on the default 25338b8a9b1dSJustin T. Gibbs * translation the device driver performs. 2534abef0e67SMarius Strobl * For sparc64, we may need adjust the geometry of large 2535abef0e67SMarius Strobl * disks in order to fit the limitations of the 16-bit 2536abef0e67SMarius Strobl * fields of the VTOC8 disk label. 25378b8a9b1dSJustin T. Gibbs */ 25388b8a9b1dSJustin T. Gibbs if (scsi_da_bios_params(&start_ccb->ccg) != 0) { 25398b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.status = CAM_REQ_CMP; 25408b8a9b1dSJustin T. Gibbs break; 25418b8a9b1dSJustin T. Gibbs } 25428b8a9b1dSJustin T. Gibbs #endif 2543227d67aaSAlexander Motin goto call_sim; 2544bb6087e5SJustin T. Gibbs case XPT_ABORT: 25452cefde5fSJustin T. Gibbs { 25462cefde5fSJustin T. Gibbs union ccb* abort_ccb; 25472cefde5fSJustin T. Gibbs 25482cefde5fSJustin T. Gibbs abort_ccb = start_ccb->cab.abort_ccb; 25492cefde5fSJustin T. Gibbs if (XPT_FC_IS_DEV_QUEUED(abort_ccb)) { 25502cefde5fSJustin T. Gibbs 25512cefde5fSJustin T. Gibbs if (abort_ccb->ccb_h.pinfo.index >= 0) { 25522cefde5fSJustin T. Gibbs struct cam_ccbq *ccbq; 255383c5d981SAlexander Motin struct cam_ed *device; 25542cefde5fSJustin T. Gibbs 255583c5d981SAlexander Motin device = abort_ccb->ccb_h.path->device; 255683c5d981SAlexander Motin ccbq = &device->ccbq; 25572cefde5fSJustin T. Gibbs cam_ccbq_remove_ccb(ccbq, abort_ccb); 25582cefde5fSJustin T. Gibbs abort_ccb->ccb_h.status = 25592cefde5fSJustin T. Gibbs CAM_REQ_ABORTED|CAM_DEV_QFRZN; 25602cefde5fSJustin T. Gibbs xpt_freeze_devq(abort_ccb->ccb_h.path, 1); 25612cefde5fSJustin T. Gibbs xpt_done(abort_ccb); 25622cefde5fSJustin T. Gibbs start_ccb->ccb_h.status = CAM_REQ_CMP; 25632cefde5fSJustin T. Gibbs break; 25642cefde5fSJustin T. Gibbs } 25652cefde5fSJustin T. Gibbs if (abort_ccb->ccb_h.pinfo.index == CAM_UNQUEUED_INDEX 25662cefde5fSJustin T. Gibbs && (abort_ccb->ccb_h.status & CAM_SIM_QUEUED) == 0) { 25672cefde5fSJustin T. Gibbs /* 25682cefde5fSJustin T. Gibbs * We've caught this ccb en route to 25692cefde5fSJustin T. Gibbs * the SIM. Flag it for abort and the 25702cefde5fSJustin T. Gibbs * SIM will do so just before starting 25712cefde5fSJustin T. Gibbs * real work on the CCB. 25722cefde5fSJustin T. Gibbs */ 25732cefde5fSJustin T. Gibbs abort_ccb->ccb_h.status = 25742cefde5fSJustin T. Gibbs CAM_REQ_ABORTED|CAM_DEV_QFRZN; 25752cefde5fSJustin T. Gibbs xpt_freeze_devq(abort_ccb->ccb_h.path, 1); 25762cefde5fSJustin T. Gibbs start_ccb->ccb_h.status = CAM_REQ_CMP; 25772cefde5fSJustin T. Gibbs break; 25782cefde5fSJustin T. Gibbs } 25792cefde5fSJustin T. Gibbs } 25802cefde5fSJustin T. Gibbs if (XPT_FC_IS_QUEUED(abort_ccb) 25812cefde5fSJustin T. Gibbs && (abort_ccb->ccb_h.pinfo.index == CAM_DONEQ_INDEX)) { 25822cefde5fSJustin T. Gibbs /* 25832cefde5fSJustin T. Gibbs * It's already completed but waiting 25842cefde5fSJustin T. Gibbs * for our SWI to get to it. 25852cefde5fSJustin T. Gibbs */ 25862cefde5fSJustin T. Gibbs start_ccb->ccb_h.status = CAM_UA_ABORT; 25872cefde5fSJustin T. Gibbs break; 25882cefde5fSJustin T. Gibbs } 25892cefde5fSJustin T. Gibbs /* 25902cefde5fSJustin T. Gibbs * If we weren't able to take care of the abort request 25912cefde5fSJustin T. Gibbs * in the XPT, pass the request down to the SIM for processing. 25922cefde5fSJustin T. Gibbs */ 25932cefde5fSJustin T. Gibbs } 259407c6eac9SPoul-Henning Kamp /* FALLTHROUGH */ 25958b8a9b1dSJustin T. Gibbs case XPT_ACCEPT_TARGET_IO: 25968b8a9b1dSJustin T. Gibbs case XPT_EN_LUN: 25978b8a9b1dSJustin T. Gibbs case XPT_IMMED_NOTIFY: 25988b8a9b1dSJustin T. Gibbs case XPT_NOTIFY_ACK: 25998b8a9b1dSJustin T. Gibbs case XPT_RESET_BUS: 26002df76c16SMatt Jacob case XPT_IMMEDIATE_NOTIFY: 26012df76c16SMatt Jacob case XPT_NOTIFY_ACKNOWLEDGE: 26022df76c16SMatt Jacob case XPT_GET_SIM_KNOB: 26032df76c16SMatt Jacob case XPT_SET_SIM_KNOB: 2604227d67aaSAlexander Motin case XPT_GET_TRAN_SETTINGS: 2605227d67aaSAlexander Motin case XPT_SET_TRAN_SETTINGS: 260687cfaf0eSJustin T. Gibbs case XPT_PATH_INQ: 2607227d67aaSAlexander Motin call_sim: 2608da396db2SAlexander Motin sim = path->bus->sim; 2609227d67aaSAlexander Motin lock = (mtx_owned(sim->mtx) == 0); 2610227d67aaSAlexander Motin if (lock) 2611227d67aaSAlexander Motin CAM_SIM_LOCK(sim); 261287cfaf0eSJustin T. Gibbs (*(sim->sim_action))(sim, start_ccb); 2613227d67aaSAlexander Motin if (lock) 2614227d67aaSAlexander Motin CAM_SIM_UNLOCK(sim); 261587cfaf0eSJustin T. Gibbs break; 261687cfaf0eSJustin T. Gibbs case XPT_PATH_STATS: 2617da396db2SAlexander Motin start_ccb->cpis.last_reset = path->bus->last_reset; 261887cfaf0eSJustin T. Gibbs start_ccb->ccb_h.status = CAM_REQ_CMP; 261987cfaf0eSJustin T. Gibbs break; 26208b8a9b1dSJustin T. Gibbs case XPT_GDEV_TYPE: 2621a5479bc5SJustin T. Gibbs { 262287cfaf0eSJustin T. Gibbs struct cam_ed *dev; 2623a5479bc5SJustin T. Gibbs 2624da396db2SAlexander Motin dev = path->device; 262587cfaf0eSJustin T. Gibbs if ((dev->flags & CAM_DEV_UNCONFIGURED) != 0) { 26268b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.status = CAM_DEV_NOT_THERE; 26278b8a9b1dSJustin T. Gibbs } else { 26288b8a9b1dSJustin T. Gibbs struct ccb_getdev *cgd; 26298b8a9b1dSJustin T. Gibbs 26308b8a9b1dSJustin T. Gibbs cgd = &start_ccb->cgd; 263152c9ce25SScott Long cgd->protocol = dev->protocol; 26328b8a9b1dSJustin T. Gibbs cgd->inq_data = dev->inq_data; 263352c9ce25SScott Long cgd->ident_data = dev->ident_data; 263430a4094fSAlexander Motin cgd->inq_flags = dev->inq_flags; 26358b8a9b1dSJustin T. Gibbs cgd->ccb_h.status = CAM_REQ_CMP; 26368b8a9b1dSJustin T. Gibbs cgd->serial_num_len = dev->serial_num_len; 26378b8a9b1dSJustin T. Gibbs if ((dev->serial_num_len > 0) 26388b8a9b1dSJustin T. Gibbs && (dev->serial_num != NULL)) 26398b8a9b1dSJustin T. Gibbs bcopy(dev->serial_num, cgd->serial_num, 26408b8a9b1dSJustin T. Gibbs dev->serial_num_len); 26418b8a9b1dSJustin T. Gibbs } 26428b8a9b1dSJustin T. Gibbs break; 2643a5479bc5SJustin T. Gibbs } 264487cfaf0eSJustin T. Gibbs case XPT_GDEV_STATS: 264587cfaf0eSJustin T. Gibbs { 264687cfaf0eSJustin T. Gibbs struct cam_ed *dev; 264787cfaf0eSJustin T. Gibbs 2648da396db2SAlexander Motin dev = path->device; 264987cfaf0eSJustin T. Gibbs if ((dev->flags & CAM_DEV_UNCONFIGURED) != 0) { 265087cfaf0eSJustin T. Gibbs start_ccb->ccb_h.status = CAM_DEV_NOT_THERE; 265187cfaf0eSJustin T. Gibbs } else { 265287cfaf0eSJustin T. Gibbs struct ccb_getdevstats *cgds; 265387cfaf0eSJustin T. Gibbs struct cam_eb *bus; 265487cfaf0eSJustin T. Gibbs struct cam_et *tar; 265587cfaf0eSJustin T. Gibbs 265687cfaf0eSJustin T. Gibbs cgds = &start_ccb->cgds; 2657da396db2SAlexander Motin bus = path->bus; 2658da396db2SAlexander Motin tar = path->target; 265987cfaf0eSJustin T. Gibbs cgds->dev_openings = dev->ccbq.dev_openings; 266087cfaf0eSJustin T. Gibbs cgds->dev_active = dev->ccbq.dev_active; 266187cfaf0eSJustin T. Gibbs cgds->devq_openings = dev->ccbq.devq_openings; 2662ea541bfdSAlexander Motin cgds->devq_queued = cam_ccbq_pending_ccb_count(&dev->ccbq); 266387cfaf0eSJustin T. Gibbs cgds->held = dev->ccbq.held; 266487cfaf0eSJustin T. Gibbs cgds->last_reset = tar->last_reset; 266552c9ce25SScott Long cgds->maxtags = dev->maxtags; 266652c9ce25SScott Long cgds->mintags = dev->mintags; 266787cfaf0eSJustin T. Gibbs if (timevalcmp(&tar->last_reset, &bus->last_reset, <)) 266887cfaf0eSJustin T. Gibbs cgds->last_reset = bus->last_reset; 266987cfaf0eSJustin T. Gibbs cgds->ccb_h.status = CAM_REQ_CMP; 267087cfaf0eSJustin T. Gibbs } 267187cfaf0eSJustin T. Gibbs break; 267287cfaf0eSJustin T. Gibbs } 26738b8a9b1dSJustin T. Gibbs case XPT_GDEVLIST: 26748b8a9b1dSJustin T. Gibbs { 26758b8a9b1dSJustin T. Gibbs struct cam_periph *nperiph; 26768b8a9b1dSJustin T. Gibbs struct periph_list *periph_head; 26778b8a9b1dSJustin T. Gibbs struct ccb_getdevlist *cgdl; 26783393f8daSKenneth D. Merry u_int i; 26798b8a9b1dSJustin T. Gibbs struct cam_ed *device; 26808b8a9b1dSJustin T. Gibbs int found; 26818b8a9b1dSJustin T. Gibbs 26828b8a9b1dSJustin T. Gibbs 26838b8a9b1dSJustin T. Gibbs found = 0; 26848b8a9b1dSJustin T. Gibbs 26858b8a9b1dSJustin T. Gibbs /* 26868b8a9b1dSJustin T. Gibbs * Don't want anyone mucking with our data. 26878b8a9b1dSJustin T. Gibbs */ 2688da396db2SAlexander Motin device = path->device; 26898b8a9b1dSJustin T. Gibbs periph_head = &device->periphs; 26908b8a9b1dSJustin T. Gibbs cgdl = &start_ccb->cgdl; 26918b8a9b1dSJustin T. Gibbs 26928b8a9b1dSJustin T. Gibbs /* 26938b8a9b1dSJustin T. Gibbs * Check and see if the list has changed since the user 26948b8a9b1dSJustin T. Gibbs * last requested a list member. If so, tell them that the 26958b8a9b1dSJustin T. Gibbs * list has changed, and therefore they need to start over 26968b8a9b1dSJustin T. Gibbs * from the beginning. 26978b8a9b1dSJustin T. Gibbs */ 26988b8a9b1dSJustin T. Gibbs if ((cgdl->index != 0) && 26998b8a9b1dSJustin T. Gibbs (cgdl->generation != device->generation)) { 27008b8a9b1dSJustin T. Gibbs cgdl->status = CAM_GDEVLIST_LIST_CHANGED; 27018b8a9b1dSJustin T. Gibbs break; 27028b8a9b1dSJustin T. Gibbs } 27038b8a9b1dSJustin T. Gibbs 27048b8a9b1dSJustin T. Gibbs /* 27058b8a9b1dSJustin T. Gibbs * Traverse the list of peripherals and attempt to find 27068b8a9b1dSJustin T. Gibbs * the requested peripheral. 27078b8a9b1dSJustin T. Gibbs */ 2708fc2ffbe6SPoul-Henning Kamp for (nperiph = SLIST_FIRST(periph_head), i = 0; 27098b8a9b1dSJustin T. Gibbs (nperiph != NULL) && (i <= cgdl->index); 2710fc2ffbe6SPoul-Henning Kamp nperiph = SLIST_NEXT(nperiph, periph_links), i++) { 27118b8a9b1dSJustin T. Gibbs if (i == cgdl->index) { 27128b8a9b1dSJustin T. Gibbs strncpy(cgdl->periph_name, 27138b8a9b1dSJustin T. Gibbs nperiph->periph_name, 27148b8a9b1dSJustin T. Gibbs DEV_IDLEN); 27158b8a9b1dSJustin T. Gibbs cgdl->unit_number = nperiph->unit_number; 27168b8a9b1dSJustin T. Gibbs found = 1; 27178b8a9b1dSJustin T. Gibbs } 27188b8a9b1dSJustin T. Gibbs } 27198b8a9b1dSJustin T. Gibbs if (found == 0) { 27208b8a9b1dSJustin T. Gibbs cgdl->status = CAM_GDEVLIST_ERROR; 27218b8a9b1dSJustin T. Gibbs break; 27228b8a9b1dSJustin T. Gibbs } 27238b8a9b1dSJustin T. Gibbs 27248b8a9b1dSJustin T. Gibbs if (nperiph == NULL) 27258b8a9b1dSJustin T. Gibbs cgdl->status = CAM_GDEVLIST_LAST_DEVICE; 27268b8a9b1dSJustin T. Gibbs else 27278b8a9b1dSJustin T. Gibbs cgdl->status = CAM_GDEVLIST_MORE_DEVS; 27288b8a9b1dSJustin T. Gibbs 27298b8a9b1dSJustin T. Gibbs cgdl->index++; 27308b8a9b1dSJustin T. Gibbs cgdl->generation = device->generation; 27318b8a9b1dSJustin T. Gibbs 27328b8a9b1dSJustin T. Gibbs cgdl->ccb_h.status = CAM_REQ_CMP; 27338b8a9b1dSJustin T. Gibbs break; 27348b8a9b1dSJustin T. Gibbs } 27358b8a9b1dSJustin T. Gibbs case XPT_DEV_MATCH: 27368b8a9b1dSJustin T. Gibbs { 27378b8a9b1dSJustin T. Gibbs dev_pos_type position_type; 27388b8a9b1dSJustin T. Gibbs struct ccb_dev_match *cdm; 27398b8a9b1dSJustin T. Gibbs 27408b8a9b1dSJustin T. Gibbs cdm = &start_ccb->cdm; 27418b8a9b1dSJustin T. Gibbs 27428b8a9b1dSJustin T. Gibbs /* 27438b8a9b1dSJustin T. Gibbs * There are two ways of getting at information in the EDT. 27448b8a9b1dSJustin T. Gibbs * The first way is via the primary EDT tree. It starts 27458b8a9b1dSJustin T. Gibbs * with a list of busses, then a list of targets on a bus, 27468b8a9b1dSJustin T. Gibbs * then devices/luns on a target, and then peripherals on a 27478b8a9b1dSJustin T. Gibbs * device/lun. The "other" way is by the peripheral driver 27488b8a9b1dSJustin T. Gibbs * lists. The peripheral driver lists are organized by 27498b8a9b1dSJustin T. Gibbs * peripheral driver. (obviously) So it makes sense to 27508b8a9b1dSJustin T. Gibbs * use the peripheral driver list if the user is looking 27518b8a9b1dSJustin T. Gibbs * for something like "da1", or all "da" devices. If the 27528b8a9b1dSJustin T. Gibbs * user is looking for something on a particular bus/target 27538b8a9b1dSJustin T. Gibbs * or lun, it's generally better to go through the EDT tree. 27548b8a9b1dSJustin T. Gibbs */ 27558b8a9b1dSJustin T. Gibbs 27568b8a9b1dSJustin T. Gibbs if (cdm->pos.position_type != CAM_DEV_POS_NONE) 27578b8a9b1dSJustin T. Gibbs position_type = cdm->pos.position_type; 27588b8a9b1dSJustin T. Gibbs else { 27593393f8daSKenneth D. Merry u_int i; 27608b8a9b1dSJustin T. Gibbs 27618b8a9b1dSJustin T. Gibbs position_type = CAM_DEV_POS_NONE; 27628b8a9b1dSJustin T. Gibbs 27638b8a9b1dSJustin T. Gibbs for (i = 0; i < cdm->num_patterns; i++) { 27648b8a9b1dSJustin T. Gibbs if ((cdm->patterns[i].type == DEV_MATCH_BUS) 27658b8a9b1dSJustin T. Gibbs ||(cdm->patterns[i].type == DEV_MATCH_DEVICE)){ 27668b8a9b1dSJustin T. Gibbs position_type = CAM_DEV_POS_EDT; 27678b8a9b1dSJustin T. Gibbs break; 27688b8a9b1dSJustin T. Gibbs } 27698b8a9b1dSJustin T. Gibbs } 27708b8a9b1dSJustin T. Gibbs 27718b8a9b1dSJustin T. Gibbs if (cdm->num_patterns == 0) 27728b8a9b1dSJustin T. Gibbs position_type = CAM_DEV_POS_EDT; 27738b8a9b1dSJustin T. Gibbs else if (position_type == CAM_DEV_POS_NONE) 27748b8a9b1dSJustin T. Gibbs position_type = CAM_DEV_POS_PDRV; 27758b8a9b1dSJustin T. Gibbs } 27768b8a9b1dSJustin T. Gibbs 27778b8a9b1dSJustin T. Gibbs switch(position_type & CAM_DEV_POS_TYPEMASK) { 27788b8a9b1dSJustin T. Gibbs case CAM_DEV_POS_EDT: 277907c6eac9SPoul-Henning Kamp xptedtmatch(cdm); 27808b8a9b1dSJustin T. Gibbs break; 27818b8a9b1dSJustin T. Gibbs case CAM_DEV_POS_PDRV: 278207c6eac9SPoul-Henning Kamp xptperiphlistmatch(cdm); 27838b8a9b1dSJustin T. Gibbs break; 27848b8a9b1dSJustin T. Gibbs default: 27858b8a9b1dSJustin T. Gibbs cdm->status = CAM_DEV_MATCH_ERROR; 27868b8a9b1dSJustin T. Gibbs break; 27878b8a9b1dSJustin T. Gibbs } 27888b8a9b1dSJustin T. Gibbs 27898b8a9b1dSJustin T. Gibbs if (cdm->status == CAM_DEV_MATCH_ERROR) 27908b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.status = CAM_REQ_CMP_ERR; 27918b8a9b1dSJustin T. Gibbs else 27928b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.status = CAM_REQ_CMP; 27938b8a9b1dSJustin T. Gibbs 27948b8a9b1dSJustin T. Gibbs break; 27958b8a9b1dSJustin T. Gibbs } 27968b8a9b1dSJustin T. Gibbs case XPT_SASYNC_CB: 27978b8a9b1dSJustin T. Gibbs { 279884f82481SScott Long struct ccb_setasync *csa; 279984f82481SScott Long struct async_node *cur_entry; 280084f82481SScott Long struct async_list *async_head; 280184f82481SScott Long u_int32_t added; 280284f82481SScott Long 280384f82481SScott Long csa = &start_ccb->csa; 280484f82481SScott Long added = csa->event_enable; 2805da396db2SAlexander Motin async_head = &path->device->asyncs; 280684f82481SScott Long 280784f82481SScott Long /* 280884f82481SScott Long * If there is already an entry for us, simply 280984f82481SScott Long * update it. 281084f82481SScott Long */ 281184f82481SScott Long cur_entry = SLIST_FIRST(async_head); 281284f82481SScott Long while (cur_entry != NULL) { 281384f82481SScott Long if ((cur_entry->callback_arg == csa->callback_arg) 281484f82481SScott Long && (cur_entry->callback == csa->callback)) 281584f82481SScott Long break; 281684f82481SScott Long cur_entry = SLIST_NEXT(cur_entry, links); 281784f82481SScott Long } 281884f82481SScott Long 281984f82481SScott Long if (cur_entry != NULL) { 282084f82481SScott Long /* 282184f82481SScott Long * If the request has no flags set, 282284f82481SScott Long * remove the entry. 282384f82481SScott Long */ 282484f82481SScott Long added &= ~cur_entry->event_enable; 282584f82481SScott Long if (csa->event_enable == 0) { 282684f82481SScott Long SLIST_REMOVE(async_head, cur_entry, 282784f82481SScott Long async_node, links); 2828da396db2SAlexander Motin xpt_release_device(path->device); 282984f82481SScott Long free(cur_entry, M_CAMXPT); 283084f82481SScott Long } else { 283184f82481SScott Long cur_entry->event_enable = csa->event_enable; 283284f82481SScott Long } 28337685edecSAlexander Motin csa->event_enable = added; 283484f82481SScott Long } else { 283584f82481SScott Long cur_entry = malloc(sizeof(*cur_entry), M_CAMXPT, 283684f82481SScott Long M_NOWAIT); 283784f82481SScott Long if (cur_entry == NULL) { 283884f82481SScott Long csa->ccb_h.status = CAM_RESRC_UNAVAIL; 283984f82481SScott Long break; 284084f82481SScott Long } 284184f82481SScott Long cur_entry->event_enable = csa->event_enable; 2842227d67aaSAlexander Motin cur_entry->event_lock = 2843227d67aaSAlexander Motin mtx_owned(path->bus->sim->mtx) ? 1 : 0; 284484f82481SScott Long cur_entry->callback_arg = csa->callback_arg; 284584f82481SScott Long cur_entry->callback = csa->callback; 284684f82481SScott Long SLIST_INSERT_HEAD(async_head, cur_entry, links); 2847da396db2SAlexander Motin xpt_acquire_device(path->device); 284884f82481SScott Long } 28498b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.status = CAM_REQ_CMP; 28508b8a9b1dSJustin T. Gibbs break; 28518b8a9b1dSJustin T. Gibbs } 28528b8a9b1dSJustin T. Gibbs case XPT_REL_SIMQ: 28538b8a9b1dSJustin T. Gibbs { 28548b8a9b1dSJustin T. Gibbs struct ccb_relsim *crs; 28558b8a9b1dSJustin T. Gibbs struct cam_ed *dev; 28568b8a9b1dSJustin T. Gibbs 28578b8a9b1dSJustin T. Gibbs crs = &start_ccb->crs; 2858da396db2SAlexander Motin dev = path->device; 28598b8a9b1dSJustin T. Gibbs if (dev == NULL) { 28608b8a9b1dSJustin T. Gibbs 28618b8a9b1dSJustin T. Gibbs crs->ccb_h.status = CAM_DEV_NOT_THERE; 28628b8a9b1dSJustin T. Gibbs break; 28638b8a9b1dSJustin T. Gibbs } 28648b8a9b1dSJustin T. Gibbs 28658b8a9b1dSJustin T. Gibbs if ((crs->release_flags & RELSIM_ADJUST_OPENINGS) != 0) { 28668b8a9b1dSJustin T. Gibbs 28678b8a9b1dSJustin T. Gibbs /* Don't ever go below one opening */ 28688b8a9b1dSJustin T. Gibbs if (crs->openings > 0) { 28697dc3213dSAlexander Motin xpt_dev_ccbq_resize(path, crs->openings); 287079ccc199SJordan K. Hubbard if (bootverbose) { 2871da396db2SAlexander Motin xpt_print(path, 28727dc3213dSAlexander Motin "number of openings is now %d\n", 28738b8a9b1dSJustin T. Gibbs crs->openings); 28748b8a9b1dSJustin T. Gibbs } 28758b8a9b1dSJustin T. Gibbs } 28768b8a9b1dSJustin T. Gibbs } 28778b8a9b1dSJustin T. Gibbs 2878227d67aaSAlexander Motin mtx_lock(&dev->sim->devq->send_mtx); 28798b8a9b1dSJustin T. Gibbs if ((crs->release_flags & RELSIM_RELEASE_AFTER_TIMEOUT) != 0) { 28808b8a9b1dSJustin T. Gibbs 28818b8a9b1dSJustin T. Gibbs if ((dev->flags & CAM_DEV_REL_TIMEOUT_PENDING) != 0) { 28828b8a9b1dSJustin T. Gibbs 28838b8a9b1dSJustin T. Gibbs /* 28848b8a9b1dSJustin T. Gibbs * Just extend the old timeout and decrement 28858b8a9b1dSJustin T. Gibbs * the freeze count so that a single timeout 28868b8a9b1dSJustin T. Gibbs * is sufficient for releasing the queue. 28878b8a9b1dSJustin T. Gibbs */ 28888b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.flags &= ~CAM_DEV_QFREEZE; 28892b83592fSScott Long callout_stop(&dev->callout); 28908b8a9b1dSJustin T. Gibbs } else { 28918b8a9b1dSJustin T. Gibbs 28928b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.flags |= CAM_DEV_QFREEZE; 28938b8a9b1dSJustin T. Gibbs } 28948b8a9b1dSJustin T. Gibbs 28952b83592fSScott Long callout_reset(&dev->callout, 28962b83592fSScott Long (crs->release_timeout * hz) / 1000, 28972b83592fSScott Long xpt_release_devq_timeout, dev); 28988b8a9b1dSJustin T. Gibbs 28998b8a9b1dSJustin T. Gibbs dev->flags |= CAM_DEV_REL_TIMEOUT_PENDING; 29008b8a9b1dSJustin T. Gibbs 29018b8a9b1dSJustin T. Gibbs } 29028b8a9b1dSJustin T. Gibbs 29038b8a9b1dSJustin T. Gibbs if ((crs->release_flags & RELSIM_RELEASE_AFTER_CMDCMPLT) != 0) { 29048b8a9b1dSJustin T. Gibbs 29058b8a9b1dSJustin T. Gibbs if ((dev->flags & CAM_DEV_REL_ON_COMPLETE) != 0) { 29068b8a9b1dSJustin T. Gibbs /* 29078b8a9b1dSJustin T. Gibbs * Decrement the freeze count so that a single 29088b8a9b1dSJustin T. Gibbs * completion is still sufficient to unfreeze 29098b8a9b1dSJustin T. Gibbs * the queue. 29108b8a9b1dSJustin T. Gibbs */ 29118b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.flags &= ~CAM_DEV_QFREEZE; 29128b8a9b1dSJustin T. Gibbs } else { 29138b8a9b1dSJustin T. Gibbs 29148b8a9b1dSJustin T. Gibbs dev->flags |= CAM_DEV_REL_ON_COMPLETE; 29158b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.flags |= CAM_DEV_QFREEZE; 29168b8a9b1dSJustin T. Gibbs } 29178b8a9b1dSJustin T. Gibbs } 29188b8a9b1dSJustin T. Gibbs 29198b8a9b1dSJustin T. Gibbs if ((crs->release_flags & RELSIM_RELEASE_AFTER_QEMPTY) != 0) { 29208b8a9b1dSJustin T. Gibbs 29218b8a9b1dSJustin T. Gibbs if ((dev->flags & CAM_DEV_REL_ON_QUEUE_EMPTY) != 0 29228b8a9b1dSJustin T. Gibbs || (dev->ccbq.dev_active == 0)) { 29238b8a9b1dSJustin T. Gibbs 29248b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.flags &= ~CAM_DEV_QFREEZE; 29258b8a9b1dSJustin T. Gibbs } else { 29268b8a9b1dSJustin T. Gibbs 29278b8a9b1dSJustin T. Gibbs dev->flags |= CAM_DEV_REL_ON_QUEUE_EMPTY; 29288b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.flags |= CAM_DEV_QFREEZE; 29298b8a9b1dSJustin T. Gibbs } 29308b8a9b1dSJustin T. Gibbs } 2931227d67aaSAlexander Motin mtx_unlock(&dev->sim->devq->send_mtx); 29328b8a9b1dSJustin T. Gibbs 2933cccf4220SAlexander Motin if ((start_ccb->ccb_h.flags & CAM_DEV_QFREEZE) == 0) 2934cccf4220SAlexander Motin xpt_release_devq(path, /*count*/1, /*run_queue*/TRUE); 2935cccf4220SAlexander Motin start_ccb->crs.qfrozen_cnt = dev->ccbq.queue.qfrozen_cnt; 29368b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.status = CAM_REQ_CMP; 29378b8a9b1dSJustin T. Gibbs break; 29388b8a9b1dSJustin T. Gibbs } 29398b8a9b1dSJustin T. Gibbs case XPT_DEBUG: { 294080d6987cSAlexander Motin struct cam_path *oldpath; 294180d6987cSAlexander Motin 2942f0f25b9cSAlexander Motin /* Check that all request bits are supported. */ 294322c7d606SAlexander Motin if (start_ccb->cdbg.flags & ~(CAM_DEBUG_COMPILE)) { 2944f0f25b9cSAlexander Motin start_ccb->ccb_h.status = CAM_FUNC_NOTAVAIL; 2945f0f25b9cSAlexander Motin break; 2946f0f25b9cSAlexander Motin } 2947f0f25b9cSAlexander Motin 294880d6987cSAlexander Motin cam_dflags = CAM_DEBUG_NONE; 29498b8a9b1dSJustin T. Gibbs if (cam_dpath != NULL) { 295080d6987cSAlexander Motin oldpath = cam_dpath; 29518b8a9b1dSJustin T. Gibbs cam_dpath = NULL; 295280d6987cSAlexander Motin xpt_free_path(oldpath); 29538b8a9b1dSJustin T. Gibbs } 295480d6987cSAlexander Motin if (start_ccb->cdbg.flags != CAM_DEBUG_NONE) { 2955e5dfa058SAlexander Motin if (xpt_create_path(&cam_dpath, NULL, 29568b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.path_id, 29578b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.target_id, 29588b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.target_lun) != 29598b8a9b1dSJustin T. Gibbs CAM_REQ_CMP) { 29608b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.status = CAM_RESRC_UNAVAIL; 2961aa872be6SMatt Jacob } else { 296280d6987cSAlexander Motin cam_dflags = start_ccb->cdbg.flags; 29638b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.status = CAM_REQ_CMP; 2964f0d9af51SMatt Jacob xpt_print(cam_dpath, "debugging flags now %x\n", 2965f0d9af51SMatt Jacob cam_dflags); 2966aa872be6SMatt Jacob } 296780d6987cSAlexander Motin } else 29688b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.status = CAM_REQ_CMP; 29698b8a9b1dSJustin T. Gibbs break; 29708b8a9b1dSJustin T. Gibbs } 29718b8a9b1dSJustin T. Gibbs case XPT_NOOP: 297287cfaf0eSJustin T. Gibbs if ((start_ccb->ccb_h.flags & CAM_DEV_QFREEZE) != 0) 2973da396db2SAlexander Motin xpt_freeze_devq(path, 1); 29748b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.status = CAM_REQ_CMP; 29758b8a9b1dSJustin T. Gibbs break; 29768b8a9b1dSJustin T. Gibbs default: 29778b8a9b1dSJustin T. Gibbs case XPT_SDEV_TYPE: 29788b8a9b1dSJustin T. Gibbs case XPT_TERM_IO: 29798b8a9b1dSJustin T. Gibbs case XPT_ENG_INQ: 29808b8a9b1dSJustin T. Gibbs /* XXX Implement */ 29813501942bSJustin T. Gibbs printf("%s: CCB type %#x not supported\n", __func__, 29823501942bSJustin T. Gibbs start_ccb->ccb_h.func_code); 29838b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.status = CAM_PROVIDE_FAIL; 2984b882a6d3SMatt Jacob if (start_ccb->ccb_h.func_code & XPT_FC_DEV_QUEUED) { 2985b882a6d3SMatt Jacob xpt_done(start_ccb); 2986b882a6d3SMatt Jacob } 29878b8a9b1dSJustin T. Gibbs break; 29888b8a9b1dSJustin T. Gibbs } 29898b8a9b1dSJustin T. Gibbs } 29908b8a9b1dSJustin T. Gibbs 29918b8a9b1dSJustin T. Gibbs void 29928b8a9b1dSJustin T. Gibbs xpt_polled_action(union ccb *start_ccb) 29938b8a9b1dSJustin T. Gibbs { 29948b8a9b1dSJustin T. Gibbs u_int32_t timeout; 29958b8a9b1dSJustin T. Gibbs struct cam_sim *sim; 29968b8a9b1dSJustin T. Gibbs struct cam_devq *devq; 29978b8a9b1dSJustin T. Gibbs struct cam_ed *dev; 29988b8a9b1dSJustin T. Gibbs 29990069293bSAlexander Motin timeout = start_ccb->ccb_h.timeout * 10; 30008b8a9b1dSJustin T. Gibbs sim = start_ccb->ccb_h.path->bus->sim; 30018b8a9b1dSJustin T. Gibbs devq = sim->devq; 30028b8a9b1dSJustin T. Gibbs dev = start_ccb->ccb_h.path->device; 30038b8a9b1dSJustin T. Gibbs 3004227d67aaSAlexander Motin mtx_unlock(&dev->device_mtx); 30054a612489SAlexander Motin 30068b8a9b1dSJustin T. Gibbs /* 30078b8a9b1dSJustin T. Gibbs * Steal an opening so that no other queued requests 30088b8a9b1dSJustin T. Gibbs * can get it before us while we simulate interrupts. 30098b8a9b1dSJustin T. Gibbs */ 3010227d67aaSAlexander Motin mtx_lock(&devq->send_mtx); 30118b8a9b1dSJustin T. Gibbs dev->ccbq.devq_openings--; 30128b8a9b1dSJustin T. Gibbs dev->ccbq.dev_openings--; 3013227d67aaSAlexander Motin while((devq->send_openings <= 0 || dev->ccbq.dev_openings < 0) && 3014227d67aaSAlexander Motin (--timeout > 0)) { 3015227d67aaSAlexander Motin mtx_unlock(&devq->send_mtx); 30160069293bSAlexander Motin DELAY(100); 3017227d67aaSAlexander Motin CAM_SIM_LOCK(sim); 30188b8a9b1dSJustin T. Gibbs (*(sim->sim_poll))(sim); 3019227d67aaSAlexander Motin CAM_SIM_UNLOCK(sim); 3020227d67aaSAlexander Motin camisr_runqueue(); 3021227d67aaSAlexander Motin mtx_lock(&devq->send_mtx); 30228b8a9b1dSJustin T. Gibbs } 30238b8a9b1dSJustin T. Gibbs dev->ccbq.devq_openings++; 30248b8a9b1dSJustin T. Gibbs dev->ccbq.dev_openings++; 3025227d67aaSAlexander Motin mtx_unlock(&devq->send_mtx); 30268b8a9b1dSJustin T. Gibbs 30278b8a9b1dSJustin T. Gibbs if (timeout != 0) { 30288b8a9b1dSJustin T. Gibbs xpt_action(start_ccb); 30298b8a9b1dSJustin T. Gibbs while(--timeout > 0) { 3030227d67aaSAlexander Motin CAM_SIM_LOCK(sim); 30318b8a9b1dSJustin T. Gibbs (*(sim->sim_poll))(sim); 3032227d67aaSAlexander Motin CAM_SIM_UNLOCK(sim); 3033227d67aaSAlexander Motin camisr_runqueue(); 30348b8a9b1dSJustin T. Gibbs if ((start_ccb->ccb_h.status & CAM_STATUS_MASK) 30358b8a9b1dSJustin T. Gibbs != CAM_REQ_INPROG) 30368b8a9b1dSJustin T. Gibbs break; 30370069293bSAlexander Motin DELAY(100); 30388b8a9b1dSJustin T. Gibbs } 30398b8a9b1dSJustin T. Gibbs if (timeout == 0) { 30408b8a9b1dSJustin T. Gibbs /* 30418b8a9b1dSJustin T. Gibbs * XXX Is it worth adding a sim_timeout entry 30428b8a9b1dSJustin T. Gibbs * point so we can attempt recovery? If 30438b8a9b1dSJustin T. Gibbs * this is only used for dumps, I don't think 30448b8a9b1dSJustin T. Gibbs * it is. 30458b8a9b1dSJustin T. Gibbs */ 30468b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.status = CAM_CMD_TIMEOUT; 30478b8a9b1dSJustin T. Gibbs } 30488b8a9b1dSJustin T. Gibbs } else { 30498b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.status = CAM_RESRC_UNAVAIL; 30508b8a9b1dSJustin T. Gibbs } 30514a612489SAlexander Motin 3052227d67aaSAlexander Motin mtx_lock(&dev->device_mtx); 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 3060227d67aaSAlexander Motin xpt_schedule(struct cam_periph *periph, u_int32_t new_priority) 30618b8a9b1dSJustin T. Gibbs { 30628b8a9b1dSJustin T. Gibbs 3063227d67aaSAlexander Motin CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("xpt_schedule\n")); 3064227d67aaSAlexander Motin cam_periph_assert(periph, MA_OWNED); 3065227d67aaSAlexander Motin if (new_priority < periph->scheduled_priority) { 3066227d67aaSAlexander Motin periph->scheduled_priority = new_priority; 3067227d67aaSAlexander Motin xpt_run_allocq(periph, 0); 30688b8a9b1dSJustin T. Gibbs } 30698b8a9b1dSJustin T. Gibbs } 30708b8a9b1dSJustin T. Gibbs 30718b8a9b1dSJustin T. Gibbs 30728b8a9b1dSJustin T. Gibbs /* 30738b8a9b1dSJustin T. Gibbs * Schedule a device to run on a given queue. 30748b8a9b1dSJustin T. Gibbs * If the device was inserted as a new entry on the queue, 30758b8a9b1dSJustin T. Gibbs * return 1 meaning the device queue should be run. If we 30768b8a9b1dSJustin T. Gibbs * were already queued, implying someone else has already 30778b8a9b1dSJustin T. Gibbs * started the queue, return 0 so the caller doesn't attempt 307877dc25ccSScott Long * to run the queue. 30798b8a9b1dSJustin T. Gibbs */ 3080227d67aaSAlexander Motin static int 30818b8a9b1dSJustin T. Gibbs xpt_schedule_dev(struct camq *queue, cam_pinfo *pinfo, 30828b8a9b1dSJustin T. Gibbs u_int32_t new_priority) 30838b8a9b1dSJustin T. Gibbs { 30848b8a9b1dSJustin T. Gibbs int retval; 30858b8a9b1dSJustin T. Gibbs u_int32_t old_priority; 30868b8a9b1dSJustin T. Gibbs 3087aa872be6SMatt Jacob CAM_DEBUG_PRINT(CAM_DEBUG_XPT, ("xpt_schedule_dev\n")); 30888b8a9b1dSJustin T. Gibbs 30898b8a9b1dSJustin T. Gibbs old_priority = pinfo->priority; 30908b8a9b1dSJustin T. Gibbs 30918b8a9b1dSJustin T. Gibbs /* 30928b8a9b1dSJustin T. Gibbs * Are we already queued? 30938b8a9b1dSJustin T. Gibbs */ 30948b8a9b1dSJustin T. Gibbs if (pinfo->index != CAM_UNQUEUED_INDEX) { 30958b8a9b1dSJustin T. Gibbs /* Simply reorder based on new priority */ 30968b8a9b1dSJustin T. Gibbs if (new_priority < old_priority) { 30978b8a9b1dSJustin T. Gibbs camq_change_priority(queue, pinfo->index, 30988b8a9b1dSJustin T. Gibbs new_priority); 3099aa872be6SMatt Jacob CAM_DEBUG_PRINT(CAM_DEBUG_XPT, 31008b8a9b1dSJustin T. Gibbs ("changed priority to %d\n", 31018b8a9b1dSJustin T. Gibbs new_priority)); 310283c5d981SAlexander Motin retval = 1; 310383c5d981SAlexander Motin } else 31048b8a9b1dSJustin T. Gibbs retval = 0; 31058b8a9b1dSJustin T. Gibbs } else { 31068b8a9b1dSJustin T. Gibbs /* New entry on the queue */ 31078b8a9b1dSJustin T. Gibbs if (new_priority < old_priority) 31088b8a9b1dSJustin T. Gibbs pinfo->priority = new_priority; 31098b8a9b1dSJustin T. Gibbs 3110aa872be6SMatt Jacob CAM_DEBUG_PRINT(CAM_DEBUG_XPT, 31118b8a9b1dSJustin T. Gibbs ("Inserting onto queue\n")); 31128bad620dSJustin T. Gibbs pinfo->generation = ++queue->generation; 31138b8a9b1dSJustin T. Gibbs camq_insert(queue, pinfo); 31148b8a9b1dSJustin T. Gibbs retval = 1; 31158b8a9b1dSJustin T. Gibbs } 31168b8a9b1dSJustin T. Gibbs return (retval); 31178b8a9b1dSJustin T. Gibbs } 31188b8a9b1dSJustin T. Gibbs 31198b8a9b1dSJustin T. Gibbs static void 3120227d67aaSAlexander Motin xpt_run_allocq_task(void *context, int pending) 31218b8a9b1dSJustin T. Gibbs { 3122227d67aaSAlexander Motin struct cam_periph *periph = context; 31238b8a9b1dSJustin T. Gibbs 3124227d67aaSAlexander Motin cam_periph_lock(periph); 3125227d67aaSAlexander Motin periph->flags &= ~CAM_PERIPH_RUN_TASK; 3126227d67aaSAlexander Motin xpt_run_allocq(periph, 1); 3127227d67aaSAlexander Motin cam_periph_unlock(periph); 3128227d67aaSAlexander Motin cam_periph_release(periph); 3129227d67aaSAlexander Motin } 3130227d67aaSAlexander Motin 3131227d67aaSAlexander Motin static void 3132227d67aaSAlexander Motin xpt_run_allocq(struct cam_periph *periph, int sleep) 3133227d67aaSAlexander Motin { 3134227d67aaSAlexander Motin struct cam_ed *device; 3135227d67aaSAlexander Motin union ccb *ccb; 3136227d67aaSAlexander Motin uint32_t prio; 3137227d67aaSAlexander Motin 3138227d67aaSAlexander Motin cam_periph_assert(periph, MA_OWNED); 3139227d67aaSAlexander Motin if (periph->periph_allocating) 3140cccf4220SAlexander Motin return; 3141227d67aaSAlexander Motin periph->periph_allocating = 1; 3142227d67aaSAlexander Motin CAM_DEBUG_PRINT(CAM_DEBUG_XPT, ("xpt_run_allocq(%p)\n", periph)); 3143227d67aaSAlexander Motin device = periph->path->device; 3144227d67aaSAlexander Motin ccb = NULL; 3145227d67aaSAlexander Motin restart: 3146227d67aaSAlexander Motin while ((prio = min(periph->scheduled_priority, 3147227d67aaSAlexander Motin periph->immediate_priority)) != CAM_PRIORITY_NONE && 3148227d67aaSAlexander Motin (periph->periph_allocated - (ccb != NULL ? 1 : 0) < 3149227d67aaSAlexander Motin device->ccbq.total_openings || prio <= CAM_PRIORITY_OOB)) { 3150cccf4220SAlexander Motin 3151227d67aaSAlexander Motin if (ccb == NULL && 3152227d67aaSAlexander Motin (ccb = xpt_get_ccb_nowait(periph)) == NULL) { 3153227d67aaSAlexander Motin if (sleep) { 3154227d67aaSAlexander Motin ccb = xpt_get_ccb(periph); 3155227d67aaSAlexander Motin goto restart; 3156227d67aaSAlexander Motin } 31578ec5ab3fSAlexander Motin if (periph->flags & CAM_PERIPH_RUN_TASK) 31588b8a9b1dSJustin T. Gibbs break; 3159*c33e4029SAlexander Motin cam_periph_doacquire(periph); 3160227d67aaSAlexander Motin periph->flags |= CAM_PERIPH_RUN_TASK; 3161227d67aaSAlexander Motin taskqueue_enqueue(xsoftc.xpt_taskq, 3162227d67aaSAlexander Motin &periph->periph_run_task); 3163227d67aaSAlexander Motin break; 31648b8a9b1dSJustin T. Gibbs } 3165227d67aaSAlexander Motin xpt_setup_ccb(&ccb->ccb_h, periph->path, prio); 3166227d67aaSAlexander Motin if (prio == periph->immediate_priority) { 3167227d67aaSAlexander Motin periph->immediate_priority = CAM_PRIORITY_NONE; 3168227d67aaSAlexander Motin CAM_DEBUG_PRINT(CAM_DEBUG_XPT, 3169227d67aaSAlexander Motin ("waking cam_periph_getccb()\n")); 3170227d67aaSAlexander Motin SLIST_INSERT_HEAD(&periph->ccb_list, &ccb->ccb_h, 3171227d67aaSAlexander Motin periph_links.sle); 3172227d67aaSAlexander Motin wakeup(&periph->ccb_list); 3173227d67aaSAlexander Motin } else { 3174227d67aaSAlexander Motin periph->scheduled_priority = CAM_PRIORITY_NONE; 3175227d67aaSAlexander Motin CAM_DEBUG_PRINT(CAM_DEBUG_XPT, 3176227d67aaSAlexander Motin ("calling periph_start()\n")); 3177227d67aaSAlexander Motin periph->periph_start(periph, ccb); 3178227d67aaSAlexander Motin } 3179227d67aaSAlexander Motin ccb = NULL; 3180227d67aaSAlexander Motin } 3181227d67aaSAlexander Motin if (ccb != NULL) 3182227d67aaSAlexander Motin xpt_release_ccb(ccb); 3183227d67aaSAlexander Motin periph->periph_allocating = 0; 31848b8a9b1dSJustin T. Gibbs } 31858b8a9b1dSJustin T. Gibbs 318683c5d981SAlexander Motin static void 3187cccf4220SAlexander Motin xpt_run_devq(struct cam_devq *devq) 31888b8a9b1dSJustin T. Gibbs { 3189de9ebb68SAlexander Motin char cdb_str[(SCSI_MAX_CDBLEN * 3) + 1]; 3190227d67aaSAlexander Motin int lock; 31918b8a9b1dSJustin T. Gibbs 3192cccf4220SAlexander Motin CAM_DEBUG_PRINT(CAM_DEBUG_XPT, ("xpt_run_devq\n")); 31938b8a9b1dSJustin T. Gibbs 3194cccf4220SAlexander Motin devq->send_queue.qfrozen_cnt++; 31958b8a9b1dSJustin T. Gibbs while ((devq->send_queue.entries > 0) 3196ec700f26SAlexander Motin && (devq->send_openings > 0) 3197cccf4220SAlexander Motin && (devq->send_queue.qfrozen_cnt <= 1)) { 31988b8a9b1dSJustin T. Gibbs struct cam_ed *device; 31998b8a9b1dSJustin T. Gibbs union ccb *work_ccb; 32008b8a9b1dSJustin T. Gibbs struct cam_sim *sim; 32018b8a9b1dSJustin T. Gibbs 3202227d67aaSAlexander Motin device = (struct cam_ed *)camq_remove(&devq->send_queue, 32035a526431SJustin T. Gibbs CAMQ_HEAD); 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 3215daa5487fSAlexander Motin mtx_lock(&xsoftc.xpt_highpower_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 */ 3223daa5487fSAlexander Motin xpt_freeze_devq_device(device, 1); 3224227d67aaSAlexander Motin STAILQ_INSERT_TAIL(&xsoftc.highpowerq, device, 3225ea541bfdSAlexander Motin highpowerq_entry); 32268b8a9b1dSJustin T. Gibbs 3227daa5487fSAlexander Motin mtx_unlock(&xsoftc.xpt_highpower_lock); 32288b8a9b1dSJustin T. Gibbs continue; 32298b8a9b1dSJustin T. Gibbs } else { 32308b8a9b1dSJustin T. Gibbs /* 32318b8a9b1dSJustin T. Gibbs * Consume a high power slot while 32328b8a9b1dSJustin T. Gibbs * this ccb runs. 32338b8a9b1dSJustin T. Gibbs */ 32342b83592fSScott Long xsoftc.num_highpower--; 32358b8a9b1dSJustin T. Gibbs } 3236daa5487fSAlexander Motin mtx_unlock(&xsoftc.xpt_highpower_lock); 32378b8a9b1dSJustin T. Gibbs } 32388b8a9b1dSJustin T. Gibbs cam_ccbq_remove_ccb(&device->ccbq, work_ccb); 32398b8a9b1dSJustin T. Gibbs cam_ccbq_send_ccb(&device->ccbq, work_ccb); 32408b8a9b1dSJustin T. Gibbs devq->send_openings--; 32418b8a9b1dSJustin T. Gibbs devq->send_active++; 3242cccf4220SAlexander Motin xpt_schedule_devq(devq, device); 3243227d67aaSAlexander Motin mtx_unlock(&devq->send_mtx); 32448b8a9b1dSJustin T. Gibbs 3245cccf4220SAlexander Motin if ((work_ccb->ccb_h.flags & CAM_DEV_QFREEZE) != 0) { 32468b8a9b1dSJustin T. Gibbs /* 32478b8a9b1dSJustin T. Gibbs * The client wants to freeze the queue 32488b8a9b1dSJustin T. Gibbs * after this CCB is sent. 32498b8a9b1dSJustin T. Gibbs */ 325083c5d981SAlexander Motin xpt_freeze_devq(work_ccb->ccb_h.path, 1); 32518b8a9b1dSJustin T. Gibbs } 32528b8a9b1dSJustin T. Gibbs 3253a4eb4f16SMatt Jacob /* In Target mode, the peripheral driver knows best... */ 3254a4eb4f16SMatt Jacob if (work_ccb->ccb_h.func_code == XPT_SCSI_IO) { 3255a4eb4f16SMatt Jacob if ((device->inq_flags & SID_CmdQue) != 0 3256a4eb4f16SMatt Jacob && work_ccb->csio.tag_action != CAM_TAG_ACTION_NONE) 32578b8a9b1dSJustin T. Gibbs work_ccb->ccb_h.flags |= CAM_TAG_ACTION_VALID; 32588b8a9b1dSJustin T. Gibbs else 32598b8a9b1dSJustin T. Gibbs /* 3260a4eb4f16SMatt Jacob * Clear this in case of a retried CCB that 3261a4eb4f16SMatt Jacob * failed due to a rejected tag. 32628b8a9b1dSJustin T. Gibbs */ 32638b8a9b1dSJustin T. Gibbs work_ccb->ccb_h.flags &= ~CAM_TAG_ACTION_VALID; 3264a4eb4f16SMatt Jacob } 32658b8a9b1dSJustin T. Gibbs 3266de9ebb68SAlexander Motin switch (work_ccb->ccb_h.func_code) { 3267de9ebb68SAlexander Motin case XPT_SCSI_IO: 3268de9ebb68SAlexander Motin CAM_DEBUG(work_ccb->ccb_h.path, 3269de9ebb68SAlexander Motin CAM_DEBUG_CDB,("%s. CDB: %s\n", 3270de9ebb68SAlexander Motin scsi_op_desc(work_ccb->csio.cdb_io.cdb_bytes[0], 3271de9ebb68SAlexander Motin &device->inq_data), 3272de9ebb68SAlexander Motin scsi_cdb_string(work_ccb->csio.cdb_io.cdb_bytes, 3273de9ebb68SAlexander Motin cdb_str, sizeof(cdb_str)))); 3274de9ebb68SAlexander Motin break; 3275de9ebb68SAlexander Motin case XPT_ATA_IO: 3276de9ebb68SAlexander Motin CAM_DEBUG(work_ccb->ccb_h.path, 3277de9ebb68SAlexander Motin CAM_DEBUG_CDB,("%s. ACB: %s\n", 3278de9ebb68SAlexander Motin ata_op_string(&work_ccb->ataio.cmd), 3279de9ebb68SAlexander Motin ata_cmd_string(&work_ccb->ataio.cmd, 3280de9ebb68SAlexander Motin cdb_str, sizeof(cdb_str)))); 3281de9ebb68SAlexander Motin break; 3282de9ebb68SAlexander Motin default: 3283de9ebb68SAlexander Motin break; 3284de9ebb68SAlexander Motin } 3285de9ebb68SAlexander Motin 32868b8a9b1dSJustin T. Gibbs /* 3287227d67aaSAlexander Motin * Device queues can be shared among multiple SIM instances 3288227d67aaSAlexander Motin * that reside on different busses. Use the SIM from the 3289227d67aaSAlexander Motin * queued device, rather than the one from the calling bus. 32908b8a9b1dSJustin T. Gibbs */ 3291227d67aaSAlexander Motin sim = device->sim; 3292227d67aaSAlexander Motin lock = (mtx_owned(sim->mtx) == 0); 3293227d67aaSAlexander Motin if (lock) 3294227d67aaSAlexander Motin CAM_SIM_LOCK(sim); 32958b8a9b1dSJustin T. Gibbs (*(sim->sim_action))(sim, work_ccb); 3296227d67aaSAlexander Motin if (lock) 3297227d67aaSAlexander Motin CAM_SIM_UNLOCK(sim); 3298227d67aaSAlexander Motin mtx_lock(&devq->send_mtx); 32998b8a9b1dSJustin T. Gibbs } 3300cccf4220SAlexander Motin devq->send_queue.qfrozen_cnt--; 33018b8a9b1dSJustin T. Gibbs } 33028b8a9b1dSJustin T. Gibbs 33038b8a9b1dSJustin T. Gibbs /* 33048b8a9b1dSJustin T. Gibbs * This function merges stuff from the slave ccb into the master ccb, while 33058b8a9b1dSJustin T. Gibbs * keeping important fields in the master ccb constant. 33068b8a9b1dSJustin T. Gibbs */ 33078b8a9b1dSJustin T. Gibbs void 33088b8a9b1dSJustin T. Gibbs xpt_merge_ccb(union ccb *master_ccb, union ccb *slave_ccb) 33098b8a9b1dSJustin T. Gibbs { 331068153f43SScott Long 33118b8a9b1dSJustin T. Gibbs /* 33128b8a9b1dSJustin T. Gibbs * Pull fields that are valid for peripheral drivers to set 33138b8a9b1dSJustin T. Gibbs * into the master CCB along with the CCB "payload". 33148b8a9b1dSJustin T. Gibbs */ 33158b8a9b1dSJustin T. Gibbs master_ccb->ccb_h.retry_count = slave_ccb->ccb_h.retry_count; 33168b8a9b1dSJustin T. Gibbs master_ccb->ccb_h.func_code = slave_ccb->ccb_h.func_code; 33178b8a9b1dSJustin T. Gibbs master_ccb->ccb_h.timeout = slave_ccb->ccb_h.timeout; 33188b8a9b1dSJustin T. Gibbs master_ccb->ccb_h.flags = slave_ccb->ccb_h.flags; 33198b8a9b1dSJustin T. Gibbs bcopy(&(&slave_ccb->ccb_h)[1], &(&master_ccb->ccb_h)[1], 33208b8a9b1dSJustin T. Gibbs sizeof(union ccb) - sizeof(struct ccb_hdr)); 33218b8a9b1dSJustin T. Gibbs } 33228b8a9b1dSJustin T. Gibbs 33238b8a9b1dSJustin T. Gibbs void 33248b8a9b1dSJustin T. Gibbs xpt_setup_ccb(struct ccb_hdr *ccb_h, struct cam_path *path, u_int32_t priority) 33258b8a9b1dSJustin T. Gibbs { 332668153f43SScott Long 33278b8a9b1dSJustin T. Gibbs CAM_DEBUG(path, CAM_DEBUG_TRACE, ("xpt_setup_ccb\n")); 33288b8a9b1dSJustin T. Gibbs ccb_h->pinfo.priority = priority; 33298b8a9b1dSJustin T. Gibbs ccb_h->path = path; 33308b8a9b1dSJustin T. Gibbs ccb_h->path_id = path->bus->path_id; 33318b8a9b1dSJustin T. Gibbs if (path->target) 33328b8a9b1dSJustin T. Gibbs ccb_h->target_id = path->target->target_id; 33338b8a9b1dSJustin T. Gibbs else 33348b8a9b1dSJustin T. Gibbs ccb_h->target_id = CAM_TARGET_WILDCARD; 33358b8a9b1dSJustin T. Gibbs if (path->device) { 33368b8a9b1dSJustin T. Gibbs ccb_h->target_lun = path->device->lun_id; 33378bad620dSJustin T. Gibbs ccb_h->pinfo.generation = ++path->device->ccbq.queue.generation; 33388b8a9b1dSJustin T. Gibbs } else { 33398b8a9b1dSJustin T. Gibbs ccb_h->target_lun = CAM_TARGET_WILDCARD; 33408b8a9b1dSJustin T. Gibbs } 33418b8a9b1dSJustin T. Gibbs ccb_h->pinfo.index = CAM_UNQUEUED_INDEX; 33428b8a9b1dSJustin T. Gibbs ccb_h->flags = 0; 3343b5595753SNathan Whitehorn ccb_h->xflags = 0; 33448b8a9b1dSJustin T. Gibbs } 33458b8a9b1dSJustin T. Gibbs 33468b8a9b1dSJustin T. Gibbs /* Path manipulation functions */ 33478b8a9b1dSJustin T. Gibbs cam_status 33488b8a9b1dSJustin T. Gibbs xpt_create_path(struct cam_path **new_path_ptr, struct cam_periph *perph, 33498b8a9b1dSJustin T. Gibbs path_id_t path_id, target_id_t target_id, lun_id_t lun_id) 33508b8a9b1dSJustin T. Gibbs { 33518b8a9b1dSJustin T. Gibbs struct cam_path *path; 33528b8a9b1dSJustin T. Gibbs cam_status status; 33538b8a9b1dSJustin T. Gibbs 3354596ee08fSAlexander Motin path = (struct cam_path *)malloc(sizeof(*path), M_CAMPATH, M_NOWAIT); 33558b8a9b1dSJustin T. Gibbs 33568b8a9b1dSJustin T. Gibbs if (path == NULL) { 33578b8a9b1dSJustin T. Gibbs status = CAM_RESRC_UNAVAIL; 33588b8a9b1dSJustin T. Gibbs return(status); 33598b8a9b1dSJustin T. Gibbs } 33608b8a9b1dSJustin T. Gibbs status = xpt_compile_path(path, perph, path_id, target_id, lun_id); 33618b8a9b1dSJustin T. Gibbs if (status != CAM_REQ_CMP) { 3362596ee08fSAlexander Motin free(path, M_CAMPATH); 33638b8a9b1dSJustin T. Gibbs path = NULL; 33648b8a9b1dSJustin T. Gibbs } 33658b8a9b1dSJustin T. Gibbs *new_path_ptr = path; 33668b8a9b1dSJustin T. Gibbs return (status); 33678b8a9b1dSJustin T. Gibbs } 33688b8a9b1dSJustin T. Gibbs 33692b83592fSScott Long cam_status 33702b83592fSScott Long xpt_create_path_unlocked(struct cam_path **new_path_ptr, 33712b83592fSScott Long struct cam_periph *periph, path_id_t path_id, 33722b83592fSScott Long target_id_t target_id, lun_id_t lun_id) 33732b83592fSScott Long { 33742b83592fSScott Long 3375227d67aaSAlexander Motin return (xpt_create_path(new_path_ptr, periph, path_id, target_id, 3376227d67aaSAlexander Motin lun_id)); 33772b83592fSScott Long } 33782b83592fSScott Long 337952c9ce25SScott Long cam_status 33808b8a9b1dSJustin T. Gibbs xpt_compile_path(struct cam_path *new_path, struct cam_periph *perph, 33818b8a9b1dSJustin T. Gibbs path_id_t path_id, target_id_t target_id, lun_id_t lun_id) 33828b8a9b1dSJustin T. Gibbs { 33838b8a9b1dSJustin T. Gibbs struct cam_eb *bus; 33848b8a9b1dSJustin T. Gibbs struct cam_et *target; 33858b8a9b1dSJustin T. Gibbs struct cam_ed *device; 33868b8a9b1dSJustin T. Gibbs cam_status status; 33878b8a9b1dSJustin T. Gibbs 33888b8a9b1dSJustin T. Gibbs status = CAM_REQ_CMP; /* Completed without error */ 33898b8a9b1dSJustin T. Gibbs target = NULL; /* Wildcarded */ 33908b8a9b1dSJustin T. Gibbs device = NULL; /* Wildcarded */ 3391a5479bc5SJustin T. Gibbs 3392a5479bc5SJustin T. Gibbs /* 3393a5479bc5SJustin T. Gibbs * We will potentially modify the EDT, so block interrupts 3394a5479bc5SJustin T. Gibbs * that may attempt to create cam paths. 3395a5479bc5SJustin T. Gibbs */ 33968b8a9b1dSJustin T. Gibbs bus = xpt_find_bus(path_id); 33978b8a9b1dSJustin T. Gibbs if (bus == NULL) { 33988b8a9b1dSJustin T. Gibbs status = CAM_PATH_INVALID; 3399c8bead2aSJustin T. Gibbs } else { 3400227d67aaSAlexander Motin xpt_lock_buses(); 3401227d67aaSAlexander Motin mtx_lock(&bus->eb_mtx); 34028b8a9b1dSJustin T. Gibbs target = xpt_find_target(bus, target_id); 34038b8a9b1dSJustin T. Gibbs if (target == NULL) { 34048b8a9b1dSJustin T. Gibbs /* Create one */ 34058b8a9b1dSJustin T. Gibbs struct cam_et *new_target; 34068b8a9b1dSJustin T. Gibbs 34078b8a9b1dSJustin T. Gibbs new_target = xpt_alloc_target(bus, target_id); 34088b8a9b1dSJustin T. Gibbs if (new_target == NULL) { 34098b8a9b1dSJustin T. Gibbs status = CAM_RESRC_UNAVAIL; 34108b8a9b1dSJustin T. Gibbs } else { 34118b8a9b1dSJustin T. Gibbs target = new_target; 34128b8a9b1dSJustin T. Gibbs } 34138b8a9b1dSJustin T. Gibbs } 3414227d67aaSAlexander Motin xpt_unlock_buses(); 3415c8bead2aSJustin T. Gibbs if (target != NULL) { 34168b8a9b1dSJustin T. Gibbs device = xpt_find_device(target, lun_id); 34178b8a9b1dSJustin T. Gibbs if (device == NULL) { 34188b8a9b1dSJustin T. Gibbs /* Create one */ 34198b8a9b1dSJustin T. Gibbs struct cam_ed *new_device; 34208b8a9b1dSJustin T. Gibbs 342152c9ce25SScott Long new_device = 342252c9ce25SScott Long (*(bus->xport->alloc_device))(bus, 34238b8a9b1dSJustin T. Gibbs target, 34248b8a9b1dSJustin T. Gibbs lun_id); 34258b8a9b1dSJustin T. Gibbs if (new_device == NULL) { 34268b8a9b1dSJustin T. Gibbs status = CAM_RESRC_UNAVAIL; 34278b8a9b1dSJustin T. Gibbs } else { 34288b8a9b1dSJustin T. Gibbs device = new_device; 34298b8a9b1dSJustin T. Gibbs } 34308b8a9b1dSJustin T. Gibbs } 34318b8a9b1dSJustin T. Gibbs } 3432227d67aaSAlexander Motin mtx_unlock(&bus->eb_mtx); 34338b8a9b1dSJustin T. Gibbs } 34348b8a9b1dSJustin T. Gibbs 34358b8a9b1dSJustin T. Gibbs /* 34368b8a9b1dSJustin T. Gibbs * Only touch the user's data if we are successful. 34378b8a9b1dSJustin T. Gibbs */ 34388b8a9b1dSJustin T. Gibbs if (status == CAM_REQ_CMP) { 34398b8a9b1dSJustin T. Gibbs new_path->periph = perph; 34408b8a9b1dSJustin T. Gibbs new_path->bus = bus; 34418b8a9b1dSJustin T. Gibbs new_path->target = target; 34428b8a9b1dSJustin T. Gibbs new_path->device = device; 34438b8a9b1dSJustin T. Gibbs CAM_DEBUG(new_path, CAM_DEBUG_TRACE, ("xpt_compile_path\n")); 34448b8a9b1dSJustin T. Gibbs } else { 34458b8a9b1dSJustin T. Gibbs if (device != NULL) 3446f98d7a47SAlexander Motin xpt_release_device(device); 34478b8a9b1dSJustin T. Gibbs if (target != NULL) 3448f98d7a47SAlexander Motin xpt_release_target(target); 3449a5479bc5SJustin T. Gibbs if (bus != NULL) 3450a5479bc5SJustin T. Gibbs xpt_release_bus(bus); 34518b8a9b1dSJustin T. Gibbs } 34528b8a9b1dSJustin T. Gibbs return (status); 34538b8a9b1dSJustin T. Gibbs } 34548b8a9b1dSJustin T. Gibbs 3455227d67aaSAlexander Motin cam_status 3456227d67aaSAlexander Motin xpt_clone_path(struct cam_path **new_path_ptr, struct cam_path *path) 3457227d67aaSAlexander Motin { 3458227d67aaSAlexander Motin struct cam_path *new_path; 3459227d67aaSAlexander Motin 3460227d67aaSAlexander Motin new_path = (struct cam_path *)malloc(sizeof(*path), M_CAMPATH, M_NOWAIT); 3461227d67aaSAlexander Motin if (new_path == NULL) 3462227d67aaSAlexander Motin return(CAM_RESRC_UNAVAIL); 3463227d67aaSAlexander Motin xpt_copy_path(new_path, path); 3464227d67aaSAlexander Motin *new_path_ptr = new_path; 3465227d67aaSAlexander Motin return (CAM_REQ_CMP); 3466227d67aaSAlexander Motin } 3467227d67aaSAlexander Motin 3468227d67aaSAlexander Motin void 3469227d67aaSAlexander Motin xpt_copy_path(struct cam_path *new_path, struct cam_path *path) 3470227d67aaSAlexander Motin { 3471227d67aaSAlexander Motin 3472227d67aaSAlexander Motin *new_path = *path; 3473227d67aaSAlexander Motin if (path->bus != NULL) 3474227d67aaSAlexander Motin xpt_acquire_bus(path->bus); 3475227d67aaSAlexander Motin if (path->target != NULL) 3476227d67aaSAlexander Motin xpt_acquire_target(path->target); 3477227d67aaSAlexander Motin if (path->device != NULL) 3478227d67aaSAlexander Motin xpt_acquire_device(path->device); 3479227d67aaSAlexander Motin } 3480227d67aaSAlexander Motin 348152c9ce25SScott Long void 34828b8a9b1dSJustin T. Gibbs xpt_release_path(struct cam_path *path) 34838b8a9b1dSJustin T. Gibbs { 34848b8a9b1dSJustin T. Gibbs CAM_DEBUG(path, CAM_DEBUG_TRACE, ("xpt_release_path\n")); 34859dd03ecfSJustin T. Gibbs if (path->device != NULL) { 3486f98d7a47SAlexander Motin xpt_release_device(path->device); 34879dd03ecfSJustin T. Gibbs path->device = NULL; 34889dd03ecfSJustin T. Gibbs } 34899dd03ecfSJustin T. Gibbs if (path->target != NULL) { 3490f98d7a47SAlexander Motin xpt_release_target(path->target); 34919dd03ecfSJustin T. Gibbs path->target = NULL; 34929dd03ecfSJustin T. Gibbs } 34939dd03ecfSJustin T. Gibbs if (path->bus != NULL) { 34949dd03ecfSJustin T. Gibbs xpt_release_bus(path->bus); 34959dd03ecfSJustin T. Gibbs path->bus = NULL; 34969dd03ecfSJustin T. Gibbs } 34978b8a9b1dSJustin T. Gibbs } 34988b8a9b1dSJustin T. Gibbs 34998b8a9b1dSJustin T. Gibbs void 35008b8a9b1dSJustin T. Gibbs xpt_free_path(struct cam_path *path) 35018b8a9b1dSJustin T. Gibbs { 350268153f43SScott Long 35038b8a9b1dSJustin T. Gibbs CAM_DEBUG(path, CAM_DEBUG_TRACE, ("xpt_free_path\n")); 35048b8a9b1dSJustin T. Gibbs xpt_release_path(path); 3505596ee08fSAlexander Motin free(path, M_CAMPATH); 35068b8a9b1dSJustin T. Gibbs } 35078b8a9b1dSJustin T. Gibbs 350815975b7bSMatt Jacob void 350915975b7bSMatt Jacob xpt_path_counts(struct cam_path *path, uint32_t *bus_ref, 351015975b7bSMatt Jacob uint32_t *periph_ref, uint32_t *target_ref, uint32_t *device_ref) 351115975b7bSMatt Jacob { 351215975b7bSMatt Jacob 35139a7c2696SAlexander Motin xpt_lock_buses(); 351415975b7bSMatt Jacob if (bus_ref) { 351515975b7bSMatt Jacob if (path->bus) 351615975b7bSMatt Jacob *bus_ref = path->bus->refcount; 351715975b7bSMatt Jacob else 351815975b7bSMatt Jacob *bus_ref = 0; 351915975b7bSMatt Jacob } 352015975b7bSMatt Jacob if (periph_ref) { 352115975b7bSMatt Jacob if (path->periph) 352215975b7bSMatt Jacob *periph_ref = path->periph->refcount; 352315975b7bSMatt Jacob else 352415975b7bSMatt Jacob *periph_ref = 0; 352515975b7bSMatt Jacob } 3526dcdf6e74SAlexander Motin xpt_unlock_buses(); 352715975b7bSMatt Jacob if (target_ref) { 352815975b7bSMatt Jacob if (path->target) 352915975b7bSMatt Jacob *target_ref = path->target->refcount; 353015975b7bSMatt Jacob else 353115975b7bSMatt Jacob *target_ref = 0; 353215975b7bSMatt Jacob } 353315975b7bSMatt Jacob if (device_ref) { 353415975b7bSMatt Jacob if (path->device) 353515975b7bSMatt Jacob *device_ref = path->device->refcount; 353615975b7bSMatt Jacob else 353715975b7bSMatt Jacob *device_ref = 0; 353815975b7bSMatt Jacob } 353915975b7bSMatt Jacob } 35408b8a9b1dSJustin T. Gibbs 35418b8a9b1dSJustin T. Gibbs /* 35422cefde5fSJustin T. Gibbs * Return -1 for failure, 0 for exact match, 1 for match with wildcards 35432cefde5fSJustin T. Gibbs * in path1, 2 for match with wildcards in path2. 35448b8a9b1dSJustin T. Gibbs */ 35458b8a9b1dSJustin T. Gibbs int 35468b8a9b1dSJustin T. Gibbs xpt_path_comp(struct cam_path *path1, struct cam_path *path2) 35478b8a9b1dSJustin T. Gibbs { 35488b8a9b1dSJustin T. Gibbs int retval = 0; 35498b8a9b1dSJustin T. Gibbs 35508b8a9b1dSJustin T. Gibbs if (path1->bus != path2->bus) { 35512cefde5fSJustin T. Gibbs if (path1->bus->path_id == CAM_BUS_WILDCARD) 35528b8a9b1dSJustin T. Gibbs retval = 1; 35532cefde5fSJustin T. Gibbs else if (path2->bus->path_id == CAM_BUS_WILDCARD) 35542cefde5fSJustin T. Gibbs retval = 2; 35558b8a9b1dSJustin T. Gibbs else 35568b8a9b1dSJustin T. Gibbs return (-1); 35578b8a9b1dSJustin T. Gibbs } 35588b8a9b1dSJustin T. Gibbs if (path1->target != path2->target) { 35592cefde5fSJustin T. Gibbs if (path1->target->target_id == CAM_TARGET_WILDCARD) { 35602cefde5fSJustin T. Gibbs if (retval == 0) 35618b8a9b1dSJustin T. Gibbs retval = 1; 35622cefde5fSJustin T. Gibbs } else if (path2->target->target_id == CAM_TARGET_WILDCARD) 35632cefde5fSJustin T. Gibbs retval = 2; 35648b8a9b1dSJustin T. Gibbs else 35658b8a9b1dSJustin T. Gibbs return (-1); 35668b8a9b1dSJustin T. Gibbs } 35678b8a9b1dSJustin T. Gibbs if (path1->device != path2->device) { 35682cefde5fSJustin T. Gibbs if (path1->device->lun_id == CAM_LUN_WILDCARD) { 35692cefde5fSJustin T. Gibbs if (retval == 0) 35708b8a9b1dSJustin T. Gibbs retval = 1; 35712cefde5fSJustin T. Gibbs } else if (path2->device->lun_id == CAM_LUN_WILDCARD) 35722cefde5fSJustin T. Gibbs retval = 2; 35738b8a9b1dSJustin T. Gibbs else 35748b8a9b1dSJustin T. Gibbs return (-1); 35758b8a9b1dSJustin T. Gibbs } 35768b8a9b1dSJustin T. Gibbs return (retval); 35778b8a9b1dSJustin T. Gibbs } 35788b8a9b1dSJustin T. Gibbs 35790d4f3c31SAlexander Motin int 35800d4f3c31SAlexander Motin xpt_path_comp_dev(struct cam_path *path, struct cam_ed *dev) 35810d4f3c31SAlexander Motin { 35820d4f3c31SAlexander Motin int retval = 0; 35830d4f3c31SAlexander Motin 35840d4f3c31SAlexander Motin if (path->bus != dev->target->bus) { 35850d4f3c31SAlexander Motin if (path->bus->path_id == CAM_BUS_WILDCARD) 35860d4f3c31SAlexander Motin retval = 1; 35870d4f3c31SAlexander Motin else if (dev->target->bus->path_id == CAM_BUS_WILDCARD) 35880d4f3c31SAlexander Motin retval = 2; 35890d4f3c31SAlexander Motin else 35900d4f3c31SAlexander Motin return (-1); 35910d4f3c31SAlexander Motin } 35920d4f3c31SAlexander Motin if (path->target != dev->target) { 35930d4f3c31SAlexander Motin if (path->target->target_id == CAM_TARGET_WILDCARD) { 35940d4f3c31SAlexander Motin if (retval == 0) 35950d4f3c31SAlexander Motin retval = 1; 35960d4f3c31SAlexander Motin } else if (dev->target->target_id == CAM_TARGET_WILDCARD) 35970d4f3c31SAlexander Motin retval = 2; 35980d4f3c31SAlexander Motin else 35990d4f3c31SAlexander Motin return (-1); 36000d4f3c31SAlexander Motin } 36010d4f3c31SAlexander Motin if (path->device != dev) { 36020d4f3c31SAlexander Motin if (path->device->lun_id == CAM_LUN_WILDCARD) { 36030d4f3c31SAlexander Motin if (retval == 0) 36040d4f3c31SAlexander Motin retval = 1; 36050d4f3c31SAlexander Motin } else if (dev->lun_id == CAM_LUN_WILDCARD) 36060d4f3c31SAlexander Motin retval = 2; 36070d4f3c31SAlexander Motin else 36080d4f3c31SAlexander Motin return (-1); 36090d4f3c31SAlexander Motin } 36100d4f3c31SAlexander Motin return (retval); 36110d4f3c31SAlexander Motin } 36120d4f3c31SAlexander Motin 36138b8a9b1dSJustin T. Gibbs void 36148b8a9b1dSJustin T. Gibbs xpt_print_path(struct cam_path *path) 36158b8a9b1dSJustin T. Gibbs { 361668153f43SScott Long 36178b8a9b1dSJustin T. Gibbs if (path == NULL) 36188b8a9b1dSJustin T. Gibbs printf("(nopath): "); 36198b8a9b1dSJustin T. Gibbs else { 36208b8a9b1dSJustin T. Gibbs if (path->periph != NULL) 36218b8a9b1dSJustin T. Gibbs printf("(%s%d:", path->periph->periph_name, 36228b8a9b1dSJustin T. Gibbs path->periph->unit_number); 36238b8a9b1dSJustin T. Gibbs else 36248b8a9b1dSJustin T. Gibbs printf("(noperiph:"); 36258b8a9b1dSJustin T. Gibbs 36268b8a9b1dSJustin T. Gibbs if (path->bus != NULL) 36278b8a9b1dSJustin T. Gibbs printf("%s%d:%d:", path->bus->sim->sim_name, 36288b8a9b1dSJustin T. Gibbs path->bus->sim->unit_number, 36298b8a9b1dSJustin T. Gibbs path->bus->sim->bus_id); 36308b8a9b1dSJustin T. Gibbs else 36318b8a9b1dSJustin T. Gibbs printf("nobus:"); 36328b8a9b1dSJustin T. Gibbs 36338b8a9b1dSJustin T. Gibbs if (path->target != NULL) 36348b8a9b1dSJustin T. Gibbs printf("%d:", path->target->target_id); 36358b8a9b1dSJustin T. Gibbs else 36368b8a9b1dSJustin T. Gibbs printf("X:"); 36378b8a9b1dSJustin T. Gibbs 36388b8a9b1dSJustin T. Gibbs if (path->device != NULL) 3639abe83505SNathan Whitehorn printf("%jx): ", (uintmax_t)path->device->lun_id); 36408b8a9b1dSJustin T. Gibbs else 36418b8a9b1dSJustin T. Gibbs printf("X): "); 36428b8a9b1dSJustin T. Gibbs } 36438b8a9b1dSJustin T. Gibbs } 36448b8a9b1dSJustin T. Gibbs 3645f0d9af51SMatt Jacob void 36460d4f3c31SAlexander Motin xpt_print_device(struct cam_ed *device) 36470d4f3c31SAlexander Motin { 36480d4f3c31SAlexander Motin 36490d4f3c31SAlexander Motin if (device == NULL) 36500d4f3c31SAlexander Motin printf("(nopath): "); 36510d4f3c31SAlexander Motin else { 3652abe83505SNathan Whitehorn printf("(noperiph:%s%d:%d:%d:%jx): ", device->sim->sim_name, 36530d4f3c31SAlexander Motin device->sim->unit_number, 36540d4f3c31SAlexander Motin device->sim->bus_id, 36550d4f3c31SAlexander Motin device->target->target_id, 3656abe83505SNathan Whitehorn (uintmax_t)device->lun_id); 36570d4f3c31SAlexander Motin } 36580d4f3c31SAlexander Motin } 36590d4f3c31SAlexander Motin 36600d4f3c31SAlexander Motin void 3661f0d9af51SMatt Jacob xpt_print(struct cam_path *path, const char *fmt, ...) 3662f0d9af51SMatt Jacob { 3663f0d9af51SMatt Jacob va_list ap; 3664f0d9af51SMatt Jacob xpt_print_path(path); 3665f0d9af51SMatt Jacob va_start(ap, fmt); 3666f0d9af51SMatt Jacob vprintf(fmt, ap); 3667f0d9af51SMatt Jacob va_end(ap); 3668f0d9af51SMatt Jacob } 3669f0d9af51SMatt Jacob 36703393f8daSKenneth D. Merry int 36713393f8daSKenneth D. Merry xpt_path_string(struct cam_path *path, char *str, size_t str_len) 36723393f8daSKenneth D. Merry { 36733393f8daSKenneth D. Merry struct sbuf sb; 36743393f8daSKenneth D. Merry 36753393f8daSKenneth D. Merry sbuf_new(&sb, str, str_len, 0); 36763393f8daSKenneth D. Merry 36773393f8daSKenneth D. Merry if (path == NULL) 36783393f8daSKenneth D. Merry sbuf_printf(&sb, "(nopath): "); 36793393f8daSKenneth D. Merry else { 36803393f8daSKenneth D. Merry if (path->periph != NULL) 36813393f8daSKenneth D. Merry sbuf_printf(&sb, "(%s%d:", path->periph->periph_name, 36823393f8daSKenneth D. Merry path->periph->unit_number); 36833393f8daSKenneth D. Merry else 36843393f8daSKenneth D. Merry sbuf_printf(&sb, "(noperiph:"); 36853393f8daSKenneth D. Merry 36863393f8daSKenneth D. Merry if (path->bus != NULL) 36873393f8daSKenneth D. Merry sbuf_printf(&sb, "%s%d:%d:", path->bus->sim->sim_name, 36883393f8daSKenneth D. Merry path->bus->sim->unit_number, 36893393f8daSKenneth D. Merry path->bus->sim->bus_id); 36903393f8daSKenneth D. Merry else 36913393f8daSKenneth D. Merry sbuf_printf(&sb, "nobus:"); 36923393f8daSKenneth D. Merry 36933393f8daSKenneth D. Merry if (path->target != NULL) 36943393f8daSKenneth D. Merry sbuf_printf(&sb, "%d:", path->target->target_id); 36953393f8daSKenneth D. Merry else 36963393f8daSKenneth D. Merry sbuf_printf(&sb, "X:"); 36973393f8daSKenneth D. Merry 36983393f8daSKenneth D. Merry if (path->device != NULL) 3699abe83505SNathan Whitehorn sbuf_printf(&sb, "%jx): ", 3700abe83505SNathan Whitehorn (uintmax_t)path->device->lun_id); 37013393f8daSKenneth D. Merry else 37023393f8daSKenneth D. Merry sbuf_printf(&sb, "X): "); 37033393f8daSKenneth D. Merry } 37043393f8daSKenneth D. Merry sbuf_finish(&sb); 37053393f8daSKenneth D. Merry 37063393f8daSKenneth D. Merry return(sbuf_len(&sb)); 37073393f8daSKenneth D. Merry } 37083393f8daSKenneth D. Merry 37098b8a9b1dSJustin T. Gibbs path_id_t 37108b8a9b1dSJustin T. Gibbs xpt_path_path_id(struct cam_path *path) 37118b8a9b1dSJustin T. Gibbs { 37128b8a9b1dSJustin T. Gibbs return(path->bus->path_id); 37138b8a9b1dSJustin T. Gibbs } 37148b8a9b1dSJustin T. Gibbs 37158b8a9b1dSJustin T. Gibbs target_id_t 37168b8a9b1dSJustin T. Gibbs xpt_path_target_id(struct cam_path *path) 37178b8a9b1dSJustin T. Gibbs { 37188b8a9b1dSJustin T. Gibbs if (path->target != NULL) 37198b8a9b1dSJustin T. Gibbs return (path->target->target_id); 37208b8a9b1dSJustin T. Gibbs else 37218b8a9b1dSJustin T. Gibbs return (CAM_TARGET_WILDCARD); 37228b8a9b1dSJustin T. Gibbs } 37238b8a9b1dSJustin T. Gibbs 37248b8a9b1dSJustin T. Gibbs lun_id_t 37258b8a9b1dSJustin T. Gibbs xpt_path_lun_id(struct cam_path *path) 37268b8a9b1dSJustin T. Gibbs { 37278b8a9b1dSJustin T. Gibbs if (path->device != NULL) 37288b8a9b1dSJustin T. Gibbs return (path->device->lun_id); 37298b8a9b1dSJustin T. Gibbs else 37308b8a9b1dSJustin T. Gibbs return (CAM_LUN_WILDCARD); 37318b8a9b1dSJustin T. Gibbs } 37328b8a9b1dSJustin T. Gibbs 37338b8a9b1dSJustin T. Gibbs struct cam_sim * 37348b8a9b1dSJustin T. Gibbs xpt_path_sim(struct cam_path *path) 37358b8a9b1dSJustin T. Gibbs { 373668153f43SScott Long 37378b8a9b1dSJustin T. Gibbs return (path->bus->sim); 37388b8a9b1dSJustin T. Gibbs } 37398b8a9b1dSJustin T. Gibbs 37408b8a9b1dSJustin T. Gibbs struct cam_periph* 37418b8a9b1dSJustin T. Gibbs xpt_path_periph(struct cam_path *path) 37428b8a9b1dSJustin T. Gibbs { 374368153f43SScott Long 37448b8a9b1dSJustin T. Gibbs return (path->periph); 37458b8a9b1dSJustin T. Gibbs } 37468b8a9b1dSJustin T. Gibbs 37470d307e09SAlexander Motin int 37480d307e09SAlexander Motin xpt_path_legacy_ata_id(struct cam_path *path) 37490d307e09SAlexander Motin { 37500d307e09SAlexander Motin struct cam_eb *bus; 37510d307e09SAlexander Motin int bus_id; 37520d307e09SAlexander Motin 37530d307e09SAlexander Motin if ((strcmp(path->bus->sim->sim_name, "ata") != 0) && 37540d307e09SAlexander Motin strcmp(path->bus->sim->sim_name, "ahcich") != 0 && 37550d307e09SAlexander Motin strcmp(path->bus->sim->sim_name, "mvsch") != 0 && 37560d307e09SAlexander Motin strcmp(path->bus->sim->sim_name, "siisch") != 0) 37570d307e09SAlexander Motin return (-1); 37580d307e09SAlexander Motin 37590d307e09SAlexander Motin if (strcmp(path->bus->sim->sim_name, "ata") == 0 && 37600d307e09SAlexander Motin path->bus->sim->unit_number < 2) { 37610d307e09SAlexander Motin bus_id = path->bus->sim->unit_number; 37620d307e09SAlexander Motin } else { 37630d307e09SAlexander Motin bus_id = 2; 37640d307e09SAlexander Motin xpt_lock_buses(); 37650d307e09SAlexander Motin TAILQ_FOREACH(bus, &xsoftc.xpt_busses, links) { 37660d307e09SAlexander Motin if (bus == path->bus) 37670d307e09SAlexander Motin break; 37680d307e09SAlexander Motin if ((strcmp(bus->sim->sim_name, "ata") == 0 && 37690d307e09SAlexander Motin bus->sim->unit_number >= 2) || 37700d307e09SAlexander Motin strcmp(bus->sim->sim_name, "ahcich") == 0 || 37710d307e09SAlexander Motin strcmp(bus->sim->sim_name, "mvsch") == 0 || 37720d307e09SAlexander Motin strcmp(bus->sim->sim_name, "siisch") == 0) 37730d307e09SAlexander Motin bus_id++; 37740d307e09SAlexander Motin } 37750d307e09SAlexander Motin xpt_unlock_buses(); 37760d307e09SAlexander Motin } 3777ce6cf987SAlexander Motin if (path->target != NULL) { 3778ce6cf987SAlexander Motin if (path->target->target_id < 2) 37790d307e09SAlexander Motin return (bus_id * 2 + path->target->target_id); 37800d307e09SAlexander Motin else 3781ce6cf987SAlexander Motin return (-1); 3782ce6cf987SAlexander Motin } else 37830d307e09SAlexander Motin return (bus_id * 2); 37840d307e09SAlexander Motin } 37850d307e09SAlexander Motin 37868b8a9b1dSJustin T. Gibbs /* 37878b8a9b1dSJustin T. Gibbs * Release a CAM control block for the caller. Remit the cost of the structure 37888b8a9b1dSJustin T. Gibbs * to the device referenced by the path. If the this device had no 'credits' 37898b8a9b1dSJustin T. Gibbs * and peripheral drivers have registered async callbacks for this notification 37908b8a9b1dSJustin T. Gibbs * call them now. 37918b8a9b1dSJustin T. Gibbs */ 37928b8a9b1dSJustin T. Gibbs void 37938b8a9b1dSJustin T. Gibbs xpt_release_ccb(union ccb *free_ccb) 37948b8a9b1dSJustin T. Gibbs { 37958b8a9b1dSJustin T. Gibbs struct cam_ed *device; 3796227d67aaSAlexander Motin struct cam_periph *periph; 379768153f43SScott Long 3798aa872be6SMatt Jacob CAM_DEBUG_PRINT(CAM_DEBUG_XPT, ("xpt_release_ccb\n")); 3799227d67aaSAlexander Motin xpt_path_assert(free_ccb->ccb_h.path, MA_OWNED); 3800227d67aaSAlexander Motin device = free_ccb->ccb_h.path->device; 3801227d67aaSAlexander Motin periph = free_ccb->ccb_h.path->periph; 38022b83592fSScott Long 38038b8a9b1dSJustin T. Gibbs xpt_free_ccb(free_ccb); 3804227d67aaSAlexander Motin periph->periph_allocated--; 3805227d67aaSAlexander Motin cam_ccbq_release_opening(&device->ccbq); 3806227d67aaSAlexander Motin xpt_run_allocq(periph, 0); 38078b8a9b1dSJustin T. Gibbs } 38088b8a9b1dSJustin T. Gibbs 38098b8a9b1dSJustin T. Gibbs /* Functions accessed by SIM drivers */ 38108b8a9b1dSJustin T. Gibbs 381152c9ce25SScott Long static struct xpt_xport xport_default = { 381252c9ce25SScott Long .alloc_device = xpt_alloc_device_default, 381352c9ce25SScott Long .action = xpt_action_default, 381452c9ce25SScott Long .async = xpt_dev_async_default, 381552c9ce25SScott Long }; 381652c9ce25SScott Long 38178b8a9b1dSJustin T. Gibbs /* 38188b8a9b1dSJustin T. Gibbs * A sim structure, listing the SIM entry points and instance 38198b8a9b1dSJustin T. Gibbs * identification info is passed to xpt_bus_register to hook the SIM 38208b8a9b1dSJustin T. Gibbs * into the CAM framework. xpt_bus_register creates a cam_eb entry 38218b8a9b1dSJustin T. Gibbs * for this new bus and places it in the array of busses and assigns 38228b8a9b1dSJustin T. Gibbs * it a path_id. The path_id may be influenced by "hard wiring" 38238b8a9b1dSJustin T. Gibbs * information specified by the user. Once interrupt services are 382402caf36eSEdward Tomasz Napierala * available, the bus will be probed. 38258b8a9b1dSJustin T. Gibbs */ 38268b8a9b1dSJustin T. Gibbs int32_t 3827b50569b7SScott Long xpt_bus_register(struct cam_sim *sim, device_t parent, u_int32_t bus) 38288b8a9b1dSJustin T. Gibbs { 38298b8a9b1dSJustin T. Gibbs struct cam_eb *new_bus; 3830434bbf6eSJustin T. Gibbs struct cam_eb *old_bus; 38318b8a9b1dSJustin T. Gibbs struct ccb_pathinq cpi; 383283c5d981SAlexander Motin struct cam_path *path; 383352c9ce25SScott Long cam_status status; 38348b8a9b1dSJustin T. Gibbs 38352b83592fSScott Long mtx_assert(sim->mtx, MA_OWNED); 383668153f43SScott Long 38378b8a9b1dSJustin T. Gibbs sim->bus_id = bus; 38388b8a9b1dSJustin T. Gibbs new_bus = (struct cam_eb *)malloc(sizeof(*new_bus), 3839227d67aaSAlexander Motin M_CAMXPT, M_NOWAIT|M_ZERO); 38408b8a9b1dSJustin T. Gibbs if (new_bus == NULL) { 38418b8a9b1dSJustin T. Gibbs /* Couldn't satisfy request */ 38428b8a9b1dSJustin T. Gibbs return (CAM_RESRC_UNAVAIL); 38438b8a9b1dSJustin T. Gibbs } 38448b8a9b1dSJustin T. Gibbs 3845227d67aaSAlexander Motin mtx_init(&new_bus->eb_mtx, "CAM bus lock", NULL, MTX_DEF); 3846434bbf6eSJustin T. Gibbs TAILQ_INIT(&new_bus->et_entries); 3847fa6099fdSEdward Tomasz Napierala cam_sim_hold(sim); 38488b8a9b1dSJustin T. Gibbs new_bus->sim = sim; 384987cfaf0eSJustin T. Gibbs timevalclear(&new_bus->last_reset); 3850434bbf6eSJustin T. Gibbs new_bus->flags = 0; 3851a5479bc5SJustin T. Gibbs new_bus->refcount = 1; /* Held until a bus_deregister event */ 3852434bbf6eSJustin T. Gibbs new_bus->generation = 0; 385352c9ce25SScott Long 38549a7c2696SAlexander Motin xpt_lock_buses(); 38556dfc67e3SAlexander Motin sim->path_id = new_bus->path_id = 38566dfc67e3SAlexander Motin xptpathid(sim->sim_name, sim->unit_number, sim->bus_id); 38572b83592fSScott Long old_bus = TAILQ_FIRST(&xsoftc.xpt_busses); 3858434bbf6eSJustin T. Gibbs while (old_bus != NULL 3859434bbf6eSJustin T. Gibbs && old_bus->path_id < new_bus->path_id) 3860434bbf6eSJustin T. Gibbs old_bus = TAILQ_NEXT(old_bus, links); 3861434bbf6eSJustin T. Gibbs if (old_bus != NULL) 3862434bbf6eSJustin T. Gibbs TAILQ_INSERT_BEFORE(old_bus, new_bus, links); 3863434bbf6eSJustin T. Gibbs else 38642b83592fSScott Long TAILQ_INSERT_TAIL(&xsoftc.xpt_busses, new_bus, links); 38652b83592fSScott Long xsoftc.bus_generation++; 38669a7c2696SAlexander Motin xpt_unlock_buses(); 38678b8a9b1dSJustin T. Gibbs 386852c9ce25SScott Long /* 386952c9ce25SScott Long * Set a default transport so that a PATH_INQ can be issued to 387052c9ce25SScott Long * the SIM. This will then allow for probing and attaching of 387152c9ce25SScott Long * a more appropriate transport. 387252c9ce25SScott Long */ 387352c9ce25SScott Long new_bus->xport = &xport_default; 38748b8a9b1dSJustin T. Gibbs 387532aa80a6SAlexander Motin status = xpt_create_path(&path, /*periph*/NULL, sim->path_id, 38768b8a9b1dSJustin T. Gibbs CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD); 3877627995dcSAlexander Motin if (status != CAM_REQ_CMP) { 3878627995dcSAlexander Motin xpt_release_bus(new_bus); 3879627995dcSAlexander Motin free(path, M_CAMXPT); 3880627995dcSAlexander Motin return (CAM_RESRC_UNAVAIL); 3881627995dcSAlexander Motin } 388252c9ce25SScott Long 388383c5d981SAlexander Motin xpt_setup_ccb(&cpi.ccb_h, path, CAM_PRIORITY_NORMAL); 38848b8a9b1dSJustin T. Gibbs cpi.ccb_h.func_code = XPT_PATH_INQ; 38858b8a9b1dSJustin T. Gibbs xpt_action((union ccb *)&cpi); 388652c9ce25SScott Long 388752c9ce25SScott Long if (cpi.ccb_h.status == CAM_REQ_CMP) { 388852c9ce25SScott Long switch (cpi.transport) { 388952c9ce25SScott Long case XPORT_SPI: 389052c9ce25SScott Long case XPORT_SAS: 389152c9ce25SScott Long case XPORT_FC: 389252c9ce25SScott Long case XPORT_USB: 389333ea30feSAlexander Motin case XPORT_ISCSI: 3894b5595753SNathan Whitehorn case XPORT_SRP: 389533ea30feSAlexander Motin case XPORT_PPB: 389652c9ce25SScott Long new_bus->xport = scsi_get_xport(); 389752c9ce25SScott Long break; 389852c9ce25SScott Long case XPORT_ATA: 389952c9ce25SScott Long case XPORT_SATA: 390052c9ce25SScott Long new_bus->xport = ata_get_xport(); 390152c9ce25SScott Long break; 390252c9ce25SScott Long default: 390352c9ce25SScott Long new_bus->xport = &xport_default; 390452c9ce25SScott Long break; 39058b8a9b1dSJustin T. Gibbs } 390652c9ce25SScott Long } 390752c9ce25SScott Long 390852c9ce25SScott Long /* Notify interested parties */ 390952c9ce25SScott Long if (sim->path_id != CAM_XPT_PATH_ID) { 391083c5d981SAlexander Motin 391183c5d981SAlexander Motin xpt_async(AC_PATH_REGISTERED, path, &cpi); 3912b01773b0SKenneth D. Merry if ((cpi.hba_misc & PIM_NOSCAN) == 0) { 3913b01773b0SKenneth D. Merry union ccb *scan_ccb; 3914b01773b0SKenneth D. Merry 391583c5d981SAlexander Motin /* Initiate bus rescan. */ 391683c5d981SAlexander Motin scan_ccb = xpt_alloc_ccb_nowait(); 3917e5736ac8SAlexander Motin if (scan_ccb != NULL) { 391883c5d981SAlexander Motin scan_ccb->ccb_h.path = path; 391983c5d981SAlexander Motin scan_ccb->ccb_h.func_code = XPT_SCAN_BUS; 392083c5d981SAlexander Motin scan_ccb->crcn.flags = 0; 392183c5d981SAlexander Motin xpt_rescan(scan_ccb); 392283c5d981SAlexander Motin } else 3923b01773b0SKenneth D. Merry xpt_print(path, 3924b01773b0SKenneth D. Merry "Can't allocate CCB to scan bus\n"); 3925b01773b0SKenneth D. Merry } else 3926b01773b0SKenneth D. Merry xpt_free_path(path); 3927e5736ac8SAlexander Motin } else 392883c5d981SAlexander Motin xpt_free_path(path); 39298b8a9b1dSJustin T. Gibbs return (CAM_SUCCESS); 39308b8a9b1dSJustin T. Gibbs } 39318b8a9b1dSJustin T. Gibbs 3932434bbf6eSJustin T. Gibbs int32_t 3933434bbf6eSJustin T. Gibbs xpt_bus_deregister(path_id_t pathid) 39348b8a9b1dSJustin T. Gibbs { 3935434bbf6eSJustin T. Gibbs struct cam_path bus_path; 3936434bbf6eSJustin T. Gibbs cam_status status; 3937434bbf6eSJustin T. Gibbs 3938434bbf6eSJustin T. Gibbs status = xpt_compile_path(&bus_path, NULL, pathid, 3939434bbf6eSJustin T. Gibbs CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD); 3940434bbf6eSJustin T. Gibbs if (status != CAM_REQ_CMP) 3941434bbf6eSJustin T. Gibbs return (status); 3942434bbf6eSJustin T. Gibbs 3943434bbf6eSJustin T. Gibbs xpt_async(AC_LOST_DEVICE, &bus_path, NULL); 3944434bbf6eSJustin T. Gibbs xpt_async(AC_PATH_DEREGISTERED, &bus_path, NULL); 3945434bbf6eSJustin T. Gibbs 3946434bbf6eSJustin T. Gibbs /* Release the reference count held while registered. */ 3947434bbf6eSJustin T. Gibbs xpt_release_bus(bus_path.bus); 3948434bbf6eSJustin T. Gibbs xpt_release_path(&bus_path); 3949434bbf6eSJustin T. Gibbs 3950434bbf6eSJustin T. Gibbs return (CAM_REQ_CMP); 3951434bbf6eSJustin T. Gibbs } 3952434bbf6eSJustin T. Gibbs 3953434bbf6eSJustin T. Gibbs static path_id_t 3954434bbf6eSJustin T. Gibbs xptnextfreepathid(void) 3955434bbf6eSJustin T. Gibbs { 3956434bbf6eSJustin T. Gibbs struct cam_eb *bus; 3957434bbf6eSJustin T. Gibbs path_id_t pathid; 39582398f0cdSPeter Wemm const char *strval; 39598b8a9b1dSJustin T. Gibbs 39606dfc67e3SAlexander Motin mtx_assert(&xsoftc.xpt_topo_lock, MA_OWNED); 3961434bbf6eSJustin T. Gibbs pathid = 0; 39622b83592fSScott Long bus = TAILQ_FIRST(&xsoftc.xpt_busses); 3963434bbf6eSJustin T. Gibbs retry: 3964434bbf6eSJustin T. Gibbs /* Find an unoccupied pathid */ 39659e6461a2SMatt Jacob while (bus != NULL && bus->path_id <= pathid) { 3966434bbf6eSJustin T. Gibbs if (bus->path_id == pathid) 3967434bbf6eSJustin T. Gibbs pathid++; 3968434bbf6eSJustin T. Gibbs bus = TAILQ_NEXT(bus, links); 3969434bbf6eSJustin T. Gibbs } 3970434bbf6eSJustin T. Gibbs 3971434bbf6eSJustin T. Gibbs /* 3972434bbf6eSJustin T. Gibbs * Ensure that this pathid is not reserved for 3973434bbf6eSJustin T. Gibbs * a bus that may be registered in the future. 3974434bbf6eSJustin T. Gibbs */ 397575f51904SPeter Wemm if (resource_string_value("scbus", pathid, "at", &strval) == 0) { 3976434bbf6eSJustin T. Gibbs ++pathid; 39778b8a9b1dSJustin T. Gibbs /* Start the search over */ 3978434bbf6eSJustin T. Gibbs goto retry; 39798b8a9b1dSJustin T. Gibbs } 3980434bbf6eSJustin T. Gibbs return (pathid); 39818b8a9b1dSJustin T. Gibbs } 39828b8a9b1dSJustin T. Gibbs 3983434bbf6eSJustin T. Gibbs static path_id_t 3984434bbf6eSJustin T. Gibbs xptpathid(const char *sim_name, int sim_unit, int sim_bus) 39858b8a9b1dSJustin T. Gibbs { 39868b8a9b1dSJustin T. Gibbs path_id_t pathid; 398775f51904SPeter Wemm int i, dunit, val; 3988642f0c46SPeter Wemm char buf[32]; 39892398f0cdSPeter Wemm const char *dname; 39908b8a9b1dSJustin T. Gibbs 39918b8a9b1dSJustin T. Gibbs pathid = CAM_XPT_PATH_ID; 399275f51904SPeter Wemm snprintf(buf, sizeof(buf), "%s%d", sim_name, sim_unit); 39936dfc67e3SAlexander Motin if (strcmp(buf, "xpt0") == 0 && sim_bus == 0) 39946dfc67e3SAlexander Motin return (pathid); 39952398f0cdSPeter Wemm i = 0; 39962398f0cdSPeter Wemm while ((resource_find_match(&i, &dname, &dunit, "at", buf)) == 0) { 39972398f0cdSPeter Wemm if (strcmp(dname, "scbus")) { 3998642f0c46SPeter Wemm /* Avoid a bit of foot shooting. */ 3999642f0c46SPeter Wemm continue; 4000642f0c46SPeter Wemm } 400175f51904SPeter Wemm if (dunit < 0) /* unwired?! */ 40028b8a9b1dSJustin T. Gibbs continue; 400375f51904SPeter Wemm if (resource_int_value("scbus", dunit, "bus", &val) == 0) { 400475f51904SPeter Wemm if (sim_bus == val) { 400575f51904SPeter Wemm pathid = dunit; 40068b8a9b1dSJustin T. Gibbs break; 40078b8a9b1dSJustin T. Gibbs } 40088b8a9b1dSJustin T. Gibbs } else if (sim_bus == 0) { 40098b8a9b1dSJustin T. Gibbs /* Unspecified matches bus 0 */ 401075f51904SPeter Wemm pathid = dunit; 40118b8a9b1dSJustin T. Gibbs break; 40128b8a9b1dSJustin T. Gibbs } else { 40138b8a9b1dSJustin T. Gibbs printf("Ambiguous scbus configuration for %s%d " 40148b8a9b1dSJustin T. Gibbs "bus %d, cannot wire down. The kernel " 40158b8a9b1dSJustin T. Gibbs "config entry for scbus%d should " 40168b8a9b1dSJustin T. Gibbs "specify a controller bus.\n" 40178b8a9b1dSJustin T. Gibbs "Scbus will be assigned dynamically.\n", 401875f51904SPeter Wemm sim_name, sim_unit, sim_bus, dunit); 40198b8a9b1dSJustin T. Gibbs break; 40208b8a9b1dSJustin T. Gibbs } 40218b8a9b1dSJustin T. Gibbs } 40228b8a9b1dSJustin T. Gibbs 4023434bbf6eSJustin T. Gibbs if (pathid == CAM_XPT_PATH_ID) 4024434bbf6eSJustin T. Gibbs pathid = xptnextfreepathid(); 40258b8a9b1dSJustin T. Gibbs return (pathid); 40268b8a9b1dSJustin T. Gibbs } 40278b8a9b1dSJustin T. Gibbs 402822c7d606SAlexander Motin static const char * 402922c7d606SAlexander Motin xpt_async_string(u_int32_t async_code) 403022c7d606SAlexander Motin { 403122c7d606SAlexander Motin 403222c7d606SAlexander Motin switch (async_code) { 403322c7d606SAlexander Motin case AC_BUS_RESET: return ("AC_BUS_RESET"); 403422c7d606SAlexander Motin case AC_UNSOL_RESEL: return ("AC_UNSOL_RESEL"); 403522c7d606SAlexander Motin case AC_SCSI_AEN: return ("AC_SCSI_AEN"); 403622c7d606SAlexander Motin case AC_SENT_BDR: return ("AC_SENT_BDR"); 403722c7d606SAlexander Motin case AC_PATH_REGISTERED: return ("AC_PATH_REGISTERED"); 403822c7d606SAlexander Motin case AC_PATH_DEREGISTERED: return ("AC_PATH_DEREGISTERED"); 403922c7d606SAlexander Motin case AC_FOUND_DEVICE: return ("AC_FOUND_DEVICE"); 404022c7d606SAlexander Motin case AC_LOST_DEVICE: return ("AC_LOST_DEVICE"); 404122c7d606SAlexander Motin case AC_TRANSFER_NEG: return ("AC_TRANSFER_NEG"); 404222c7d606SAlexander Motin case AC_INQ_CHANGED: return ("AC_INQ_CHANGED"); 404322c7d606SAlexander Motin case AC_GETDEV_CHANGED: return ("AC_GETDEV_CHANGED"); 404422c7d606SAlexander Motin case AC_CONTRACT: return ("AC_CONTRACT"); 404522c7d606SAlexander Motin case AC_ADVINFO_CHANGED: return ("AC_ADVINFO_CHANGED"); 40463631c638SAlexander Motin case AC_UNIT_ATTENTION: return ("AC_UNIT_ATTENTION"); 404722c7d606SAlexander Motin } 404822c7d606SAlexander Motin return ("AC_UNKNOWN"); 404922c7d606SAlexander Motin } 405022c7d606SAlexander Motin 4051227d67aaSAlexander Motin static int 4052227d67aaSAlexander Motin xpt_async_size(u_int32_t async_code) 40538b8a9b1dSJustin T. Gibbs { 40548b8a9b1dSJustin T. Gibbs 4055227d67aaSAlexander Motin switch (async_code) { 4056227d67aaSAlexander Motin case AC_BUS_RESET: return (0); 4057227d67aaSAlexander Motin case AC_UNSOL_RESEL: return (0); 4058227d67aaSAlexander Motin case AC_SCSI_AEN: return (0); 4059227d67aaSAlexander Motin case AC_SENT_BDR: return (0); 4060227d67aaSAlexander Motin case AC_PATH_REGISTERED: return (sizeof(struct ccb_pathinq)); 4061227d67aaSAlexander Motin case AC_PATH_DEREGISTERED: return (0); 4062227d67aaSAlexander Motin case AC_FOUND_DEVICE: return (sizeof(struct ccb_getdev)); 4063227d67aaSAlexander Motin case AC_LOST_DEVICE: return (0); 4064227d67aaSAlexander Motin case AC_TRANSFER_NEG: return (sizeof(struct ccb_trans_settings)); 4065227d67aaSAlexander Motin case AC_INQ_CHANGED: return (0); 4066227d67aaSAlexander Motin case AC_GETDEV_CHANGED: return (0); 4067227d67aaSAlexander Motin case AC_CONTRACT: return (sizeof(struct ac_contract)); 4068227d67aaSAlexander Motin case AC_ADVINFO_CHANGED: return (-1); 4069227d67aaSAlexander Motin case AC_UNIT_ATTENTION: return (sizeof(struct ccb_scsiio)); 4070227d67aaSAlexander Motin } 4071227d67aaSAlexander Motin return (0); 4072227d67aaSAlexander Motin } 4073227d67aaSAlexander Motin 4074227d67aaSAlexander Motin static int 4075227d67aaSAlexander Motin xpt_async_process_dev(struct cam_ed *device, void *arg) 4076227d67aaSAlexander Motin { 4077227d67aaSAlexander Motin union ccb *ccb = arg; 4078227d67aaSAlexander Motin struct cam_path *path = ccb->ccb_h.path; 4079227d67aaSAlexander Motin void *async_arg = ccb->casync.async_arg_ptr; 4080227d67aaSAlexander Motin u_int32_t async_code = ccb->casync.async_code; 4081227d67aaSAlexander Motin int relock; 4082227d67aaSAlexander Motin 4083227d67aaSAlexander Motin if (path->device != device 4084227d67aaSAlexander Motin && path->device->lun_id != CAM_LUN_WILDCARD 4085227d67aaSAlexander Motin && device->lun_id != CAM_LUN_WILDCARD) 4086227d67aaSAlexander Motin return (1); 40878b8a9b1dSJustin T. Gibbs 4088a5479bc5SJustin T. Gibbs /* 4089227d67aaSAlexander Motin * The async callback could free the device. 4090227d67aaSAlexander Motin * If it is a broadcast async, it doesn't hold 4091227d67aaSAlexander Motin * device reference, so take our own reference. 4092a5479bc5SJustin T. Gibbs */ 4093227d67aaSAlexander Motin xpt_acquire_device(device); 40948b8a9b1dSJustin T. Gibbs 4095227d67aaSAlexander Motin /* 4096227d67aaSAlexander Motin * If async for specific device is to be delivered to 4097227d67aaSAlexander Motin * the wildcard client, take the specific device lock. 4098227d67aaSAlexander Motin * XXX: We may need a way for client to specify it. 4099227d67aaSAlexander Motin */ 4100227d67aaSAlexander Motin if ((device->lun_id == CAM_LUN_WILDCARD && 4101227d67aaSAlexander Motin path->device->lun_id != CAM_LUN_WILDCARD) || 4102227d67aaSAlexander Motin (device->target->target_id == CAM_TARGET_WILDCARD && 4103227d67aaSAlexander Motin path->target->target_id != CAM_TARGET_WILDCARD) || 4104227d67aaSAlexander Motin (device->target->bus->path_id == CAM_BUS_WILDCARD && 4105227d67aaSAlexander Motin path->target->bus->path_id != CAM_BUS_WILDCARD)) { 4106227d67aaSAlexander Motin mtx_unlock(&device->device_mtx); 4107227d67aaSAlexander Motin xpt_path_lock(path); 4108227d67aaSAlexander Motin relock = 1; 4109227d67aaSAlexander Motin } else 4110227d67aaSAlexander Motin relock = 0; 4111227d67aaSAlexander Motin 4112227d67aaSAlexander Motin (*(device->target->bus->xport->async))(async_code, 4113227d67aaSAlexander Motin device->target->bus, device->target, device, async_arg); 4114227d67aaSAlexander Motin xpt_async_bcast(&device->asyncs, async_code, path, async_arg); 4115227d67aaSAlexander Motin 4116227d67aaSAlexander Motin if (relock) { 4117227d67aaSAlexander Motin xpt_path_unlock(path); 4118227d67aaSAlexander Motin mtx_lock(&device->device_mtx); 4119227d67aaSAlexander Motin } 4120227d67aaSAlexander Motin xpt_release_device(device); 4121227d67aaSAlexander Motin return (1); 4122227d67aaSAlexander Motin } 4123227d67aaSAlexander Motin 4124227d67aaSAlexander Motin static int 4125227d67aaSAlexander Motin xpt_async_process_tgt(struct cam_et *target, void *arg) 4126227d67aaSAlexander Motin { 4127227d67aaSAlexander Motin union ccb *ccb = arg; 4128227d67aaSAlexander Motin struct cam_path *path = ccb->ccb_h.path; 4129227d67aaSAlexander Motin 4130227d67aaSAlexander Motin if (path->target != target 4131227d67aaSAlexander Motin && path->target->target_id != CAM_TARGET_WILDCARD 4132227d67aaSAlexander Motin && target->target_id != CAM_TARGET_WILDCARD) 4133227d67aaSAlexander Motin return (1); 4134227d67aaSAlexander Motin 4135227d67aaSAlexander Motin if (ccb->casync.async_code == AC_SENT_BDR) { 4136227d67aaSAlexander Motin /* Update our notion of when the last reset occurred */ 4137227d67aaSAlexander Motin microtime(&target->last_reset); 4138227d67aaSAlexander Motin } 4139227d67aaSAlexander Motin 4140227d67aaSAlexander Motin return (xptdevicetraverse(target, NULL, xpt_async_process_dev, ccb)); 4141227d67aaSAlexander Motin } 4142227d67aaSAlexander Motin 4143227d67aaSAlexander Motin static void 4144227d67aaSAlexander Motin xpt_async_process(struct cam_periph *periph, union ccb *ccb) 4145227d67aaSAlexander Motin { 4146227d67aaSAlexander Motin struct cam_eb *bus; 4147227d67aaSAlexander Motin struct cam_path *path; 4148227d67aaSAlexander Motin void *async_arg; 4149227d67aaSAlexander Motin u_int32_t async_code; 4150227d67aaSAlexander Motin 4151227d67aaSAlexander Motin path = ccb->ccb_h.path; 4152227d67aaSAlexander Motin async_code = ccb->casync.async_code; 4153227d67aaSAlexander Motin async_arg = ccb->casync.async_arg_ptr; 4154227d67aaSAlexander Motin CAM_DEBUG(path, CAM_DEBUG_TRACE | CAM_DEBUG_INFO, 4155227d67aaSAlexander Motin ("xpt_async(%s)\n", xpt_async_string(async_code))); 41568b8a9b1dSJustin T. Gibbs bus = path->bus; 41578b8a9b1dSJustin T. Gibbs 41588b8a9b1dSJustin T. Gibbs if (async_code == AC_BUS_RESET) { 415987cfaf0eSJustin T. Gibbs /* Update our notion of when the last reset occurred */ 416087cfaf0eSJustin T. Gibbs microtime(&bus->last_reset); 41618b8a9b1dSJustin T. Gibbs } 41628b8a9b1dSJustin T. Gibbs 4163227d67aaSAlexander Motin xpttargettraverse(bus, NULL, xpt_async_process_tgt, ccb); 4164c8bead2aSJustin T. Gibbs 4165c8bead2aSJustin T. Gibbs /* 4166c8bead2aSJustin T. Gibbs * If this wasn't a fully wildcarded async, tell all 4167c8bead2aSJustin T. Gibbs * clients that want all async events. 4168c8bead2aSJustin T. Gibbs */ 4169227d67aaSAlexander Motin if (bus != xpt_periph->path->bus) { 4170227d67aaSAlexander Motin xpt_path_lock(xpt_periph->path); 4171227d67aaSAlexander Motin xpt_async_process_dev(xpt_periph->path->device, ccb); 4172227d67aaSAlexander Motin xpt_path_unlock(xpt_periph->path); 4173227d67aaSAlexander Motin } 4174227d67aaSAlexander Motin 4175227d67aaSAlexander Motin if (path->device != NULL && path->device->lun_id != CAM_LUN_WILDCARD) 4176227d67aaSAlexander Motin xpt_release_devq(path, 1, TRUE); 4177227d67aaSAlexander Motin else 4178227d67aaSAlexander Motin xpt_release_simq(path->bus->sim, TRUE); 4179227d67aaSAlexander Motin if (ccb->casync.async_arg_size > 0) 4180227d67aaSAlexander Motin free(async_arg, M_CAMXPT); 4181227d67aaSAlexander Motin xpt_free_path(path); 4182227d67aaSAlexander Motin xpt_free_ccb(ccb); 41838b8a9b1dSJustin T. Gibbs } 41848b8a9b1dSJustin T. Gibbs 41858b8a9b1dSJustin T. Gibbs static void 41868b8a9b1dSJustin T. Gibbs xpt_async_bcast(struct async_list *async_head, 41878b8a9b1dSJustin T. Gibbs u_int32_t async_code, 41888b8a9b1dSJustin T. Gibbs struct cam_path *path, void *async_arg) 41898b8a9b1dSJustin T. Gibbs { 41908b8a9b1dSJustin T. Gibbs struct async_node *cur_entry; 4191227d67aaSAlexander Motin int lock; 41928b8a9b1dSJustin T. Gibbs 41938b8a9b1dSJustin T. Gibbs cur_entry = SLIST_FIRST(async_head); 41948b8a9b1dSJustin T. Gibbs while (cur_entry != NULL) { 41958b8a9b1dSJustin T. Gibbs struct async_node *next_entry; 41968b8a9b1dSJustin T. Gibbs /* 41978b8a9b1dSJustin T. Gibbs * Grab the next list entry before we call the current 41988b8a9b1dSJustin T. Gibbs * entry's callback. This is because the callback function 41998b8a9b1dSJustin T. Gibbs * can delete its async callback entry. 42008b8a9b1dSJustin T. Gibbs */ 42018b8a9b1dSJustin T. Gibbs next_entry = SLIST_NEXT(cur_entry, links); 4202227d67aaSAlexander Motin if ((cur_entry->event_enable & async_code) != 0) { 4203227d67aaSAlexander Motin lock = cur_entry->event_lock; 4204227d67aaSAlexander Motin if (lock) 4205227d67aaSAlexander Motin CAM_SIM_LOCK(path->device->sim); 42068b8a9b1dSJustin T. Gibbs cur_entry->callback(cur_entry->callback_arg, 42078b8a9b1dSJustin T. Gibbs async_code, path, 42088b8a9b1dSJustin T. Gibbs async_arg); 4209227d67aaSAlexander Motin if (lock) 4210227d67aaSAlexander Motin CAM_SIM_UNLOCK(path->device->sim); 4211227d67aaSAlexander Motin } 42128b8a9b1dSJustin T. Gibbs cur_entry = next_entry; 42138b8a9b1dSJustin T. Gibbs } 42148b8a9b1dSJustin T. Gibbs } 42158b8a9b1dSJustin T. Gibbs 4216227d67aaSAlexander Motin void 4217227d67aaSAlexander Motin xpt_async(u_int32_t async_code, struct cam_path *path, void *async_arg) 4218227d67aaSAlexander Motin { 4219227d67aaSAlexander Motin union ccb *ccb; 4220227d67aaSAlexander Motin int size; 4221227d67aaSAlexander Motin 4222227d67aaSAlexander Motin ccb = xpt_alloc_ccb_nowait(); 4223227d67aaSAlexander Motin if (ccb == NULL) { 4224227d67aaSAlexander Motin xpt_print(path, "Can't allocate CCB to send %s\n", 4225227d67aaSAlexander Motin xpt_async_string(async_code)); 4226227d67aaSAlexander Motin return; 4227227d67aaSAlexander Motin } 4228227d67aaSAlexander Motin 4229227d67aaSAlexander Motin if (xpt_clone_path(&ccb->ccb_h.path, path) != CAM_REQ_CMP) { 4230227d67aaSAlexander Motin xpt_print(path, "Can't allocate path to send %s\n", 4231227d67aaSAlexander Motin xpt_async_string(async_code)); 4232227d67aaSAlexander Motin xpt_free_ccb(ccb); 4233227d67aaSAlexander Motin return; 4234227d67aaSAlexander Motin } 4235227d67aaSAlexander Motin ccb->ccb_h.path->periph = NULL; 4236227d67aaSAlexander Motin ccb->ccb_h.func_code = XPT_ASYNC; 4237227d67aaSAlexander Motin ccb->ccb_h.cbfcnp = xpt_async_process; 4238227d67aaSAlexander Motin ccb->ccb_h.flags |= CAM_UNLOCKED; 4239227d67aaSAlexander Motin ccb->casync.async_code = async_code; 4240227d67aaSAlexander Motin ccb->casync.async_arg_size = 0; 4241227d67aaSAlexander Motin size = xpt_async_size(async_code); 4242227d67aaSAlexander Motin if (size > 0 && async_arg != NULL) { 4243227d67aaSAlexander Motin ccb->casync.async_arg_ptr = malloc(size, M_CAMXPT, M_NOWAIT); 4244227d67aaSAlexander Motin if (ccb->casync.async_arg_ptr == NULL) { 4245227d67aaSAlexander Motin xpt_print(path, "Can't allocate argument to send %s\n", 4246227d67aaSAlexander Motin xpt_async_string(async_code)); 4247227d67aaSAlexander Motin xpt_free_path(ccb->ccb_h.path); 4248227d67aaSAlexander Motin xpt_free_ccb(ccb); 4249227d67aaSAlexander Motin return; 4250227d67aaSAlexander Motin } 4251227d67aaSAlexander Motin memcpy(ccb->casync.async_arg_ptr, async_arg, size); 4252227d67aaSAlexander Motin ccb->casync.async_arg_size = size; 4253227d67aaSAlexander Motin } else if (size < 0) 4254227d67aaSAlexander Motin ccb->casync.async_arg_size = size; 4255227d67aaSAlexander Motin if (path->device != NULL && path->device->lun_id != CAM_LUN_WILDCARD) 4256227d67aaSAlexander Motin xpt_freeze_devq(path, 1); 4257227d67aaSAlexander Motin else 4258227d67aaSAlexander Motin xpt_freeze_simq(path->bus->sim, 1); 4259227d67aaSAlexander Motin xpt_done(ccb); 4260227d67aaSAlexander Motin } 4261227d67aaSAlexander Motin 42622f22d08dSJustin T. Gibbs static void 426352c9ce25SScott Long xpt_dev_async_default(u_int32_t async_code, struct cam_eb *bus, 426452c9ce25SScott Long struct cam_et *target, struct cam_ed *device, 426552c9ce25SScott Long void *async_arg) 42662f22d08dSJustin T. Gibbs { 4267227d67aaSAlexander Motin 4268227d67aaSAlexander Motin /* 4269227d67aaSAlexander Motin * We only need to handle events for real devices. 4270227d67aaSAlexander Motin */ 4271227d67aaSAlexander Motin if (target->target_id == CAM_TARGET_WILDCARD 4272227d67aaSAlexander Motin || device->lun_id == CAM_LUN_WILDCARD) 4273227d67aaSAlexander Motin return; 4274227d67aaSAlexander Motin 4275b882a6d3SMatt Jacob printf("%s called\n", __func__); 42762f22d08dSJustin T. Gibbs } 42772f22d08dSJustin T. Gibbs 4278daa5487fSAlexander Motin static uint32_t 4279daa5487fSAlexander Motin xpt_freeze_devq_device(struct cam_ed *dev, u_int count) 4280daa5487fSAlexander Motin { 4281daa5487fSAlexander Motin struct cam_devq *devq; 4282daa5487fSAlexander Motin uint32_t freeze; 4283daa5487fSAlexander Motin 4284daa5487fSAlexander Motin devq = dev->sim->devq; 4285daa5487fSAlexander Motin mtx_assert(&devq->send_mtx, MA_OWNED); 4286daa5487fSAlexander Motin CAM_DEBUG_DEV(dev, CAM_DEBUG_TRACE, 4287daa5487fSAlexander Motin ("xpt_freeze_devq_device(%d) %u->%u\n", count, 4288daa5487fSAlexander Motin dev->ccbq.queue.qfrozen_cnt, dev->ccbq.queue.qfrozen_cnt + count)); 4289daa5487fSAlexander Motin freeze = (dev->ccbq.queue.qfrozen_cnt += count); 4290daa5487fSAlexander Motin /* Remove frozen device from sendq. */ 4291daa5487fSAlexander Motin if (device_is_queued(dev)) 4292daa5487fSAlexander Motin camq_remove(&devq->send_queue, dev->devq_entry.index); 4293daa5487fSAlexander Motin return (freeze); 4294daa5487fSAlexander Motin } 4295daa5487fSAlexander Motin 42968b8a9b1dSJustin T. Gibbs u_int32_t 4297cccf4220SAlexander Motin xpt_freeze_devq(struct cam_path *path, u_int count) 429883c5d981SAlexander Motin { 429983c5d981SAlexander Motin struct cam_ed *dev = path->device; 4300227d67aaSAlexander Motin struct cam_devq *devq; 4301227d67aaSAlexander Motin uint32_t freeze; 430283c5d981SAlexander Motin 4303227d67aaSAlexander Motin devq = dev->sim->devq; 4304227d67aaSAlexander Motin mtx_lock(&devq->send_mtx); 4305daa5487fSAlexander Motin CAM_DEBUG(path, CAM_DEBUG_TRACE, ("xpt_freeze_devq(%d)\n", count)); 4306daa5487fSAlexander Motin freeze = xpt_freeze_devq_device(dev, count); 4307227d67aaSAlexander Motin mtx_unlock(&devq->send_mtx); 4308227d67aaSAlexander Motin return (freeze); 43098b8a9b1dSJustin T. Gibbs } 43108b8a9b1dSJustin T. Gibbs 43118b8a9b1dSJustin T. Gibbs u_int32_t 43128b8a9b1dSJustin T. Gibbs xpt_freeze_simq(struct cam_sim *sim, u_int count) 43138b8a9b1dSJustin T. Gibbs { 4314227d67aaSAlexander Motin struct cam_devq *devq; 4315227d67aaSAlexander Motin uint32_t freeze; 4316ec700f26SAlexander Motin 4317227d67aaSAlexander Motin devq = sim->devq; 4318227d67aaSAlexander Motin mtx_lock(&devq->send_mtx); 4319227d67aaSAlexander Motin freeze = (devq->send_queue.qfrozen_cnt += count); 4320227d67aaSAlexander Motin mtx_unlock(&devq->send_mtx); 4321227d67aaSAlexander Motin return (freeze); 43228b8a9b1dSJustin T. Gibbs } 43238b8a9b1dSJustin T. Gibbs 43248b8a9b1dSJustin T. Gibbs static void 43258b8a9b1dSJustin T. Gibbs xpt_release_devq_timeout(void *arg) 43268b8a9b1dSJustin T. Gibbs { 4327227d67aaSAlexander Motin struct cam_ed *dev; 4328227d67aaSAlexander Motin struct cam_devq *devq; 43298b8a9b1dSJustin T. Gibbs 4330227d67aaSAlexander Motin dev = (struct cam_ed *)arg; 4331227d67aaSAlexander Motin CAM_DEBUG_DEV(dev, CAM_DEBUG_TRACE, ("xpt_release_devq_timeout\n")); 4332227d67aaSAlexander Motin devq = dev->sim->devq; 4333227d67aaSAlexander Motin mtx_assert(&devq->send_mtx, MA_OWNED); 4334227d67aaSAlexander Motin if (xpt_release_devq_device(dev, /*count*/1, /*run_queue*/TRUE)) 4335227d67aaSAlexander Motin xpt_run_devq(devq); 43368b8a9b1dSJustin T. Gibbs } 43378b8a9b1dSJustin T. Gibbs 43388b8a9b1dSJustin T. Gibbs void 43392cefde5fSJustin T. Gibbs xpt_release_devq(struct cam_path *path, u_int count, int run_queue) 43402cefde5fSJustin T. Gibbs { 4341227d67aaSAlexander Motin struct cam_ed *dev; 4342227d67aaSAlexander Motin struct cam_devq *devq; 434368153f43SScott Long 43440d4f3c31SAlexander Motin CAM_DEBUG(path, CAM_DEBUG_TRACE, ("xpt_release_devq(%d, %d)\n", 43450d4f3c31SAlexander Motin count, run_queue)); 4346227d67aaSAlexander Motin dev = path->device; 4347227d67aaSAlexander Motin devq = dev->sim->devq; 4348227d67aaSAlexander Motin mtx_lock(&devq->send_mtx); 4349227d67aaSAlexander Motin if (xpt_release_devq_device(dev, count, run_queue)) 4350227d67aaSAlexander Motin xpt_run_devq(dev->sim->devq); 4351227d67aaSAlexander Motin mtx_unlock(&devq->send_mtx); 435283c5d981SAlexander Motin } 435383c5d981SAlexander Motin 4354227d67aaSAlexander Motin static int 4355cccf4220SAlexander Motin xpt_release_devq_device(struct cam_ed *dev, u_int count, int run_queue) 43568b8a9b1dSJustin T. Gibbs { 43578b8a9b1dSJustin T. Gibbs 4358227d67aaSAlexander Motin mtx_assert(&dev->sim->devq->send_mtx, MA_OWNED); 43590d4f3c31SAlexander Motin CAM_DEBUG_DEV(dev, CAM_DEBUG_TRACE, 43600d4f3c31SAlexander Motin ("xpt_release_devq_device(%d, %d) %u->%u\n", count, run_queue, 43610d4f3c31SAlexander Motin dev->ccbq.queue.qfrozen_cnt, dev->ccbq.queue.qfrozen_cnt - count)); 4362cccf4220SAlexander Motin if (count > dev->ccbq.queue.qfrozen_cnt) { 436383c5d981SAlexander Motin #ifdef INVARIANTS 4364cccf4220SAlexander Motin printf("xpt_release_devq(): requested %u > present %u\n", 4365cccf4220SAlexander Motin count, dev->ccbq.queue.qfrozen_cnt); 436683c5d981SAlexander Motin #endif 4367cccf4220SAlexander Motin count = dev->ccbq.queue.qfrozen_cnt; 436883c5d981SAlexander Motin } 4369cccf4220SAlexander Motin dev->ccbq.queue.qfrozen_cnt -= count; 4370cccf4220SAlexander Motin if (dev->ccbq.queue.qfrozen_cnt == 0) { 43718b8a9b1dSJustin T. Gibbs /* 43728b8a9b1dSJustin T. Gibbs * No longer need to wait for a successful 43738b8a9b1dSJustin T. Gibbs * command completion. 43748b8a9b1dSJustin T. Gibbs */ 43758b8a9b1dSJustin T. Gibbs dev->flags &= ~CAM_DEV_REL_ON_COMPLETE; 43768b8a9b1dSJustin T. Gibbs /* 43778b8a9b1dSJustin T. Gibbs * Remove any timeouts that might be scheduled 43788b8a9b1dSJustin T. Gibbs * to release this queue. 43798b8a9b1dSJustin T. Gibbs */ 43808b8a9b1dSJustin T. Gibbs if ((dev->flags & CAM_DEV_REL_TIMEOUT_PENDING) != 0) { 43812b83592fSScott Long callout_stop(&dev->callout); 43828b8a9b1dSJustin T. Gibbs dev->flags &= ~CAM_DEV_REL_TIMEOUT_PENDING; 43838b8a9b1dSJustin T. Gibbs } 43848b8a9b1dSJustin T. Gibbs /* 43858b8a9b1dSJustin T. Gibbs * Now that we are unfrozen schedule the 43868b8a9b1dSJustin T. Gibbs * device so any pending transactions are 43878b8a9b1dSJustin T. Gibbs * run. 43888b8a9b1dSJustin T. Gibbs */ 4389227d67aaSAlexander Motin xpt_schedule_devq(dev->sim->devq, dev); 4390227d67aaSAlexander Motin } else 4391227d67aaSAlexander Motin run_queue = 0; 4392227d67aaSAlexander Motin return (run_queue); 439383c5d981SAlexander Motin } 43948b8a9b1dSJustin T. Gibbs 43958b8a9b1dSJustin T. Gibbs void 43968b8a9b1dSJustin T. Gibbs xpt_release_simq(struct cam_sim *sim, int run_queue) 43978b8a9b1dSJustin T. Gibbs { 4398227d67aaSAlexander Motin struct cam_devq *devq; 43998b8a9b1dSJustin T. Gibbs 4400227d67aaSAlexander Motin devq = sim->devq; 4401227d67aaSAlexander Motin mtx_lock(&devq->send_mtx); 4402227d67aaSAlexander Motin if (devq->send_queue.qfrozen_cnt <= 0) { 440383c5d981SAlexander Motin #ifdef INVARIANTS 440483c5d981SAlexander Motin printf("xpt_release_simq: requested 1 > present %u\n", 4405227d67aaSAlexander Motin devq->send_queue.qfrozen_cnt); 440683c5d981SAlexander Motin #endif 440783c5d981SAlexander Motin } else 4408227d67aaSAlexander Motin devq->send_queue.qfrozen_cnt--; 4409227d67aaSAlexander Motin if (devq->send_queue.qfrozen_cnt == 0) { 44108b8a9b1dSJustin T. Gibbs /* 44118b8a9b1dSJustin T. Gibbs * If there is a timeout scheduled to release this 44128b8a9b1dSJustin T. Gibbs * sim queue, remove it. The queue frozen count is 44138b8a9b1dSJustin T. Gibbs * already at 0. 44148b8a9b1dSJustin T. Gibbs */ 44158b8a9b1dSJustin T. Gibbs if ((sim->flags & CAM_SIM_REL_TIMEOUT_PENDING) != 0){ 44162b83592fSScott Long callout_stop(&sim->callout); 44178b8a9b1dSJustin T. Gibbs sim->flags &= ~CAM_SIM_REL_TIMEOUT_PENDING; 44188b8a9b1dSJustin T. Gibbs } 44198b8a9b1dSJustin T. Gibbs if (run_queue) { 44208b8a9b1dSJustin T. Gibbs /* 44218b8a9b1dSJustin T. Gibbs * Now that we are unfrozen run the send queue. 44228b8a9b1dSJustin T. Gibbs */ 4423cccf4220SAlexander Motin xpt_run_devq(sim->devq); 442477dc25ccSScott Long } 442577dc25ccSScott Long } 4426227d67aaSAlexander Motin mtx_unlock(&devq->send_mtx); 44278b8a9b1dSJustin T. Gibbs } 44288b8a9b1dSJustin T. Gibbs 44292b83592fSScott Long /* 44302b83592fSScott Long * XXX Appears to be unused. 44312b83592fSScott Long */ 44328b8a9b1dSJustin T. Gibbs static void 44338b8a9b1dSJustin T. Gibbs xpt_release_simq_timeout(void *arg) 44348b8a9b1dSJustin T. Gibbs { 44358b8a9b1dSJustin T. Gibbs struct cam_sim *sim; 44368b8a9b1dSJustin T. Gibbs 44378b8a9b1dSJustin T. Gibbs sim = (struct cam_sim *)arg; 44388b8a9b1dSJustin T. Gibbs xpt_release_simq(sim, /* run_queue */ TRUE); 44398b8a9b1dSJustin T. Gibbs } 44408b8a9b1dSJustin T. Gibbs 44418b8a9b1dSJustin T. Gibbs void 4442a5479bc5SJustin T. Gibbs xpt_done(union ccb *done_ccb) 44438b8a9b1dSJustin T. Gibbs { 4444227d67aaSAlexander Motin struct cam_doneq *queue; 4445227d67aaSAlexander Motin int run, hash; 44468b8a9b1dSJustin T. Gibbs 44478b8a9b1dSJustin T. Gibbs CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_TRACE, ("xpt_done\n")); 4448227d67aaSAlexander Motin if ((done_ccb->ccb_h.func_code & XPT_FC_QUEUED) == 0) 4449227d67aaSAlexander Motin return; 4450227d67aaSAlexander Motin 4451227d67aaSAlexander Motin hash = (done_ccb->ccb_h.path_id + done_ccb->ccb_h.target_id + 4452227d67aaSAlexander Motin done_ccb->ccb_h.target_lun) % cam_num_doneqs; 4453227d67aaSAlexander Motin queue = &cam_doneqs[hash]; 4454227d67aaSAlexander Motin mtx_lock(&queue->cam_doneq_mtx); 4455227d67aaSAlexander Motin run = (queue->cam_doneq_sleep && STAILQ_EMPTY(&queue->cam_doneq)); 4456227d67aaSAlexander Motin STAILQ_INSERT_TAIL(&queue->cam_doneq, &done_ccb->ccb_h, sim_links.stqe); 44578b8a9b1dSJustin T. Gibbs done_ccb->ccb_h.pinfo.index = CAM_DONEQ_INDEX; 4458227d67aaSAlexander Motin mtx_unlock(&queue->cam_doneq_mtx); 4459227d67aaSAlexander Motin if (run) 4460227d67aaSAlexander Motin wakeup(&queue->cam_doneq); 44618b8a9b1dSJustin T. Gibbs } 44628b8a9b1dSJustin T. Gibbs 4463711f6613SAlexander Motin void 4464227d67aaSAlexander Motin xpt_done_direct(union ccb *done_ccb) 4465711f6613SAlexander Motin { 4466711f6613SAlexander Motin 4467227d67aaSAlexander Motin CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_TRACE, ("xpt_done_direct\n")); 4468227d67aaSAlexander Motin if ((done_ccb->ccb_h.func_code & XPT_FC_QUEUED) == 0) 4469227d67aaSAlexander Motin return; 4470711f6613SAlexander Motin 4471227d67aaSAlexander Motin xpt_done_process(&done_ccb->ccb_h); 4472711f6613SAlexander Motin } 4473711f6613SAlexander Motin 44748b8a9b1dSJustin T. Gibbs union ccb * 44758008a935SScott Long xpt_alloc_ccb() 44768b8a9b1dSJustin T. Gibbs { 44778b8a9b1dSJustin T. Gibbs union ccb *new_ccb; 44788b8a9b1dSJustin T. Gibbs 4479596ee08fSAlexander Motin new_ccb = malloc(sizeof(*new_ccb), M_CAMCCB, M_ZERO|M_WAITOK); 4480362abc44STai-hwa Liang return (new_ccb); 4481362abc44STai-hwa Liang } 4482362abc44STai-hwa Liang 4483362abc44STai-hwa Liang union ccb * 44848008a935SScott Long xpt_alloc_ccb_nowait() 4485362abc44STai-hwa Liang { 4486362abc44STai-hwa Liang union ccb *new_ccb; 4487362abc44STai-hwa Liang 4488596ee08fSAlexander Motin new_ccb = malloc(sizeof(*new_ccb), M_CAMCCB, M_ZERO|M_NOWAIT); 44898b8a9b1dSJustin T. Gibbs return (new_ccb); 44908b8a9b1dSJustin T. Gibbs } 44918b8a9b1dSJustin T. Gibbs 44928b8a9b1dSJustin T. Gibbs void 44938b8a9b1dSJustin T. Gibbs xpt_free_ccb(union ccb *free_ccb) 44948b8a9b1dSJustin T. Gibbs { 4495596ee08fSAlexander Motin free(free_ccb, M_CAMCCB); 44968b8a9b1dSJustin T. Gibbs } 44978b8a9b1dSJustin T. Gibbs 44988b8a9b1dSJustin T. Gibbs 44998b8a9b1dSJustin T. Gibbs 45008b8a9b1dSJustin T. Gibbs /* Private XPT functions */ 45018b8a9b1dSJustin T. Gibbs 45028b8a9b1dSJustin T. Gibbs /* 45038b8a9b1dSJustin T. Gibbs * Get a CAM control block for the caller. Charge the structure to the device 4504227d67aaSAlexander Motin * referenced by the path. If we don't have sufficient resources to allocate 4505227d67aaSAlexander Motin * more ccbs, we return NULL. 45068b8a9b1dSJustin T. Gibbs */ 45078b8a9b1dSJustin T. Gibbs static union ccb * 4508227d67aaSAlexander Motin xpt_get_ccb_nowait(struct cam_periph *periph) 45098b8a9b1dSJustin T. Gibbs { 45108b8a9b1dSJustin T. Gibbs union ccb *new_ccb; 45118b8a9b1dSJustin T. Gibbs 4512227d67aaSAlexander Motin new_ccb = malloc(sizeof(*new_ccb), M_CAMCCB, M_NOWAIT); 4513227d67aaSAlexander Motin if (new_ccb == NULL) 45148b8a9b1dSJustin T. Gibbs return (NULL); 4515227d67aaSAlexander Motin periph->periph_allocated++; 4516227d67aaSAlexander Motin cam_ccbq_take_opening(&periph->path->device->ccbq); 45178b8a9b1dSJustin T. Gibbs return (new_ccb); 45188b8a9b1dSJustin T. Gibbs } 45198b8a9b1dSJustin T. Gibbs 4520227d67aaSAlexander Motin static union ccb * 4521227d67aaSAlexander Motin xpt_get_ccb(struct cam_periph *periph) 4522227d67aaSAlexander Motin { 4523227d67aaSAlexander Motin union ccb *new_ccb; 4524227d67aaSAlexander Motin 4525227d67aaSAlexander Motin cam_periph_unlock(periph); 4526227d67aaSAlexander Motin new_ccb = malloc(sizeof(*new_ccb), M_CAMCCB, M_WAITOK); 4527227d67aaSAlexander Motin cam_periph_lock(periph); 4528227d67aaSAlexander Motin periph->periph_allocated++; 4529227d67aaSAlexander Motin cam_ccbq_take_opening(&periph->path->device->ccbq); 4530227d67aaSAlexander Motin return (new_ccb); 4531227d67aaSAlexander Motin } 4532227d67aaSAlexander Motin 4533227d67aaSAlexander Motin union ccb * 4534227d67aaSAlexander Motin cam_periph_getccb(struct cam_periph *periph, u_int32_t priority) 4535227d67aaSAlexander Motin { 4536227d67aaSAlexander Motin struct ccb_hdr *ccb_h; 4537227d67aaSAlexander Motin 4538227d67aaSAlexander Motin CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("cam_periph_getccb\n")); 4539227d67aaSAlexander Motin cam_periph_assert(periph, MA_OWNED); 4540227d67aaSAlexander Motin while ((ccb_h = SLIST_FIRST(&periph->ccb_list)) == NULL || 4541227d67aaSAlexander Motin ccb_h->pinfo.priority != priority) { 4542227d67aaSAlexander Motin if (priority < periph->immediate_priority) { 4543227d67aaSAlexander Motin periph->immediate_priority = priority; 4544227d67aaSAlexander Motin xpt_run_allocq(periph, 0); 4545227d67aaSAlexander Motin } else 4546227d67aaSAlexander Motin cam_periph_sleep(periph, &periph->ccb_list, PRIBIO, 4547227d67aaSAlexander Motin "cgticb", 0); 4548227d67aaSAlexander Motin } 4549227d67aaSAlexander Motin SLIST_REMOVE_HEAD(&periph->ccb_list, periph_links.sle); 4550227d67aaSAlexander Motin return ((union ccb *)ccb_h); 4551227d67aaSAlexander Motin } 4552227d67aaSAlexander Motin 4553227d67aaSAlexander Motin static void 4554227d67aaSAlexander Motin xpt_acquire_bus(struct cam_eb *bus) 4555227d67aaSAlexander Motin { 4556227d67aaSAlexander Motin 4557227d67aaSAlexander Motin xpt_lock_buses(); 4558227d67aaSAlexander Motin bus->refcount++; 4559227d67aaSAlexander Motin xpt_unlock_buses(); 4560227d67aaSAlexander Motin } 4561227d67aaSAlexander Motin 4562a5479bc5SJustin T. Gibbs static void 4563a5479bc5SJustin T. Gibbs xpt_release_bus(struct cam_eb *bus) 4564a5479bc5SJustin T. Gibbs { 4565a5479bc5SJustin T. Gibbs 45669a7c2696SAlexander Motin xpt_lock_buses(); 456715975b7bSMatt Jacob KASSERT(bus->refcount >= 1, ("bus->refcount >= 1")); 4568dcdf6e74SAlexander Motin if (--bus->refcount > 0) { 4569dcdf6e74SAlexander Motin xpt_unlock_buses(); 4570dcdf6e74SAlexander Motin return; 4571dcdf6e74SAlexander Motin } 45722b83592fSScott Long TAILQ_REMOVE(&xsoftc.xpt_busses, bus, links); 45732b83592fSScott Long xsoftc.bus_generation++; 45749a7c2696SAlexander Motin xpt_unlock_buses(); 4575227d67aaSAlexander Motin KASSERT(TAILQ_EMPTY(&bus->et_entries), 4576227d67aaSAlexander Motin ("destroying bus, but target list is not empty")); 4577fa6099fdSEdward Tomasz Napierala cam_sim_release(bus->sim); 4578227d67aaSAlexander Motin mtx_destroy(&bus->eb_mtx); 4579362abc44STai-hwa Liang free(bus, M_CAMXPT); 4580a5479bc5SJustin T. Gibbs } 45818b8a9b1dSJustin T. Gibbs 45828b8a9b1dSJustin T. Gibbs static struct cam_et * 45838b8a9b1dSJustin T. Gibbs xpt_alloc_target(struct cam_eb *bus, target_id_t target_id) 45848b8a9b1dSJustin T. Gibbs { 4585dcdf6e74SAlexander Motin struct cam_et *cur_target, *target; 45868b8a9b1dSJustin T. Gibbs 4587227d67aaSAlexander Motin mtx_assert(&xsoftc.xpt_topo_lock, MA_OWNED); 4588227d67aaSAlexander Motin mtx_assert(&bus->eb_mtx, MA_OWNED); 45893501942bSJustin T. Gibbs target = (struct cam_et *)malloc(sizeof(*target), M_CAMXPT, 45903501942bSJustin T. Gibbs M_NOWAIT|M_ZERO); 4591dcdf6e74SAlexander Motin if (target == NULL) 4592dcdf6e74SAlexander Motin return (NULL); 45938b8a9b1dSJustin T. Gibbs 4594434bbf6eSJustin T. Gibbs TAILQ_INIT(&target->ed_entries); 45958b8a9b1dSJustin T. Gibbs target->bus = bus; 45968b8a9b1dSJustin T. Gibbs target->target_id = target_id; 45978b8a9b1dSJustin T. Gibbs target->refcount = 1; 4598434bbf6eSJustin T. Gibbs target->generation = 0; 459982b361b1SMatt Jacob target->luns = NULL; 4600227d67aaSAlexander Motin mtx_init(&target->luns_mtx, "CAM LUNs lock", NULL, MTX_DEF); 4601434bbf6eSJustin T. Gibbs timevalclear(&target->last_reset); 4602a5479bc5SJustin T. Gibbs /* 4603a5479bc5SJustin T. Gibbs * Hold a reference to our parent bus so it 4604a5479bc5SJustin T. Gibbs * will not go away before we do. 4605a5479bc5SJustin T. Gibbs */ 4606a5479bc5SJustin T. Gibbs bus->refcount++; 46078b8a9b1dSJustin T. Gibbs 46088b8a9b1dSJustin T. Gibbs /* Insertion sort into our bus's target list */ 46098b8a9b1dSJustin T. Gibbs cur_target = TAILQ_FIRST(&bus->et_entries); 46108b8a9b1dSJustin T. Gibbs while (cur_target != NULL && cur_target->target_id < target_id) 46118b8a9b1dSJustin T. Gibbs cur_target = TAILQ_NEXT(cur_target, links); 46128b8a9b1dSJustin T. Gibbs if (cur_target != NULL) { 46138b8a9b1dSJustin T. Gibbs TAILQ_INSERT_BEFORE(cur_target, target, links); 46148b8a9b1dSJustin T. Gibbs } else { 46158b8a9b1dSJustin T. Gibbs TAILQ_INSERT_TAIL(&bus->et_entries, target, links); 46168b8a9b1dSJustin T. Gibbs } 4617a5479bc5SJustin T. Gibbs bus->generation++; 46188b8a9b1dSJustin T. Gibbs return (target); 46198b8a9b1dSJustin T. Gibbs } 46208b8a9b1dSJustin T. Gibbs 4621a5479bc5SJustin T. Gibbs static void 4622227d67aaSAlexander Motin xpt_acquire_target(struct cam_et *target) 4623227d67aaSAlexander Motin { 4624227d67aaSAlexander Motin struct cam_eb *bus = target->bus; 4625227d67aaSAlexander Motin 4626227d67aaSAlexander Motin mtx_lock(&bus->eb_mtx); 4627227d67aaSAlexander Motin target->refcount++; 4628227d67aaSAlexander Motin mtx_unlock(&bus->eb_mtx); 4629227d67aaSAlexander Motin } 4630227d67aaSAlexander Motin 4631227d67aaSAlexander Motin static void 4632f98d7a47SAlexander Motin xpt_release_target(struct cam_et *target) 46338b8a9b1dSJustin T. Gibbs { 4634227d67aaSAlexander Motin struct cam_eb *bus = target->bus; 4635a5479bc5SJustin T. Gibbs 4636227d67aaSAlexander Motin mtx_lock(&bus->eb_mtx); 4637227d67aaSAlexander Motin if (--target->refcount > 0) { 4638227d67aaSAlexander Motin mtx_unlock(&bus->eb_mtx); 4639dcdf6e74SAlexander Motin return; 4640227d67aaSAlexander Motin } 4641227d67aaSAlexander Motin TAILQ_REMOVE(&bus->et_entries, target, links); 4642227d67aaSAlexander Motin bus->generation++; 4643227d67aaSAlexander Motin mtx_unlock(&bus->eb_mtx); 4644dcdf6e74SAlexander Motin KASSERT(TAILQ_EMPTY(&target->ed_entries), 4645227d67aaSAlexander Motin ("destroying target, but device list is not empty")); 4646227d67aaSAlexander Motin xpt_release_bus(bus); 4647227d67aaSAlexander Motin mtx_destroy(&target->luns_mtx); 464882b361b1SMatt Jacob if (target->luns) 464982b361b1SMatt Jacob free(target->luns, M_CAMXPT); 4650362abc44STai-hwa Liang free(target, M_CAMXPT); 465177dc25ccSScott Long } 46528b8a9b1dSJustin T. Gibbs 46538b8a9b1dSJustin T. Gibbs static struct cam_ed * 465452c9ce25SScott Long xpt_alloc_device_default(struct cam_eb *bus, struct cam_et *target, 465552c9ce25SScott Long lun_id_t lun_id) 465652c9ce25SScott Long { 4657dcdf6e74SAlexander Motin struct cam_ed *device; 465852c9ce25SScott Long 465952c9ce25SScott Long device = xpt_alloc_device(bus, target, lun_id); 466052c9ce25SScott Long if (device == NULL) 466152c9ce25SScott Long return (NULL); 466252c9ce25SScott Long 466352c9ce25SScott Long device->mintags = 1; 466452c9ce25SScott Long device->maxtags = 1; 466552c9ce25SScott Long return (device); 466652c9ce25SScott Long } 466752c9ce25SScott Long 4668227d67aaSAlexander Motin static void 4669227d67aaSAlexander Motin xpt_destroy_device(void *context, int pending) 4670227d67aaSAlexander Motin { 4671227d67aaSAlexander Motin struct cam_ed *device = context; 4672227d67aaSAlexander Motin 4673227d67aaSAlexander Motin mtx_lock(&device->device_mtx); 4674227d67aaSAlexander Motin mtx_destroy(&device->device_mtx); 4675227d67aaSAlexander Motin free(device, M_CAMDEV); 4676227d67aaSAlexander Motin } 4677227d67aaSAlexander Motin 467852c9ce25SScott Long struct cam_ed * 46798b8a9b1dSJustin T. Gibbs xpt_alloc_device(struct cam_eb *bus, struct cam_et *target, lun_id_t lun_id) 46808b8a9b1dSJustin T. Gibbs { 4681dcdf6e74SAlexander Motin struct cam_ed *cur_device, *device; 46828b8a9b1dSJustin T. Gibbs struct cam_devq *devq; 4683a5479bc5SJustin T. Gibbs cam_status status; 46848b8a9b1dSJustin T. Gibbs 4685227d67aaSAlexander Motin mtx_assert(&bus->eb_mtx, MA_OWNED); 46868b8a9b1dSJustin T. Gibbs /* Make space for us in the device queue on our bus */ 46878b8a9b1dSJustin T. Gibbs devq = bus->sim->devq; 4688227d67aaSAlexander Motin mtx_lock(&devq->send_mtx); 4689cccf4220SAlexander Motin status = cam_devq_resize(devq, devq->send_queue.array_size + 1); 4690227d67aaSAlexander Motin mtx_unlock(&devq->send_mtx); 4691dcdf6e74SAlexander Motin if (status != CAM_REQ_CMP) 4692dcdf6e74SAlexander Motin return (NULL); 46938b8a9b1dSJustin T. Gibbs 46948b8a9b1dSJustin T. Gibbs device = (struct cam_ed *)malloc(sizeof(*device), 4695596ee08fSAlexander Motin M_CAMDEV, M_NOWAIT|M_ZERO); 4696dcdf6e74SAlexander Motin if (device == NULL) 4697dcdf6e74SAlexander Motin return (NULL); 46988b8a9b1dSJustin T. Gibbs 4699227d67aaSAlexander Motin cam_init_pinfo(&device->devq_entry); 47008b8a9b1dSJustin T. Gibbs device->target = target; 47018b8a9b1dSJustin T. Gibbs device->lun_id = lun_id; 47022b83592fSScott Long device->sim = bus->sim; 47038b8a9b1dSJustin T. Gibbs if (cam_ccbq_init(&device->ccbq, 47048b8a9b1dSJustin T. Gibbs bus->sim->max_dev_openings) != 0) { 4705596ee08fSAlexander Motin free(device, M_CAMDEV); 47068b8a9b1dSJustin T. Gibbs return (NULL); 47078b8a9b1dSJustin T. Gibbs } 4708434bbf6eSJustin T. Gibbs SLIST_INIT(&device->asyncs); 4709434bbf6eSJustin T. Gibbs SLIST_INIT(&device->periphs); 4710434bbf6eSJustin T. Gibbs device->generation = 0; 4711434bbf6eSJustin T. Gibbs device->flags = CAM_DEV_UNCONFIGURED; 4712434bbf6eSJustin T. Gibbs device->tag_delay_count = 0; 4713df8f9080SJustin T. Gibbs device->tag_saved_openings = 0; 4714434bbf6eSJustin T. Gibbs device->refcount = 1; 4715227d67aaSAlexander Motin mtx_init(&device->device_mtx, "CAM device lock", NULL, MTX_DEF); 4716227d67aaSAlexander Motin callout_init_mtx(&device->callout, &devq->send_mtx, 0); 4717227d67aaSAlexander Motin TASK_INIT(&device->device_destroy_task, 0, xpt_destroy_device, device); 4718227d67aaSAlexander Motin /* 4719227d67aaSAlexander Motin * Hold a reference to our parent bus so it 4720227d67aaSAlexander Motin * will not go away before we do. 4721227d67aaSAlexander Motin */ 4722227d67aaSAlexander Motin target->refcount++; 4723434bbf6eSJustin T. Gibbs 4724dcdf6e74SAlexander Motin cur_device = TAILQ_FIRST(&target->ed_entries); 4725dcdf6e74SAlexander Motin while (cur_device != NULL && cur_device->lun_id < lun_id) 4726dcdf6e74SAlexander Motin cur_device = TAILQ_NEXT(cur_device, links); 4727dcdf6e74SAlexander Motin if (cur_device != NULL) 4728dcdf6e74SAlexander Motin TAILQ_INSERT_BEFORE(cur_device, device, links); 4729dcdf6e74SAlexander Motin else 4730dcdf6e74SAlexander Motin TAILQ_INSERT_TAIL(&target->ed_entries, device, links); 4731dcdf6e74SAlexander Motin target->generation++; 47328b8a9b1dSJustin T. Gibbs return (device); 47338b8a9b1dSJustin T. Gibbs } 47348b8a9b1dSJustin T. Gibbs 4735f98d7a47SAlexander Motin void 4736f98d7a47SAlexander Motin xpt_acquire_device(struct cam_ed *device) 47378b8a9b1dSJustin T. Gibbs { 4738227d67aaSAlexander Motin struct cam_eb *bus = device->target->bus; 47398b8a9b1dSJustin T. Gibbs 4740227d67aaSAlexander Motin mtx_lock(&bus->eb_mtx); 4741f98d7a47SAlexander Motin device->refcount++; 4742227d67aaSAlexander Motin mtx_unlock(&bus->eb_mtx); 4743f98d7a47SAlexander Motin } 4744f98d7a47SAlexander Motin 4745f98d7a47SAlexander Motin void 4746f98d7a47SAlexander Motin xpt_release_device(struct cam_ed *device) 4747f98d7a47SAlexander Motin { 4748227d67aaSAlexander Motin struct cam_eb *bus = device->target->bus; 47498b8a9b1dSJustin T. Gibbs struct cam_devq *devq; 47508b8a9b1dSJustin T. Gibbs 4751227d67aaSAlexander Motin mtx_lock(&bus->eb_mtx); 4752227d67aaSAlexander Motin if (--device->refcount > 0) { 4753227d67aaSAlexander Motin mtx_unlock(&bus->eb_mtx); 4754dcdf6e74SAlexander Motin return; 4755227d67aaSAlexander Motin } 4756227d67aaSAlexander Motin 4757227d67aaSAlexander Motin TAILQ_REMOVE(&device->target->ed_entries, device,links); 4758227d67aaSAlexander Motin device->target->generation++; 4759227d67aaSAlexander Motin mtx_unlock(&bus->eb_mtx); 4760227d67aaSAlexander Motin 4761227d67aaSAlexander Motin /* Release our slot in the devq */ 4762227d67aaSAlexander Motin devq = bus->sim->devq; 4763227d67aaSAlexander Motin mtx_lock(&devq->send_mtx); 4764227d67aaSAlexander Motin cam_devq_resize(devq, devq->send_queue.array_size - 1); 4765227d67aaSAlexander Motin mtx_unlock(&devq->send_mtx); 4766dcdf6e74SAlexander Motin 4767dcdf6e74SAlexander Motin KASSERT(SLIST_EMPTY(&device->periphs), 4768227d67aaSAlexander Motin ("destroying device, but periphs list is not empty")); 4769227d67aaSAlexander Motin KASSERT(device->devq_entry.index == CAM_UNQUEUED_INDEX, 4770227d67aaSAlexander Motin ("destroying device while still queued for ccbs")); 47712cefde5fSJustin T. Gibbs 47722cefde5fSJustin T. Gibbs if ((device->flags & CAM_DEV_REL_TIMEOUT_PENDING) != 0) 47732b83592fSScott Long callout_stop(&device->callout); 47742cefde5fSJustin T. Gibbs 4775227d67aaSAlexander Motin xpt_release_target(device->target); 4776227d67aaSAlexander Motin 477720a7933fSAlexander Motin cam_ccbq_fini(&device->ccbq); 4778e6bd5983SKenneth D. Merry /* 4779e6bd5983SKenneth D. Merry * Free allocated memory. free(9) does nothing if the 4780e6bd5983SKenneth D. Merry * supplied pointer is NULL, so it is safe to call without 4781e6bd5983SKenneth D. Merry * checking. 4782e6bd5983SKenneth D. Merry */ 4783e6bd5983SKenneth D. Merry free(device->supported_vpds, M_CAMXPT); 4784e6bd5983SKenneth D. Merry free(device->device_id, M_CAMXPT); 4785e6bd5983SKenneth D. Merry free(device->physpath, M_CAMXPT); 4786e6bd5983SKenneth D. Merry free(device->rcap_buf, M_CAMXPT); 4787e6bd5983SKenneth D. Merry free(device->serial_num, M_CAMXPT); 4788227d67aaSAlexander Motin taskqueue_enqueue(xsoftc.xpt_taskq, &device->device_destroy_task); 47898b8a9b1dSJustin T. Gibbs } 47908b8a9b1dSJustin T. Gibbs 479152c9ce25SScott Long u_int32_t 47928b8a9b1dSJustin T. Gibbs xpt_dev_ccbq_resize(struct cam_path *path, int newopenings) 47938b8a9b1dSJustin T. Gibbs { 47948b8a9b1dSJustin T. Gibbs int result; 47958b8a9b1dSJustin T. Gibbs struct cam_ed *dev; 47968b8a9b1dSJustin T. Gibbs 47978b8a9b1dSJustin T. Gibbs dev = path->device; 4798227d67aaSAlexander Motin mtx_lock(&dev->sim->devq->send_mtx); 47998b8a9b1dSJustin T. Gibbs result = cam_ccbq_resize(&dev->ccbq, newopenings); 4800227d67aaSAlexander Motin mtx_unlock(&dev->sim->devq->send_mtx); 4801df8f9080SJustin T. Gibbs if ((dev->flags & CAM_DEV_TAG_AFTER_COUNT) != 0 4802df8f9080SJustin T. Gibbs || (dev->inq_flags & SID_CmdQue) != 0) 4803df8f9080SJustin T. Gibbs dev->tag_saved_openings = newopenings; 48048b8a9b1dSJustin T. Gibbs return (result); 48058b8a9b1dSJustin T. Gibbs } 48068b8a9b1dSJustin T. Gibbs 48078b8a9b1dSJustin T. Gibbs static struct cam_eb * 48088b8a9b1dSJustin T. Gibbs xpt_find_bus(path_id_t path_id) 48098b8a9b1dSJustin T. Gibbs { 48108b8a9b1dSJustin T. Gibbs struct cam_eb *bus; 48118b8a9b1dSJustin T. Gibbs 48129a7c2696SAlexander Motin xpt_lock_buses(); 48132b83592fSScott Long for (bus = TAILQ_FIRST(&xsoftc.xpt_busses); 48148b8a9b1dSJustin T. Gibbs bus != NULL; 48158b8a9b1dSJustin T. Gibbs bus = TAILQ_NEXT(bus, links)) { 4816a5479bc5SJustin T. Gibbs if (bus->path_id == path_id) { 4817a5479bc5SJustin T. Gibbs bus->refcount++; 48188b8a9b1dSJustin T. Gibbs break; 48198b8a9b1dSJustin T. Gibbs } 4820a5479bc5SJustin T. Gibbs } 48219a7c2696SAlexander Motin xpt_unlock_buses(); 48228b8a9b1dSJustin T. Gibbs return (bus); 48238b8a9b1dSJustin T. Gibbs } 48248b8a9b1dSJustin T. Gibbs 48258b8a9b1dSJustin T. Gibbs static struct cam_et * 48268b8a9b1dSJustin T. Gibbs xpt_find_target(struct cam_eb *bus, target_id_t target_id) 48278b8a9b1dSJustin T. Gibbs { 48288b8a9b1dSJustin T. Gibbs struct cam_et *target; 48298b8a9b1dSJustin T. Gibbs 4830227d67aaSAlexander Motin mtx_assert(&bus->eb_mtx, MA_OWNED); 48318b8a9b1dSJustin T. Gibbs for (target = TAILQ_FIRST(&bus->et_entries); 48328b8a9b1dSJustin T. Gibbs target != NULL; 48338b8a9b1dSJustin T. Gibbs target = TAILQ_NEXT(target, links)) { 48348b8a9b1dSJustin T. Gibbs if (target->target_id == target_id) { 48358b8a9b1dSJustin T. Gibbs target->refcount++; 48368b8a9b1dSJustin T. Gibbs break; 48378b8a9b1dSJustin T. Gibbs } 48388b8a9b1dSJustin T. Gibbs } 48398b8a9b1dSJustin T. Gibbs return (target); 48408b8a9b1dSJustin T. Gibbs } 48418b8a9b1dSJustin T. Gibbs 48428b8a9b1dSJustin T. Gibbs static struct cam_ed * 48438b8a9b1dSJustin T. Gibbs xpt_find_device(struct cam_et *target, lun_id_t lun_id) 48448b8a9b1dSJustin T. Gibbs { 48458b8a9b1dSJustin T. Gibbs struct cam_ed *device; 48468b8a9b1dSJustin T. Gibbs 4847227d67aaSAlexander Motin mtx_assert(&target->bus->eb_mtx, MA_OWNED); 48488b8a9b1dSJustin T. Gibbs for (device = TAILQ_FIRST(&target->ed_entries); 48498b8a9b1dSJustin T. Gibbs device != NULL; 48508b8a9b1dSJustin T. Gibbs device = TAILQ_NEXT(device, links)) { 48518b8a9b1dSJustin T. Gibbs if (device->lun_id == lun_id) { 48528b8a9b1dSJustin T. Gibbs device->refcount++; 48538b8a9b1dSJustin T. Gibbs break; 48548b8a9b1dSJustin T. Gibbs } 48558b8a9b1dSJustin T. Gibbs } 48568b8a9b1dSJustin T. Gibbs return (device); 48578b8a9b1dSJustin T. Gibbs } 48588b8a9b1dSJustin T. Gibbs 485930a4094fSAlexander Motin void 4860f0adc790SJustin T. Gibbs xpt_start_tags(struct cam_path *path) 4861f0adc790SJustin T. Gibbs { 4862fd21cc5eSJustin T. Gibbs struct ccb_relsim crs; 4863fd21cc5eSJustin T. Gibbs struct cam_ed *device; 4864fd21cc5eSJustin T. Gibbs struct cam_sim *sim; 4865fd21cc5eSJustin T. Gibbs int newopenings; 4866fd21cc5eSJustin T. Gibbs 4867fd21cc5eSJustin T. Gibbs device = path->device; 4868fd21cc5eSJustin T. Gibbs sim = path->bus->sim; 4869fd21cc5eSJustin T. Gibbs device->flags &= ~CAM_DEV_TAG_AFTER_COUNT; 4870fd21cc5eSJustin T. Gibbs xpt_freeze_devq(path, /*count*/1); 4871fd21cc5eSJustin T. Gibbs device->inq_flags |= SID_CmdQue; 4872df8f9080SJustin T. Gibbs if (device->tag_saved_openings != 0) 4873df8f9080SJustin T. Gibbs newopenings = device->tag_saved_openings; 4874df8f9080SJustin T. Gibbs else 487552c9ce25SScott Long newopenings = min(device->maxtags, 4876df8f9080SJustin T. Gibbs sim->max_tagged_dev_openings); 4877f0adc790SJustin T. Gibbs xpt_dev_ccbq_resize(path, newopenings); 4878581b2e78SAlexander Motin xpt_async(AC_GETDEV_CHANGED, path, NULL); 4879bbfa4aa1SAlexander Motin xpt_setup_ccb(&crs.ccb_h, path, CAM_PRIORITY_NORMAL); 4880fd21cc5eSJustin T. Gibbs crs.ccb_h.func_code = XPT_REL_SIMQ; 4881fd21cc5eSJustin T. Gibbs crs.release_flags = RELSIM_RELEASE_AFTER_QEMPTY; 4882fd21cc5eSJustin T. Gibbs crs.openings 4883fd21cc5eSJustin T. Gibbs = crs.release_timeout 4884fd21cc5eSJustin T. Gibbs = crs.qfrozen_cnt 4885fd21cc5eSJustin T. Gibbs = 0; 4886fd21cc5eSJustin T. Gibbs xpt_action((union ccb *)&crs); 4887fd21cc5eSJustin T. Gibbs } 4888fd21cc5eSJustin T. Gibbs 488930a4094fSAlexander Motin void 489030a4094fSAlexander Motin xpt_stop_tags(struct cam_path *path) 489130a4094fSAlexander Motin { 489230a4094fSAlexander Motin struct ccb_relsim crs; 489330a4094fSAlexander Motin struct cam_ed *device; 489430a4094fSAlexander Motin struct cam_sim *sim; 489530a4094fSAlexander Motin 489630a4094fSAlexander Motin device = path->device; 489730a4094fSAlexander Motin sim = path->bus->sim; 489830a4094fSAlexander Motin device->flags &= ~CAM_DEV_TAG_AFTER_COUNT; 489930a4094fSAlexander Motin device->tag_delay_count = 0; 490030a4094fSAlexander Motin xpt_freeze_devq(path, /*count*/1); 490130a4094fSAlexander Motin device->inq_flags &= ~SID_CmdQue; 490230a4094fSAlexander Motin xpt_dev_ccbq_resize(path, sim->max_dev_openings); 4903581b2e78SAlexander Motin xpt_async(AC_GETDEV_CHANGED, path, NULL); 490430a4094fSAlexander Motin xpt_setup_ccb(&crs.ccb_h, path, CAM_PRIORITY_NORMAL); 490530a4094fSAlexander Motin crs.ccb_h.func_code = XPT_REL_SIMQ; 490630a4094fSAlexander Motin crs.release_flags = RELSIM_RELEASE_AFTER_QEMPTY; 490730a4094fSAlexander Motin crs.openings 490830a4094fSAlexander Motin = crs.release_timeout 490930a4094fSAlexander Motin = crs.qfrozen_cnt 491030a4094fSAlexander Motin = 0; 491130a4094fSAlexander Motin xpt_action((union ccb *)&crs); 491230a4094fSAlexander Motin } 491330a4094fSAlexander Motin 491483c5d981SAlexander Motin static void 491583c5d981SAlexander Motin xpt_boot_delay(void *arg) 49168b8a9b1dSJustin T. Gibbs { 49172b83592fSScott Long 491883c5d981SAlexander Motin xpt_release_boot(); 49198b8a9b1dSJustin T. Gibbs } 49208b8a9b1dSJustin T. Gibbs 49218b8a9b1dSJustin T. Gibbs static void 49228b8a9b1dSJustin T. Gibbs xpt_config(void *arg) 49238b8a9b1dSJustin T. Gibbs { 49243393f8daSKenneth D. Merry /* 49253393f8daSKenneth D. Merry * Now that interrupts are enabled, go find our devices 49263393f8daSKenneth D. Merry */ 4927227d67aaSAlexander Motin if (taskqueue_start_threads(&xsoftc.xpt_taskq, 1, PRIBIO, "CAM taskq")) 4928227d67aaSAlexander Motin printf("xpt_config: failed to create taskqueue thread.\n"); 49298b8a9b1dSJustin T. Gibbs 4930f0f25b9cSAlexander Motin /* Setup debugging path */ 49318b8a9b1dSJustin T. Gibbs if (cam_dflags != CAM_DEBUG_NONE) { 4932227d67aaSAlexander Motin if (xpt_create_path(&cam_dpath, NULL, 49338b8a9b1dSJustin T. Gibbs CAM_DEBUG_BUS, CAM_DEBUG_TARGET, 49348b8a9b1dSJustin T. Gibbs CAM_DEBUG_LUN) != CAM_REQ_CMP) { 49358b8a9b1dSJustin T. Gibbs printf("xpt_config: xpt_create_path() failed for debug" 49368b8a9b1dSJustin T. Gibbs " target %d:%d:%d, debugging disabled\n", 49378b8a9b1dSJustin T. Gibbs CAM_DEBUG_BUS, CAM_DEBUG_TARGET, CAM_DEBUG_LUN); 49388b8a9b1dSJustin T. Gibbs cam_dflags = CAM_DEBUG_NONE; 49398b8a9b1dSJustin T. Gibbs } 49408b8a9b1dSJustin T. Gibbs } else 49418b8a9b1dSJustin T. Gibbs cam_dpath = NULL; 49428b8a9b1dSJustin T. Gibbs 494383c5d981SAlexander Motin periphdriver_init(1); 494483c5d981SAlexander Motin xpt_hold_boot(); 494583c5d981SAlexander Motin callout_init(&xsoftc.boot_callout, 1); 494683c5d981SAlexander Motin callout_reset(&xsoftc.boot_callout, hz * xsoftc.boot_delay / 1000, 494783c5d981SAlexander Motin xpt_boot_delay, NULL); 494883c5d981SAlexander Motin /* Fire up rescan thread. */ 4949227d67aaSAlexander Motin if (kproc_kthread_add(xpt_scanner_thread, NULL, &cam_proc, NULL, 0, 0, 4950227d67aaSAlexander Motin "cam", "scanner")) { 49516f15a274SAlexander Motin printf("xpt_config: failed to create rescan thread.\n"); 49521e637ba6SAlexander Motin } 495383c5d981SAlexander Motin } 49548b8a9b1dSJustin T. Gibbs 495583c5d981SAlexander Motin void 495683c5d981SAlexander Motin xpt_hold_boot(void) 495783c5d981SAlexander Motin { 495883c5d981SAlexander Motin xpt_lock_buses(); 495983c5d981SAlexander Motin xsoftc.buses_to_config++; 496083c5d981SAlexander Motin xpt_unlock_buses(); 496183c5d981SAlexander Motin } 496283c5d981SAlexander Motin 496383c5d981SAlexander Motin void 496483c5d981SAlexander Motin xpt_release_boot(void) 496583c5d981SAlexander Motin { 496683c5d981SAlexander Motin xpt_lock_buses(); 496783c5d981SAlexander Motin xsoftc.buses_to_config--; 496883c5d981SAlexander Motin if (xsoftc.buses_to_config == 0 && xsoftc.buses_config_done == 0) { 496983c5d981SAlexander Motin struct xpt_task *task; 497083c5d981SAlexander Motin 497183c5d981SAlexander Motin xsoftc.buses_config_done = 1; 497283c5d981SAlexander Motin xpt_unlock_buses(); 4973ecdf1113SJustin T. Gibbs /* Call manually because we don't have any busses */ 497483c5d981SAlexander Motin task = malloc(sizeof(struct xpt_task), M_CAMXPT, M_NOWAIT); 497583c5d981SAlexander Motin if (task != NULL) { 497683c5d981SAlexander Motin TASK_INIT(&task->task, 0, xpt_finishconfig_task, task); 497783c5d981SAlexander Motin taskqueue_enqueue(taskqueue_thread, &task->task); 49782863f7b1SJustin T. Gibbs } 497983c5d981SAlexander Motin } else 498083c5d981SAlexander Motin xpt_unlock_buses(); 49812863f7b1SJustin T. Gibbs } 49828b8a9b1dSJustin T. Gibbs 49838b8a9b1dSJustin T. Gibbs /* 49848b8a9b1dSJustin T. Gibbs * If the given device only has one peripheral attached to it, and if that 49858b8a9b1dSJustin T. Gibbs * peripheral is the passthrough driver, announce it. This insures that the 49868b8a9b1dSJustin T. Gibbs * user sees some sort of announcement for every peripheral in their system. 49878b8a9b1dSJustin T. Gibbs */ 49888b8a9b1dSJustin T. Gibbs static int 49898b8a9b1dSJustin T. Gibbs xptpassannouncefunc(struct cam_ed *device, void *arg) 49908b8a9b1dSJustin T. Gibbs { 49918b8a9b1dSJustin T. Gibbs struct cam_periph *periph; 49928b8a9b1dSJustin T. Gibbs int i; 49938b8a9b1dSJustin T. Gibbs 49948b8a9b1dSJustin T. Gibbs for (periph = SLIST_FIRST(&device->periphs), i = 0; periph != NULL; 49958b8a9b1dSJustin T. Gibbs periph = SLIST_NEXT(periph, periph_links), i++); 49968b8a9b1dSJustin T. Gibbs 49978b8a9b1dSJustin T. Gibbs periph = SLIST_FIRST(&device->periphs); 49988b8a9b1dSJustin T. Gibbs if ((i == 1) 49998b8a9b1dSJustin T. Gibbs && (strncmp(periph->periph_name, "pass", 4) == 0)) 50008b8a9b1dSJustin T. Gibbs xpt_announce_periph(periph, NULL); 50018b8a9b1dSJustin T. Gibbs 50028b8a9b1dSJustin T. Gibbs return(1); 50038b8a9b1dSJustin T. Gibbs } 50048b8a9b1dSJustin T. Gibbs 50058b8a9b1dSJustin T. Gibbs static void 50062b83592fSScott Long xpt_finishconfig_task(void *context, int pending) 50078b8a9b1dSJustin T. Gibbs { 50088b8a9b1dSJustin T. Gibbs 500983c5d981SAlexander Motin periphdriver_init(2); 50102b83592fSScott Long /* 50112b83592fSScott Long * Check for devices with no "standard" peripheral driver 50122b83592fSScott Long * attached. For any devices like that, announce the 50132b83592fSScott Long * passthrough driver so the user will see something. 50142b83592fSScott Long */ 50153089bb2eSAlexander Motin if (!bootverbose) 50162b83592fSScott Long xpt_for_all_devices(xptpassannouncefunc, NULL); 50172b83592fSScott Long 50182b83592fSScott Long /* Release our hook so that the boot can continue. */ 50192b83592fSScott Long config_intrhook_disestablish(xsoftc.xpt_config_hook); 50200dd50e9bSScott Long free(xsoftc.xpt_config_hook, M_CAMXPT); 50212b83592fSScott Long xsoftc.xpt_config_hook = NULL; 50222b83592fSScott Long 50232b83592fSScott Long free(context, M_CAMXPT); 50242b83592fSScott Long } 50252b83592fSScott Long 502685d92640SScott Long cam_status 502785d92640SScott Long xpt_register_async(int event, ac_callback_t *cbfunc, void *cbarg, 502885d92640SScott Long struct cam_path *path) 502985d92640SScott Long { 503085d92640SScott Long struct ccb_setasync csa; 503185d92640SScott Long cam_status status; 503285d92640SScott Long int xptpath = 0; 503385d92640SScott Long 503485d92640SScott Long if (path == NULL) { 503585d92640SScott Long status = xpt_create_path(&path, /*periph*/NULL, CAM_XPT_PATH_ID, 503685d92640SScott Long CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD); 5037227d67aaSAlexander Motin if (status != CAM_REQ_CMP) 503885d92640SScott Long return (status); 5039227d67aaSAlexander Motin xpt_path_lock(path); 504085d92640SScott Long xptpath = 1; 504185d92640SScott Long } 504285d92640SScott Long 504383c5d981SAlexander Motin xpt_setup_ccb(&csa.ccb_h, path, CAM_PRIORITY_NORMAL); 504485d92640SScott Long csa.ccb_h.func_code = XPT_SASYNC_CB; 504585d92640SScott Long csa.event_enable = event; 504685d92640SScott Long csa.callback = cbfunc; 504785d92640SScott Long csa.callback_arg = cbarg; 504885d92640SScott Long xpt_action((union ccb *)&csa); 504985d92640SScott Long status = csa.ccb_h.status; 50503501942bSJustin T. Gibbs 505185d92640SScott Long if (xptpath) { 5052227d67aaSAlexander Motin xpt_path_unlock(path); 505385d92640SScott Long xpt_free_path(path); 50543501942bSJustin T. Gibbs } 50557685edecSAlexander Motin 50567685edecSAlexander Motin if ((status == CAM_REQ_CMP) && 50577685edecSAlexander Motin (csa.event_enable & AC_FOUND_DEVICE)) { 50587685edecSAlexander Motin /* 50597685edecSAlexander Motin * Get this peripheral up to date with all 50607685edecSAlexander Motin * the currently existing devices. 50617685edecSAlexander Motin */ 50627685edecSAlexander Motin xpt_for_all_devices(xptsetasyncfunc, &csa); 50637685edecSAlexander Motin } 50647685edecSAlexander Motin if ((status == CAM_REQ_CMP) && 50657685edecSAlexander Motin (csa.event_enable & AC_PATH_REGISTERED)) { 50667685edecSAlexander Motin /* 50677685edecSAlexander Motin * Get this peripheral up to date with all 50687685edecSAlexander Motin * the currently existing busses. 50697685edecSAlexander Motin */ 50707685edecSAlexander Motin xpt_for_all_busses(xptsetasyncbusfunc, &csa); 50717685edecSAlexander Motin } 50723501942bSJustin T. Gibbs 507385d92640SScott Long return (status); 507485d92640SScott Long } 507585d92640SScott Long 50768b8a9b1dSJustin T. Gibbs static void 50778b8a9b1dSJustin T. Gibbs xptaction(struct cam_sim *sim, union ccb *work_ccb) 50788b8a9b1dSJustin T. Gibbs { 50798b8a9b1dSJustin T. Gibbs CAM_DEBUG(work_ccb->ccb_h.path, CAM_DEBUG_TRACE, ("xptaction\n")); 50808b8a9b1dSJustin T. Gibbs 50818b8a9b1dSJustin T. Gibbs switch (work_ccb->ccb_h.func_code) { 50828b8a9b1dSJustin T. Gibbs /* Common cases first */ 50838b8a9b1dSJustin T. Gibbs case XPT_PATH_INQ: /* Path routing inquiry */ 50848b8a9b1dSJustin T. Gibbs { 50858b8a9b1dSJustin T. Gibbs struct ccb_pathinq *cpi; 50868b8a9b1dSJustin T. Gibbs 50878b8a9b1dSJustin T. Gibbs cpi = &work_ccb->cpi; 50888b8a9b1dSJustin T. Gibbs cpi->version_num = 1; /* XXX??? */ 50898b8a9b1dSJustin T. Gibbs cpi->hba_inquiry = 0; 50908b8a9b1dSJustin T. Gibbs cpi->target_sprt = 0; 50918b8a9b1dSJustin T. Gibbs cpi->hba_misc = 0; 50928b8a9b1dSJustin T. Gibbs cpi->hba_eng_cnt = 0; 50938b8a9b1dSJustin T. Gibbs cpi->max_target = 0; 50948b8a9b1dSJustin T. Gibbs cpi->max_lun = 0; 50958b8a9b1dSJustin T. Gibbs cpi->initiator_id = 0; 50968b8a9b1dSJustin T. Gibbs strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN); 50978b8a9b1dSJustin T. Gibbs strncpy(cpi->hba_vid, "", HBA_IDLEN); 50988b8a9b1dSJustin T. Gibbs strncpy(cpi->dev_name, sim->sim_name, DEV_IDLEN); 50998b8a9b1dSJustin T. Gibbs cpi->unit_number = sim->unit_number; 51008b8a9b1dSJustin T. Gibbs cpi->bus_id = sim->bus_id; 51019deea857SKenneth D. Merry cpi->base_transfer_speed = 0; 51023393f8daSKenneth D. Merry cpi->protocol = PROTO_UNSPECIFIED; 51033393f8daSKenneth D. Merry cpi->protocol_version = PROTO_VERSION_UNSPECIFIED; 51043393f8daSKenneth D. Merry cpi->transport = XPORT_UNSPECIFIED; 51053393f8daSKenneth D. Merry cpi->transport_version = XPORT_VERSION_UNSPECIFIED; 51068b8a9b1dSJustin T. Gibbs cpi->ccb_h.status = CAM_REQ_CMP; 51078b8a9b1dSJustin T. Gibbs xpt_done(work_ccb); 51088b8a9b1dSJustin T. Gibbs break; 51098b8a9b1dSJustin T. Gibbs } 51108b8a9b1dSJustin T. Gibbs default: 51118b8a9b1dSJustin T. Gibbs work_ccb->ccb_h.status = CAM_REQ_INVALID; 51128b8a9b1dSJustin T. Gibbs xpt_done(work_ccb); 51138b8a9b1dSJustin T. Gibbs break; 51148b8a9b1dSJustin T. Gibbs } 51158b8a9b1dSJustin T. Gibbs } 51168b8a9b1dSJustin T. Gibbs 51178b8a9b1dSJustin T. Gibbs /* 5118434bbf6eSJustin T. Gibbs * The xpt as a "controller" has no interrupt sources, so polling 5119434bbf6eSJustin T. Gibbs * is a no-op. 5120434bbf6eSJustin T. Gibbs */ 5121434bbf6eSJustin T. Gibbs static void 5122434bbf6eSJustin T. Gibbs xptpoll(struct cam_sim *sim) 5123434bbf6eSJustin T. Gibbs { 5124434bbf6eSJustin T. Gibbs } 5125434bbf6eSJustin T. Gibbs 51262b83592fSScott Long void 51272b83592fSScott Long xpt_lock_buses(void) 51282b83592fSScott Long { 51292b83592fSScott Long mtx_lock(&xsoftc.xpt_topo_lock); 51302b83592fSScott Long } 51312b83592fSScott Long 51322b83592fSScott Long void 51332b83592fSScott Long xpt_unlock_buses(void) 51342b83592fSScott Long { 51352b83592fSScott Long mtx_unlock(&xsoftc.xpt_topo_lock); 51362b83592fSScott Long } 51372b83592fSScott Long 5138227d67aaSAlexander Motin struct mtx * 5139227d67aaSAlexander Motin xpt_path_mtx(struct cam_path *path) 51408b8a9b1dSJustin T. Gibbs { 5141227d67aaSAlexander Motin 5142227d67aaSAlexander Motin return (&path->device->device_mtx); 5143227d67aaSAlexander Motin } 5144227d67aaSAlexander Motin 5145227d67aaSAlexander Motin static void 5146227d67aaSAlexander Motin xpt_done_process(struct ccb_hdr *ccb_h) 5147227d67aaSAlexander Motin { 51482b83592fSScott Long struct cam_sim *sim; 5149227d67aaSAlexander Motin struct cam_devq *devq; 5150227d67aaSAlexander Motin struct mtx *mtx = NULL; 51518b8a9b1dSJustin T. Gibbs 51528b8a9b1dSJustin T. Gibbs if (ccb_h->flags & CAM_HIGH_POWER) { 51538b8a9b1dSJustin T. Gibbs struct highpowerlist *hphead; 5154ea541bfdSAlexander Motin struct cam_ed *device; 51558b8a9b1dSJustin T. Gibbs 5156daa5487fSAlexander Motin mtx_lock(&xsoftc.xpt_highpower_lock); 51572b83592fSScott Long hphead = &xsoftc.highpowerq; 51588b8a9b1dSJustin T. Gibbs 5159ea541bfdSAlexander Motin device = STAILQ_FIRST(hphead); 51608b8a9b1dSJustin T. Gibbs 51618b8a9b1dSJustin T. Gibbs /* 51628b8a9b1dSJustin T. Gibbs * Increment the count since this command is done. 51638b8a9b1dSJustin T. Gibbs */ 51642b83592fSScott Long xsoftc.num_highpower++; 51658b8a9b1dSJustin T. Gibbs 51668b8a9b1dSJustin T. Gibbs /* 51678b8a9b1dSJustin T. Gibbs * Any high powered commands queued up? 51688b8a9b1dSJustin T. Gibbs */ 5169ea541bfdSAlexander Motin if (device != NULL) { 51708b8a9b1dSJustin T. Gibbs 5171ea541bfdSAlexander Motin STAILQ_REMOVE_HEAD(hphead, highpowerq_entry); 5172daa5487fSAlexander Motin mtx_unlock(&xsoftc.xpt_highpower_lock); 51738b8a9b1dSJustin T. Gibbs 5174227d67aaSAlexander Motin mtx_lock(&device->sim->devq->send_mtx); 5175ea541bfdSAlexander Motin xpt_release_devq_device(device, 51762cefde5fSJustin T. Gibbs /*count*/1, /*runqueue*/TRUE); 5177227d67aaSAlexander Motin mtx_unlock(&device->sim->devq->send_mtx); 51782b83592fSScott Long } else 5179daa5487fSAlexander Motin mtx_unlock(&xsoftc.xpt_highpower_lock); 51808b8a9b1dSJustin T. Gibbs } 51812b83592fSScott Long 5182227d67aaSAlexander Motin sim = ccb_h->path->bus->sim; 5183227d67aaSAlexander Motin 5184227d67aaSAlexander Motin if (ccb_h->status & CAM_RELEASE_SIMQ) { 5185227d67aaSAlexander Motin xpt_release_simq(sim, /*run_queue*/FALSE); 5186227d67aaSAlexander Motin ccb_h->status &= ~CAM_RELEASE_SIMQ; 5187227d67aaSAlexander Motin } 5188227d67aaSAlexander Motin 5189227d67aaSAlexander Motin if ((ccb_h->flags & CAM_DEV_QFRZDIS) 5190227d67aaSAlexander Motin && (ccb_h->status & CAM_DEV_QFRZN)) { 5191227d67aaSAlexander Motin xpt_release_devq(ccb_h->path, /*count*/1, 5192227d67aaSAlexander Motin /*run_queue*/FALSE); 5193227d67aaSAlexander Motin ccb_h->status &= ~CAM_DEV_QFRZN; 5194227d67aaSAlexander Motin } 5195227d67aaSAlexander Motin 5196227d67aaSAlexander Motin devq = sim->devq; 51979deea857SKenneth D. Merry if ((ccb_h->func_code & XPT_FC_USER_CCB) == 0) { 5198227d67aaSAlexander Motin struct cam_ed *dev = ccb_h->path->device; 51998b8a9b1dSJustin T. Gibbs 5200227d67aaSAlexander Motin mtx_lock(&devq->send_mtx); 5201227d67aaSAlexander Motin devq->send_active--; 5202227d67aaSAlexander Motin devq->send_openings++; 52038b8a9b1dSJustin T. Gibbs cam_ccbq_ccb_done(&dev->ccbq, (union ccb *)ccb_h); 52048b8a9b1dSJustin T. Gibbs 5205b9c473b2SAlexander Motin if (((dev->flags & CAM_DEV_REL_ON_QUEUE_EMPTY) != 0 52068b8a9b1dSJustin T. Gibbs && (dev->ccbq.dev_active == 0))) { 5207b9c473b2SAlexander Motin dev->flags &= ~CAM_DEV_REL_ON_QUEUE_EMPTY; 5208227d67aaSAlexander Motin xpt_release_devq_device(dev, /*count*/1, 5209b9c473b2SAlexander Motin /*run_queue*/FALSE); 5210b9c473b2SAlexander Motin } 5211b9c473b2SAlexander Motin 5212b9c473b2SAlexander Motin if (((dev->flags & CAM_DEV_REL_ON_COMPLETE) != 0 5213b9c473b2SAlexander Motin && (ccb_h->status&CAM_STATUS_MASK) != CAM_REQUEUE_REQ)) { 5214b9c473b2SAlexander Motin dev->flags &= ~CAM_DEV_REL_ON_COMPLETE; 5215227d67aaSAlexander Motin xpt_release_devq_device(dev, /*count*/1, 521683c5d981SAlexander Motin /*run_queue*/FALSE); 52178b8a9b1dSJustin T. Gibbs } 52188b8a9b1dSJustin T. Gibbs 5219227d67aaSAlexander Motin if (!device_is_queued(dev)) 5220227d67aaSAlexander Motin (void)xpt_schedule_devq(devq, dev); 5221227d67aaSAlexander Motin mtx_unlock(&devq->send_mtx); 5222227d67aaSAlexander Motin 5223227d67aaSAlexander Motin if ((dev->flags & CAM_DEV_TAG_AFTER_COUNT) != 0) { 5224227d67aaSAlexander Motin mtx = xpt_path_mtx(ccb_h->path); 5225227d67aaSAlexander Motin mtx_lock(mtx); 5226227d67aaSAlexander Motin 5227fd21cc5eSJustin T. Gibbs if ((dev->flags & CAM_DEV_TAG_AFTER_COUNT) != 0 5228fd21cc5eSJustin T. Gibbs && (--dev->tag_delay_count == 0)) 5229fd21cc5eSJustin T. Gibbs xpt_start_tags(ccb_h->path); 52303501942bSJustin T. Gibbs } 52318b8a9b1dSJustin T. Gibbs } 52328b8a9b1dSJustin T. Gibbs 5233227d67aaSAlexander Motin if ((ccb_h->flags & CAM_UNLOCKED) == 0) { 5234227d67aaSAlexander Motin if (mtx == NULL) { 5235227d67aaSAlexander Motin mtx = xpt_path_mtx(ccb_h->path); 5236227d67aaSAlexander Motin mtx_lock(mtx); 5237434bbf6eSJustin T. Gibbs } 5238227d67aaSAlexander Motin } else { 5239227d67aaSAlexander Motin if (mtx != NULL) { 5240227d67aaSAlexander Motin mtx_unlock(mtx); 5241227d67aaSAlexander Motin mtx = NULL; 5242227d67aaSAlexander Motin } 52438b8a9b1dSJustin T. Gibbs } 52448b8a9b1dSJustin T. Gibbs 52458b8a9b1dSJustin T. Gibbs /* Call the peripheral driver's callback */ 5246f1486b51SAlexander Motin ccb_h->pinfo.index = CAM_UNQUEUED_INDEX; 5247434bbf6eSJustin T. Gibbs (*ccb_h->cbfcnp)(ccb_h->path->periph, (union ccb *)ccb_h); 5248227d67aaSAlexander Motin if (mtx != NULL) 5249227d67aaSAlexander Motin mtx_unlock(mtx); 5250227d67aaSAlexander Motin 5251227d67aaSAlexander Motin mtx_lock(&devq->send_mtx); 5252227d67aaSAlexander Motin xpt_run_devq(devq); 5253227d67aaSAlexander Motin mtx_unlock(&devq->send_mtx); 5254227d67aaSAlexander Motin } 5255227d67aaSAlexander Motin 5256227d67aaSAlexander Motin void 5257227d67aaSAlexander Motin xpt_done_td(void *arg) 5258227d67aaSAlexander Motin { 5259227d67aaSAlexander Motin struct cam_doneq *queue = arg; 5260227d67aaSAlexander Motin struct ccb_hdr *ccb_h; 5261227d67aaSAlexander Motin STAILQ_HEAD(, ccb_hdr) doneq; 5262227d67aaSAlexander Motin 5263227d67aaSAlexander Motin STAILQ_INIT(&doneq); 5264227d67aaSAlexander Motin mtx_lock(&queue->cam_doneq_mtx); 5265227d67aaSAlexander Motin while (1) { 5266227d67aaSAlexander Motin while (STAILQ_EMPTY(&queue->cam_doneq)) { 5267227d67aaSAlexander Motin queue->cam_doneq_sleep = 1; 5268227d67aaSAlexander Motin msleep(&queue->cam_doneq, &queue->cam_doneq_mtx, 5269227d67aaSAlexander Motin PRIBIO, "-", 0); 5270227d67aaSAlexander Motin queue->cam_doneq_sleep = 0; 5271227d67aaSAlexander Motin } 5272227d67aaSAlexander Motin STAILQ_CONCAT(&doneq, &queue->cam_doneq); 5273227d67aaSAlexander Motin mtx_unlock(&queue->cam_doneq_mtx); 5274227d67aaSAlexander Motin 5275227d67aaSAlexander Motin THREAD_NO_SLEEPING(); 5276227d67aaSAlexander Motin while ((ccb_h = STAILQ_FIRST(&doneq)) != NULL) { 5277227d67aaSAlexander Motin STAILQ_REMOVE_HEAD(&doneq, sim_links.stqe); 5278227d67aaSAlexander Motin xpt_done_process(ccb_h); 5279227d67aaSAlexander Motin } 5280227d67aaSAlexander Motin THREAD_SLEEPING_OK(); 5281227d67aaSAlexander Motin 5282227d67aaSAlexander Motin mtx_lock(&queue->cam_doneq_mtx); 5283227d67aaSAlexander Motin } 5284227d67aaSAlexander Motin } 5285227d67aaSAlexander Motin 5286227d67aaSAlexander Motin static void 5287227d67aaSAlexander Motin camisr_runqueue(void) 5288227d67aaSAlexander Motin { 5289227d67aaSAlexander Motin struct ccb_hdr *ccb_h; 5290227d67aaSAlexander Motin struct cam_doneq *queue; 5291227d67aaSAlexander Motin int i; 5292227d67aaSAlexander Motin 5293227d67aaSAlexander Motin /* Process global queues. */ 5294227d67aaSAlexander Motin for (i = 0; i < cam_num_doneqs; i++) { 5295227d67aaSAlexander Motin queue = &cam_doneqs[i]; 5296227d67aaSAlexander Motin mtx_lock(&queue->cam_doneq_mtx); 5297227d67aaSAlexander Motin while ((ccb_h = STAILQ_FIRST(&queue->cam_doneq)) != NULL) { 5298227d67aaSAlexander Motin STAILQ_REMOVE_HEAD(&queue->cam_doneq, sim_links.stqe); 5299227d67aaSAlexander Motin mtx_unlock(&queue->cam_doneq_mtx); 5300227d67aaSAlexander Motin xpt_done_process(ccb_h); 5301227d67aaSAlexander Motin mtx_lock(&queue->cam_doneq_mtx); 5302227d67aaSAlexander Motin } 5303227d67aaSAlexander Motin mtx_unlock(&queue->cam_doneq_mtx); 53048b8a9b1dSJustin T. Gibbs } 53058b8a9b1dSJustin T. Gibbs } 5306