1898b0535SWarner Losh /*- 28b8a9b1dSJustin T. Gibbs * Implementation of the Common Access Method Transport (XPT) layer. 38b8a9b1dSJustin T. Gibbs * 4bec9534dSPedro F. Giffuni * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 5bec9534dSPedro F. Giffuni * 6c8bead2aSJustin T. Gibbs * Copyright (c) 1997, 1998, 1999 Justin T. Gibbs. 759190eaaSKenneth D. Merry * Copyright (c) 1997, 1998, 1999 Kenneth D. Merry. 88b8a9b1dSJustin T. Gibbs * All rights reserved. 98b8a9b1dSJustin T. Gibbs * 108b8a9b1dSJustin T. Gibbs * Redistribution and use in source and binary forms, with or without 118b8a9b1dSJustin T. Gibbs * modification, are permitted provided that the following conditions 128b8a9b1dSJustin T. Gibbs * are met: 138b8a9b1dSJustin T. Gibbs * 1. Redistributions of source code must retain the above copyright 148b8a9b1dSJustin T. Gibbs * notice, this list of conditions, and the following disclaimer, 158b8a9b1dSJustin T. Gibbs * without modification, immediately at the beginning of the file. 168b8a9b1dSJustin T. Gibbs * 2. The name of the author may not be used to endorse or promote products 178b8a9b1dSJustin T. Gibbs * derived from this software without specific prior written permission. 188b8a9b1dSJustin T. Gibbs * 198b8a9b1dSJustin T. Gibbs * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 208b8a9b1dSJustin T. Gibbs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 218b8a9b1dSJustin T. Gibbs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 228b8a9b1dSJustin T. Gibbs * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 238b8a9b1dSJustin T. Gibbs * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 248b8a9b1dSJustin T. Gibbs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 258b8a9b1dSJustin T. Gibbs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 268b8a9b1dSJustin T. Gibbs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 278b8a9b1dSJustin T. Gibbs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 288b8a9b1dSJustin T. Gibbs * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 298b8a9b1dSJustin T. Gibbs * SUCH DAMAGE. 308b8a9b1dSJustin T. Gibbs */ 319c963d87SDavid E. O'Brien 322379d1d6SWarner Losh #include "opt_printf.h" 332379d1d6SWarner Losh 349c963d87SDavid E. O'Brien #include <sys/cdefs.h> 359c963d87SDavid E. O'Brien __FBSDID("$FreeBSD$"); 369c963d87SDavid E. O'Brien 378b8a9b1dSJustin T. Gibbs #include <sys/param.h> 388532d381SConrad Meyer #include <sys/bio.h> 399a94c9c5SJohn Baldwin #include <sys/bus.h> 408b8a9b1dSJustin T. Gibbs #include <sys/systm.h> 418b8a9b1dSJustin T. Gibbs #include <sys/types.h> 428b8a9b1dSJustin T. Gibbs #include <sys/malloc.h> 438b8a9b1dSJustin T. Gibbs #include <sys/kernel.h> 4487cfaf0eSJustin T. Gibbs #include <sys/time.h> 458b8a9b1dSJustin T. Gibbs #include <sys/conf.h> 468b8a9b1dSJustin T. Gibbs #include <sys/fcntl.h> 47227d67aaSAlexander Motin #include <sys/proc.h> 483393f8daSKenneth D. Merry #include <sys/sbuf.h> 49227d67aaSAlexander Motin #include <sys/smp.h> 502b83592fSScott Long #include <sys/taskqueue.h> 518b8a9b1dSJustin T. Gibbs 52ef3cf714SScott Long #include <sys/lock.h> 53ef3cf714SScott Long #include <sys/mutex.h> 543b87a552SMatt Jacob #include <sys/sysctl.h> 559e6461a2SMatt Jacob #include <sys/kthread.h> 56ef3cf714SScott Long 578b8a9b1dSJustin T. Gibbs #include <cam/cam.h> 588b8a9b1dSJustin T. Gibbs #include <cam/cam_ccb.h> 59e4c9cba7SWarner Losh #include <cam/cam_iosched.h> 608b8a9b1dSJustin T. Gibbs #include <cam/cam_periph.h> 6152c9ce25SScott Long #include <cam/cam_queue.h> 628b8a9b1dSJustin T. Gibbs #include <cam/cam_sim.h> 638b8a9b1dSJustin T. Gibbs #include <cam/cam_xpt.h> 648b8a9b1dSJustin T. Gibbs #include <cam/cam_xpt_sim.h> 658b8a9b1dSJustin T. Gibbs #include <cam/cam_xpt_periph.h> 6652c9ce25SScott Long #include <cam/cam_xpt_internal.h> 678b8a9b1dSJustin T. Gibbs #include <cam/cam_debug.h> 6825a2902cSScott Long #include <cam/cam_compat.h> 698b8a9b1dSJustin T. Gibbs 708b8a9b1dSJustin T. Gibbs #include <cam/scsi/scsi_all.h> 718b8a9b1dSJustin T. Gibbs #include <cam/scsi/scsi_message.h> 728b8a9b1dSJustin T. Gibbs #include <cam/scsi/scsi_pass.h> 73abef0e67SMarius Strobl 74abef0e67SMarius Strobl #include <machine/md_var.h> /* geometry translation */ 75f0d9af51SMatt Jacob #include <machine/stdarg.h> /* for xpt_print below */ 76abef0e67SMarius Strobl 778b8a9b1dSJustin T. Gibbs #include "opt_cam.h" 788b8a9b1dSJustin T. Gibbs 792379d1d6SWarner Losh /* Wild guess based on not wanting to grow the stack too much */ 802379d1d6SWarner Losh #define XPT_PRINT_MAXLEN 512 812379d1d6SWarner Losh #ifdef PRINTF_BUFR_SIZE 822379d1d6SWarner Losh #define XPT_PRINT_LEN PRINTF_BUFR_SIZE 832379d1d6SWarner Losh #else 842379d1d6SWarner Losh #define XPT_PRINT_LEN 128 852379d1d6SWarner Losh #endif 862379d1d6SWarner Losh _Static_assert(XPT_PRINT_LEN <= XPT_PRINT_MAXLEN, "XPT_PRINT_LEN is too large"); 872379d1d6SWarner Losh 8852c9ce25SScott Long /* 8952c9ce25SScott Long * This is the maximum number of high powered commands (e.g. start unit) 9052c9ce25SScott Long * that can be outstanding at a particular time. 9152c9ce25SScott Long */ 9252c9ce25SScott Long #ifndef CAM_MAX_HIGHPOWER 9352c9ce25SScott Long #define CAM_MAX_HIGHPOWER 4 9452c9ce25SScott Long #endif 9552c9ce25SScott Long 968b8a9b1dSJustin T. Gibbs /* Datastructures internal to the xpt layer */ 97362abc44STai-hwa Liang MALLOC_DEFINE(M_CAMXPT, "CAM XPT", "CAM XPT buffers"); 98596ee08fSAlexander Motin MALLOC_DEFINE(M_CAMDEV, "CAM DEV", "CAM devices"); 99596ee08fSAlexander Motin MALLOC_DEFINE(M_CAMCCB, "CAM CCB", "CAM CCBs"); 100596ee08fSAlexander Motin MALLOC_DEFINE(M_CAMPATH, "CAM path", "CAM paths"); 1018b8a9b1dSJustin T. Gibbs 1028b8a9b1dSJustin T. Gibbs struct xpt_softc { 103636870ffSWill Andrews uint32_t xpt_generation; 104636870ffSWill Andrews 1052b83592fSScott Long /* number of high powered commands that can go through right now */ 106daa5487fSAlexander Motin struct mtx xpt_highpower_lock; 107ea541bfdSAlexander Motin STAILQ_HEAD(highpowerlist, cam_ed) highpowerq; 1082b83592fSScott Long int num_highpower; 1092b83592fSScott Long 1102b83592fSScott Long /* queue for handling async rescan requests. */ 1112b83592fSScott Long TAILQ_HEAD(, ccb_hdr) ccb_scanq; 11283c5d981SAlexander Motin int buses_to_config; 11383c5d981SAlexander Motin int buses_config_done; 1145d01277fSScott Long int announce_nosbuf; 1152b83592fSScott Long 116db4fcadfSConrad Meyer /* 117db4fcadfSConrad Meyer * Registered buses 118db4fcadfSConrad Meyer * 119db4fcadfSConrad Meyer * N.B., "busses" is an archaic spelling of "buses". In new code 120db4fcadfSConrad Meyer * "buses" is preferred. 121db4fcadfSConrad Meyer */ 1222b83592fSScott Long TAILQ_HEAD(,cam_eb) xpt_busses; 1232b83592fSScott Long u_int bus_generation; 1242b83592fSScott Long 12583c5d981SAlexander Motin int boot_delay; 12683c5d981SAlexander Motin struct callout boot_callout; 127a4876fbfSAlexander Motin struct task boot_task; 128a4876fbfSAlexander Motin struct root_hold_token xpt_rootmount; 12983c5d981SAlexander Motin 1302b83592fSScott Long struct mtx xpt_topo_lock; 131227d67aaSAlexander Motin struct taskqueue *xpt_taskq; 1328b8a9b1dSJustin T. Gibbs }; 1338b8a9b1dSJustin T. Gibbs 1348b8a9b1dSJustin T. Gibbs typedef enum { 1358b8a9b1dSJustin T. Gibbs DM_RET_COPY = 0x01, 1368b8a9b1dSJustin T. Gibbs DM_RET_FLAG_MASK = 0x0f, 1378b8a9b1dSJustin T. Gibbs DM_RET_NONE = 0x00, 1388b8a9b1dSJustin T. Gibbs DM_RET_STOP = 0x10, 1398b8a9b1dSJustin T. Gibbs DM_RET_DESCEND = 0x20, 1408b8a9b1dSJustin T. Gibbs DM_RET_ERROR = 0x30, 1418b8a9b1dSJustin T. Gibbs DM_RET_ACTION_MASK = 0xf0 1428b8a9b1dSJustin T. Gibbs } dev_match_ret; 1438b8a9b1dSJustin T. Gibbs 1448b8a9b1dSJustin T. Gibbs typedef enum { 1458b8a9b1dSJustin T. Gibbs XPT_DEPTH_BUS, 1468b8a9b1dSJustin T. Gibbs XPT_DEPTH_TARGET, 1478b8a9b1dSJustin T. Gibbs XPT_DEPTH_DEVICE, 1488b8a9b1dSJustin T. Gibbs XPT_DEPTH_PERIPH 1498b8a9b1dSJustin T. Gibbs } xpt_traverse_depth; 1508b8a9b1dSJustin T. Gibbs 1518b8a9b1dSJustin T. Gibbs struct xpt_traverse_config { 1528b8a9b1dSJustin T. Gibbs xpt_traverse_depth depth; 1538b8a9b1dSJustin T. Gibbs void *tr_func; 1548b8a9b1dSJustin T. Gibbs void *tr_arg; 1558b8a9b1dSJustin T. Gibbs }; 1568b8a9b1dSJustin T. Gibbs 1578b8a9b1dSJustin T. Gibbs typedef int xpt_busfunc_t (struct cam_eb *bus, void *arg); 1588b8a9b1dSJustin T. Gibbs typedef int xpt_targetfunc_t (struct cam_et *target, void *arg); 1598b8a9b1dSJustin T. Gibbs typedef int xpt_devicefunc_t (struct cam_ed *device, void *arg); 1608b8a9b1dSJustin T. Gibbs typedef int xpt_periphfunc_t (struct cam_periph *periph, void *arg); 1618b8a9b1dSJustin T. Gibbs typedef int xpt_pdrvfunc_t (struct periph_driver **pdrv, void *arg); 1628b8a9b1dSJustin T. Gibbs 1638b8a9b1dSJustin T. Gibbs /* Transport layer configuration information */ 1648b8a9b1dSJustin T. Gibbs static struct xpt_softc xsoftc; 1658b8a9b1dSJustin T. Gibbs 1665719711fSEdward Tomasz Napierala MTX_SYSINIT(xpt_topo_init, &xsoftc.xpt_topo_lock, "XPT topology lock", MTX_DEF); 1675719711fSEdward Tomasz Napierala 16883c5d981SAlexander Motin SYSCTL_INT(_kern_cam, OID_AUTO, boot_delay, CTLFLAG_RDTUN, 16983c5d981SAlexander Motin &xsoftc.boot_delay, 0, "Bus registration wait time"); 170636870ffSWill Andrews SYSCTL_UINT(_kern_cam, OID_AUTO, xpt_generation, CTLFLAG_RD, 171636870ffSWill Andrews &xsoftc.xpt_generation, 0, "CAM peripheral generation count"); 1725d01277fSScott Long SYSCTL_INT(_kern_cam, OID_AUTO, announce_nosbuf, CTLFLAG_RWTUN, 1735d01277fSScott Long &xsoftc.announce_nosbuf, 0, "Don't use sbuf for announcements"); 17483c5d981SAlexander Motin 175227d67aaSAlexander Motin struct cam_doneq { 176227d67aaSAlexander Motin struct mtx_padalign cam_doneq_mtx; 177227d67aaSAlexander Motin STAILQ_HEAD(, ccb_hdr) cam_doneq; 178227d67aaSAlexander Motin int cam_doneq_sleep; 179227d67aaSAlexander Motin }; 1808b8a9b1dSJustin T. Gibbs 181227d67aaSAlexander Motin static struct cam_doneq cam_doneqs[MAXCPU]; 182227d67aaSAlexander Motin static int cam_num_doneqs; 183227d67aaSAlexander Motin static struct proc *cam_proc; 184227d67aaSAlexander Motin 185227d67aaSAlexander Motin SYSCTL_INT(_kern_cam, OID_AUTO, num_doneqs, CTLFLAG_RDTUN, 186227d67aaSAlexander Motin &cam_num_doneqs, 0, "Number of completion queues/threads"); 1878b8a9b1dSJustin T. Gibbs 1889a1c8571SNick Hibma struct cam_periph *xpt_periph; 1899a1c8571SNick Hibma 1908b8a9b1dSJustin T. Gibbs static periph_init_t xpt_periph_init; 1918b8a9b1dSJustin T. Gibbs 1928b8a9b1dSJustin T. Gibbs static struct periph_driver xpt_driver = 1938b8a9b1dSJustin T. Gibbs { 1948b8a9b1dSJustin T. Gibbs xpt_periph_init, "xpt", 1951e637ba6SAlexander Motin TAILQ_HEAD_INITIALIZER(xpt_driver.units), /* generation */ 0, 1961e637ba6SAlexander Motin CAM_PERIPH_DRV_EARLY 1978b8a9b1dSJustin T. Gibbs }; 1988b8a9b1dSJustin T. Gibbs 1990b7c27b9SPeter Wemm PERIPHDRIVER_DECLARE(xpt, xpt_driver); 2008b8a9b1dSJustin T. Gibbs 2018b8a9b1dSJustin T. Gibbs static d_open_t xptopen; 2028b8a9b1dSJustin T. Gibbs static d_close_t xptclose; 2038b8a9b1dSJustin T. Gibbs static d_ioctl_t xptioctl; 20425a2902cSScott Long static d_ioctl_t xptdoioctl; 2058b8a9b1dSJustin T. Gibbs 2064e2f199eSPoul-Henning Kamp static struct cdevsw xpt_cdevsw = { 207dc08ffecSPoul-Henning Kamp .d_version = D_VERSION, 2082b83592fSScott Long .d_flags = 0, 2097ac40f5fSPoul-Henning Kamp .d_open = xptopen, 2107ac40f5fSPoul-Henning Kamp .d_close = xptclose, 2117ac40f5fSPoul-Henning Kamp .d_ioctl = xptioctl, 2127ac40f5fSPoul-Henning Kamp .d_name = "xpt", 2138b8a9b1dSJustin T. Gibbs }; 2148b8a9b1dSJustin T. Gibbs 2158b8a9b1dSJustin T. Gibbs /* Storage for debugging datastructures */ 2168b8a9b1dSJustin T. Gibbs struct cam_path *cam_dpath; 217*61322a0aSAlexander Motin u_int32_t __read_mostly cam_dflags = CAM_DEBUG_FLAGS; 218af3b2549SHans Petter Selasky SYSCTL_UINT(_kern_cam, OID_AUTO, dflags, CTLFLAG_RWTUN, 219f0f25b9cSAlexander Motin &cam_dflags, 0, "Enabled debug flags"); 220f0f25b9cSAlexander Motin u_int32_t cam_debug_delay = CAM_DEBUG_DELAY; 221af3b2549SHans Petter Selasky SYSCTL_UINT(_kern_cam, OID_AUTO, debug_delay, CTLFLAG_RWTUN, 222f0f25b9cSAlexander Motin &cam_debug_delay, 0, "Delay in us after each debug message"); 2238b8a9b1dSJustin T. Gibbs 2246d2a8f1cSPeter Wemm /* Our boot-time initialization hook */ 22574bd1c10SNick Hibma static int cam_module_event_handler(module_t, int /*modeventtype_t*/, void *); 22674bd1c10SNick Hibma 22774bd1c10SNick Hibma static moduledata_t cam_moduledata = { 22874bd1c10SNick Hibma "cam", 22974bd1c10SNick Hibma cam_module_event_handler, 23074bd1c10SNick Hibma NULL 23174bd1c10SNick Hibma }; 23274bd1c10SNick Hibma 2332b83592fSScott Long static int xpt_init(void *); 23474bd1c10SNick Hibma 23574bd1c10SNick Hibma DECLARE_MODULE(cam, cam_moduledata, SI_SUB_CONFIGURE, SI_ORDER_SECOND); 23674bd1c10SNick Hibma MODULE_VERSION(cam, 1); 23774bd1c10SNick Hibma 2388b8a9b1dSJustin T. Gibbs 2398b8a9b1dSJustin T. Gibbs static void xpt_async_bcast(struct async_list *async_head, 2408b8a9b1dSJustin T. Gibbs u_int32_t async_code, 2418b8a9b1dSJustin T. Gibbs struct cam_path *path, 2428b8a9b1dSJustin T. Gibbs void *async_arg); 243434bbf6eSJustin T. Gibbs static path_id_t xptnextfreepathid(void); 244434bbf6eSJustin T. Gibbs static path_id_t xptpathid(const char *sim_name, int sim_unit, int sim_bus); 245227d67aaSAlexander Motin static union ccb *xpt_get_ccb(struct cam_periph *periph); 246227d67aaSAlexander Motin static union ccb *xpt_get_ccb_nowait(struct cam_periph *periph); 247227d67aaSAlexander Motin static void xpt_run_allocq(struct cam_periph *periph, int sleep); 248227d67aaSAlexander Motin static void xpt_run_allocq_task(void *context, int pending); 249cccf4220SAlexander Motin static void xpt_run_devq(struct cam_devq *devq); 2508b8a9b1dSJustin T. Gibbs static timeout_t xpt_release_devq_timeout; 2512b83592fSScott Long static void xpt_release_simq_timeout(void *arg) __unused; 252227d67aaSAlexander Motin static void xpt_acquire_bus(struct cam_eb *bus); 253a5479bc5SJustin T. Gibbs static void xpt_release_bus(struct cam_eb *bus); 254daa5487fSAlexander Motin static uint32_t xpt_freeze_devq_device(struct cam_ed *dev, u_int count); 255227d67aaSAlexander Motin static int xpt_release_devq_device(struct cam_ed *dev, u_int count, 256cccf4220SAlexander Motin int run_queue); 2578b8a9b1dSJustin T. Gibbs static struct cam_et* 2588b8a9b1dSJustin T. Gibbs xpt_alloc_target(struct cam_eb *bus, target_id_t target_id); 259227d67aaSAlexander Motin static void xpt_acquire_target(struct cam_et *target); 260f98d7a47SAlexander Motin static void xpt_release_target(struct cam_et *target); 2618b8a9b1dSJustin T. Gibbs static struct cam_eb* 2628b8a9b1dSJustin T. Gibbs xpt_find_bus(path_id_t path_id); 2638b8a9b1dSJustin T. Gibbs static struct cam_et* 2648b8a9b1dSJustin T. Gibbs xpt_find_target(struct cam_eb *bus, target_id_t target_id); 2658b8a9b1dSJustin T. Gibbs static struct cam_ed* 2668b8a9b1dSJustin T. Gibbs xpt_find_device(struct cam_et *target, lun_id_t lun_id); 2678b8a9b1dSJustin T. Gibbs static void xpt_config(void *arg); 268a4876fbfSAlexander Motin static void xpt_hold_boot_locked(void); 269227d67aaSAlexander Motin static int xpt_schedule_dev(struct camq *queue, cam_pinfo *dev_pinfo, 270227d67aaSAlexander Motin u_int32_t new_priority); 2718b8a9b1dSJustin T. Gibbs static xpt_devicefunc_t xptpassannouncefunc; 2728b8a9b1dSJustin T. Gibbs static void xptaction(struct cam_sim *sim, union ccb *work_ccb); 273434bbf6eSJustin T. Gibbs static void xptpoll(struct cam_sim *sim); 274227d67aaSAlexander Motin static void camisr_runqueue(void); 275227d67aaSAlexander Motin static void xpt_done_process(struct ccb_hdr *ccb_h); 276227d67aaSAlexander Motin static void xpt_done_td(void *); 2778b8a9b1dSJustin T. Gibbs static dev_match_ret xptbusmatch(struct dev_match_pattern *patterns, 2783393f8daSKenneth D. Merry u_int num_patterns, struct cam_eb *bus); 2798b8a9b1dSJustin T. Gibbs static dev_match_ret xptdevicematch(struct dev_match_pattern *patterns, 2803393f8daSKenneth D. Merry u_int num_patterns, 2813393f8daSKenneth D. Merry struct cam_ed *device); 2828b8a9b1dSJustin T. Gibbs static dev_match_ret xptperiphmatch(struct dev_match_pattern *patterns, 2833393f8daSKenneth D. Merry u_int num_patterns, 2848b8a9b1dSJustin T. Gibbs struct cam_periph *periph); 2858b8a9b1dSJustin T. Gibbs static xpt_busfunc_t xptedtbusfunc; 2868b8a9b1dSJustin T. Gibbs static xpt_targetfunc_t xptedttargetfunc; 2878b8a9b1dSJustin T. Gibbs static xpt_devicefunc_t xptedtdevicefunc; 2888b8a9b1dSJustin T. Gibbs static xpt_periphfunc_t xptedtperiphfunc; 2898b8a9b1dSJustin T. Gibbs static xpt_pdrvfunc_t xptplistpdrvfunc; 2908b8a9b1dSJustin T. Gibbs static xpt_periphfunc_t xptplistperiphfunc; 2918b8a9b1dSJustin T. Gibbs static int xptedtmatch(struct ccb_dev_match *cdm); 2928b8a9b1dSJustin T. Gibbs static int xptperiphlistmatch(struct ccb_dev_match *cdm); 2938b8a9b1dSJustin T. Gibbs static int xptbustraverse(struct cam_eb *start_bus, 2948b8a9b1dSJustin T. Gibbs xpt_busfunc_t *tr_func, void *arg); 2958b8a9b1dSJustin T. Gibbs static int xpttargettraverse(struct cam_eb *bus, 2968b8a9b1dSJustin T. Gibbs struct cam_et *start_target, 2978b8a9b1dSJustin T. Gibbs xpt_targetfunc_t *tr_func, void *arg); 2988b8a9b1dSJustin T. Gibbs static int xptdevicetraverse(struct cam_et *target, 2998b8a9b1dSJustin T. Gibbs struct cam_ed *start_device, 3008b8a9b1dSJustin T. Gibbs xpt_devicefunc_t *tr_func, void *arg); 3018b8a9b1dSJustin T. Gibbs static int xptperiphtraverse(struct cam_ed *device, 3028b8a9b1dSJustin T. Gibbs struct cam_periph *start_periph, 3038b8a9b1dSJustin T. Gibbs xpt_periphfunc_t *tr_func, void *arg); 3048b8a9b1dSJustin T. Gibbs static int xptpdrvtraverse(struct periph_driver **start_pdrv, 3058b8a9b1dSJustin T. Gibbs xpt_pdrvfunc_t *tr_func, void *arg); 3068b8a9b1dSJustin T. Gibbs static int xptpdperiphtraverse(struct periph_driver **pdrv, 3078b8a9b1dSJustin T. Gibbs struct cam_periph *start_periph, 3088b8a9b1dSJustin T. Gibbs xpt_periphfunc_t *tr_func, 3098b8a9b1dSJustin T. Gibbs void *arg); 3108b8a9b1dSJustin T. Gibbs static xpt_busfunc_t xptdefbusfunc; 3118b8a9b1dSJustin T. Gibbs static xpt_targetfunc_t xptdeftargetfunc; 3128b8a9b1dSJustin T. Gibbs static xpt_devicefunc_t xptdefdevicefunc; 3138b8a9b1dSJustin T. Gibbs static xpt_periphfunc_t xptdefperiphfunc; 31483c5d981SAlexander Motin static void xpt_finishconfig_task(void *context, int pending); 31552c9ce25SScott Long static void xpt_dev_async_default(u_int32_t async_code, 31652c9ce25SScott Long struct cam_eb *bus, 31752c9ce25SScott Long struct cam_et *target, 31852c9ce25SScott Long struct cam_ed *device, 31952c9ce25SScott Long void *async_arg); 32052c9ce25SScott Long static struct cam_ed * xpt_alloc_device_default(struct cam_eb *bus, 32152c9ce25SScott Long struct cam_et *target, 32252c9ce25SScott Long lun_id_t lun_id); 3238b8a9b1dSJustin T. Gibbs static xpt_devicefunc_t xptsetasyncfunc; 3248b8a9b1dSJustin T. Gibbs static xpt_busfunc_t xptsetasyncbusfunc; 3258b8a9b1dSJustin T. Gibbs static cam_status xptregister(struct cam_periph *periph, 3268b8a9b1dSJustin T. Gibbs void *arg); 327cccf4220SAlexander Motin static __inline int device_is_queued(struct cam_ed *device); 3288b8a9b1dSJustin T. Gibbs 3298b8a9b1dSJustin T. Gibbs static __inline int 330cccf4220SAlexander Motin xpt_schedule_devq(struct cam_devq *devq, struct cam_ed *dev) 33130a4094fSAlexander Motin { 33230a4094fSAlexander Motin int retval; 33330a4094fSAlexander Motin 334227d67aaSAlexander Motin mtx_assert(&devq->send_mtx, MA_OWNED); 33583c5d981SAlexander Motin if ((dev->ccbq.queue.entries > 0) && 33683c5d981SAlexander Motin (dev->ccbq.dev_openings > 0) && 337cccf4220SAlexander Motin (dev->ccbq.queue.qfrozen_cnt == 0)) { 33830a4094fSAlexander Motin /* 33930a4094fSAlexander Motin * The priority of a device waiting for controller 3406bccea7cSRebecca Cran * resources is that of the highest priority CCB 34130a4094fSAlexander Motin * enqueued. 34230a4094fSAlexander Motin */ 34330a4094fSAlexander Motin retval = 344cccf4220SAlexander Motin xpt_schedule_dev(&devq->send_queue, 345227d67aaSAlexander Motin &dev->devq_entry, 34683c5d981SAlexander Motin CAMQ_GET_PRIO(&dev->ccbq.queue)); 34730a4094fSAlexander Motin } else { 34830a4094fSAlexander Motin retval = 0; 34930a4094fSAlexander Motin } 35030a4094fSAlexander Motin return (retval); 35130a4094fSAlexander Motin } 35230a4094fSAlexander Motin 35330a4094fSAlexander Motin static __inline int 354cccf4220SAlexander Motin device_is_queued(struct cam_ed *device) 3558b8a9b1dSJustin T. Gibbs { 356227d67aaSAlexander Motin return (device->devq_entry.index != CAM_UNQUEUED_INDEX); 3578b8a9b1dSJustin T. Gibbs } 3588b8a9b1dSJustin T. Gibbs 3598b8a9b1dSJustin T. Gibbs static void 3608b8a9b1dSJustin T. Gibbs xpt_periph_init() 3618b8a9b1dSJustin T. Gibbs { 36273d26919SKenneth D. Merry make_dev(&xpt_cdevsw, 0, UID_ROOT, GID_OPERATOR, 0600, "xpt0"); 3638b8a9b1dSJustin T. Gibbs } 3648b8a9b1dSJustin T. Gibbs 3658b8a9b1dSJustin T. Gibbs static int 36689c9c53dSPoul-Henning Kamp xptopen(struct cdev *dev, int flags, int fmt, struct thread *td) 3678b8a9b1dSJustin T. Gibbs { 3688b8a9b1dSJustin T. Gibbs 3698b8a9b1dSJustin T. Gibbs /* 37066a0780eSKenneth D. Merry * Only allow read-write access. 37166a0780eSKenneth D. Merry */ 37266a0780eSKenneth D. Merry if (((flags & FWRITE) == 0) || ((flags & FREAD) == 0)) 37366a0780eSKenneth D. Merry return(EPERM); 37466a0780eSKenneth D. Merry 37566a0780eSKenneth D. Merry /* 3768b8a9b1dSJustin T. Gibbs * We don't allow nonblocking access. 3778b8a9b1dSJustin T. Gibbs */ 3788b8a9b1dSJustin T. Gibbs if ((flags & O_NONBLOCK) != 0) { 3792b83592fSScott Long printf("%s: can't do nonblocking access\n", devtoname(dev)); 3808b8a9b1dSJustin T. Gibbs return(ENODEV); 3818b8a9b1dSJustin T. Gibbs } 3828b8a9b1dSJustin T. Gibbs 3838b8a9b1dSJustin T. Gibbs return(0); 3848b8a9b1dSJustin T. Gibbs } 3858b8a9b1dSJustin T. Gibbs 3868b8a9b1dSJustin T. Gibbs static int 38789c9c53dSPoul-Henning Kamp xptclose(struct cdev *dev, int flag, int fmt, struct thread *td) 3888b8a9b1dSJustin T. Gibbs { 3898b8a9b1dSJustin T. Gibbs 3908b8a9b1dSJustin T. Gibbs return(0); 3918b8a9b1dSJustin T. Gibbs } 3928b8a9b1dSJustin T. Gibbs 3932b83592fSScott Long /* 3942b83592fSScott Long * Don't automatically grab the xpt softc lock here even though this is going 3952b83592fSScott Long * through the xpt device. The xpt device is really just a back door for 3962b83592fSScott Long * accessing other devices and SIMs, so the right thing to do is to grab 3972b83592fSScott Long * the appropriate SIM lock once the bus/SIM is located. 3982b83592fSScott Long */ 3998b8a9b1dSJustin T. Gibbs static int 40089c9c53dSPoul-Henning Kamp xptioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, struct thread *td) 4018b8a9b1dSJustin T. Gibbs { 4022b83592fSScott Long int error; 4038b8a9b1dSJustin T. Gibbs 40425a2902cSScott Long if ((error = xptdoioctl(dev, cmd, addr, flag, td)) == ENOTTY) { 405f564de00SScott Long error = cam_compat_ioctl(dev, cmd, addr, flag, td, xptdoioctl); 40625a2902cSScott Long } 40725a2902cSScott Long return (error); 40825a2902cSScott Long } 40925a2902cSScott Long 41025a2902cSScott Long static int 41125a2902cSScott Long xptdoioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, struct thread *td) 41225a2902cSScott Long { 41325a2902cSScott Long int error; 41425a2902cSScott Long 4158b8a9b1dSJustin T. Gibbs error = 0; 4168b8a9b1dSJustin T. Gibbs 4178b8a9b1dSJustin T. Gibbs switch(cmd) { 4188b8a9b1dSJustin T. Gibbs /* 4198b8a9b1dSJustin T. Gibbs * For the transport layer CAMIOCOMMAND ioctl, we really only want 4208b8a9b1dSJustin T. Gibbs * to accept CCB types that don't quite make sense to send through a 4218c7a96c5SScott Long * passthrough driver. XPT_PATH_INQ is an exception to this, as stated 4228c7a96c5SScott Long * in the CAM spec. 4238b8a9b1dSJustin T. Gibbs */ 4248b8a9b1dSJustin T. Gibbs case CAMIOCOMMAND: { 4258b8a9b1dSJustin T. Gibbs union ccb *ccb; 4268b8a9b1dSJustin T. Gibbs union ccb *inccb; 4272b83592fSScott Long struct cam_eb *bus; 4288b8a9b1dSJustin T. Gibbs 4298b8a9b1dSJustin T. Gibbs inccb = (union ccb *)addr; 4308fc77fffSConrad Meyer #if defined(BUF_TRACKING) || defined(FULL_BUF_TRACKING) 4318fc77fffSConrad Meyer if (inccb->ccb_h.func_code == XPT_SCSI_IO) 4328fc77fffSConrad Meyer inccb->csio.bio = NULL; 4338fc77fffSConrad Meyer #endif 4348b8a9b1dSJustin T. Gibbs 435a0bbf9e0SMark Johnston if (inccb->ccb_h.flags & CAM_UNLOCKED) 436a0bbf9e0SMark Johnston return (EINVAL); 437a0bbf9e0SMark Johnston 4382b83592fSScott Long bus = xpt_find_bus(inccb->ccb_h.path_id); 4390e85f214SMatt Jacob if (bus == NULL) 4400e85f214SMatt Jacob return (EINVAL); 4410e85f214SMatt Jacob 4420e85f214SMatt Jacob switch (inccb->ccb_h.func_code) { 4430e85f214SMatt Jacob case XPT_SCAN_BUS: 4440e85f214SMatt Jacob case XPT_RESET_BUS: 4450e85f214SMatt Jacob if (inccb->ccb_h.target_id != CAM_TARGET_WILDCARD || 4460e85f214SMatt Jacob inccb->ccb_h.target_lun != CAM_LUN_WILDCARD) { 4470e85f214SMatt Jacob xpt_release_bus(bus); 4480e85f214SMatt Jacob return (EINVAL); 4490e85f214SMatt Jacob } 4500e85f214SMatt Jacob break; 4510e85f214SMatt Jacob case XPT_SCAN_TGT: 4520e85f214SMatt Jacob if (inccb->ccb_h.target_id == CAM_TARGET_WILDCARD || 4530e85f214SMatt Jacob inccb->ccb_h.target_lun != CAM_LUN_WILDCARD) { 4540e85f214SMatt Jacob xpt_release_bus(bus); 4550e85f214SMatt Jacob return (EINVAL); 4560e85f214SMatt Jacob } 4570e85f214SMatt Jacob break; 4580e85f214SMatt Jacob default: 4592b83592fSScott Long break; 4602b83592fSScott Long } 4612b83592fSScott Long 4628b8a9b1dSJustin T. Gibbs switch(inccb->ccb_h.func_code) { 4638b8a9b1dSJustin T. Gibbs case XPT_SCAN_BUS: 4648b8a9b1dSJustin T. Gibbs case XPT_RESET_BUS: 4658c7a96c5SScott Long case XPT_PATH_INQ: 4668fcf57f5SJustin T. Gibbs case XPT_ENG_INQ: 4678b8a9b1dSJustin T. Gibbs case XPT_SCAN_LUN: 4680e85f214SMatt Jacob case XPT_SCAN_TGT: 4698b8a9b1dSJustin T. Gibbs 4708008a935SScott Long ccb = xpt_alloc_ccb(); 4712b83592fSScott Long 4728b8a9b1dSJustin T. Gibbs /* 4738b8a9b1dSJustin T. Gibbs * Create a path using the bus, target, and lun the 4748b8a9b1dSJustin T. Gibbs * user passed in. 4758b8a9b1dSJustin T. Gibbs */ 476e5dfa058SAlexander Motin if (xpt_create_path(&ccb->ccb_h.path, NULL, 4778b8a9b1dSJustin T. Gibbs inccb->ccb_h.path_id, 4788b8a9b1dSJustin T. Gibbs inccb->ccb_h.target_id, 4798b8a9b1dSJustin T. Gibbs inccb->ccb_h.target_lun) != 4808b8a9b1dSJustin T. Gibbs CAM_REQ_CMP){ 4818b8a9b1dSJustin T. Gibbs error = EINVAL; 4828b8a9b1dSJustin T. Gibbs xpt_free_ccb(ccb); 4838b8a9b1dSJustin T. Gibbs break; 4848b8a9b1dSJustin T. Gibbs } 4858b8a9b1dSJustin T. Gibbs /* Ensure all of our fields are correct */ 4868b8a9b1dSJustin T. Gibbs xpt_setup_ccb(&ccb->ccb_h, ccb->ccb_h.path, 4878b8a9b1dSJustin T. Gibbs inccb->ccb_h.pinfo.priority); 4888b8a9b1dSJustin T. Gibbs xpt_merge_ccb(ccb, inccb); 489227d67aaSAlexander Motin xpt_path_lock(ccb->ccb_h.path); 4908b8a9b1dSJustin T. Gibbs cam_periph_runccb(ccb, NULL, 0, 0, NULL); 491227d67aaSAlexander Motin xpt_path_unlock(ccb->ccb_h.path); 4928b8a9b1dSJustin T. Gibbs bcopy(ccb, inccb, sizeof(union ccb)); 4938b8a9b1dSJustin T. Gibbs xpt_free_path(ccb->ccb_h.path); 4948b8a9b1dSJustin T. Gibbs xpt_free_ccb(ccb); 4958b8a9b1dSJustin T. Gibbs break; 4968b8a9b1dSJustin T. Gibbs 4978b8a9b1dSJustin T. Gibbs case XPT_DEBUG: { 4988b8a9b1dSJustin T. Gibbs union ccb ccb; 4998b8a9b1dSJustin T. Gibbs 5008b8a9b1dSJustin T. Gibbs /* 501aa872be6SMatt Jacob * This is an immediate CCB, so it's okay to 5028b8a9b1dSJustin T. Gibbs * allocate it on the stack. 5038b8a9b1dSJustin T. Gibbs */ 5048b8a9b1dSJustin T. Gibbs 5058b8a9b1dSJustin T. Gibbs /* 5068b8a9b1dSJustin T. Gibbs * Create a path using the bus, target, and lun the 5078b8a9b1dSJustin T. Gibbs * user passed in. 5088b8a9b1dSJustin T. Gibbs */ 509e5dfa058SAlexander Motin if (xpt_create_path(&ccb.ccb_h.path, NULL, 5108b8a9b1dSJustin T. Gibbs inccb->ccb_h.path_id, 5118b8a9b1dSJustin T. Gibbs inccb->ccb_h.target_id, 5128b8a9b1dSJustin T. Gibbs inccb->ccb_h.target_lun) != 5138b8a9b1dSJustin T. Gibbs CAM_REQ_CMP){ 5148b8a9b1dSJustin T. Gibbs error = EINVAL; 5158b8a9b1dSJustin T. Gibbs break; 5168b8a9b1dSJustin T. Gibbs } 5178b8a9b1dSJustin T. Gibbs /* Ensure all of our fields are correct */ 5188b8a9b1dSJustin T. Gibbs xpt_setup_ccb(&ccb.ccb_h, ccb.ccb_h.path, 5198b8a9b1dSJustin T. Gibbs inccb->ccb_h.pinfo.priority); 5208b8a9b1dSJustin T. Gibbs xpt_merge_ccb(&ccb, inccb); 5218b8a9b1dSJustin T. Gibbs xpt_action(&ccb); 5228b8a9b1dSJustin T. Gibbs bcopy(&ccb, inccb, sizeof(union ccb)); 5238b8a9b1dSJustin T. Gibbs xpt_free_path(ccb.ccb_h.path); 5248b8a9b1dSJustin T. Gibbs break; 5258b8a9b1dSJustin T. Gibbs 5268b8a9b1dSJustin T. Gibbs } 5278b8a9b1dSJustin T. Gibbs case XPT_DEV_MATCH: { 5288b8a9b1dSJustin T. Gibbs struct cam_periph_map_info mapinfo; 52959190eaaSKenneth D. Merry struct cam_path *old_path; 5308b8a9b1dSJustin T. Gibbs 5318b8a9b1dSJustin T. Gibbs /* 5328b8a9b1dSJustin T. Gibbs * We can't deal with physical addresses for this 5338b8a9b1dSJustin T. Gibbs * type of transaction. 5348b8a9b1dSJustin T. Gibbs */ 535dd0b4fb6SKonstantin Belousov if ((inccb->ccb_h.flags & CAM_DATA_MASK) != 536dd0b4fb6SKonstantin Belousov CAM_DATA_VADDR) { 5378b8a9b1dSJustin T. Gibbs error = EINVAL; 5388b8a9b1dSJustin T. Gibbs break; 5398b8a9b1dSJustin T. Gibbs } 54059190eaaSKenneth D. Merry 54159190eaaSKenneth D. Merry /* 54259190eaaSKenneth D. Merry * Save this in case the caller had it set to 54359190eaaSKenneth D. Merry * something in particular. 54459190eaaSKenneth D. Merry */ 54559190eaaSKenneth D. Merry old_path = inccb->ccb_h.path; 54659190eaaSKenneth D. Merry 54759190eaaSKenneth D. Merry /* 54859190eaaSKenneth D. Merry * We really don't need a path for the matching 54959190eaaSKenneth D. Merry * code. The path is needed because of the 55059190eaaSKenneth D. Merry * debugging statements in xpt_action(). They 55159190eaaSKenneth D. Merry * assume that the CCB has a valid path. 55259190eaaSKenneth D. Merry */ 55359190eaaSKenneth D. Merry inccb->ccb_h.path = xpt_periph->path; 55459190eaaSKenneth D. Merry 5558b8a9b1dSJustin T. Gibbs bzero(&mapinfo, sizeof(mapinfo)); 5568b8a9b1dSJustin T. Gibbs 5578b8a9b1dSJustin T. Gibbs /* 5588b8a9b1dSJustin T. Gibbs * Map the pattern and match buffers into kernel 5598b8a9b1dSJustin T. Gibbs * virtual address space. 5608b8a9b1dSJustin T. Gibbs */ 561de239312SAlexander Motin error = cam_periph_mapmem(inccb, &mapinfo, MAXPHYS); 5628b8a9b1dSJustin T. Gibbs 56359190eaaSKenneth D. Merry if (error) { 56459190eaaSKenneth D. Merry inccb->ccb_h.path = old_path; 5658b8a9b1dSJustin T. Gibbs break; 56659190eaaSKenneth D. Merry } 5678b8a9b1dSJustin T. Gibbs 5688b8a9b1dSJustin T. Gibbs /* 5698b8a9b1dSJustin T. Gibbs * This is an immediate CCB, we can send it on directly. 5708b8a9b1dSJustin T. Gibbs */ 5718b8a9b1dSJustin T. Gibbs xpt_action(inccb); 5728b8a9b1dSJustin T. Gibbs 5738b8a9b1dSJustin T. Gibbs /* 5748b8a9b1dSJustin T. Gibbs * Map the buffers back into user space. 5758b8a9b1dSJustin T. Gibbs */ 5768b8a9b1dSJustin T. Gibbs cam_periph_unmapmem(inccb, &mapinfo); 5778b8a9b1dSJustin T. Gibbs 57859190eaaSKenneth D. Merry inccb->ccb_h.path = old_path; 57959190eaaSKenneth D. Merry 5808b8a9b1dSJustin T. Gibbs error = 0; 5818b8a9b1dSJustin T. Gibbs break; 5828b8a9b1dSJustin T. Gibbs } 5838b8a9b1dSJustin T. Gibbs default: 5848fcf57f5SJustin T. Gibbs error = ENOTSUP; 5858b8a9b1dSJustin T. Gibbs break; 5868b8a9b1dSJustin T. Gibbs } 587daddc001SScott Long xpt_release_bus(bus); 5888b8a9b1dSJustin T. Gibbs break; 5898b8a9b1dSJustin T. Gibbs } 5908b8a9b1dSJustin T. Gibbs /* 5918b8a9b1dSJustin T. Gibbs * This is the getpassthru ioctl. It takes a XPT_GDEVLIST ccb as input, 5928b8a9b1dSJustin T. Gibbs * with the periphal driver name and unit name filled in. The other 5938b8a9b1dSJustin T. Gibbs * fields don't really matter as input. The passthrough driver name 5948b8a9b1dSJustin T. Gibbs * ("pass"), and unit number are passed back in the ccb. The current 5958b8a9b1dSJustin T. Gibbs * device generation number, and the index into the device peripheral 5968b8a9b1dSJustin T. Gibbs * driver list, and the status are also passed back. Note that 5978b8a9b1dSJustin T. Gibbs * since we do everything in one pass, unlike the XPT_GDEVLIST ccb, 5988b8a9b1dSJustin T. Gibbs * we never return a status of CAM_GDEVLIST_LIST_CHANGED. It is 5998b8a9b1dSJustin T. Gibbs * (or rather should be) impossible for the device peripheral driver 6008b8a9b1dSJustin T. Gibbs * list to change since we look at the whole thing in one pass, and 60177dc25ccSScott Long * we do it with lock protection. 6028b8a9b1dSJustin T. Gibbs * 6038b8a9b1dSJustin T. Gibbs */ 6048b8a9b1dSJustin T. Gibbs case CAMGETPASSTHRU: { 6058b8a9b1dSJustin T. Gibbs union ccb *ccb; 6068b8a9b1dSJustin T. Gibbs struct cam_periph *periph; 6078b8a9b1dSJustin T. Gibbs struct periph_driver **p_drv; 6088b8a9b1dSJustin T. Gibbs char *name; 6093393f8daSKenneth D. Merry u_int unit; 610621a60d4SKenneth D. Merry int base_periph_found; 6118b8a9b1dSJustin T. Gibbs 6128b8a9b1dSJustin T. Gibbs ccb = (union ccb *)addr; 6138b8a9b1dSJustin T. Gibbs unit = ccb->cgdl.unit_number; 6148b8a9b1dSJustin T. Gibbs name = ccb->cgdl.periph_name; 615621a60d4SKenneth D. Merry base_periph_found = 0; 6168fc77fffSConrad Meyer #if defined(BUF_TRACKING) || defined(FULL_BUF_TRACKING) 6178fc77fffSConrad Meyer if (ccb->ccb_h.func_code == XPT_SCSI_IO) 6188fc77fffSConrad Meyer ccb->csio.bio = NULL; 6198fc77fffSConrad Meyer #endif 620621a60d4SKenneth D. Merry 6218b8a9b1dSJustin T. Gibbs /* 6228b8a9b1dSJustin T. Gibbs * Sanity check -- make sure we don't get a null peripheral 6238b8a9b1dSJustin T. Gibbs * driver name. 6248b8a9b1dSJustin T. Gibbs */ 6258b8a9b1dSJustin T. Gibbs if (*ccb->cgdl.periph_name == '\0') { 6268b8a9b1dSJustin T. Gibbs error = EINVAL; 6278b8a9b1dSJustin T. Gibbs break; 6288b8a9b1dSJustin T. Gibbs } 6298b8a9b1dSJustin T. Gibbs 6308b8a9b1dSJustin T. Gibbs /* Keep the list from changing while we traverse it */ 6319a7c2696SAlexander Motin xpt_lock_buses(); 6328b8a9b1dSJustin T. Gibbs 6338b8a9b1dSJustin T. Gibbs /* first find our driver in the list of drivers */ 6340b7c27b9SPeter Wemm for (p_drv = periph_drivers; *p_drv != NULL; p_drv++) 6358b8a9b1dSJustin T. Gibbs if (strcmp((*p_drv)->driver_name, name) == 0) 6368b8a9b1dSJustin T. Gibbs break; 6378b8a9b1dSJustin T. Gibbs 6388b8a9b1dSJustin T. Gibbs if (*p_drv == NULL) { 6399a7c2696SAlexander Motin xpt_unlock_buses(); 6408b8a9b1dSJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_CMP_ERR; 6418b8a9b1dSJustin T. Gibbs ccb->cgdl.status = CAM_GDEVLIST_ERROR; 6428b8a9b1dSJustin T. Gibbs *ccb->cgdl.periph_name = '\0'; 6438b8a9b1dSJustin T. Gibbs ccb->cgdl.unit_number = 0; 6448b8a9b1dSJustin T. Gibbs error = ENOENT; 6458b8a9b1dSJustin T. Gibbs break; 6468b8a9b1dSJustin T. Gibbs } 6478b8a9b1dSJustin T. Gibbs 6488b8a9b1dSJustin T. Gibbs /* 6498b8a9b1dSJustin T. Gibbs * Run through every peripheral instance of this driver 6508b8a9b1dSJustin T. Gibbs * and check to see whether it matches the unit passed 6518b8a9b1dSJustin T. Gibbs * in by the user. If it does, get out of the loops and 6528b8a9b1dSJustin T. Gibbs * find the passthrough driver associated with that 6538b8a9b1dSJustin T. Gibbs * peripheral driver. 6548b8a9b1dSJustin T. Gibbs */ 6558b8a9b1dSJustin T. Gibbs for (periph = TAILQ_FIRST(&(*p_drv)->units); periph != NULL; 6568b8a9b1dSJustin T. Gibbs periph = TAILQ_NEXT(periph, unit_links)) { 6578b8a9b1dSJustin T. Gibbs 658a29779e8SAlexander Motin if (periph->unit_number == unit) 6598b8a9b1dSJustin T. Gibbs break; 6608b8a9b1dSJustin T. Gibbs } 6618b8a9b1dSJustin T. Gibbs /* 6628b8a9b1dSJustin T. Gibbs * If we found the peripheral driver that the user passed 6638b8a9b1dSJustin T. Gibbs * in, go through all of the peripheral drivers for that 6648b8a9b1dSJustin T. Gibbs * particular device and look for a passthrough driver. 6658b8a9b1dSJustin T. Gibbs */ 6668b8a9b1dSJustin T. Gibbs if (periph != NULL) { 6678b8a9b1dSJustin T. Gibbs struct cam_ed *device; 6688b8a9b1dSJustin T. Gibbs int i; 6698b8a9b1dSJustin T. Gibbs 670621a60d4SKenneth D. Merry base_periph_found = 1; 6718b8a9b1dSJustin T. Gibbs device = periph->path->device; 672fc2ffbe6SPoul-Henning Kamp for (i = 0, periph = SLIST_FIRST(&device->periphs); 6738b8a9b1dSJustin T. Gibbs periph != NULL; 674fc2ffbe6SPoul-Henning Kamp periph = SLIST_NEXT(periph, periph_links), i++) { 6758b8a9b1dSJustin T. Gibbs /* 6768b8a9b1dSJustin T. Gibbs * Check to see whether we have a 6778b8a9b1dSJustin T. Gibbs * passthrough device or not. 6788b8a9b1dSJustin T. Gibbs */ 6798b8a9b1dSJustin T. Gibbs if (strcmp(periph->periph_name, "pass") == 0) { 6808b8a9b1dSJustin T. Gibbs /* 6818b8a9b1dSJustin T. Gibbs * Fill in the getdevlist fields. 6828b8a9b1dSJustin T. Gibbs */ 683b0f662feSAlan Somers strlcpy(ccb->cgdl.periph_name, 684b0f662feSAlan Somers periph->periph_name, 685b0f662feSAlan Somers sizeof(ccb->cgdl.periph_name)); 6868b8a9b1dSJustin T. Gibbs ccb->cgdl.unit_number = 6878b8a9b1dSJustin T. Gibbs periph->unit_number; 688fc2ffbe6SPoul-Henning Kamp if (SLIST_NEXT(periph, periph_links)) 6898b8a9b1dSJustin T. Gibbs ccb->cgdl.status = 6908b8a9b1dSJustin T. Gibbs CAM_GDEVLIST_MORE_DEVS; 6918b8a9b1dSJustin T. Gibbs else 6928b8a9b1dSJustin T. Gibbs ccb->cgdl.status = 6938b8a9b1dSJustin T. Gibbs CAM_GDEVLIST_LAST_DEVICE; 6948b8a9b1dSJustin T. Gibbs ccb->cgdl.generation = 6958b8a9b1dSJustin T. Gibbs device->generation; 6968b8a9b1dSJustin T. Gibbs ccb->cgdl.index = i; 6978b8a9b1dSJustin T. Gibbs /* 6988b8a9b1dSJustin T. Gibbs * Fill in some CCB header fields 6998b8a9b1dSJustin T. Gibbs * that the user may want. 7008b8a9b1dSJustin T. Gibbs */ 7018b8a9b1dSJustin T. Gibbs ccb->ccb_h.path_id = 7028b8a9b1dSJustin T. Gibbs periph->path->bus->path_id; 7038b8a9b1dSJustin T. Gibbs ccb->ccb_h.target_id = 7048b8a9b1dSJustin T. Gibbs periph->path->target->target_id; 7058b8a9b1dSJustin T. Gibbs ccb->ccb_h.target_lun = 7068b8a9b1dSJustin T. Gibbs periph->path->device->lun_id; 7078b8a9b1dSJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_CMP; 7088b8a9b1dSJustin T. Gibbs break; 7098b8a9b1dSJustin T. Gibbs } 7108b8a9b1dSJustin T. Gibbs } 7118b8a9b1dSJustin T. Gibbs } 7128b8a9b1dSJustin T. Gibbs 7138b8a9b1dSJustin T. Gibbs /* 7148b8a9b1dSJustin T. Gibbs * If the periph is null here, one of two things has 7158b8a9b1dSJustin T. Gibbs * happened. The first possibility is that we couldn't 7168b8a9b1dSJustin T. Gibbs * find the unit number of the particular peripheral driver 7178b8a9b1dSJustin T. Gibbs * that the user is asking about. e.g. the user asks for 7188b8a9b1dSJustin T. Gibbs * the passthrough driver for "da11". We find the list of 7198b8a9b1dSJustin T. Gibbs * "da" peripherals all right, but there is no unit 11. 7208b8a9b1dSJustin T. Gibbs * The other possibility is that we went through the list 7218b8a9b1dSJustin T. Gibbs * of peripheral drivers attached to the device structure, 7228b8a9b1dSJustin T. Gibbs * but didn't find one with the name "pass". Either way, 7238b8a9b1dSJustin T. Gibbs * we return ENOENT, since we couldn't find something. 7248b8a9b1dSJustin T. Gibbs */ 7258b8a9b1dSJustin T. Gibbs if (periph == NULL) { 7268b8a9b1dSJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_CMP_ERR; 7278b8a9b1dSJustin T. Gibbs ccb->cgdl.status = CAM_GDEVLIST_ERROR; 7288b8a9b1dSJustin T. Gibbs *ccb->cgdl.periph_name = '\0'; 7298b8a9b1dSJustin T. Gibbs ccb->cgdl.unit_number = 0; 7308b8a9b1dSJustin T. Gibbs error = ENOENT; 731621a60d4SKenneth D. Merry /* 732621a60d4SKenneth D. Merry * It is unfortunate that this is even necessary, 733621a60d4SKenneth D. Merry * but there are many, many clueless users out there. 734621a60d4SKenneth D. Merry * If this is true, the user is looking for the 735621a60d4SKenneth D. Merry * passthrough driver, but doesn't have one in his 736621a60d4SKenneth D. Merry * kernel. 737621a60d4SKenneth D. Merry */ 738621a60d4SKenneth D. Merry if (base_periph_found == 1) { 739621a60d4SKenneth D. Merry printf("xptioctl: pass driver is not in the " 740621a60d4SKenneth D. Merry "kernel\n"); 741935c968aSChristian Brueffer printf("xptioctl: put \"device pass\" in " 742621a60d4SKenneth D. Merry "your kernel config file\n"); 743621a60d4SKenneth D. Merry } 7448b8a9b1dSJustin T. Gibbs } 7459a7c2696SAlexander Motin xpt_unlock_buses(); 7468b8a9b1dSJustin T. Gibbs break; 7478b8a9b1dSJustin T. Gibbs } 7488b8a9b1dSJustin T. Gibbs default: 7498b8a9b1dSJustin T. Gibbs error = ENOTTY; 7508b8a9b1dSJustin T. Gibbs break; 7518b8a9b1dSJustin T. Gibbs } 7528b8a9b1dSJustin T. Gibbs 7538b8a9b1dSJustin T. Gibbs return(error); 7548b8a9b1dSJustin T. Gibbs } 7558b8a9b1dSJustin T. Gibbs 75674bd1c10SNick Hibma static int 75774bd1c10SNick Hibma cam_module_event_handler(module_t mod, int what, void *arg) 75874bd1c10SNick Hibma { 7592b83592fSScott Long int error; 7602b83592fSScott Long 7612b83592fSScott Long switch (what) { 7622b83592fSScott Long case MOD_LOAD: 7632b83592fSScott Long if ((error = xpt_init(NULL)) != 0) 7642b83592fSScott Long return (error); 7652b83592fSScott Long break; 7662b83592fSScott Long case MOD_UNLOAD: 76774bd1c10SNick Hibma return EBUSY; 7682b83592fSScott Long default: 7693e019deaSPoul-Henning Kamp return EOPNOTSUPP; 77074bd1c10SNick Hibma } 77174bd1c10SNick Hibma 77274bd1c10SNick Hibma return 0; 77374bd1c10SNick Hibma } 77474bd1c10SNick Hibma 77508f13879SWarner Losh static struct xpt_proto * 77608f13879SWarner Losh xpt_proto_find(cam_proto proto) 77708f13879SWarner Losh { 77808f13879SWarner Losh struct xpt_proto **pp; 77908f13879SWarner Losh 78008f13879SWarner Losh SET_FOREACH(pp, cam_xpt_proto_set) { 78108f13879SWarner Losh if ((*pp)->proto == proto) 78208f13879SWarner Losh return *pp; 78308f13879SWarner Losh } 78408f13879SWarner Losh 78508f13879SWarner Losh return NULL; 78608f13879SWarner Losh } 78708f13879SWarner Losh 78883c5d981SAlexander Motin static void 78983c5d981SAlexander Motin xpt_rescan_done(struct cam_periph *periph, union ccb *done_ccb) 79083c5d981SAlexander Motin { 79183c5d981SAlexander Motin 79283c5d981SAlexander Motin if (done_ccb->ccb_h.ppriv_ptr1 == NULL) { 79383c5d981SAlexander Motin xpt_free_path(done_ccb->ccb_h.path); 79483c5d981SAlexander Motin xpt_free_ccb(done_ccb); 79583c5d981SAlexander Motin } else { 79683c5d981SAlexander Motin done_ccb->ccb_h.cbfcnp = done_ccb->ccb_h.ppriv_ptr1; 79783c5d981SAlexander Motin (*done_ccb->ccb_h.cbfcnp)(periph, done_ccb); 79883c5d981SAlexander Motin } 79983c5d981SAlexander Motin xpt_release_boot(); 80083c5d981SAlexander Motin } 80183c5d981SAlexander Motin 8029e6461a2SMatt Jacob /* thread to handle bus rescans */ 8039e6461a2SMatt Jacob static void 8049e6461a2SMatt Jacob xpt_scanner_thread(void *dummy) 8059e6461a2SMatt Jacob { 8069e6461a2SMatt Jacob union ccb *ccb; 807227d67aaSAlexander Motin struct cam_path path; 8082b83592fSScott Long 8092b83592fSScott Long xpt_lock_buses(); 81083c5d981SAlexander Motin for (;;) { 8115a73cc12SKenneth D. Merry if (TAILQ_EMPTY(&xsoftc.ccb_scanq)) 8122b83592fSScott Long msleep(&xsoftc.ccb_scanq, &xsoftc.xpt_topo_lock, PRIBIO, 8133710ae64SAlexander Motin "-", 0); 81483c5d981SAlexander Motin if ((ccb = (union ccb *)TAILQ_FIRST(&xsoftc.ccb_scanq)) != NULL) { 81583c5d981SAlexander Motin TAILQ_REMOVE(&xsoftc.ccb_scanq, &ccb->ccb_h, sim_links.tqe); 8162b83592fSScott Long xpt_unlock_buses(); 8172b83592fSScott Long 818227d67aaSAlexander Motin /* 819227d67aaSAlexander Motin * Since lock can be dropped inside and path freed 820227d67aaSAlexander Motin * by completion callback even before return here, 821227d67aaSAlexander Motin * take our own path copy for reference. 822227d67aaSAlexander Motin */ 823227d67aaSAlexander Motin xpt_copy_path(&path, ccb->ccb_h.path); 824227d67aaSAlexander Motin xpt_path_lock(&path); 82583c5d981SAlexander Motin xpt_action(ccb); 826227d67aaSAlexander Motin xpt_path_unlock(&path); 827227d67aaSAlexander Motin xpt_release_path(&path); 82883c5d981SAlexander Motin 82983c5d981SAlexander Motin xpt_lock_buses(); 8309e6461a2SMatt Jacob } 8319e6461a2SMatt Jacob } 8329e6461a2SMatt Jacob } 8339e6461a2SMatt Jacob 8349e6461a2SMatt Jacob void 8359e6461a2SMatt Jacob xpt_rescan(union ccb *ccb) 8369e6461a2SMatt Jacob { 8379e6461a2SMatt Jacob struct ccb_hdr *hdr; 8382b83592fSScott Long 83983c5d981SAlexander Motin /* Prepare request */ 8400e85f214SMatt Jacob if (ccb->ccb_h.path->target->target_id == CAM_TARGET_WILDCARD && 841411cadaeSAlexander Motin ccb->ccb_h.path->device->lun_id == CAM_LUN_WILDCARD) 84283c5d981SAlexander Motin ccb->ccb_h.func_code = XPT_SCAN_BUS; 8430e85f214SMatt Jacob else if (ccb->ccb_h.path->target->target_id != CAM_TARGET_WILDCARD && 8440e85f214SMatt Jacob ccb->ccb_h.path->device->lun_id == CAM_LUN_WILDCARD) 8450e85f214SMatt Jacob ccb->ccb_h.func_code = XPT_SCAN_TGT; 8460e85f214SMatt Jacob else if (ccb->ccb_h.path->target->target_id != CAM_TARGET_WILDCARD && 8470e85f214SMatt Jacob ccb->ccb_h.path->device->lun_id != CAM_LUN_WILDCARD) 84883c5d981SAlexander Motin ccb->ccb_h.func_code = XPT_SCAN_LUN; 8490e85f214SMatt Jacob else { 8500e85f214SMatt Jacob xpt_print(ccb->ccb_h.path, "illegal scan path\n"); 8510e85f214SMatt Jacob xpt_free_path(ccb->ccb_h.path); 8520e85f214SMatt Jacob xpt_free_ccb(ccb); 8530e85f214SMatt Jacob return; 8540e85f214SMatt Jacob } 85569be012fSWarner Losh CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE, 85669be012fSWarner Losh ("xpt_rescan: func %#x %s\n", ccb->ccb_h.func_code, 85769be012fSWarner Losh xpt_action_name(ccb->ccb_h.func_code))); 85869be012fSWarner Losh 85983c5d981SAlexander Motin ccb->ccb_h.ppriv_ptr1 = ccb->ccb_h.cbfcnp; 86083c5d981SAlexander Motin ccb->ccb_h.cbfcnp = xpt_rescan_done; 86183c5d981SAlexander Motin xpt_setup_ccb(&ccb->ccb_h, ccb->ccb_h.path, CAM_PRIORITY_XPT); 86283c5d981SAlexander Motin /* Don't make duplicate entries for the same paths. */ 8632b83592fSScott Long xpt_lock_buses(); 86483c5d981SAlexander Motin if (ccb->ccb_h.ppriv_ptr1 == NULL) { 8652b83592fSScott Long TAILQ_FOREACH(hdr, &xsoftc.ccb_scanq, sim_links.tqe) { 8669e6461a2SMatt Jacob if (xpt_path_comp(hdr->path, ccb->ccb_h.path) == 0) { 8675a73cc12SKenneth D. Merry wakeup(&xsoftc.ccb_scanq); 8682b83592fSScott Long xpt_unlock_buses(); 8699e6461a2SMatt Jacob xpt_print(ccb->ccb_h.path, "rescan already queued\n"); 8709e6461a2SMatt Jacob xpt_free_path(ccb->ccb_h.path); 8719e6461a2SMatt Jacob xpt_free_ccb(ccb); 8729e6461a2SMatt Jacob return; 8739e6461a2SMatt Jacob } 8749e6461a2SMatt Jacob } 87583c5d981SAlexander Motin } 8762b83592fSScott Long TAILQ_INSERT_TAIL(&xsoftc.ccb_scanq, &ccb->ccb_h, sim_links.tqe); 877a4876fbfSAlexander Motin xpt_hold_boot_locked(); 8782b83592fSScott Long wakeup(&xsoftc.ccb_scanq); 8792b83592fSScott Long xpt_unlock_buses(); 8809e6461a2SMatt Jacob } 8819e6461a2SMatt Jacob 8828b8a9b1dSJustin T. Gibbs /* Functions accessed by the peripheral drivers */ 8832b83592fSScott Long static int 8849e6461a2SMatt Jacob xpt_init(void *dummy) 8858b8a9b1dSJustin T. Gibbs { 8868b8a9b1dSJustin T. Gibbs struct cam_sim *xpt_sim; 8878b8a9b1dSJustin T. Gibbs struct cam_path *path; 888434bbf6eSJustin T. Gibbs struct cam_devq *devq; 8898b8a9b1dSJustin T. Gibbs cam_status status; 890227d67aaSAlexander Motin int error, i; 8918b8a9b1dSJustin T. Gibbs 8922b83592fSScott Long TAILQ_INIT(&xsoftc.xpt_busses); 8932b83592fSScott Long TAILQ_INIT(&xsoftc.ccb_scanq); 8942b83592fSScott Long STAILQ_INIT(&xsoftc.highpowerq); 8952b83592fSScott Long xsoftc.num_highpower = CAM_MAX_HIGHPOWER; 8968b8a9b1dSJustin T. Gibbs 897daa5487fSAlexander Motin mtx_init(&xsoftc.xpt_highpower_lock, "XPT highpower lock", NULL, MTX_DEF); 898227d67aaSAlexander Motin xsoftc.xpt_taskq = taskqueue_create("CAM XPT task", M_WAITOK, 899227d67aaSAlexander Motin taskqueue_thread_enqueue, /*context*/&xsoftc.xpt_taskq); 900ef3cf714SScott Long 9016b156f61SSean Bruno #ifdef CAM_BOOT_DELAY 9026b156f61SSean Bruno /* 9036b156f61SSean Bruno * Override this value at compile time to assist our users 9046b156f61SSean Bruno * who don't use loader to boot a kernel. 9056b156f61SSean Bruno */ 9066b156f61SSean Bruno xsoftc.boot_delay = CAM_BOOT_DELAY; 9076b156f61SSean Bruno #endif 908a4876fbfSAlexander Motin 9098b8a9b1dSJustin T. Gibbs /* 9101ffe5851SPedro F. Giffuni * The xpt layer is, itself, the equivalent of a SIM. 9118b8a9b1dSJustin T. Gibbs * Allow 16 ccbs in the ccb pool for it. This should 912db4fcadfSConrad Meyer * give decent parallelism when we probe buses and 9138b8a9b1dSJustin T. Gibbs * perform other XPT functions. 9148b8a9b1dSJustin T. Gibbs */ 915434bbf6eSJustin T. Gibbs devq = cam_simq_alloc(16); 916434bbf6eSJustin T. Gibbs xpt_sim = cam_sim_alloc(xptaction, 917434bbf6eSJustin T. Gibbs xptpoll, 918434bbf6eSJustin T. Gibbs "xpt", 919434bbf6eSJustin T. Gibbs /*softc*/NULL, 920434bbf6eSJustin T. Gibbs /*unit*/0, 9217e8baf37SAlexander Motin /*mtx*/NULL, 922434bbf6eSJustin T. Gibbs /*max_dev_transactions*/0, 923434bbf6eSJustin T. Gibbs /*max_tagged_dev_transactions*/0, 924434bbf6eSJustin T. Gibbs devq); 9252b83592fSScott Long if (xpt_sim == NULL) 9262b83592fSScott Long return (ENOMEM); 9278b8a9b1dSJustin T. Gibbs 928b50569b7SScott Long if ((status = xpt_bus_register(xpt_sim, NULL, 0)) != CAM_SUCCESS) { 929a2821e04SMatt Jacob printf("xpt_init: xpt_bus_register failed with status %#x," 930df826980SMatt Jacob " failing attach\n", status); 9312b83592fSScott Long return (EINVAL); 932df826980SMatt Jacob } 9338b8a9b1dSJustin T. Gibbs 9348b8a9b1dSJustin T. Gibbs /* 9358b8a9b1dSJustin T. Gibbs * Looking at the XPT from the SIM layer, the XPT is 9361ffe5851SPedro F. Giffuni * the equivalent of a peripheral driver. Allocate 9378b8a9b1dSJustin T. Gibbs * a peripheral driver entry for us. 9388b8a9b1dSJustin T. Gibbs */ 9398b8a9b1dSJustin T. Gibbs if ((status = xpt_create_path(&path, NULL, CAM_XPT_PATH_ID, 9408b8a9b1dSJustin T. Gibbs CAM_TARGET_WILDCARD, 9418b8a9b1dSJustin T. Gibbs CAM_LUN_WILDCARD)) != CAM_REQ_CMP) { 9428b8a9b1dSJustin T. Gibbs printf("xpt_init: xpt_create_path failed with status %#x," 9438b8a9b1dSJustin T. Gibbs " failing attach\n", status); 9442b83592fSScott Long return (EINVAL); 9458b8a9b1dSJustin T. Gibbs } 946daa5487fSAlexander Motin xpt_path_lock(path); 947ee9c90c7SKenneth D. Merry cam_periph_alloc(xptregister, NULL, NULL, NULL, "xpt", CAM_PERIPH_BIO, 9482b83592fSScott Long path, NULL, 0, xpt_sim); 949daa5487fSAlexander Motin xpt_path_unlock(path); 9508b8a9b1dSJustin T. Gibbs xpt_free_path(path); 951daa5487fSAlexander Motin 952227d67aaSAlexander Motin if (cam_num_doneqs < 1) 953227d67aaSAlexander Motin cam_num_doneqs = 1 + mp_ncpus / 6; 954227d67aaSAlexander Motin else if (cam_num_doneqs > MAXCPU) 955227d67aaSAlexander Motin cam_num_doneqs = MAXCPU; 956227d67aaSAlexander Motin for (i = 0; i < cam_num_doneqs; i++) { 957227d67aaSAlexander Motin mtx_init(&cam_doneqs[i].cam_doneq_mtx, "CAM doneq", NULL, 958227d67aaSAlexander Motin MTX_DEF); 959227d67aaSAlexander Motin STAILQ_INIT(&cam_doneqs[i].cam_doneq); 960227d67aaSAlexander Motin error = kproc_kthread_add(xpt_done_td, &cam_doneqs[i], 961227d67aaSAlexander Motin &cam_proc, NULL, 0, 0, "cam", "doneq%d", i); 962227d67aaSAlexander Motin if (error != 0) { 963227d67aaSAlexander Motin cam_num_doneqs = i; 964227d67aaSAlexander Motin break; 965227d67aaSAlexander Motin } 966227d67aaSAlexander Motin } 967227d67aaSAlexander Motin if (cam_num_doneqs < 1) { 968227d67aaSAlexander Motin printf("xpt_init: Cannot init completion queues " 969227d67aaSAlexander Motin "- failing attach\n"); 970227d67aaSAlexander Motin return (ENOMEM); 971227d67aaSAlexander Motin } 972a4876fbfSAlexander Motin 9738b8a9b1dSJustin T. Gibbs /* 9748b8a9b1dSJustin T. Gibbs * Register a callback for when interrupts are enabled. 9758b8a9b1dSJustin T. Gibbs */ 976a4876fbfSAlexander Motin config_intrhook_oneshot(xpt_config, NULL); 9778b8a9b1dSJustin T. Gibbs 9782b83592fSScott Long return (0); 9798b8a9b1dSJustin T. Gibbs } 9808b8a9b1dSJustin T. Gibbs 9818b8a9b1dSJustin T. Gibbs static cam_status 9828b8a9b1dSJustin T. Gibbs xptregister(struct cam_periph *periph, void *arg) 9838b8a9b1dSJustin T. Gibbs { 9842b83592fSScott Long struct cam_sim *xpt_sim; 9852b83592fSScott Long 9868b8a9b1dSJustin T. Gibbs if (periph == NULL) { 9878b8a9b1dSJustin T. Gibbs printf("xptregister: periph was NULL!!\n"); 9888b8a9b1dSJustin T. Gibbs return(CAM_REQ_CMP_ERR); 9898b8a9b1dSJustin T. Gibbs } 9908b8a9b1dSJustin T. Gibbs 9912b83592fSScott Long xpt_sim = (struct cam_sim *)arg; 9922b83592fSScott Long xpt_sim->softc = periph; 9938b8a9b1dSJustin T. Gibbs xpt_periph = periph; 9942b83592fSScott Long periph->softc = NULL; 9958b8a9b1dSJustin T. Gibbs 9968b8a9b1dSJustin T. Gibbs return(CAM_REQ_CMP); 9978b8a9b1dSJustin T. Gibbs } 9988b8a9b1dSJustin T. Gibbs 9998b8a9b1dSJustin T. Gibbs int32_t 10008b8a9b1dSJustin T. Gibbs xpt_add_periph(struct cam_periph *periph) 10018b8a9b1dSJustin T. Gibbs { 10028b8a9b1dSJustin T. Gibbs struct cam_ed *device; 10038b8a9b1dSJustin T. Gibbs int32_t status; 10048b8a9b1dSJustin T. Gibbs 1005227d67aaSAlexander Motin TASK_INIT(&periph->periph_run_task, 0, xpt_run_allocq_task, periph); 10068b8a9b1dSJustin T. Gibbs device = periph->path->device; 10078b8a9b1dSJustin T. Gibbs status = CAM_REQ_CMP; 10088b8a9b1dSJustin T. Gibbs if (device != NULL) { 1009227d67aaSAlexander Motin mtx_lock(&device->target->bus->eb_mtx); 10108b8a9b1dSJustin T. Gibbs device->generation++; 1011227d67aaSAlexander Motin SLIST_INSERT_HEAD(&device->periphs, periph, periph_links); 1012227d67aaSAlexander Motin mtx_unlock(&device->target->bus->eb_mtx); 1013636870ffSWill Andrews atomic_add_32(&xsoftc.xpt_generation, 1); 10148b8a9b1dSJustin T. Gibbs } 10158b8a9b1dSJustin T. Gibbs 10168b8a9b1dSJustin T. Gibbs return (status); 10178b8a9b1dSJustin T. Gibbs } 10188b8a9b1dSJustin T. Gibbs 10198b8a9b1dSJustin T. Gibbs void 1020a29779e8SAlexander Motin xpt_remove_periph(struct cam_periph *periph) 10218b8a9b1dSJustin T. Gibbs { 10228b8a9b1dSJustin T. Gibbs struct cam_ed *device; 10238b8a9b1dSJustin T. Gibbs 10248b8a9b1dSJustin T. Gibbs device = periph->path->device; 10258b8a9b1dSJustin T. Gibbs if (device != NULL) { 1026227d67aaSAlexander Motin mtx_lock(&device->target->bus->eb_mtx); 10278b8a9b1dSJustin T. Gibbs device->generation++; 1028227d67aaSAlexander Motin SLIST_REMOVE(&device->periphs, periph, cam_periph, periph_links); 1029227d67aaSAlexander Motin mtx_unlock(&device->target->bus->eb_mtx); 1030636870ffSWill Andrews atomic_add_32(&xsoftc.xpt_generation, 1); 10318b8a9b1dSJustin T. Gibbs } 10328b8a9b1dSJustin T. Gibbs } 10338b8a9b1dSJustin T. Gibbs 10343393f8daSKenneth D. Merry 10353393f8daSKenneth D. Merry void 10363393f8daSKenneth D. Merry xpt_announce_periph(struct cam_periph *periph, char *announce_string) 10373393f8daSKenneth D. Merry { 103857079b17SAlexander Motin struct cam_path *path = periph->path; 103908f13879SWarner Losh struct xpt_proto *proto; 10403393f8daSKenneth D. Merry 1041227d67aaSAlexander Motin cam_periph_assert(periph, MA_OWNED); 10428d36a71bSAlexander Motin periph->flags |= CAM_PERIPH_ANNOUNCED; 104368153f43SScott Long 1044abe83505SNathan Whitehorn printf("%s%d at %s%d bus %d scbus%d target %d lun %jx\n", 10453393f8daSKenneth D. Merry periph->periph_name, periph->unit_number, 10463393f8daSKenneth D. Merry path->bus->sim->sim_name, 10473393f8daSKenneth D. Merry path->bus->sim->unit_number, 10483393f8daSKenneth D. Merry path->bus->sim->bus_id, 1049ad413009SAlexander Motin path->bus->path_id, 10503393f8daSKenneth D. Merry path->target->target_id, 1051abe83505SNathan Whitehorn (uintmax_t)path->device->lun_id); 10523393f8daSKenneth D. Merry printf("%s%d: ", periph->periph_name, periph->unit_number); 105308f13879SWarner Losh proto = xpt_proto_find(path->device->protocol); 105408f13879SWarner Losh if (proto) 105508f13879SWarner Losh proto->ops->announce(path->device); 105652c9ce25SScott Long else 105708f13879SWarner Losh printf("%s%d: Unknown protocol device %d\n", 105808f13879SWarner Losh periph->periph_name, periph->unit_number, 105908f13879SWarner Losh path->device->protocol); 1060aa93041dSAlexander Motin if (path->device->serial_num_len > 0) { 10613393f8daSKenneth D. Merry /* Don't wrap the screen - print only the first 60 chars */ 10623393f8daSKenneth D. Merry printf("%s%d: Serial Number %.60s\n", periph->periph_name, 10633393f8daSKenneth D. Merry periph->unit_number, path->device->serial_num); 10643393f8daSKenneth D. Merry } 106557079b17SAlexander Motin /* Announce transport details. */ 106608f13879SWarner Losh path->bus->xport->ops->announce(periph); 106757079b17SAlexander Motin /* Announce command queueing. */ 10683393f8daSKenneth D. Merry if (path->device->inq_flags & SID_CmdQue 10693393f8daSKenneth D. Merry || path->device->flags & CAM_DEV_TAG_AFTER_COUNT) { 10700aacc535SAlexander Motin printf("%s%d: Command Queueing enabled\n", 10713393f8daSKenneth D. Merry periph->periph_name, periph->unit_number); 10723393f8daSKenneth D. Merry } 107357079b17SAlexander Motin /* Announce caller's details if they've passed in. */ 10743393f8daSKenneth D. Merry if (announce_string != NULL) 10753393f8daSKenneth D. Merry printf("%s%d: %s\n", periph->periph_name, 10763393f8daSKenneth D. Merry periph->unit_number, announce_string); 10773393f8daSKenneth D. Merry } 10788b8a9b1dSJustin T. Gibbs 10796fb5c84eSSteven Hartland void 10805d01277fSScott Long xpt_announce_periph_sbuf(struct cam_periph *periph, struct sbuf *sb, 10815d01277fSScott Long char *announce_string) 10825d01277fSScott Long { 10835d01277fSScott Long struct cam_path *path = periph->path; 10845d01277fSScott Long struct xpt_proto *proto; 10855d01277fSScott Long 10865d01277fSScott Long cam_periph_assert(periph, MA_OWNED); 10875d01277fSScott Long periph->flags |= CAM_PERIPH_ANNOUNCED; 10885d01277fSScott Long 10895d01277fSScott Long /* Fall back to the non-sbuf method if necessary */ 10905d01277fSScott Long if (xsoftc.announce_nosbuf != 0) { 10915d01277fSScott Long xpt_announce_periph(periph, announce_string); 10925d01277fSScott Long return; 10935d01277fSScott Long } 10945d01277fSScott Long proto = xpt_proto_find(path->device->protocol); 10955d01277fSScott Long if (((proto != NULL) && (proto->ops->announce_sbuf == NULL)) || 10965d01277fSScott Long (path->bus->xport->ops->announce_sbuf == NULL)) { 10975d01277fSScott Long xpt_announce_periph(periph, announce_string); 10985d01277fSScott Long return; 10995d01277fSScott Long } 11005d01277fSScott Long 11015d01277fSScott Long sbuf_printf(sb, "%s%d at %s%d bus %d scbus%d target %d lun %jx\n", 11025d01277fSScott Long periph->periph_name, periph->unit_number, 11035d01277fSScott Long path->bus->sim->sim_name, 11045d01277fSScott Long path->bus->sim->unit_number, 11055d01277fSScott Long path->bus->sim->bus_id, 11065d01277fSScott Long path->bus->path_id, 11075d01277fSScott Long path->target->target_id, 11085d01277fSScott Long (uintmax_t)path->device->lun_id); 11095d01277fSScott Long sbuf_printf(sb, "%s%d: ", periph->periph_name, periph->unit_number); 11105d01277fSScott Long 11115d01277fSScott Long if (proto) 11125d01277fSScott Long proto->ops->announce_sbuf(path->device, sb); 11135d01277fSScott Long else 11145d01277fSScott Long sbuf_printf(sb, "%s%d: Unknown protocol device %d\n", 11155d01277fSScott Long periph->periph_name, periph->unit_number, 11165d01277fSScott Long path->device->protocol); 11175d01277fSScott Long if (path->device->serial_num_len > 0) { 11185d01277fSScott Long /* Don't wrap the screen - print only the first 60 chars */ 11195d01277fSScott Long sbuf_printf(sb, "%s%d: Serial Number %.60s\n", 11205d01277fSScott Long periph->periph_name, periph->unit_number, 11215d01277fSScott Long path->device->serial_num); 11225d01277fSScott Long } 11235d01277fSScott Long /* Announce transport details. */ 11245d01277fSScott Long path->bus->xport->ops->announce_sbuf(periph, sb); 11255d01277fSScott Long /* Announce command queueing. */ 11265d01277fSScott Long if (path->device->inq_flags & SID_CmdQue 11275d01277fSScott Long || path->device->flags & CAM_DEV_TAG_AFTER_COUNT) { 11285d01277fSScott Long sbuf_printf(sb, "%s%d: Command Queueing enabled\n", 11295d01277fSScott Long periph->periph_name, periph->unit_number); 11305d01277fSScott Long } 11315d01277fSScott Long /* Announce caller's details if they've passed in. */ 11325d01277fSScott Long if (announce_string != NULL) 11335d01277fSScott Long sbuf_printf(sb, "%s%d: %s\n", periph->periph_name, 11345d01277fSScott Long periph->unit_number, announce_string); 11355d01277fSScott Long } 11365d01277fSScott Long 11375d01277fSScott Long void 11386fb5c84eSSteven Hartland xpt_announce_quirks(struct cam_periph *periph, int quirks, char *bit_string) 11396fb5c84eSSteven Hartland { 11406fb5c84eSSteven Hartland if (quirks != 0) { 11416fb5c84eSSteven Hartland printf("%s%d: quirks=0x%b\n", periph->periph_name, 11426fb5c84eSSteven Hartland periph->unit_number, quirks, bit_string); 11436fb5c84eSSteven Hartland } 11446fb5c84eSSteven Hartland } 11456fb5c84eSSteven Hartland 11468d36a71bSAlexander Motin void 11475d01277fSScott Long xpt_announce_quirks_sbuf(struct cam_periph *periph, struct sbuf *sb, 11485d01277fSScott Long int quirks, char *bit_string) 11495d01277fSScott Long { 11505d01277fSScott Long if (xsoftc.announce_nosbuf != 0) { 11515d01277fSScott Long xpt_announce_quirks(periph, quirks, bit_string); 11525d01277fSScott Long return; 11535d01277fSScott Long } 11545d01277fSScott Long 11555d01277fSScott Long if (quirks != 0) { 11565d01277fSScott Long sbuf_printf(sb, "%s%d: quirks=0x%b\n", periph->periph_name, 11575d01277fSScott Long periph->unit_number, quirks, bit_string); 11585d01277fSScott Long } 11595d01277fSScott Long } 11605d01277fSScott Long 11615d01277fSScott Long void 11628d36a71bSAlexander Motin xpt_denounce_periph(struct cam_periph *periph) 11638d36a71bSAlexander Motin { 11648d36a71bSAlexander Motin struct cam_path *path = periph->path; 116508f13879SWarner Losh struct xpt_proto *proto; 11668d36a71bSAlexander Motin 1167227d67aaSAlexander Motin cam_periph_assert(periph, MA_OWNED); 1168abe83505SNathan Whitehorn printf("%s%d at %s%d bus %d scbus%d target %d lun %jx\n", 11698d36a71bSAlexander Motin periph->periph_name, periph->unit_number, 11708d36a71bSAlexander Motin path->bus->sim->sim_name, 11718d36a71bSAlexander Motin path->bus->sim->unit_number, 11728d36a71bSAlexander Motin path->bus->sim->bus_id, 11738d36a71bSAlexander Motin path->bus->path_id, 11748d36a71bSAlexander Motin path->target->target_id, 1175abe83505SNathan Whitehorn (uintmax_t)path->device->lun_id); 11768d36a71bSAlexander Motin printf("%s%d: ", periph->periph_name, periph->unit_number); 117708f13879SWarner Losh proto = xpt_proto_find(path->device->protocol); 117808f13879SWarner Losh if (proto) 117908f13879SWarner Losh proto->ops->denounce(path->device); 11808d36a71bSAlexander Motin else 118108f13879SWarner Losh printf("%s%d: Unknown protocol device %d\n", 118208f13879SWarner Losh periph->periph_name, periph->unit_number, 118308f13879SWarner Losh path->device->protocol); 11848d36a71bSAlexander Motin if (path->device->serial_num_len > 0) 11858d36a71bSAlexander Motin printf(" s/n %.60s", path->device->serial_num); 11868d36a71bSAlexander Motin printf(" detached\n"); 11878d36a71bSAlexander Motin } 11888d36a71bSAlexander Motin 11895d01277fSScott Long void 11905d01277fSScott Long xpt_denounce_periph_sbuf(struct cam_periph *periph, struct sbuf *sb) 11915d01277fSScott Long { 11925d01277fSScott Long struct cam_path *path = periph->path; 11935d01277fSScott Long struct xpt_proto *proto; 11945d01277fSScott Long 11955d01277fSScott Long cam_periph_assert(periph, MA_OWNED); 11965d01277fSScott Long 11975d01277fSScott Long /* Fall back to the non-sbuf method if necessary */ 11985d01277fSScott Long if (xsoftc.announce_nosbuf != 0) { 11995d01277fSScott Long xpt_denounce_periph(periph); 12005d01277fSScott Long return; 12015d01277fSScott Long } 12025d01277fSScott Long proto = xpt_proto_find(path->device->protocol); 12035d01277fSScott Long if ((proto != NULL) && (proto->ops->denounce_sbuf == NULL)) { 12045d01277fSScott Long xpt_denounce_periph(periph); 12055d01277fSScott Long return; 12065d01277fSScott Long } 12075d01277fSScott Long 12085d01277fSScott Long sbuf_printf(sb, "%s%d at %s%d bus %d scbus%d target %d lun %jx\n", 12095d01277fSScott Long periph->periph_name, periph->unit_number, 12105d01277fSScott Long path->bus->sim->sim_name, 12115d01277fSScott Long path->bus->sim->unit_number, 12125d01277fSScott Long path->bus->sim->bus_id, 12135d01277fSScott Long path->bus->path_id, 12145d01277fSScott Long path->target->target_id, 12155d01277fSScott Long (uintmax_t)path->device->lun_id); 12165d01277fSScott Long sbuf_printf(sb, "%s%d: ", periph->periph_name, periph->unit_number); 12175d01277fSScott Long 12185d01277fSScott Long if (proto) 12195d01277fSScott Long proto->ops->denounce_sbuf(path->device, sb); 12205d01277fSScott Long else 12215d01277fSScott Long sbuf_printf(sb, "%s%d: Unknown protocol device %d\n", 12225d01277fSScott Long periph->periph_name, periph->unit_number, 12235d01277fSScott Long path->device->protocol); 12245d01277fSScott Long if (path->device->serial_num_len > 0) 12255d01277fSScott Long sbuf_printf(sb, " s/n %.60s", path->device->serial_num); 12265d01277fSScott Long sbuf_printf(sb, " detached\n"); 12275d01277fSScott Long } 12288d36a71bSAlexander Motin 12293501942bSJustin T. Gibbs int 12303501942bSJustin T. Gibbs xpt_getattr(char *buf, size_t len, const char *attr, struct cam_path *path) 12313501942bSJustin T. Gibbs { 123200d72d57SAlexander Motin int ret = -1, l, o; 12333501942bSJustin T. Gibbs struct ccb_dev_advinfo cdai; 12340feb46b0SScott Long struct scsi_vpd_device_id *did; 1235ccba7102SAlexander Motin struct scsi_vpd_id_descriptor *idd; 12363501942bSJustin T. Gibbs 1237227d67aaSAlexander Motin xpt_path_assert(path, MA_OWNED); 12386884b662SAlexander Motin 12393501942bSJustin T. Gibbs memset(&cdai, 0, sizeof(cdai)); 12403501942bSJustin T. Gibbs xpt_setup_ccb(&cdai.ccb_h, path, CAM_PRIORITY_NORMAL); 12413501942bSJustin T. Gibbs cdai.ccb_h.func_code = XPT_DEV_ADVINFO; 1242ab4327bbSAlexander Motin cdai.flags = CDAI_FLAG_NONE; 12433501942bSJustin T. Gibbs cdai.bufsiz = len; 124435a9ffc3SAlexander Motin cdai.buf = buf; 12453501942bSJustin T. Gibbs 12463501942bSJustin T. Gibbs if (!strcmp(attr, "GEOM::ident")) 12473501942bSJustin T. Gibbs cdai.buftype = CDAI_TYPE_SERIAL_NUM; 12483501942bSJustin T. Gibbs else if (!strcmp(attr, "GEOM::physpath")) 12493501942bSJustin T. Gibbs cdai.buftype = CDAI_TYPE_PHYS_PATH; 125040f27d7cSAlexander Motin else if (strcmp(attr, "GEOM::lunid") == 0 || 125140f27d7cSAlexander Motin strcmp(attr, "GEOM::lunname") == 0) { 1252ccba7102SAlexander Motin cdai.buftype = CDAI_TYPE_SCSI_DEVID; 1253ccba7102SAlexander Motin cdai.bufsiz = CAM_SCSI_DEVID_MAXLEN; 125435a9ffc3SAlexander Motin cdai.buf = malloc(cdai.bufsiz, M_CAMXPT, M_NOWAIT); 12553501942bSJustin T. Gibbs if (cdai.buf == NULL) { 12563501942bSJustin T. Gibbs ret = ENOMEM; 12573501942bSJustin T. Gibbs goto out; 12583501942bSJustin T. Gibbs } 125935a9ffc3SAlexander Motin } else 126035a9ffc3SAlexander Motin goto out; 126135a9ffc3SAlexander Motin 12623501942bSJustin T. Gibbs xpt_action((union ccb *)&cdai); /* can only be synchronous */ 12633501942bSJustin T. Gibbs if ((cdai.ccb_h.status & CAM_DEV_QFRZN) != 0) 12643501942bSJustin T. Gibbs cam_release_devq(cdai.ccb_h.path, 0, 0, 0, FALSE); 12653501942bSJustin T. Gibbs if (cdai.provsiz == 0) 12663501942bSJustin T. Gibbs goto out; 12670feb46b0SScott Long switch(cdai.buftype) { 12680feb46b0SScott Long case CDAI_TYPE_SCSI_DEVID: 12690feb46b0SScott Long did = (struct scsi_vpd_device_id *)cdai.buf; 127040f27d7cSAlexander Motin if (strcmp(attr, "GEOM::lunid") == 0) { 12710feb46b0SScott Long idd = scsi_get_devid(did, cdai.provsiz, 12720feb46b0SScott Long scsi_devid_is_lun_naa); 1273ccba7102SAlexander Motin if (idd == NULL) 12740feb46b0SScott Long idd = scsi_get_devid(did, cdai.provsiz, 12750feb46b0SScott Long scsi_devid_is_lun_eui64); 127600d72d57SAlexander Motin if (idd == NULL) 12770feb46b0SScott Long idd = scsi_get_devid(did, cdai.provsiz, 12780feb46b0SScott Long scsi_devid_is_lun_uuid); 127900d72d57SAlexander Motin if (idd == NULL) 12800feb46b0SScott Long idd = scsi_get_devid(did, cdai.provsiz, 12810feb46b0SScott Long scsi_devid_is_lun_md5); 128240f27d7cSAlexander Motin } else 128340f27d7cSAlexander Motin idd = NULL; 12840feb46b0SScott Long 1285ccba7102SAlexander Motin if (idd == NULL) 12860feb46b0SScott Long idd = scsi_get_devid(did, cdai.provsiz, 12870feb46b0SScott Long scsi_devid_is_lun_t10); 1288ccba7102SAlexander Motin if (idd == NULL) 12890feb46b0SScott Long idd = scsi_get_devid(did, cdai.provsiz, 12900feb46b0SScott Long scsi_devid_is_lun_name); 1291ccba7102SAlexander Motin if (idd == NULL) 12920feb46b0SScott Long break; 12930feb46b0SScott Long 1294ccba7102SAlexander Motin ret = 0; 12950feb46b0SScott Long if ((idd->proto_codeset & SVPD_ID_CODESET_MASK) == 12960feb46b0SScott Long SVPD_ID_CODESET_ASCII) { 1297fa91cabfSAlexander Motin if (idd->length < len) { 1298fa91cabfSAlexander Motin for (l = 0; l < idd->length; l++) 1299fa91cabfSAlexander Motin buf[l] = idd->identifier[l] ? 1300fa91cabfSAlexander Motin idd->identifier[l] : ' '; 1301fa91cabfSAlexander Motin buf[l] = 0; 1302fa91cabfSAlexander Motin } else 1303fa91cabfSAlexander Motin ret = EFAULT; 13040feb46b0SScott Long break; 13050feb46b0SScott Long } 13060feb46b0SScott Long if ((idd->proto_codeset & SVPD_ID_CODESET_MASK) == 13070feb46b0SScott Long SVPD_ID_CODESET_UTF8) { 1308ccba7102SAlexander Motin l = strnlen(idd->identifier, idd->length); 1309ccba7102SAlexander Motin if (l < len) { 1310ccba7102SAlexander Motin bcopy(idd->identifier, buf, l); 1311ccba7102SAlexander Motin buf[l] = 0; 1312ccba7102SAlexander Motin } else 1313ccba7102SAlexander Motin ret = EFAULT; 13140feb46b0SScott Long break; 13150feb46b0SScott Long } 13160feb46b0SScott Long if ((idd->id_type & SVPD_ID_TYPE_MASK) == 13170feb46b0SScott Long SVPD_ID_TYPE_UUID && idd->identifier[0] == 0x10) { 13180feb46b0SScott Long if ((idd->length - 2) * 2 + 4 >= len) { 13190feb46b0SScott Long ret = EFAULT; 13200feb46b0SScott Long break; 13210feb46b0SScott Long } 132200d72d57SAlexander Motin for (l = 2, o = 0; l < idd->length; l++) { 13233157c368SAlexander Motin if (l == 6 || l == 8 || l == 10 || l == 12) 13243157c368SAlexander Motin o += sprintf(buf + o, "-"); 132500d72d57SAlexander Motin o += sprintf(buf + o, "%02x", 132600d72d57SAlexander Motin idd->identifier[l]); 132700d72d57SAlexander Motin } 13280feb46b0SScott Long break; 13290feb46b0SScott Long } 1330ccba7102SAlexander Motin if (idd->length * 2 < len) { 1331ccba7102SAlexander Motin for (l = 0; l < idd->length; l++) 1332ccba7102SAlexander Motin sprintf(buf + l * 2, "%02x", 1333ccba7102SAlexander Motin idd->identifier[l]); 1334ccba7102SAlexander Motin } else 1335ccba7102SAlexander Motin ret = EFAULT; 13360feb46b0SScott Long break; 13370feb46b0SScott Long default: 133835a9ffc3SAlexander Motin if (cdai.provsiz < len) { 133935a9ffc3SAlexander Motin cdai.buf[cdai.provsiz] = 0; 13403501942bSJustin T. Gibbs ret = 0; 134135a9ffc3SAlexander Motin } else 13423501942bSJustin T. Gibbs ret = EFAULT; 13430feb46b0SScott Long break; 1344ccba7102SAlexander Motin } 13453501942bSJustin T. Gibbs 13463501942bSJustin T. Gibbs out: 134735a9ffc3SAlexander Motin if ((char *)cdai.buf != buf) 13483501942bSJustin T. Gibbs free(cdai.buf, M_CAMXPT); 13493501942bSJustin T. Gibbs return ret; 13503501942bSJustin T. Gibbs } 13513501942bSJustin T. Gibbs 13528b8a9b1dSJustin T. Gibbs static dev_match_ret 13533393f8daSKenneth D. Merry xptbusmatch(struct dev_match_pattern *patterns, u_int num_patterns, 13548b8a9b1dSJustin T. Gibbs struct cam_eb *bus) 13558b8a9b1dSJustin T. Gibbs { 13568b8a9b1dSJustin T. Gibbs dev_match_ret retval; 1357167e63e3SPedro F. Giffuni u_int i; 13588b8a9b1dSJustin T. Gibbs 13598b8a9b1dSJustin T. Gibbs retval = DM_RET_NONE; 13608b8a9b1dSJustin T. Gibbs 13618b8a9b1dSJustin T. Gibbs /* 13628b8a9b1dSJustin T. Gibbs * If we aren't given something to match against, that's an error. 13638b8a9b1dSJustin T. Gibbs */ 13648b8a9b1dSJustin T. Gibbs if (bus == NULL) 13658b8a9b1dSJustin T. Gibbs return(DM_RET_ERROR); 13668b8a9b1dSJustin T. Gibbs 13678b8a9b1dSJustin T. Gibbs /* 13688b8a9b1dSJustin T. Gibbs * If there are no match entries, then this bus matches no 13698b8a9b1dSJustin T. Gibbs * matter what. 13708b8a9b1dSJustin T. Gibbs */ 13718b8a9b1dSJustin T. Gibbs if ((patterns == NULL) || (num_patterns == 0)) 13728b8a9b1dSJustin T. Gibbs return(DM_RET_DESCEND | DM_RET_COPY); 13738b8a9b1dSJustin T. Gibbs 13748b8a9b1dSJustin T. Gibbs for (i = 0; i < num_patterns; i++) { 13758b8a9b1dSJustin T. Gibbs struct bus_match_pattern *cur_pattern; 13768b8a9b1dSJustin T. Gibbs 13778b8a9b1dSJustin T. Gibbs /* 13788b8a9b1dSJustin T. Gibbs * If the pattern in question isn't for a bus node, we 13798b8a9b1dSJustin T. Gibbs * aren't interested. However, we do indicate to the 13808b8a9b1dSJustin T. Gibbs * calling routine that we should continue descending the 13818b8a9b1dSJustin T. Gibbs * tree, since the user wants to match against lower-level 13828b8a9b1dSJustin T. Gibbs * EDT elements. 13838b8a9b1dSJustin T. Gibbs */ 13848b8a9b1dSJustin T. Gibbs if (patterns[i].type != DEV_MATCH_BUS) { 13858b8a9b1dSJustin T. Gibbs if ((retval & DM_RET_ACTION_MASK) == DM_RET_NONE) 13868b8a9b1dSJustin T. Gibbs retval |= DM_RET_DESCEND; 13878b8a9b1dSJustin T. Gibbs continue; 13888b8a9b1dSJustin T. Gibbs } 13898b8a9b1dSJustin T. Gibbs 13908b8a9b1dSJustin T. Gibbs cur_pattern = &patterns[i].pattern.bus_pattern; 13918b8a9b1dSJustin T. Gibbs 13928b8a9b1dSJustin T. Gibbs /* 13938b8a9b1dSJustin T. Gibbs * If they want to match any bus node, we give them any 13948b8a9b1dSJustin T. Gibbs * device node. 13958b8a9b1dSJustin T. Gibbs */ 13968b8a9b1dSJustin T. Gibbs if (cur_pattern->flags == BUS_MATCH_ANY) { 13978b8a9b1dSJustin T. Gibbs /* set the copy flag */ 13988b8a9b1dSJustin T. Gibbs retval |= DM_RET_COPY; 13998b8a9b1dSJustin T. Gibbs 14008b8a9b1dSJustin T. Gibbs /* 14018b8a9b1dSJustin T. Gibbs * If we've already decided on an action, go ahead 14028b8a9b1dSJustin T. Gibbs * and return. 14038b8a9b1dSJustin T. Gibbs */ 14048b8a9b1dSJustin T. Gibbs if ((retval & DM_RET_ACTION_MASK) != DM_RET_NONE) 14058b8a9b1dSJustin T. Gibbs return(retval); 14068b8a9b1dSJustin T. Gibbs } 14078b8a9b1dSJustin T. Gibbs 14088b8a9b1dSJustin T. Gibbs /* 14098b8a9b1dSJustin T. Gibbs * Not sure why someone would do this... 14108b8a9b1dSJustin T. Gibbs */ 14118b8a9b1dSJustin T. Gibbs if (cur_pattern->flags == BUS_MATCH_NONE) 14128b8a9b1dSJustin T. Gibbs continue; 14138b8a9b1dSJustin T. Gibbs 14148b8a9b1dSJustin T. Gibbs if (((cur_pattern->flags & BUS_MATCH_PATH) != 0) 14158b8a9b1dSJustin T. Gibbs && (cur_pattern->path_id != bus->path_id)) 14168b8a9b1dSJustin T. Gibbs continue; 14178b8a9b1dSJustin T. Gibbs 14188b8a9b1dSJustin T. Gibbs if (((cur_pattern->flags & BUS_MATCH_BUS_ID) != 0) 14198b8a9b1dSJustin T. Gibbs && (cur_pattern->bus_id != bus->sim->bus_id)) 14208b8a9b1dSJustin T. Gibbs continue; 14218b8a9b1dSJustin T. Gibbs 14228b8a9b1dSJustin T. Gibbs if (((cur_pattern->flags & BUS_MATCH_UNIT) != 0) 14238b8a9b1dSJustin T. Gibbs && (cur_pattern->unit_number != bus->sim->unit_number)) 14248b8a9b1dSJustin T. Gibbs continue; 14258b8a9b1dSJustin T. Gibbs 14268b8a9b1dSJustin T. Gibbs if (((cur_pattern->flags & BUS_MATCH_NAME) != 0) 14278b8a9b1dSJustin T. Gibbs && (strncmp(cur_pattern->dev_name, bus->sim->sim_name, 14288b8a9b1dSJustin T. Gibbs DEV_IDLEN) != 0)) 14298b8a9b1dSJustin T. Gibbs continue; 14308b8a9b1dSJustin T. Gibbs 14318b8a9b1dSJustin T. Gibbs /* 14328b8a9b1dSJustin T. Gibbs * If we get to this point, the user definitely wants 14338b8a9b1dSJustin T. Gibbs * information on this bus. So tell the caller to copy the 14348b8a9b1dSJustin T. Gibbs * data out. 14358b8a9b1dSJustin T. Gibbs */ 14368b8a9b1dSJustin T. Gibbs retval |= DM_RET_COPY; 14378b8a9b1dSJustin T. Gibbs 14388b8a9b1dSJustin T. Gibbs /* 14398b8a9b1dSJustin T. Gibbs * If the return action has been set to descend, then we 14408b8a9b1dSJustin T. Gibbs * know that we've already seen a non-bus matching 14418b8a9b1dSJustin T. Gibbs * expression, therefore we need to further descend the tree. 14428b8a9b1dSJustin T. Gibbs * This won't change by continuing around the loop, so we 14438b8a9b1dSJustin T. Gibbs * go ahead and return. If we haven't seen a non-bus 14448b8a9b1dSJustin T. Gibbs * matching expression, we keep going around the loop until 14458b8a9b1dSJustin T. Gibbs * we exhaust the matching expressions. We'll set the stop 14468b8a9b1dSJustin T. Gibbs * flag once we fall out of the loop. 14478b8a9b1dSJustin T. Gibbs */ 14488b8a9b1dSJustin T. Gibbs if ((retval & DM_RET_ACTION_MASK) == DM_RET_DESCEND) 14498b8a9b1dSJustin T. Gibbs return(retval); 14508b8a9b1dSJustin T. Gibbs } 14518b8a9b1dSJustin T. Gibbs 14528b8a9b1dSJustin T. Gibbs /* 14538b8a9b1dSJustin T. Gibbs * If the return action hasn't been set to descend yet, that means 14548b8a9b1dSJustin T. Gibbs * we haven't seen anything other than bus matching patterns. So 14558b8a9b1dSJustin T. Gibbs * tell the caller to stop descending the tree -- the user doesn't 14568b8a9b1dSJustin T. Gibbs * want to match against lower level tree elements. 14578b8a9b1dSJustin T. Gibbs */ 14588b8a9b1dSJustin T. Gibbs if ((retval & DM_RET_ACTION_MASK) == DM_RET_NONE) 14598b8a9b1dSJustin T. Gibbs retval |= DM_RET_STOP; 14608b8a9b1dSJustin T. Gibbs 14618b8a9b1dSJustin T. Gibbs return(retval); 14628b8a9b1dSJustin T. Gibbs } 14638b8a9b1dSJustin T. Gibbs 14648b8a9b1dSJustin T. Gibbs static dev_match_ret 14653393f8daSKenneth D. Merry xptdevicematch(struct dev_match_pattern *patterns, u_int num_patterns, 14668b8a9b1dSJustin T. Gibbs struct cam_ed *device) 14678b8a9b1dSJustin T. Gibbs { 14688b8a9b1dSJustin T. Gibbs dev_match_ret retval; 1469167e63e3SPedro F. Giffuni u_int i; 14708b8a9b1dSJustin T. Gibbs 14718b8a9b1dSJustin T. Gibbs retval = DM_RET_NONE; 14728b8a9b1dSJustin T. Gibbs 14738b8a9b1dSJustin T. Gibbs /* 14748b8a9b1dSJustin T. Gibbs * If we aren't given something to match against, that's an error. 14758b8a9b1dSJustin T. Gibbs */ 14768b8a9b1dSJustin T. Gibbs if (device == NULL) 14778b8a9b1dSJustin T. Gibbs return(DM_RET_ERROR); 14788b8a9b1dSJustin T. Gibbs 14798b8a9b1dSJustin T. Gibbs /* 14808b8a9b1dSJustin T. Gibbs * If there are no match entries, then this device matches no 14818b8a9b1dSJustin T. Gibbs * matter what. 14828b8a9b1dSJustin T. Gibbs */ 148359e75884SColin Percival if ((patterns == NULL) || (num_patterns == 0)) 14848b8a9b1dSJustin T. Gibbs return(DM_RET_DESCEND | DM_RET_COPY); 14858b8a9b1dSJustin T. Gibbs 14868b8a9b1dSJustin T. Gibbs for (i = 0; i < num_patterns; i++) { 14878b8a9b1dSJustin T. Gibbs struct device_match_pattern *cur_pattern; 14883501942bSJustin T. Gibbs struct scsi_vpd_device_id *device_id_page; 14898b8a9b1dSJustin T. Gibbs 14908b8a9b1dSJustin T. Gibbs /* 14918b8a9b1dSJustin T. Gibbs * If the pattern in question isn't for a device node, we 14928b8a9b1dSJustin T. Gibbs * aren't interested. 14938b8a9b1dSJustin T. Gibbs */ 14948b8a9b1dSJustin T. Gibbs if (patterns[i].type != DEV_MATCH_DEVICE) { 14958b8a9b1dSJustin T. Gibbs if ((patterns[i].type == DEV_MATCH_PERIPH) 14968b8a9b1dSJustin T. Gibbs && ((retval & DM_RET_ACTION_MASK) == DM_RET_NONE)) 14978b8a9b1dSJustin T. Gibbs retval |= DM_RET_DESCEND; 14988b8a9b1dSJustin T. Gibbs continue; 14998b8a9b1dSJustin T. Gibbs } 15008b8a9b1dSJustin T. Gibbs 15018b8a9b1dSJustin T. Gibbs cur_pattern = &patterns[i].pattern.device_pattern; 15028b8a9b1dSJustin T. Gibbs 15033501942bSJustin T. Gibbs /* Error out if mutually exclusive options are specified. */ 15043501942bSJustin T. Gibbs if ((cur_pattern->flags & (DEV_MATCH_INQUIRY|DEV_MATCH_DEVID)) 15053501942bSJustin T. Gibbs == (DEV_MATCH_INQUIRY|DEV_MATCH_DEVID)) 15063501942bSJustin T. Gibbs return(DM_RET_ERROR); 15073501942bSJustin T. Gibbs 15088b8a9b1dSJustin T. Gibbs /* 15098b8a9b1dSJustin T. Gibbs * If they want to match any device node, we give them any 15108b8a9b1dSJustin T. Gibbs * device node. 15118b8a9b1dSJustin T. Gibbs */ 15123501942bSJustin T. Gibbs if (cur_pattern->flags == DEV_MATCH_ANY) 15133501942bSJustin T. Gibbs goto copy_dev_node; 15148b8a9b1dSJustin T. Gibbs 15158b8a9b1dSJustin T. Gibbs /* 15168b8a9b1dSJustin T. Gibbs * Not sure why someone would do this... 15178b8a9b1dSJustin T. Gibbs */ 15188b8a9b1dSJustin T. Gibbs if (cur_pattern->flags == DEV_MATCH_NONE) 15198b8a9b1dSJustin T. Gibbs continue; 15208b8a9b1dSJustin T. Gibbs 15218b8a9b1dSJustin T. Gibbs if (((cur_pattern->flags & DEV_MATCH_PATH) != 0) 15228b8a9b1dSJustin T. Gibbs && (cur_pattern->path_id != device->target->bus->path_id)) 15238b8a9b1dSJustin T. Gibbs continue; 15248b8a9b1dSJustin T. Gibbs 15258b8a9b1dSJustin T. Gibbs if (((cur_pattern->flags & DEV_MATCH_TARGET) != 0) 15268b8a9b1dSJustin T. Gibbs && (cur_pattern->target_id != device->target->target_id)) 15278b8a9b1dSJustin T. Gibbs continue; 15288b8a9b1dSJustin T. Gibbs 15298b8a9b1dSJustin T. Gibbs if (((cur_pattern->flags & DEV_MATCH_LUN) != 0) 15308b8a9b1dSJustin T. Gibbs && (cur_pattern->target_lun != device->lun_id)) 15318b8a9b1dSJustin T. Gibbs continue; 15328b8a9b1dSJustin T. Gibbs 15338b8a9b1dSJustin T. Gibbs if (((cur_pattern->flags & DEV_MATCH_INQUIRY) != 0) 15348b8a9b1dSJustin T. Gibbs && (cam_quirkmatch((caddr_t)&device->inq_data, 15353501942bSJustin T. Gibbs (caddr_t)&cur_pattern->data.inq_pat, 15363501942bSJustin T. Gibbs 1, sizeof(cur_pattern->data.inq_pat), 15378b8a9b1dSJustin T. Gibbs scsi_static_inquiry_match) == NULL)) 15388b8a9b1dSJustin T. Gibbs continue; 15398b8a9b1dSJustin T. Gibbs 15403501942bSJustin T. Gibbs device_id_page = (struct scsi_vpd_device_id *)device->device_id; 15413501942bSJustin T. Gibbs if (((cur_pattern->flags & DEV_MATCH_DEVID) != 0) 15423501942bSJustin T. Gibbs && (device->device_id_len < SVPD_DEVICE_ID_HDR_LEN 15433501942bSJustin T. Gibbs || scsi_devid_match((uint8_t *)device_id_page->desc_list, 15443501942bSJustin T. Gibbs device->device_id_len 15453501942bSJustin T. Gibbs - SVPD_DEVICE_ID_HDR_LEN, 15463501942bSJustin T. Gibbs cur_pattern->data.devid_pat.id, 15473501942bSJustin T. Gibbs cur_pattern->data.devid_pat.id_len) != 0)) 15483501942bSJustin T. Gibbs continue; 15493501942bSJustin T. Gibbs 15503501942bSJustin T. Gibbs copy_dev_node: 15518b8a9b1dSJustin T. Gibbs /* 15528b8a9b1dSJustin T. Gibbs * If we get to this point, the user definitely wants 15538b8a9b1dSJustin T. Gibbs * information on this device. So tell the caller to copy 15548b8a9b1dSJustin T. Gibbs * the data out. 15558b8a9b1dSJustin T. Gibbs */ 15568b8a9b1dSJustin T. Gibbs retval |= DM_RET_COPY; 15578b8a9b1dSJustin T. Gibbs 15588b8a9b1dSJustin T. Gibbs /* 15598b8a9b1dSJustin T. Gibbs * If the return action has been set to descend, then we 15608b8a9b1dSJustin T. Gibbs * know that we've already seen a peripheral matching 15618b8a9b1dSJustin T. Gibbs * expression, therefore we need to further descend the tree. 15628b8a9b1dSJustin T. Gibbs * This won't change by continuing around the loop, so we 15638b8a9b1dSJustin T. Gibbs * go ahead and return. If we haven't seen a peripheral 15648b8a9b1dSJustin T. Gibbs * matching expression, we keep going around the loop until 15658b8a9b1dSJustin T. Gibbs * we exhaust the matching expressions. We'll set the stop 15668b8a9b1dSJustin T. Gibbs * flag once we fall out of the loop. 15678b8a9b1dSJustin T. Gibbs */ 15688b8a9b1dSJustin T. Gibbs if ((retval & DM_RET_ACTION_MASK) == DM_RET_DESCEND) 15698b8a9b1dSJustin T. Gibbs return(retval); 15708b8a9b1dSJustin T. Gibbs } 15718b8a9b1dSJustin T. Gibbs 15728b8a9b1dSJustin T. Gibbs /* 15738b8a9b1dSJustin T. Gibbs * If the return action hasn't been set to descend yet, that means 15748b8a9b1dSJustin T. Gibbs * we haven't seen any peripheral matching patterns. So tell the 15758b8a9b1dSJustin T. Gibbs * caller to stop descending the tree -- the user doesn't want to 15768b8a9b1dSJustin T. Gibbs * match against lower level tree elements. 15778b8a9b1dSJustin T. Gibbs */ 15788b8a9b1dSJustin T. Gibbs if ((retval & DM_RET_ACTION_MASK) == DM_RET_NONE) 15798b8a9b1dSJustin T. Gibbs retval |= DM_RET_STOP; 15808b8a9b1dSJustin T. Gibbs 15818b8a9b1dSJustin T. Gibbs return(retval); 15828b8a9b1dSJustin T. Gibbs } 15838b8a9b1dSJustin T. Gibbs 15848b8a9b1dSJustin T. Gibbs /* 15858b8a9b1dSJustin T. Gibbs * Match a single peripheral against any number of match patterns. 15868b8a9b1dSJustin T. Gibbs */ 15878b8a9b1dSJustin T. Gibbs static dev_match_ret 15883393f8daSKenneth D. Merry xptperiphmatch(struct dev_match_pattern *patterns, u_int num_patterns, 15898b8a9b1dSJustin T. Gibbs struct cam_periph *periph) 15908b8a9b1dSJustin T. Gibbs { 15918b8a9b1dSJustin T. Gibbs dev_match_ret retval; 1592167e63e3SPedro F. Giffuni u_int i; 15938b8a9b1dSJustin T. Gibbs 15948b8a9b1dSJustin T. Gibbs /* 15958b8a9b1dSJustin T. Gibbs * If we aren't given something to match against, that's an error. 15968b8a9b1dSJustin T. Gibbs */ 15978b8a9b1dSJustin T. Gibbs if (periph == NULL) 15988b8a9b1dSJustin T. Gibbs return(DM_RET_ERROR); 15998b8a9b1dSJustin T. Gibbs 16008b8a9b1dSJustin T. Gibbs /* 16018b8a9b1dSJustin T. Gibbs * If there are no match entries, then this peripheral matches no 16028b8a9b1dSJustin T. Gibbs * matter what. 16038b8a9b1dSJustin T. Gibbs */ 16048b8a9b1dSJustin T. Gibbs if ((patterns == NULL) || (num_patterns == 0)) 16058b8a9b1dSJustin T. Gibbs return(DM_RET_STOP | DM_RET_COPY); 16068b8a9b1dSJustin T. Gibbs 16078b8a9b1dSJustin T. Gibbs /* 16088b8a9b1dSJustin T. Gibbs * There aren't any nodes below a peripheral node, so there's no 16098b8a9b1dSJustin T. Gibbs * reason to descend the tree any further. 16108b8a9b1dSJustin T. Gibbs */ 16118b8a9b1dSJustin T. Gibbs retval = DM_RET_STOP; 16128b8a9b1dSJustin T. Gibbs 16138b8a9b1dSJustin T. Gibbs for (i = 0; i < num_patterns; i++) { 16148b8a9b1dSJustin T. Gibbs struct periph_match_pattern *cur_pattern; 16158b8a9b1dSJustin T. Gibbs 16168b8a9b1dSJustin T. Gibbs /* 16178b8a9b1dSJustin T. Gibbs * If the pattern in question isn't for a peripheral, we 16188b8a9b1dSJustin T. Gibbs * aren't interested. 16198b8a9b1dSJustin T. Gibbs */ 16208b8a9b1dSJustin T. Gibbs if (patterns[i].type != DEV_MATCH_PERIPH) 16218b8a9b1dSJustin T. Gibbs continue; 16228b8a9b1dSJustin T. Gibbs 16238b8a9b1dSJustin T. Gibbs cur_pattern = &patterns[i].pattern.periph_pattern; 16248b8a9b1dSJustin T. Gibbs 16258b8a9b1dSJustin T. Gibbs /* 16268b8a9b1dSJustin T. Gibbs * If they want to match on anything, then we will do so. 16278b8a9b1dSJustin T. Gibbs */ 16288b8a9b1dSJustin T. Gibbs if (cur_pattern->flags == PERIPH_MATCH_ANY) { 16298b8a9b1dSJustin T. Gibbs /* set the copy flag */ 16308b8a9b1dSJustin T. Gibbs retval |= DM_RET_COPY; 16318b8a9b1dSJustin T. Gibbs 16328b8a9b1dSJustin T. Gibbs /* 16338b8a9b1dSJustin T. Gibbs * We've already set the return action to stop, 16348b8a9b1dSJustin T. Gibbs * since there are no nodes below peripherals in 16358b8a9b1dSJustin T. Gibbs * the tree. 16368b8a9b1dSJustin T. Gibbs */ 16378b8a9b1dSJustin T. Gibbs return(retval); 16388b8a9b1dSJustin T. Gibbs } 16398b8a9b1dSJustin T. Gibbs 16408b8a9b1dSJustin T. Gibbs /* 16418b8a9b1dSJustin T. Gibbs * Not sure why someone would do this... 16428b8a9b1dSJustin T. Gibbs */ 16438b8a9b1dSJustin T. Gibbs if (cur_pattern->flags == PERIPH_MATCH_NONE) 16448b8a9b1dSJustin T. Gibbs continue; 16458b8a9b1dSJustin T. Gibbs 16468b8a9b1dSJustin T. Gibbs if (((cur_pattern->flags & PERIPH_MATCH_PATH) != 0) 16478b8a9b1dSJustin T. Gibbs && (cur_pattern->path_id != periph->path->bus->path_id)) 16488b8a9b1dSJustin T. Gibbs continue; 16498b8a9b1dSJustin T. Gibbs 16508b8a9b1dSJustin T. Gibbs /* 16518b8a9b1dSJustin T. Gibbs * For the target and lun id's, we have to make sure the 16528b8a9b1dSJustin T. Gibbs * target and lun pointers aren't NULL. The xpt peripheral 16538b8a9b1dSJustin T. Gibbs * has a wildcard target and device. 16548b8a9b1dSJustin T. Gibbs */ 16558b8a9b1dSJustin T. Gibbs if (((cur_pattern->flags & PERIPH_MATCH_TARGET) != 0) 16568b8a9b1dSJustin T. Gibbs && ((periph->path->target == NULL) 16578b8a9b1dSJustin T. Gibbs ||(cur_pattern->target_id != periph->path->target->target_id))) 16588b8a9b1dSJustin T. Gibbs continue; 16598b8a9b1dSJustin T. Gibbs 16608b8a9b1dSJustin T. Gibbs if (((cur_pattern->flags & PERIPH_MATCH_LUN) != 0) 16618b8a9b1dSJustin T. Gibbs && ((periph->path->device == NULL) 16628b8a9b1dSJustin T. Gibbs || (cur_pattern->target_lun != periph->path->device->lun_id))) 16638b8a9b1dSJustin T. Gibbs continue; 16648b8a9b1dSJustin T. Gibbs 16658b8a9b1dSJustin T. Gibbs if (((cur_pattern->flags & PERIPH_MATCH_UNIT) != 0) 16668b8a9b1dSJustin T. Gibbs && (cur_pattern->unit_number != periph->unit_number)) 16678b8a9b1dSJustin T. Gibbs continue; 16688b8a9b1dSJustin T. Gibbs 16698b8a9b1dSJustin T. Gibbs if (((cur_pattern->flags & PERIPH_MATCH_NAME) != 0) 16708b8a9b1dSJustin T. Gibbs && (strncmp(cur_pattern->periph_name, periph->periph_name, 16718b8a9b1dSJustin T. Gibbs DEV_IDLEN) != 0)) 16728b8a9b1dSJustin T. Gibbs continue; 16738b8a9b1dSJustin T. Gibbs 16748b8a9b1dSJustin T. Gibbs /* 16758b8a9b1dSJustin T. Gibbs * If we get to this point, the user definitely wants 16768b8a9b1dSJustin T. Gibbs * information on this peripheral. So tell the caller to 16778b8a9b1dSJustin T. Gibbs * copy the data out. 16788b8a9b1dSJustin T. Gibbs */ 16798b8a9b1dSJustin T. Gibbs retval |= DM_RET_COPY; 16808b8a9b1dSJustin T. Gibbs 16818b8a9b1dSJustin T. Gibbs /* 16828b8a9b1dSJustin T. Gibbs * The return action has already been set to stop, since 16838b8a9b1dSJustin T. Gibbs * peripherals don't have any nodes below them in the EDT. 16848b8a9b1dSJustin T. Gibbs */ 16858b8a9b1dSJustin T. Gibbs return(retval); 16868b8a9b1dSJustin T. Gibbs } 16878b8a9b1dSJustin T. Gibbs 16888b8a9b1dSJustin T. Gibbs /* 16898b8a9b1dSJustin T. Gibbs * If we get to this point, the peripheral that was passed in 16908b8a9b1dSJustin T. Gibbs * doesn't match any of the patterns. 16918b8a9b1dSJustin T. Gibbs */ 16928b8a9b1dSJustin T. Gibbs return(retval); 16938b8a9b1dSJustin T. Gibbs } 16948b8a9b1dSJustin T. Gibbs 16958b8a9b1dSJustin T. Gibbs static int 16968b8a9b1dSJustin T. Gibbs xptedtbusfunc(struct cam_eb *bus, void *arg) 16978b8a9b1dSJustin T. Gibbs { 16988b8a9b1dSJustin T. Gibbs struct ccb_dev_match *cdm; 1699227d67aaSAlexander Motin struct cam_et *target; 17008b8a9b1dSJustin T. Gibbs dev_match_ret retval; 17018b8a9b1dSJustin T. Gibbs 17028b8a9b1dSJustin T. Gibbs cdm = (struct ccb_dev_match *)arg; 17038b8a9b1dSJustin T. Gibbs 17048b8a9b1dSJustin T. Gibbs /* 17058b8a9b1dSJustin T. Gibbs * If our position is for something deeper in the tree, that means 17068b8a9b1dSJustin T. Gibbs * that we've already seen this node. So, we keep going down. 17078b8a9b1dSJustin T. Gibbs */ 17088b8a9b1dSJustin T. Gibbs if ((cdm->pos.position_type & CAM_DEV_POS_BUS) 17098b8a9b1dSJustin T. Gibbs && (cdm->pos.cookie.bus == bus) 17108b8a9b1dSJustin T. Gibbs && (cdm->pos.position_type & CAM_DEV_POS_TARGET) 17118b8a9b1dSJustin T. Gibbs && (cdm->pos.cookie.target != NULL)) 17128b8a9b1dSJustin T. Gibbs retval = DM_RET_DESCEND; 17138b8a9b1dSJustin T. Gibbs else 17148b8a9b1dSJustin T. Gibbs retval = xptbusmatch(cdm->patterns, cdm->num_patterns, bus); 17158b8a9b1dSJustin T. Gibbs 17168b8a9b1dSJustin T. Gibbs /* 17178b8a9b1dSJustin T. Gibbs * If we got an error, bail out of the search. 17188b8a9b1dSJustin T. Gibbs */ 17198b8a9b1dSJustin T. Gibbs if ((retval & DM_RET_ACTION_MASK) == DM_RET_ERROR) { 17208b8a9b1dSJustin T. Gibbs cdm->status = CAM_DEV_MATCH_ERROR; 17218b8a9b1dSJustin T. Gibbs return(0); 17228b8a9b1dSJustin T. Gibbs } 17238b8a9b1dSJustin T. Gibbs 17248b8a9b1dSJustin T. Gibbs /* 17258b8a9b1dSJustin T. Gibbs * If the copy flag is set, copy this bus out. 17268b8a9b1dSJustin T. Gibbs */ 17278b8a9b1dSJustin T. Gibbs if (retval & DM_RET_COPY) { 17288b8a9b1dSJustin T. Gibbs int spaceleft, j; 17298b8a9b1dSJustin T. Gibbs 17308b8a9b1dSJustin T. Gibbs spaceleft = cdm->match_buf_len - (cdm->num_matches * 17318b8a9b1dSJustin T. Gibbs sizeof(struct dev_match_result)); 17328b8a9b1dSJustin T. Gibbs 17338b8a9b1dSJustin T. Gibbs /* 17348b8a9b1dSJustin T. Gibbs * If we don't have enough space to put in another 17358b8a9b1dSJustin T. Gibbs * match result, save our position and tell the 17368b8a9b1dSJustin T. Gibbs * user there are more devices to check. 17378b8a9b1dSJustin T. Gibbs */ 17388b8a9b1dSJustin T. Gibbs if (spaceleft < sizeof(struct dev_match_result)) { 17398b8a9b1dSJustin T. Gibbs bzero(&cdm->pos, sizeof(cdm->pos)); 17408b8a9b1dSJustin T. Gibbs cdm->pos.position_type = 17418b8a9b1dSJustin T. Gibbs CAM_DEV_POS_EDT | CAM_DEV_POS_BUS; 17428b8a9b1dSJustin T. Gibbs 17438b8a9b1dSJustin T. Gibbs cdm->pos.cookie.bus = bus; 17448b8a9b1dSJustin T. Gibbs cdm->pos.generations[CAM_BUS_GENERATION]= 17452b83592fSScott Long xsoftc.bus_generation; 17468b8a9b1dSJustin T. Gibbs cdm->status = CAM_DEV_MATCH_MORE; 17478b8a9b1dSJustin T. Gibbs return(0); 17488b8a9b1dSJustin T. Gibbs } 17498b8a9b1dSJustin T. Gibbs j = cdm->num_matches; 17508b8a9b1dSJustin T. Gibbs cdm->num_matches++; 17518b8a9b1dSJustin T. Gibbs cdm->matches[j].type = DEV_MATCH_BUS; 17528b8a9b1dSJustin T. Gibbs cdm->matches[j].result.bus_result.path_id = bus->path_id; 17538b8a9b1dSJustin T. Gibbs cdm->matches[j].result.bus_result.bus_id = bus->sim->bus_id; 17548b8a9b1dSJustin T. Gibbs cdm->matches[j].result.bus_result.unit_number = 17558b8a9b1dSJustin T. Gibbs bus->sim->unit_number; 1756b0f662feSAlan Somers strlcpy(cdm->matches[j].result.bus_result.dev_name, 1757b0f662feSAlan Somers bus->sim->sim_name, 1758b0f662feSAlan Somers sizeof(cdm->matches[j].result.bus_result.dev_name)); 17598b8a9b1dSJustin T. Gibbs } 17608b8a9b1dSJustin T. Gibbs 17618b8a9b1dSJustin T. Gibbs /* 1762db4fcadfSConrad Meyer * If the user is only interested in buses, there's no 17638b8a9b1dSJustin T. Gibbs * reason to descend to the next level in the tree. 17648b8a9b1dSJustin T. Gibbs */ 17658b8a9b1dSJustin T. Gibbs if ((retval & DM_RET_ACTION_MASK) == DM_RET_STOP) 17668b8a9b1dSJustin T. Gibbs return(1); 17678b8a9b1dSJustin T. Gibbs 17688b8a9b1dSJustin T. Gibbs /* 17698b8a9b1dSJustin T. Gibbs * If there is a target generation recorded, check it to 17708b8a9b1dSJustin T. Gibbs * make sure the target list hasn't changed. 17718b8a9b1dSJustin T. Gibbs */ 1772227d67aaSAlexander Motin mtx_lock(&bus->eb_mtx); 17738b8a9b1dSJustin T. Gibbs if ((cdm->pos.position_type & CAM_DEV_POS_BUS) 17748b8a9b1dSJustin T. Gibbs && (cdm->pos.cookie.bus == bus) 17758b8a9b1dSJustin T. Gibbs && (cdm->pos.position_type & CAM_DEV_POS_TARGET) 1776227d67aaSAlexander Motin && (cdm->pos.cookie.target != NULL)) { 1777227d67aaSAlexander Motin if ((cdm->pos.generations[CAM_TARGET_GENERATION] != 1778227d67aaSAlexander Motin bus->generation)) { 1779227d67aaSAlexander Motin mtx_unlock(&bus->eb_mtx); 1780227d67aaSAlexander Motin cdm->status = CAM_DEV_MATCH_LIST_CHANGED; 1781227d67aaSAlexander Motin return (0); 1782227d67aaSAlexander Motin } 1783227d67aaSAlexander Motin target = (struct cam_et *)cdm->pos.cookie.target; 1784227d67aaSAlexander Motin target->refcount++; 1785227d67aaSAlexander Motin } else 1786227d67aaSAlexander Motin target = NULL; 1787227d67aaSAlexander Motin mtx_unlock(&bus->eb_mtx); 1788227d67aaSAlexander Motin 1789227d67aaSAlexander Motin return (xpttargettraverse(bus, target, xptedttargetfunc, arg)); 17908b8a9b1dSJustin T. Gibbs } 17918b8a9b1dSJustin T. Gibbs 17928b8a9b1dSJustin T. Gibbs static int 17938b8a9b1dSJustin T. Gibbs xptedttargetfunc(struct cam_et *target, void *arg) 17948b8a9b1dSJustin T. Gibbs { 17958b8a9b1dSJustin T. Gibbs struct ccb_dev_match *cdm; 1796227d67aaSAlexander Motin struct cam_eb *bus; 1797227d67aaSAlexander Motin struct cam_ed *device; 17988b8a9b1dSJustin T. Gibbs 17998b8a9b1dSJustin T. Gibbs cdm = (struct ccb_dev_match *)arg; 1800227d67aaSAlexander Motin bus = target->bus; 18018b8a9b1dSJustin T. Gibbs 18028b8a9b1dSJustin T. Gibbs /* 18038b8a9b1dSJustin T. Gibbs * If there is a device list generation recorded, check it to 18048b8a9b1dSJustin T. Gibbs * make sure the device list hasn't changed. 18058b8a9b1dSJustin T. Gibbs */ 1806227d67aaSAlexander Motin mtx_lock(&bus->eb_mtx); 18078b8a9b1dSJustin T. Gibbs if ((cdm->pos.position_type & CAM_DEV_POS_BUS) 1808227d67aaSAlexander Motin && (cdm->pos.cookie.bus == bus) 18098b8a9b1dSJustin T. Gibbs && (cdm->pos.position_type & CAM_DEV_POS_TARGET) 18108b8a9b1dSJustin T. Gibbs && (cdm->pos.cookie.target == target) 18118b8a9b1dSJustin T. Gibbs && (cdm->pos.position_type & CAM_DEV_POS_DEVICE) 1812227d67aaSAlexander Motin && (cdm->pos.cookie.device != NULL)) { 1813227d67aaSAlexander Motin if (cdm->pos.generations[CAM_DEV_GENERATION] != 1814227d67aaSAlexander Motin target->generation) { 1815227d67aaSAlexander Motin mtx_unlock(&bus->eb_mtx); 18168b8a9b1dSJustin T. Gibbs cdm->status = CAM_DEV_MATCH_LIST_CHANGED; 18178b8a9b1dSJustin T. Gibbs return(0); 18188b8a9b1dSJustin T. Gibbs } 1819227d67aaSAlexander Motin device = (struct cam_ed *)cdm->pos.cookie.device; 1820227d67aaSAlexander Motin device->refcount++; 1821227d67aaSAlexander Motin } else 1822227d67aaSAlexander Motin device = NULL; 1823227d67aaSAlexander Motin mtx_unlock(&bus->eb_mtx); 18248b8a9b1dSJustin T. Gibbs 1825227d67aaSAlexander Motin return (xptdevicetraverse(target, device, xptedtdevicefunc, arg)); 18268b8a9b1dSJustin T. Gibbs } 18278b8a9b1dSJustin T. Gibbs 18288b8a9b1dSJustin T. Gibbs static int 18298b8a9b1dSJustin T. Gibbs xptedtdevicefunc(struct cam_ed *device, void *arg) 18308b8a9b1dSJustin T. Gibbs { 1831227d67aaSAlexander Motin struct cam_eb *bus; 1832227d67aaSAlexander Motin struct cam_periph *periph; 18338b8a9b1dSJustin T. Gibbs struct ccb_dev_match *cdm; 18348b8a9b1dSJustin T. Gibbs dev_match_ret retval; 18358b8a9b1dSJustin T. Gibbs 18368b8a9b1dSJustin T. Gibbs cdm = (struct ccb_dev_match *)arg; 1837227d67aaSAlexander Motin bus = device->target->bus; 18388b8a9b1dSJustin T. Gibbs 18398b8a9b1dSJustin T. Gibbs /* 18408b8a9b1dSJustin T. Gibbs * If our position is for something deeper in the tree, that means 18418b8a9b1dSJustin T. Gibbs * that we've already seen this node. So, we keep going down. 18428b8a9b1dSJustin T. Gibbs */ 18438b8a9b1dSJustin T. Gibbs if ((cdm->pos.position_type & CAM_DEV_POS_DEVICE) 18448b8a9b1dSJustin T. Gibbs && (cdm->pos.cookie.device == device) 18458b8a9b1dSJustin T. Gibbs && (cdm->pos.position_type & CAM_DEV_POS_PERIPH) 18468b8a9b1dSJustin T. Gibbs && (cdm->pos.cookie.periph != NULL)) 18478b8a9b1dSJustin T. Gibbs retval = DM_RET_DESCEND; 18488b8a9b1dSJustin T. Gibbs else 18498b8a9b1dSJustin T. Gibbs retval = xptdevicematch(cdm->patterns, cdm->num_patterns, 18508b8a9b1dSJustin T. Gibbs device); 18518b8a9b1dSJustin T. Gibbs 18528b8a9b1dSJustin T. Gibbs if ((retval & DM_RET_ACTION_MASK) == DM_RET_ERROR) { 18538b8a9b1dSJustin T. Gibbs cdm->status = CAM_DEV_MATCH_ERROR; 18548b8a9b1dSJustin T. Gibbs return(0); 18558b8a9b1dSJustin T. Gibbs } 18568b8a9b1dSJustin T. Gibbs 18578b8a9b1dSJustin T. Gibbs /* 18588b8a9b1dSJustin T. Gibbs * If the copy flag is set, copy this device out. 18598b8a9b1dSJustin T. Gibbs */ 18608b8a9b1dSJustin T. Gibbs if (retval & DM_RET_COPY) { 18618b8a9b1dSJustin T. Gibbs int spaceleft, j; 18628b8a9b1dSJustin T. Gibbs 18638b8a9b1dSJustin T. Gibbs spaceleft = cdm->match_buf_len - (cdm->num_matches * 18648b8a9b1dSJustin T. Gibbs sizeof(struct dev_match_result)); 18658b8a9b1dSJustin T. Gibbs 18668b8a9b1dSJustin T. Gibbs /* 18678b8a9b1dSJustin T. Gibbs * If we don't have enough space to put in another 18688b8a9b1dSJustin T. Gibbs * match result, save our position and tell the 18698b8a9b1dSJustin T. Gibbs * user there are more devices to check. 18708b8a9b1dSJustin T. Gibbs */ 18718b8a9b1dSJustin T. Gibbs if (spaceleft < sizeof(struct dev_match_result)) { 18728b8a9b1dSJustin T. Gibbs bzero(&cdm->pos, sizeof(cdm->pos)); 18738b8a9b1dSJustin T. Gibbs cdm->pos.position_type = 18748b8a9b1dSJustin T. Gibbs CAM_DEV_POS_EDT | CAM_DEV_POS_BUS | 18758b8a9b1dSJustin T. Gibbs CAM_DEV_POS_TARGET | CAM_DEV_POS_DEVICE; 18768b8a9b1dSJustin T. Gibbs 18778b8a9b1dSJustin T. Gibbs cdm->pos.cookie.bus = device->target->bus; 18788b8a9b1dSJustin T. Gibbs cdm->pos.generations[CAM_BUS_GENERATION]= 18792b83592fSScott Long xsoftc.bus_generation; 18808b8a9b1dSJustin T. Gibbs cdm->pos.cookie.target = device->target; 18818b8a9b1dSJustin T. Gibbs cdm->pos.generations[CAM_TARGET_GENERATION] = 18828b8a9b1dSJustin T. Gibbs device->target->bus->generation; 18838b8a9b1dSJustin T. Gibbs cdm->pos.cookie.device = device; 18848b8a9b1dSJustin T. Gibbs cdm->pos.generations[CAM_DEV_GENERATION] = 18858b8a9b1dSJustin T. Gibbs device->target->generation; 18868b8a9b1dSJustin T. Gibbs cdm->status = CAM_DEV_MATCH_MORE; 18878b8a9b1dSJustin T. Gibbs return(0); 18888b8a9b1dSJustin T. Gibbs } 18898b8a9b1dSJustin T. Gibbs j = cdm->num_matches; 18908b8a9b1dSJustin T. Gibbs cdm->num_matches++; 18918b8a9b1dSJustin T. Gibbs cdm->matches[j].type = DEV_MATCH_DEVICE; 18928b8a9b1dSJustin T. Gibbs cdm->matches[j].result.device_result.path_id = 18938b8a9b1dSJustin T. Gibbs device->target->bus->path_id; 18948b8a9b1dSJustin T. Gibbs cdm->matches[j].result.device_result.target_id = 18958b8a9b1dSJustin T. Gibbs device->target->target_id; 18968b8a9b1dSJustin T. Gibbs cdm->matches[j].result.device_result.target_lun = 18978b8a9b1dSJustin T. Gibbs device->lun_id; 189852c9ce25SScott Long cdm->matches[j].result.device_result.protocol = 189952c9ce25SScott Long device->protocol; 19008b8a9b1dSJustin T. Gibbs bcopy(&device->inq_data, 19018b8a9b1dSJustin T. Gibbs &cdm->matches[j].result.device_result.inq_data, 19028b8a9b1dSJustin T. Gibbs sizeof(struct scsi_inquiry_data)); 190352c9ce25SScott Long bcopy(&device->ident_data, 190452c9ce25SScott Long &cdm->matches[j].result.device_result.ident_data, 190552c9ce25SScott Long sizeof(struct ata_params)); 19069deea857SKenneth D. Merry 19079deea857SKenneth D. Merry /* Let the user know whether this device is unconfigured */ 19089deea857SKenneth D. Merry if (device->flags & CAM_DEV_UNCONFIGURED) 19099deea857SKenneth D. Merry cdm->matches[j].result.device_result.flags = 19109deea857SKenneth D. Merry DEV_RESULT_UNCONFIGURED; 19119deea857SKenneth D. Merry else 19129deea857SKenneth D. Merry cdm->matches[j].result.device_result.flags = 19139deea857SKenneth D. Merry DEV_RESULT_NOFLAG; 19148b8a9b1dSJustin T. Gibbs } 19158b8a9b1dSJustin T. Gibbs 19168b8a9b1dSJustin T. Gibbs /* 19178b8a9b1dSJustin T. Gibbs * If the user isn't interested in peripherals, don't descend 19188b8a9b1dSJustin T. Gibbs * the tree any further. 19198b8a9b1dSJustin T. Gibbs */ 19208b8a9b1dSJustin T. Gibbs if ((retval & DM_RET_ACTION_MASK) == DM_RET_STOP) 19218b8a9b1dSJustin T. Gibbs return(1); 19228b8a9b1dSJustin T. Gibbs 19238b8a9b1dSJustin T. Gibbs /* 19248b8a9b1dSJustin T. Gibbs * If there is a peripheral list generation recorded, make sure 19258b8a9b1dSJustin T. Gibbs * it hasn't changed. 19268b8a9b1dSJustin T. Gibbs */ 1927227d67aaSAlexander Motin xpt_lock_buses(); 1928227d67aaSAlexander Motin mtx_lock(&bus->eb_mtx); 19298b8a9b1dSJustin T. Gibbs if ((cdm->pos.position_type & CAM_DEV_POS_BUS) 1930227d67aaSAlexander Motin && (cdm->pos.cookie.bus == bus) 19318b8a9b1dSJustin T. Gibbs && (cdm->pos.position_type & CAM_DEV_POS_TARGET) 19328b8a9b1dSJustin T. Gibbs && (cdm->pos.cookie.target == device->target) 19338b8a9b1dSJustin T. Gibbs && (cdm->pos.position_type & CAM_DEV_POS_DEVICE) 19348b8a9b1dSJustin T. Gibbs && (cdm->pos.cookie.device == device) 19358b8a9b1dSJustin T. Gibbs && (cdm->pos.position_type & CAM_DEV_POS_PERIPH) 1936227d67aaSAlexander Motin && (cdm->pos.cookie.periph != NULL)) { 1937227d67aaSAlexander Motin if (cdm->pos.generations[CAM_PERIPH_GENERATION] != 1938227d67aaSAlexander Motin device->generation) { 1939227d67aaSAlexander Motin mtx_unlock(&bus->eb_mtx); 1940227d67aaSAlexander Motin xpt_unlock_buses(); 1941227d67aaSAlexander Motin cdm->status = CAM_DEV_MATCH_LIST_CHANGED; 1942227d67aaSAlexander Motin return(0); 1943227d67aaSAlexander Motin } 1944227d67aaSAlexander Motin periph = (struct cam_periph *)cdm->pos.cookie.periph; 1945227d67aaSAlexander Motin periph->refcount++; 1946227d67aaSAlexander Motin } else 1947227d67aaSAlexander Motin periph = NULL; 1948227d67aaSAlexander Motin mtx_unlock(&bus->eb_mtx); 1949227d67aaSAlexander Motin xpt_unlock_buses(); 1950227d67aaSAlexander Motin 1951227d67aaSAlexander Motin return (xptperiphtraverse(device, periph, xptedtperiphfunc, arg)); 19528b8a9b1dSJustin T. Gibbs } 19538b8a9b1dSJustin T. Gibbs 19548b8a9b1dSJustin T. Gibbs static int 19558b8a9b1dSJustin T. Gibbs xptedtperiphfunc(struct cam_periph *periph, void *arg) 19568b8a9b1dSJustin T. Gibbs { 19578b8a9b1dSJustin T. Gibbs struct ccb_dev_match *cdm; 19588b8a9b1dSJustin T. Gibbs dev_match_ret retval; 19598b8a9b1dSJustin T. Gibbs 19608b8a9b1dSJustin T. Gibbs cdm = (struct ccb_dev_match *)arg; 19618b8a9b1dSJustin T. Gibbs 19628b8a9b1dSJustin T. Gibbs retval = xptperiphmatch(cdm->patterns, cdm->num_patterns, periph); 19638b8a9b1dSJustin T. Gibbs 19648b8a9b1dSJustin T. Gibbs if ((retval & DM_RET_ACTION_MASK) == DM_RET_ERROR) { 19658b8a9b1dSJustin T. Gibbs cdm->status = CAM_DEV_MATCH_ERROR; 19668b8a9b1dSJustin T. Gibbs return(0); 19678b8a9b1dSJustin T. Gibbs } 19688b8a9b1dSJustin T. Gibbs 19698b8a9b1dSJustin T. Gibbs /* 19708b8a9b1dSJustin T. Gibbs * If the copy flag is set, copy this peripheral out. 19718b8a9b1dSJustin T. Gibbs */ 19728b8a9b1dSJustin T. Gibbs if (retval & DM_RET_COPY) { 19738b8a9b1dSJustin T. Gibbs int spaceleft, j; 1974b0f662feSAlan Somers size_t l; 19758b8a9b1dSJustin T. Gibbs 19768b8a9b1dSJustin T. Gibbs spaceleft = cdm->match_buf_len - (cdm->num_matches * 19778b8a9b1dSJustin T. Gibbs sizeof(struct dev_match_result)); 19788b8a9b1dSJustin T. Gibbs 19798b8a9b1dSJustin T. Gibbs /* 19808b8a9b1dSJustin T. Gibbs * If we don't have enough space to put in another 19818b8a9b1dSJustin T. Gibbs * match result, save our position and tell the 19828b8a9b1dSJustin T. Gibbs * user there are more devices to check. 19838b8a9b1dSJustin T. Gibbs */ 19848b8a9b1dSJustin T. Gibbs if (spaceleft < sizeof(struct dev_match_result)) { 19858b8a9b1dSJustin T. Gibbs bzero(&cdm->pos, sizeof(cdm->pos)); 19868b8a9b1dSJustin T. Gibbs cdm->pos.position_type = 19878b8a9b1dSJustin T. Gibbs CAM_DEV_POS_EDT | CAM_DEV_POS_BUS | 19888b8a9b1dSJustin T. Gibbs CAM_DEV_POS_TARGET | CAM_DEV_POS_DEVICE | 19898b8a9b1dSJustin T. Gibbs CAM_DEV_POS_PERIPH; 19908b8a9b1dSJustin T. Gibbs 19918b8a9b1dSJustin T. Gibbs cdm->pos.cookie.bus = periph->path->bus; 19928b8a9b1dSJustin T. Gibbs cdm->pos.generations[CAM_BUS_GENERATION]= 19932b83592fSScott Long xsoftc.bus_generation; 19948b8a9b1dSJustin T. Gibbs cdm->pos.cookie.target = periph->path->target; 19958b8a9b1dSJustin T. Gibbs cdm->pos.generations[CAM_TARGET_GENERATION] = 19968b8a9b1dSJustin T. Gibbs periph->path->bus->generation; 19978b8a9b1dSJustin T. Gibbs cdm->pos.cookie.device = periph->path->device; 19988b8a9b1dSJustin T. Gibbs cdm->pos.generations[CAM_DEV_GENERATION] = 19998b8a9b1dSJustin T. Gibbs periph->path->target->generation; 20008b8a9b1dSJustin T. Gibbs cdm->pos.cookie.periph = periph; 20018b8a9b1dSJustin T. Gibbs cdm->pos.generations[CAM_PERIPH_GENERATION] = 20028b8a9b1dSJustin T. Gibbs periph->path->device->generation; 20038b8a9b1dSJustin T. Gibbs cdm->status = CAM_DEV_MATCH_MORE; 20048b8a9b1dSJustin T. Gibbs return(0); 20058b8a9b1dSJustin T. Gibbs } 20068b8a9b1dSJustin T. Gibbs 20078b8a9b1dSJustin T. Gibbs j = cdm->num_matches; 20088b8a9b1dSJustin T. Gibbs cdm->num_matches++; 20098b8a9b1dSJustin T. Gibbs cdm->matches[j].type = DEV_MATCH_PERIPH; 20108b8a9b1dSJustin T. Gibbs cdm->matches[j].result.periph_result.path_id = 20118b8a9b1dSJustin T. Gibbs periph->path->bus->path_id; 20128b8a9b1dSJustin T. Gibbs cdm->matches[j].result.periph_result.target_id = 20138b8a9b1dSJustin T. Gibbs periph->path->target->target_id; 20148b8a9b1dSJustin T. Gibbs cdm->matches[j].result.periph_result.target_lun = 20158b8a9b1dSJustin T. Gibbs periph->path->device->lun_id; 20168b8a9b1dSJustin T. Gibbs cdm->matches[j].result.periph_result.unit_number = 20178b8a9b1dSJustin T. Gibbs periph->unit_number; 2018b0f662feSAlan Somers l = sizeof(cdm->matches[j].result.periph_result.periph_name); 2019b0f662feSAlan Somers strlcpy(cdm->matches[j].result.periph_result.periph_name, 2020b0f662feSAlan Somers periph->periph_name, l); 20218b8a9b1dSJustin T. Gibbs } 20228b8a9b1dSJustin T. Gibbs 20238b8a9b1dSJustin T. Gibbs return(1); 20248b8a9b1dSJustin T. Gibbs } 20258b8a9b1dSJustin T. Gibbs 20268b8a9b1dSJustin T. Gibbs static int 20278b8a9b1dSJustin T. Gibbs xptedtmatch(struct ccb_dev_match *cdm) 20288b8a9b1dSJustin T. Gibbs { 2029227d67aaSAlexander Motin struct cam_eb *bus; 20308b8a9b1dSJustin T. Gibbs int ret; 20318b8a9b1dSJustin T. Gibbs 20328b8a9b1dSJustin T. Gibbs cdm->num_matches = 0; 20338b8a9b1dSJustin T. Gibbs 20348b8a9b1dSJustin T. Gibbs /* 20358b8a9b1dSJustin T. Gibbs * Check the bus list generation. If it has changed, the user 20368b8a9b1dSJustin T. Gibbs * needs to reset everything and start over. 20378b8a9b1dSJustin T. Gibbs */ 2038227d67aaSAlexander Motin xpt_lock_buses(); 20398b8a9b1dSJustin T. Gibbs if ((cdm->pos.position_type & CAM_DEV_POS_BUS) 2040227d67aaSAlexander Motin && (cdm->pos.cookie.bus != NULL)) { 2041227d67aaSAlexander Motin if (cdm->pos.generations[CAM_BUS_GENERATION] != 2042227d67aaSAlexander Motin xsoftc.bus_generation) { 2043227d67aaSAlexander Motin xpt_unlock_buses(); 20448b8a9b1dSJustin T. Gibbs cdm->status = CAM_DEV_MATCH_LIST_CHANGED; 20458b8a9b1dSJustin T. Gibbs return(0); 20468b8a9b1dSJustin T. Gibbs } 2047227d67aaSAlexander Motin bus = (struct cam_eb *)cdm->pos.cookie.bus; 2048227d67aaSAlexander Motin bus->refcount++; 2049227d67aaSAlexander Motin } else 2050227d67aaSAlexander Motin bus = NULL; 2051227d67aaSAlexander Motin xpt_unlock_buses(); 20528b8a9b1dSJustin T. Gibbs 2053227d67aaSAlexander Motin ret = xptbustraverse(bus, xptedtbusfunc, cdm); 20548b8a9b1dSJustin T. Gibbs 20558b8a9b1dSJustin T. Gibbs /* 20568b8a9b1dSJustin T. Gibbs * If we get back 0, that means that we had to stop before fully 20578b8a9b1dSJustin T. Gibbs * traversing the EDT. It also means that one of the subroutines 20588b8a9b1dSJustin T. Gibbs * has set the status field to the proper value. If we get back 1, 20598b8a9b1dSJustin T. Gibbs * we've fully traversed the EDT and copied out any matching entries. 20608b8a9b1dSJustin T. Gibbs */ 20618b8a9b1dSJustin T. Gibbs if (ret == 1) 20628b8a9b1dSJustin T. Gibbs cdm->status = CAM_DEV_MATCH_LAST; 20638b8a9b1dSJustin T. Gibbs 20648b8a9b1dSJustin T. Gibbs return(ret); 20658b8a9b1dSJustin T. Gibbs } 20668b8a9b1dSJustin T. Gibbs 20678b8a9b1dSJustin T. Gibbs static int 20688b8a9b1dSJustin T. Gibbs xptplistpdrvfunc(struct periph_driver **pdrv, void *arg) 20698b8a9b1dSJustin T. Gibbs { 2070227d67aaSAlexander Motin struct cam_periph *periph; 20718b8a9b1dSJustin T. Gibbs struct ccb_dev_match *cdm; 20728b8a9b1dSJustin T. Gibbs 20738b8a9b1dSJustin T. Gibbs cdm = (struct ccb_dev_match *)arg; 20748b8a9b1dSJustin T. Gibbs 2075227d67aaSAlexander Motin xpt_lock_buses(); 20768b8a9b1dSJustin T. Gibbs if ((cdm->pos.position_type & CAM_DEV_POS_PDPTR) 20778b8a9b1dSJustin T. Gibbs && (cdm->pos.cookie.pdrv == pdrv) 20788b8a9b1dSJustin T. Gibbs && (cdm->pos.position_type & CAM_DEV_POS_PERIPH) 2079227d67aaSAlexander Motin && (cdm->pos.cookie.periph != NULL)) { 2080227d67aaSAlexander Motin if (cdm->pos.generations[CAM_PERIPH_GENERATION] != 2081227d67aaSAlexander Motin (*pdrv)->generation) { 2082227d67aaSAlexander Motin xpt_unlock_buses(); 20838b8a9b1dSJustin T. Gibbs cdm->status = CAM_DEV_MATCH_LIST_CHANGED; 20848b8a9b1dSJustin T. Gibbs return(0); 20858b8a9b1dSJustin T. Gibbs } 2086227d67aaSAlexander Motin periph = (struct cam_periph *)cdm->pos.cookie.periph; 2087227d67aaSAlexander Motin periph->refcount++; 2088227d67aaSAlexander Motin } else 2089227d67aaSAlexander Motin periph = NULL; 2090227d67aaSAlexander Motin xpt_unlock_buses(); 20918b8a9b1dSJustin T. Gibbs 2092227d67aaSAlexander Motin return (xptpdperiphtraverse(pdrv, periph, xptplistperiphfunc, arg)); 20938b8a9b1dSJustin T. Gibbs } 20948b8a9b1dSJustin T. Gibbs 20958b8a9b1dSJustin T. Gibbs static int 20968b8a9b1dSJustin T. Gibbs xptplistperiphfunc(struct cam_periph *periph, void *arg) 20978b8a9b1dSJustin T. Gibbs { 20988b8a9b1dSJustin T. Gibbs struct ccb_dev_match *cdm; 20998b8a9b1dSJustin T. Gibbs dev_match_ret retval; 21008b8a9b1dSJustin T. Gibbs 21018b8a9b1dSJustin T. Gibbs cdm = (struct ccb_dev_match *)arg; 21028b8a9b1dSJustin T. Gibbs 21038b8a9b1dSJustin T. Gibbs retval = xptperiphmatch(cdm->patterns, cdm->num_patterns, periph); 21048b8a9b1dSJustin T. Gibbs 21058b8a9b1dSJustin T. Gibbs if ((retval & DM_RET_ACTION_MASK) == DM_RET_ERROR) { 21068b8a9b1dSJustin T. Gibbs cdm->status = CAM_DEV_MATCH_ERROR; 21078b8a9b1dSJustin T. Gibbs return(0); 21088b8a9b1dSJustin T. Gibbs } 21098b8a9b1dSJustin T. Gibbs 21108b8a9b1dSJustin T. Gibbs /* 21118b8a9b1dSJustin T. Gibbs * If the copy flag is set, copy this peripheral out. 21128b8a9b1dSJustin T. Gibbs */ 21138b8a9b1dSJustin T. Gibbs if (retval & DM_RET_COPY) { 21148b8a9b1dSJustin T. Gibbs int spaceleft, j; 2115b0f662feSAlan Somers size_t l; 21168b8a9b1dSJustin T. Gibbs 21178b8a9b1dSJustin T. Gibbs spaceleft = cdm->match_buf_len - (cdm->num_matches * 21188b8a9b1dSJustin T. Gibbs sizeof(struct dev_match_result)); 21198b8a9b1dSJustin T. Gibbs 21208b8a9b1dSJustin T. Gibbs /* 21218b8a9b1dSJustin T. Gibbs * If we don't have enough space to put in another 21228b8a9b1dSJustin T. Gibbs * match result, save our position and tell the 21238b8a9b1dSJustin T. Gibbs * user there are more devices to check. 21248b8a9b1dSJustin T. Gibbs */ 21258b8a9b1dSJustin T. Gibbs if (spaceleft < sizeof(struct dev_match_result)) { 21268b8a9b1dSJustin T. Gibbs struct periph_driver **pdrv; 21278b8a9b1dSJustin T. Gibbs 21288b8a9b1dSJustin T. Gibbs pdrv = NULL; 21298b8a9b1dSJustin T. Gibbs bzero(&cdm->pos, sizeof(cdm->pos)); 21308b8a9b1dSJustin T. Gibbs cdm->pos.position_type = 21318b8a9b1dSJustin T. Gibbs CAM_DEV_POS_PDRV | CAM_DEV_POS_PDPTR | 21328b8a9b1dSJustin T. Gibbs CAM_DEV_POS_PERIPH; 21338b8a9b1dSJustin T. Gibbs 21348b8a9b1dSJustin T. Gibbs /* 21358b8a9b1dSJustin T. Gibbs * This may look a bit non-sensical, but it is 21368b8a9b1dSJustin T. Gibbs * actually quite logical. There are very few 21378b8a9b1dSJustin T. Gibbs * peripheral drivers, and bloating every peripheral 21388b8a9b1dSJustin T. Gibbs * structure with a pointer back to its parent 21398b8a9b1dSJustin T. Gibbs * peripheral driver linker set entry would cost 21408b8a9b1dSJustin T. Gibbs * more in the long run than doing this quick lookup. 21418b8a9b1dSJustin T. Gibbs */ 21420b7c27b9SPeter Wemm for (pdrv = periph_drivers; *pdrv != NULL; pdrv++) { 21438b8a9b1dSJustin T. Gibbs if (strcmp((*pdrv)->driver_name, 21448b8a9b1dSJustin T. Gibbs periph->periph_name) == 0) 21458b8a9b1dSJustin T. Gibbs break; 21468b8a9b1dSJustin T. Gibbs } 21478b8a9b1dSJustin T. Gibbs 214801910babSScott Long if (*pdrv == NULL) { 21498b8a9b1dSJustin T. Gibbs cdm->status = CAM_DEV_MATCH_ERROR; 21508b8a9b1dSJustin T. Gibbs return(0); 21518b8a9b1dSJustin T. Gibbs } 21528b8a9b1dSJustin T. Gibbs 21538b8a9b1dSJustin T. Gibbs cdm->pos.cookie.pdrv = pdrv; 21548b8a9b1dSJustin T. Gibbs /* 21558b8a9b1dSJustin T. Gibbs * The periph generation slot does double duty, as 21568b8a9b1dSJustin T. Gibbs * does the periph pointer slot. They are used for 21578b8a9b1dSJustin T. Gibbs * both edt and pdrv lookups and positioning. 21588b8a9b1dSJustin T. Gibbs */ 21598b8a9b1dSJustin T. Gibbs cdm->pos.cookie.periph = periph; 21608b8a9b1dSJustin T. Gibbs cdm->pos.generations[CAM_PERIPH_GENERATION] = 21618b8a9b1dSJustin T. Gibbs (*pdrv)->generation; 21628b8a9b1dSJustin T. Gibbs cdm->status = CAM_DEV_MATCH_MORE; 21638b8a9b1dSJustin T. Gibbs return(0); 21648b8a9b1dSJustin T. Gibbs } 21658b8a9b1dSJustin T. Gibbs 21668b8a9b1dSJustin T. Gibbs j = cdm->num_matches; 21678b8a9b1dSJustin T. Gibbs cdm->num_matches++; 21688b8a9b1dSJustin T. Gibbs cdm->matches[j].type = DEV_MATCH_PERIPH; 21698b8a9b1dSJustin T. Gibbs cdm->matches[j].result.periph_result.path_id = 21708b8a9b1dSJustin T. Gibbs periph->path->bus->path_id; 21718b8a9b1dSJustin T. Gibbs 21728b8a9b1dSJustin T. Gibbs /* 21738b8a9b1dSJustin T. Gibbs * The transport layer peripheral doesn't have a target or 21748b8a9b1dSJustin T. Gibbs * lun. 21758b8a9b1dSJustin T. Gibbs */ 21768b8a9b1dSJustin T. Gibbs if (periph->path->target) 21778b8a9b1dSJustin T. Gibbs cdm->matches[j].result.periph_result.target_id = 21788b8a9b1dSJustin T. Gibbs periph->path->target->target_id; 21798b8a9b1dSJustin T. Gibbs else 2180431d3a5bSAlexander Motin cdm->matches[j].result.periph_result.target_id = 2181431d3a5bSAlexander Motin CAM_TARGET_WILDCARD; 21828b8a9b1dSJustin T. Gibbs 21838b8a9b1dSJustin T. Gibbs if (periph->path->device) 21848b8a9b1dSJustin T. Gibbs cdm->matches[j].result.periph_result.target_lun = 21858b8a9b1dSJustin T. Gibbs periph->path->device->lun_id; 21868b8a9b1dSJustin T. Gibbs else 2187431d3a5bSAlexander Motin cdm->matches[j].result.periph_result.target_lun = 2188431d3a5bSAlexander Motin CAM_LUN_WILDCARD; 21898b8a9b1dSJustin T. Gibbs 21908b8a9b1dSJustin T. Gibbs cdm->matches[j].result.periph_result.unit_number = 21918b8a9b1dSJustin T. Gibbs periph->unit_number; 2192b0f662feSAlan Somers l = sizeof(cdm->matches[j].result.periph_result.periph_name); 2193b0f662feSAlan Somers strlcpy(cdm->matches[j].result.periph_result.periph_name, 2194b0f662feSAlan Somers periph->periph_name, l); 21958b8a9b1dSJustin T. Gibbs } 21968b8a9b1dSJustin T. Gibbs 21978b8a9b1dSJustin T. Gibbs return(1); 21988b8a9b1dSJustin T. Gibbs } 21998b8a9b1dSJustin T. Gibbs 22008b8a9b1dSJustin T. Gibbs static int 22018b8a9b1dSJustin T. Gibbs xptperiphlistmatch(struct ccb_dev_match *cdm) 22028b8a9b1dSJustin T. Gibbs { 22038b8a9b1dSJustin T. Gibbs int ret; 22048b8a9b1dSJustin T. Gibbs 22058b8a9b1dSJustin T. Gibbs cdm->num_matches = 0; 22068b8a9b1dSJustin T. Gibbs 22078b8a9b1dSJustin T. Gibbs /* 22088b8a9b1dSJustin T. Gibbs * At this point in the edt traversal function, we check the bus 2209db4fcadfSConrad Meyer * list generation to make sure that no buses have been added or 22108b8a9b1dSJustin T. Gibbs * removed since the user last sent a XPT_DEV_MATCH ccb through. 22118b8a9b1dSJustin T. Gibbs * For the peripheral driver list traversal function, however, we 22128b8a9b1dSJustin T. Gibbs * don't have to worry about new peripheral driver types coming or 22138b8a9b1dSJustin T. Gibbs * going; they're in a linker set, and therefore can't change 22148b8a9b1dSJustin T. Gibbs * without a recompile. 22158b8a9b1dSJustin T. Gibbs */ 22168b8a9b1dSJustin T. Gibbs 22178b8a9b1dSJustin T. Gibbs if ((cdm->pos.position_type & CAM_DEV_POS_PDPTR) 22188b8a9b1dSJustin T. Gibbs && (cdm->pos.cookie.pdrv != NULL)) 22198b8a9b1dSJustin T. Gibbs ret = xptpdrvtraverse( 22208b8a9b1dSJustin T. Gibbs (struct periph_driver **)cdm->pos.cookie.pdrv, 22218b8a9b1dSJustin T. Gibbs xptplistpdrvfunc, cdm); 22228b8a9b1dSJustin T. Gibbs else 22238b8a9b1dSJustin T. Gibbs ret = xptpdrvtraverse(NULL, xptplistpdrvfunc, cdm); 22248b8a9b1dSJustin T. Gibbs 22258b8a9b1dSJustin T. Gibbs /* 22268b8a9b1dSJustin T. Gibbs * If we get back 0, that means that we had to stop before fully 22278b8a9b1dSJustin T. Gibbs * traversing the peripheral driver tree. It also means that one of 22288b8a9b1dSJustin T. Gibbs * the subroutines has set the status field to the proper value. If 22298b8a9b1dSJustin T. Gibbs * we get back 1, we've fully traversed the EDT and copied out any 22308b8a9b1dSJustin T. Gibbs * matching entries. 22318b8a9b1dSJustin T. Gibbs */ 22328b8a9b1dSJustin T. Gibbs if (ret == 1) 22338b8a9b1dSJustin T. Gibbs cdm->status = CAM_DEV_MATCH_LAST; 22348b8a9b1dSJustin T. Gibbs 22358b8a9b1dSJustin T. Gibbs return(ret); 22368b8a9b1dSJustin T. Gibbs } 22378b8a9b1dSJustin T. Gibbs 22388b8a9b1dSJustin T. Gibbs static int 22398b8a9b1dSJustin T. Gibbs xptbustraverse(struct cam_eb *start_bus, xpt_busfunc_t *tr_func, void *arg) 22408b8a9b1dSJustin T. Gibbs { 22418b8a9b1dSJustin T. Gibbs struct cam_eb *bus, *next_bus; 22428b8a9b1dSJustin T. Gibbs int retval; 22438b8a9b1dSJustin T. Gibbs 22448b8a9b1dSJustin T. Gibbs retval = 1; 2245227d67aaSAlexander Motin if (start_bus) 2246227d67aaSAlexander Motin bus = start_bus; 2247227d67aaSAlexander Motin else { 22489a7c2696SAlexander Motin xpt_lock_buses(); 2249227d67aaSAlexander Motin bus = TAILQ_FIRST(&xsoftc.xpt_busses); 2250227d67aaSAlexander Motin if (bus == NULL) { 22519a7c2696SAlexander Motin xpt_unlock_buses(); 2252227d67aaSAlexander Motin return (retval); 2253227d67aaSAlexander Motin } 2254227d67aaSAlexander Motin bus->refcount++; 2255227d67aaSAlexander Motin xpt_unlock_buses(); 2256227d67aaSAlexander Motin } 2257227d67aaSAlexander Motin for (; bus != NULL; bus = next_bus) { 22588b8a9b1dSJustin T. Gibbs retval = tr_func(bus, arg); 2259227d67aaSAlexander Motin if (retval == 0) { 2260227d67aaSAlexander Motin xpt_release_bus(bus); 2261227d67aaSAlexander Motin break; 2262227d67aaSAlexander Motin } 22639a7c2696SAlexander Motin xpt_lock_buses(); 22648900f4b8SKenneth D. Merry next_bus = TAILQ_NEXT(bus, links); 2265227d67aaSAlexander Motin if (next_bus) 2266227d67aaSAlexander Motin next_bus->refcount++; 22679a7c2696SAlexander Motin xpt_unlock_buses(); 22688900f4b8SKenneth D. Merry xpt_release_bus(bus); 22698b8a9b1dSJustin T. Gibbs } 22708b8a9b1dSJustin T. Gibbs return(retval); 22718b8a9b1dSJustin T. Gibbs } 22728b8a9b1dSJustin T. Gibbs 22738b8a9b1dSJustin T. Gibbs static int 22748b8a9b1dSJustin T. Gibbs xpttargettraverse(struct cam_eb *bus, struct cam_et *start_target, 22758b8a9b1dSJustin T. Gibbs xpt_targetfunc_t *tr_func, void *arg) 22768b8a9b1dSJustin T. Gibbs { 22778b8a9b1dSJustin T. Gibbs struct cam_et *target, *next_target; 22788b8a9b1dSJustin T. Gibbs int retval; 22798b8a9b1dSJustin T. Gibbs 22808b8a9b1dSJustin T. Gibbs retval = 1; 2281227d67aaSAlexander Motin if (start_target) 2282227d67aaSAlexander Motin target = start_target; 2283227d67aaSAlexander Motin else { 2284227d67aaSAlexander Motin mtx_lock(&bus->eb_mtx); 2285227d67aaSAlexander Motin target = TAILQ_FIRST(&bus->et_entries); 2286227d67aaSAlexander Motin if (target == NULL) { 2287227d67aaSAlexander Motin mtx_unlock(&bus->eb_mtx); 22888b8a9b1dSJustin T. Gibbs return (retval); 22898b8a9b1dSJustin T. Gibbs } 2290227d67aaSAlexander Motin target->refcount++; 2291227d67aaSAlexander Motin mtx_unlock(&bus->eb_mtx); 2292227d67aaSAlexander Motin } 2293227d67aaSAlexander Motin for (; target != NULL; target = next_target) { 2294227d67aaSAlexander Motin retval = tr_func(target, arg); 2295227d67aaSAlexander Motin if (retval == 0) { 2296227d67aaSAlexander Motin xpt_release_target(target); 2297227d67aaSAlexander Motin break; 2298227d67aaSAlexander Motin } 2299227d67aaSAlexander Motin mtx_lock(&bus->eb_mtx); 2300227d67aaSAlexander Motin next_target = TAILQ_NEXT(target, links); 2301227d67aaSAlexander Motin if (next_target) 2302227d67aaSAlexander Motin next_target->refcount++; 2303227d67aaSAlexander Motin mtx_unlock(&bus->eb_mtx); 2304227d67aaSAlexander Motin xpt_release_target(target); 2305227d67aaSAlexander Motin } 23068b8a9b1dSJustin T. Gibbs return(retval); 23078b8a9b1dSJustin T. Gibbs } 23088b8a9b1dSJustin T. Gibbs 23098b8a9b1dSJustin T. Gibbs static int 23108b8a9b1dSJustin T. Gibbs xptdevicetraverse(struct cam_et *target, struct cam_ed *start_device, 23118b8a9b1dSJustin T. Gibbs xpt_devicefunc_t *tr_func, void *arg) 23128b8a9b1dSJustin T. Gibbs { 2313227d67aaSAlexander Motin struct cam_eb *bus; 23148b8a9b1dSJustin T. Gibbs struct cam_ed *device, *next_device; 23158b8a9b1dSJustin T. Gibbs int retval; 23168b8a9b1dSJustin T. Gibbs 23178b8a9b1dSJustin T. Gibbs retval = 1; 2318227d67aaSAlexander Motin bus = target->bus; 2319227d67aaSAlexander Motin if (start_device) 2320227d67aaSAlexander Motin device = start_device; 2321227d67aaSAlexander Motin else { 2322227d67aaSAlexander Motin mtx_lock(&bus->eb_mtx); 2323227d67aaSAlexander Motin device = TAILQ_FIRST(&target->ed_entries); 2324227d67aaSAlexander Motin if (device == NULL) { 2325227d67aaSAlexander Motin mtx_unlock(&bus->eb_mtx); 23268b8a9b1dSJustin T. Gibbs return (retval); 23278b8a9b1dSJustin T. Gibbs } 2328227d67aaSAlexander Motin device->refcount++; 2329227d67aaSAlexander Motin mtx_unlock(&bus->eb_mtx); 2330227d67aaSAlexander Motin } 2331227d67aaSAlexander Motin for (; device != NULL; device = next_device) { 2332227d67aaSAlexander Motin mtx_lock(&device->device_mtx); 2333227d67aaSAlexander Motin retval = tr_func(device, arg); 2334227d67aaSAlexander Motin mtx_unlock(&device->device_mtx); 2335227d67aaSAlexander Motin if (retval == 0) { 2336227d67aaSAlexander Motin xpt_release_device(device); 2337227d67aaSAlexander Motin break; 2338227d67aaSAlexander Motin } 2339227d67aaSAlexander Motin mtx_lock(&bus->eb_mtx); 2340227d67aaSAlexander Motin next_device = TAILQ_NEXT(device, links); 2341227d67aaSAlexander Motin if (next_device) 2342227d67aaSAlexander Motin next_device->refcount++; 2343227d67aaSAlexander Motin mtx_unlock(&bus->eb_mtx); 2344227d67aaSAlexander Motin xpt_release_device(device); 2345227d67aaSAlexander Motin } 23468b8a9b1dSJustin T. Gibbs return(retval); 23478b8a9b1dSJustin T. Gibbs } 23488b8a9b1dSJustin T. Gibbs 23498b8a9b1dSJustin T. Gibbs static int 23508b8a9b1dSJustin T. Gibbs xptperiphtraverse(struct cam_ed *device, struct cam_periph *start_periph, 23518b8a9b1dSJustin T. Gibbs xpt_periphfunc_t *tr_func, void *arg) 23528b8a9b1dSJustin T. Gibbs { 2353227d67aaSAlexander Motin struct cam_eb *bus; 23548b8a9b1dSJustin T. Gibbs struct cam_periph *periph, *next_periph; 23558b8a9b1dSJustin T. Gibbs int retval; 23568b8a9b1dSJustin T. Gibbs 23578b8a9b1dSJustin T. Gibbs retval = 1; 23588b8a9b1dSJustin T. Gibbs 2359227d67aaSAlexander Motin bus = device->target->bus; 2360227d67aaSAlexander Motin if (start_periph) 2361227d67aaSAlexander Motin periph = start_periph; 2362227d67aaSAlexander Motin else { 23638900f4b8SKenneth D. Merry xpt_lock_buses(); 2364227d67aaSAlexander Motin mtx_lock(&bus->eb_mtx); 2365227d67aaSAlexander Motin periph = SLIST_FIRST(&device->periphs); 2366227d67aaSAlexander Motin while (periph != NULL && (periph->flags & CAM_PERIPH_FREE) != 0) 2367227d67aaSAlexander Motin periph = SLIST_NEXT(periph, periph_links); 2368227d67aaSAlexander Motin if (periph == NULL) { 2369227d67aaSAlexander Motin mtx_unlock(&bus->eb_mtx); 23708900f4b8SKenneth D. Merry xpt_unlock_buses(); 2371227d67aaSAlexander Motin return (retval); 2372227d67aaSAlexander Motin } 2373227d67aaSAlexander Motin periph->refcount++; 2374227d67aaSAlexander Motin mtx_unlock(&bus->eb_mtx); 2375227d67aaSAlexander Motin xpt_unlock_buses(); 2376227d67aaSAlexander Motin } 2377227d67aaSAlexander Motin for (; periph != NULL; periph = next_periph) { 2378227d67aaSAlexander Motin retval = tr_func(periph, arg); 2379227d67aaSAlexander Motin if (retval == 0) { 23809813c936SAlexander Motin cam_periph_release_locked(periph); 2381227d67aaSAlexander Motin break; 2382227d67aaSAlexander Motin } 2383227d67aaSAlexander Motin xpt_lock_buses(); 2384227d67aaSAlexander Motin mtx_lock(&bus->eb_mtx); 2385227d67aaSAlexander Motin next_periph = SLIST_NEXT(periph, periph_links); 2386227d67aaSAlexander Motin while (next_periph != NULL && 2387227d67aaSAlexander Motin (next_periph->flags & CAM_PERIPH_FREE) != 0) 2388840a5dd4SAlexander Motin next_periph = SLIST_NEXT(next_periph, periph_links); 2389227d67aaSAlexander Motin if (next_periph) 2390227d67aaSAlexander Motin next_periph->refcount++; 2391227d67aaSAlexander Motin mtx_unlock(&bus->eb_mtx); 2392227d67aaSAlexander Motin xpt_unlock_buses(); 2393227d67aaSAlexander Motin cam_periph_release_locked(periph); 2394227d67aaSAlexander Motin } 23958b8a9b1dSJustin T. Gibbs return(retval); 23968b8a9b1dSJustin T. Gibbs } 23978b8a9b1dSJustin T. Gibbs 23988b8a9b1dSJustin T. Gibbs static int 23998b8a9b1dSJustin T. Gibbs xptpdrvtraverse(struct periph_driver **start_pdrv, 24008b8a9b1dSJustin T. Gibbs xpt_pdrvfunc_t *tr_func, void *arg) 24018b8a9b1dSJustin T. Gibbs { 24028b8a9b1dSJustin T. Gibbs struct periph_driver **pdrv; 24038b8a9b1dSJustin T. Gibbs int retval; 24048b8a9b1dSJustin T. Gibbs 24058b8a9b1dSJustin T. Gibbs retval = 1; 24068b8a9b1dSJustin T. Gibbs 24078b8a9b1dSJustin T. Gibbs /* 24088b8a9b1dSJustin T. Gibbs * We don't traverse the peripheral driver list like we do the 24098b8a9b1dSJustin T. Gibbs * other lists, because it is a linker set, and therefore cannot be 24108b8a9b1dSJustin T. Gibbs * changed during runtime. If the peripheral driver list is ever 24118b8a9b1dSJustin T. Gibbs * re-done to be something other than a linker set (i.e. it can 24128b8a9b1dSJustin T. Gibbs * change while the system is running), the list traversal should 24138b8a9b1dSJustin T. Gibbs * be modified to work like the other traversal functions. 24148b8a9b1dSJustin T. Gibbs */ 24150b7c27b9SPeter Wemm for (pdrv = (start_pdrv ? start_pdrv : periph_drivers); 24168b8a9b1dSJustin T. Gibbs *pdrv != NULL; pdrv++) { 24178b8a9b1dSJustin T. Gibbs retval = tr_func(pdrv, arg); 24188b8a9b1dSJustin T. Gibbs 24198b8a9b1dSJustin T. Gibbs if (retval == 0) 24208b8a9b1dSJustin T. Gibbs return(retval); 24218b8a9b1dSJustin T. Gibbs } 24228b8a9b1dSJustin T. Gibbs 24238b8a9b1dSJustin T. Gibbs return(retval); 24248b8a9b1dSJustin T. Gibbs } 24258b8a9b1dSJustin T. Gibbs 24268b8a9b1dSJustin T. Gibbs static int 24278b8a9b1dSJustin T. Gibbs xptpdperiphtraverse(struct periph_driver **pdrv, 24288b8a9b1dSJustin T. Gibbs struct cam_periph *start_periph, 24298b8a9b1dSJustin T. Gibbs xpt_periphfunc_t *tr_func, void *arg) 24308b8a9b1dSJustin T. Gibbs { 24318b8a9b1dSJustin T. Gibbs struct cam_periph *periph, *next_periph; 24328b8a9b1dSJustin T. Gibbs int retval; 24338b8a9b1dSJustin T. Gibbs 24348b8a9b1dSJustin T. Gibbs retval = 1; 24358b8a9b1dSJustin T. Gibbs 2436227d67aaSAlexander Motin if (start_periph) 2437227d67aaSAlexander Motin periph = start_periph; 2438227d67aaSAlexander Motin else { 2439f1e2546aSMatt Jacob xpt_lock_buses(); 2440227d67aaSAlexander Motin periph = TAILQ_FIRST(&(*pdrv)->units); 2441227d67aaSAlexander Motin while (periph != NULL && (periph->flags & CAM_PERIPH_FREE) != 0) 2442227d67aaSAlexander Motin periph = TAILQ_NEXT(periph, unit_links); 2443227d67aaSAlexander Motin if (periph == NULL) { 2444227d67aaSAlexander Motin xpt_unlock_buses(); 2445227d67aaSAlexander Motin return (retval); 24468900f4b8SKenneth D. Merry } 24478900f4b8SKenneth D. Merry periph->refcount++; 2448dcdf6e74SAlexander Motin xpt_unlock_buses(); 24498b8a9b1dSJustin T. Gibbs } 2450227d67aaSAlexander Motin for (; periph != NULL; periph = next_periph) { 2451227d67aaSAlexander Motin cam_periph_lock(periph); 2452227d67aaSAlexander Motin retval = tr_func(periph, arg); 2453227d67aaSAlexander Motin cam_periph_unlock(periph); 2454227d67aaSAlexander Motin if (retval == 0) { 2455227d67aaSAlexander Motin cam_periph_release(periph); 2456227d67aaSAlexander Motin break; 2457227d67aaSAlexander Motin } 2458227d67aaSAlexander Motin xpt_lock_buses(); 2459227d67aaSAlexander Motin next_periph = TAILQ_NEXT(periph, unit_links); 2460227d67aaSAlexander Motin while (next_periph != NULL && 2461227d67aaSAlexander Motin (next_periph->flags & CAM_PERIPH_FREE) != 0) 2462840a5dd4SAlexander Motin next_periph = TAILQ_NEXT(next_periph, unit_links); 2463227d67aaSAlexander Motin if (next_periph) 2464227d67aaSAlexander Motin next_periph->refcount++; 2465f1e2546aSMatt Jacob xpt_unlock_buses(); 2466227d67aaSAlexander Motin cam_periph_release(periph); 2467227d67aaSAlexander Motin } 24688b8a9b1dSJustin T. Gibbs return(retval); 24698b8a9b1dSJustin T. Gibbs } 24708b8a9b1dSJustin T. Gibbs 24718b8a9b1dSJustin T. Gibbs static int 24728b8a9b1dSJustin T. Gibbs xptdefbusfunc(struct cam_eb *bus, void *arg) 24738b8a9b1dSJustin T. Gibbs { 24748b8a9b1dSJustin T. Gibbs struct xpt_traverse_config *tr_config; 24758b8a9b1dSJustin T. Gibbs 24768b8a9b1dSJustin T. Gibbs tr_config = (struct xpt_traverse_config *)arg; 24778b8a9b1dSJustin T. Gibbs 24788b8a9b1dSJustin T. Gibbs if (tr_config->depth == XPT_DEPTH_BUS) { 24798b8a9b1dSJustin T. Gibbs xpt_busfunc_t *tr_func; 24808b8a9b1dSJustin T. Gibbs 24818b8a9b1dSJustin T. Gibbs tr_func = (xpt_busfunc_t *)tr_config->tr_func; 24828b8a9b1dSJustin T. Gibbs 24838b8a9b1dSJustin T. Gibbs return(tr_func(bus, tr_config->tr_arg)); 24848b8a9b1dSJustin T. Gibbs } else 24858b8a9b1dSJustin T. Gibbs return(xpttargettraverse(bus, NULL, xptdeftargetfunc, arg)); 24868b8a9b1dSJustin T. Gibbs } 24878b8a9b1dSJustin T. Gibbs 24888b8a9b1dSJustin T. Gibbs static int 24898b8a9b1dSJustin T. Gibbs xptdeftargetfunc(struct cam_et *target, void *arg) 24908b8a9b1dSJustin T. Gibbs { 24918b8a9b1dSJustin T. Gibbs struct xpt_traverse_config *tr_config; 24928b8a9b1dSJustin T. Gibbs 24938b8a9b1dSJustin T. Gibbs tr_config = (struct xpt_traverse_config *)arg; 24948b8a9b1dSJustin T. Gibbs 24958b8a9b1dSJustin T. Gibbs if (tr_config->depth == XPT_DEPTH_TARGET) { 24968b8a9b1dSJustin T. Gibbs xpt_targetfunc_t *tr_func; 24978b8a9b1dSJustin T. Gibbs 24988b8a9b1dSJustin T. Gibbs tr_func = (xpt_targetfunc_t *)tr_config->tr_func; 24998b8a9b1dSJustin T. Gibbs 25008b8a9b1dSJustin T. Gibbs return(tr_func(target, tr_config->tr_arg)); 25018b8a9b1dSJustin T. Gibbs } else 25028b8a9b1dSJustin T. Gibbs return(xptdevicetraverse(target, NULL, xptdefdevicefunc, arg)); 25038b8a9b1dSJustin T. Gibbs } 25048b8a9b1dSJustin T. Gibbs 25058b8a9b1dSJustin T. Gibbs static int 25068b8a9b1dSJustin T. Gibbs xptdefdevicefunc(struct cam_ed *device, void *arg) 25078b8a9b1dSJustin T. Gibbs { 25088b8a9b1dSJustin T. Gibbs struct xpt_traverse_config *tr_config; 25098b8a9b1dSJustin T. Gibbs 25108b8a9b1dSJustin T. Gibbs tr_config = (struct xpt_traverse_config *)arg; 25118b8a9b1dSJustin T. Gibbs 25128b8a9b1dSJustin T. Gibbs if (tr_config->depth == XPT_DEPTH_DEVICE) { 25138b8a9b1dSJustin T. Gibbs xpt_devicefunc_t *tr_func; 25148b8a9b1dSJustin T. Gibbs 25158b8a9b1dSJustin T. Gibbs tr_func = (xpt_devicefunc_t *)tr_config->tr_func; 25168b8a9b1dSJustin T. Gibbs 25178b8a9b1dSJustin T. Gibbs return(tr_func(device, tr_config->tr_arg)); 25188b8a9b1dSJustin T. Gibbs } else 25198b8a9b1dSJustin T. Gibbs return(xptperiphtraverse(device, NULL, xptdefperiphfunc, arg)); 25208b8a9b1dSJustin T. Gibbs } 25218b8a9b1dSJustin T. Gibbs 25228b8a9b1dSJustin T. Gibbs static int 25238b8a9b1dSJustin T. Gibbs xptdefperiphfunc(struct cam_periph *periph, void *arg) 25248b8a9b1dSJustin T. Gibbs { 25258b8a9b1dSJustin T. Gibbs struct xpt_traverse_config *tr_config; 25268b8a9b1dSJustin T. Gibbs xpt_periphfunc_t *tr_func; 25278b8a9b1dSJustin T. Gibbs 25288b8a9b1dSJustin T. Gibbs tr_config = (struct xpt_traverse_config *)arg; 25298b8a9b1dSJustin T. Gibbs 25308b8a9b1dSJustin T. Gibbs tr_func = (xpt_periphfunc_t *)tr_config->tr_func; 25318b8a9b1dSJustin T. Gibbs 25328b8a9b1dSJustin T. Gibbs /* 25338b8a9b1dSJustin T. Gibbs * Unlike the other default functions, we don't check for depth 25348b8a9b1dSJustin T. Gibbs * here. The peripheral driver level is the last level in the EDT, 25358b8a9b1dSJustin T. Gibbs * so if we're here, we should execute the function in question. 25368b8a9b1dSJustin T. Gibbs */ 25378b8a9b1dSJustin T. Gibbs return(tr_func(periph, tr_config->tr_arg)); 25388b8a9b1dSJustin T. Gibbs } 25398b8a9b1dSJustin T. Gibbs 25408b8a9b1dSJustin T. Gibbs /* 25418b8a9b1dSJustin T. Gibbs * Execute the given function for every bus in the EDT. 25428b8a9b1dSJustin T. Gibbs */ 25438b8a9b1dSJustin T. Gibbs static int 25448b8a9b1dSJustin T. Gibbs xpt_for_all_busses(xpt_busfunc_t *tr_func, void *arg) 25458b8a9b1dSJustin T. Gibbs { 25468b8a9b1dSJustin T. Gibbs struct xpt_traverse_config tr_config; 25478b8a9b1dSJustin T. Gibbs 25488b8a9b1dSJustin T. Gibbs tr_config.depth = XPT_DEPTH_BUS; 25498b8a9b1dSJustin T. Gibbs tr_config.tr_func = tr_func; 25508b8a9b1dSJustin T. Gibbs tr_config.tr_arg = arg; 25518b8a9b1dSJustin T. Gibbs 25528b8a9b1dSJustin T. Gibbs return(xptbustraverse(NULL, xptdefbusfunc, &tr_config)); 25538b8a9b1dSJustin T. Gibbs } 25548b8a9b1dSJustin T. Gibbs 25558b8a9b1dSJustin T. Gibbs /* 25568b8a9b1dSJustin T. Gibbs * Execute the given function for every device in the EDT. 25578b8a9b1dSJustin T. Gibbs */ 25588b8a9b1dSJustin T. Gibbs static int 25598b8a9b1dSJustin T. Gibbs xpt_for_all_devices(xpt_devicefunc_t *tr_func, void *arg) 25608b8a9b1dSJustin T. Gibbs { 25618b8a9b1dSJustin T. Gibbs struct xpt_traverse_config tr_config; 25628b8a9b1dSJustin T. Gibbs 25638b8a9b1dSJustin T. Gibbs tr_config.depth = XPT_DEPTH_DEVICE; 25648b8a9b1dSJustin T. Gibbs tr_config.tr_func = tr_func; 25658b8a9b1dSJustin T. Gibbs tr_config.tr_arg = arg; 25668b8a9b1dSJustin T. Gibbs 25678b8a9b1dSJustin T. Gibbs return(xptbustraverse(NULL, xptdefbusfunc, &tr_config)); 25688b8a9b1dSJustin T. Gibbs } 25698b8a9b1dSJustin T. Gibbs 25708b8a9b1dSJustin T. Gibbs static int 25718b8a9b1dSJustin T. Gibbs xptsetasyncfunc(struct cam_ed *device, void *arg) 25728b8a9b1dSJustin T. Gibbs { 25738b8a9b1dSJustin T. Gibbs struct cam_path path; 25748b8a9b1dSJustin T. Gibbs struct ccb_getdev cgd; 25757685edecSAlexander Motin struct ccb_setasync *csa = (struct ccb_setasync *)arg; 25768b8a9b1dSJustin T. Gibbs 2577c8bead2aSJustin T. Gibbs /* 2578c8bead2aSJustin T. Gibbs * Don't report unconfigured devices (Wildcard devs, 2579c8bead2aSJustin T. Gibbs * devices only for target mode, device instances 2580c8bead2aSJustin T. Gibbs * that have been invalidated but are waiting for 2581c8bead2aSJustin T. Gibbs * their last reference count to be released). 2582c8bead2aSJustin T. Gibbs */ 2583c8bead2aSJustin T. Gibbs if ((device->flags & CAM_DEV_UNCONFIGURED) != 0) 2584c8bead2aSJustin T. Gibbs return (1); 2585c8bead2aSJustin T. Gibbs 25868b8a9b1dSJustin T. Gibbs xpt_compile_path(&path, 25878b8a9b1dSJustin T. Gibbs NULL, 25888b8a9b1dSJustin T. Gibbs device->target->bus->path_id, 25898b8a9b1dSJustin T. Gibbs device->target->target_id, 25908b8a9b1dSJustin T. Gibbs device->lun_id); 2591bbfa4aa1SAlexander Motin xpt_setup_ccb(&cgd.ccb_h, &path, CAM_PRIORITY_NORMAL); 25928b8a9b1dSJustin T. Gibbs cgd.ccb_h.func_code = XPT_GDEV_TYPE; 25938b8a9b1dSJustin T. Gibbs xpt_action((union ccb *)&cgd); 25947685edecSAlexander Motin csa->callback(csa->callback_arg, 25958b8a9b1dSJustin T. Gibbs AC_FOUND_DEVICE, 25968b8a9b1dSJustin T. Gibbs &path, &cgd); 25978b8a9b1dSJustin T. Gibbs xpt_release_path(&path); 25988b8a9b1dSJustin T. Gibbs 25998b8a9b1dSJustin T. Gibbs return(1); 26008b8a9b1dSJustin T. Gibbs } 2601c8bead2aSJustin T. Gibbs 26028b8a9b1dSJustin T. Gibbs static int 26038b8a9b1dSJustin T. Gibbs xptsetasyncbusfunc(struct cam_eb *bus, void *arg) 26048b8a9b1dSJustin T. Gibbs { 26058b8a9b1dSJustin T. Gibbs struct cam_path path; 26068b8a9b1dSJustin T. Gibbs struct ccb_pathinq cpi; 26077685edecSAlexander Motin struct ccb_setasync *csa = (struct ccb_setasync *)arg; 26088b8a9b1dSJustin T. Gibbs 26098b8a9b1dSJustin T. Gibbs xpt_compile_path(&path, /*periph*/NULL, 26106dfc67e3SAlexander Motin bus->path_id, 26118b8a9b1dSJustin T. Gibbs CAM_TARGET_WILDCARD, 26128b8a9b1dSJustin T. Gibbs CAM_LUN_WILDCARD); 2613227d67aaSAlexander Motin xpt_path_lock(&path); 2614762a7f4fSWarner Losh xpt_path_inq(&cpi, &path); 26157685edecSAlexander Motin csa->callback(csa->callback_arg, 26168b8a9b1dSJustin T. Gibbs AC_PATH_REGISTERED, 26178b8a9b1dSJustin T. Gibbs &path, &cpi); 2618227d67aaSAlexander Motin xpt_path_unlock(&path); 26198b8a9b1dSJustin T. Gibbs xpt_release_path(&path); 26208b8a9b1dSJustin T. Gibbs 26218b8a9b1dSJustin T. Gibbs return(1); 26228b8a9b1dSJustin T. Gibbs } 26238b8a9b1dSJustin T. Gibbs 26248b8a9b1dSJustin T. Gibbs void 26258b8a9b1dSJustin T. Gibbs xpt_action(union ccb *start_ccb) 26268b8a9b1dSJustin T. Gibbs { 26279911ecf9SJustin T. Gibbs 262882727824SWarner Losh CAM_DEBUG(start_ccb->ccb_h.path, CAM_DEBUG_TRACE, 262969be012fSWarner Losh ("xpt_action: func %#x %s\n", start_ccb->ccb_h.func_code, 263069be012fSWarner Losh xpt_action_name(start_ccb->ccb_h.func_code))); 26318b8a9b1dSJustin T. Gibbs 26328b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.status = CAM_REQ_INPROG; 2633ded2b706SWarner Losh (*(start_ccb->ccb_h.path->bus->xport->ops->action))(start_ccb); 263452c9ce25SScott Long } 263552c9ce25SScott Long 263652c9ce25SScott Long void 263752c9ce25SScott Long xpt_action_default(union ccb *start_ccb) 263852c9ce25SScott Long { 2639da396db2SAlexander Motin struct cam_path *path; 2640227d67aaSAlexander Motin struct cam_sim *sim; 2641401ed17aSAlexander Motin struct mtx *mtx; 264252c9ce25SScott Long 2643da396db2SAlexander Motin path = start_ccb->ccb_h.path; 264482727824SWarner Losh CAM_DEBUG(path, CAM_DEBUG_TRACE, 264569be012fSWarner Losh ("xpt_action_default: func %#x %s\n", start_ccb->ccb_h.func_code, 264669be012fSWarner Losh xpt_action_name(start_ccb->ccb_h.func_code))); 264752c9ce25SScott Long 26488b8a9b1dSJustin T. Gibbs switch (start_ccb->ccb_h.func_code) { 26498b8a9b1dSJustin T. Gibbs case XPT_SCSI_IO: 2650d05caa00SKenneth D. Merry { 26513393f8daSKenneth D. Merry struct cam_ed *device; 2652d05caa00SKenneth D. Merry 26538b8a9b1dSJustin T. Gibbs /* 26548b8a9b1dSJustin T. Gibbs * For the sake of compatibility with SCSI-1 26558b8a9b1dSJustin T. Gibbs * devices that may not understand the identify 26568b8a9b1dSJustin T. Gibbs * message, we include lun information in the 26578b8a9b1dSJustin T. Gibbs * second byte of all commands. SCSI-1 specifies 26588b8a9b1dSJustin T. Gibbs * that luns are a 3 bit value and reserves only 3 26598b8a9b1dSJustin T. Gibbs * bits for lun information in the CDB. Later 26608b8a9b1dSJustin T. Gibbs * revisions of the SCSI spec allow for more than 8 26618b8a9b1dSJustin T. Gibbs * luns, but have deprecated lun information in the 26628b8a9b1dSJustin T. Gibbs * CDB. So, if the lun won't fit, we must omit. 26638b8a9b1dSJustin T. Gibbs * 26648b8a9b1dSJustin T. Gibbs * Also be aware that during initial probing for devices, 26658b8a9b1dSJustin T. Gibbs * the inquiry information is unknown but initialized to 0. 26668b8a9b1dSJustin T. Gibbs * This means that this code will be exercised while probing 26678b8a9b1dSJustin T. Gibbs * devices with an ANSI revision greater than 2. 26688b8a9b1dSJustin T. Gibbs */ 2669da396db2SAlexander Motin device = path->device; 26703393f8daSKenneth D. Merry if (device->protocol_version <= SCSI_REV_2 26718b8a9b1dSJustin T. Gibbs && start_ccb->ccb_h.target_lun < 8 26728b8a9b1dSJustin T. Gibbs && (start_ccb->ccb_h.flags & CAM_CDB_POINTER) == 0) { 26738b8a9b1dSJustin T. Gibbs 26748b8a9b1dSJustin T. Gibbs start_ccb->csio.cdb_io.cdb_bytes[1] |= 26758b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.target_lun << 5; 26768b8a9b1dSJustin T. Gibbs } 26778b8a9b1dSJustin T. Gibbs start_ccb->csio.scsi_status = SCSI_STATUS_OK; 2678d05caa00SKenneth D. Merry } 267907c6eac9SPoul-Henning Kamp /* FALLTHROUGH */ 26808b8a9b1dSJustin T. Gibbs case XPT_TARGET_IO: 26818b8a9b1dSJustin T. Gibbs case XPT_CONT_TARGET_IO: 26822cefde5fSJustin T. Gibbs start_ccb->csio.sense_resid = 0; 26832cefde5fSJustin T. Gibbs start_ccb->csio.resid = 0; 26842cefde5fSJustin T. Gibbs /* FALLTHROUGH */ 268552c9ce25SScott Long case XPT_ATA_IO: 2686de9ebb68SAlexander Motin if (start_ccb->ccb_h.func_code == XPT_ATA_IO) 268752c9ce25SScott Long start_ccb->ataio.resid = 0; 2688b882a6d3SMatt Jacob /* FALLTHROUGH */ 2689b24ced67SWarner Losh case XPT_NVME_IO: 2690df424515SWarner Losh /* FALLTHROUGH */ 2691df424515SWarner Losh case XPT_NVME_ADMIN: 2692b24ced67SWarner Losh /* FALLTHROUGH */ 2693a94a63f0SWarner Losh case XPT_MMC_IO: 2694a94a63f0SWarner Losh /* XXX just like nmve_io? */ 269510e1cf63SKenneth D. Merry case XPT_RESET_DEV: 26968b8a9b1dSJustin T. Gibbs case XPT_ENG_EXEC: 269706e79492SKenneth D. Merry case XPT_SMP_IO: 26982cefde5fSJustin T. Gibbs { 2699227d67aaSAlexander Motin struct cam_devq *devq; 27002cefde5fSJustin T. Gibbs 2701227d67aaSAlexander Motin devq = path->bus->sim->devq; 2702227d67aaSAlexander Motin mtx_lock(&devq->send_mtx); 2703227d67aaSAlexander Motin cam_ccbq_insert_ccb(&path->device->ccbq, start_ccb); 2704227d67aaSAlexander Motin if (xpt_schedule_devq(devq, path->device) != 0) 2705227d67aaSAlexander Motin xpt_run_devq(devq); 2706227d67aaSAlexander Motin mtx_unlock(&devq->send_mtx); 2707227d67aaSAlexander Motin break; 2708227d67aaSAlexander Motin } 2709227d67aaSAlexander Motin case XPT_CALC_GEOMETRY: 27108b8a9b1dSJustin T. Gibbs /* Filter out garbage */ 27118b8a9b1dSJustin T. Gibbs if (start_ccb->ccg.block_size == 0 27128b8a9b1dSJustin T. Gibbs || start_ccb->ccg.volume_size == 0) { 27138b8a9b1dSJustin T. Gibbs start_ccb->ccg.cylinders = 0; 27148b8a9b1dSJustin T. Gibbs start_ccb->ccg.heads = 0; 27158b8a9b1dSJustin T. Gibbs start_ccb->ccg.secs_per_track = 0; 27168b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.status = CAM_REQ_CMP; 27178b8a9b1dSJustin T. Gibbs break; 27188b8a9b1dSJustin T. Gibbs } 27192b375b4eSYoshihiro Takahashi #if defined(__sparc64__) 27208b8a9b1dSJustin T. Gibbs /* 2721abef0e67SMarius Strobl * For sparc64, we may need adjust the geometry of large 2722abef0e67SMarius Strobl * disks in order to fit the limitations of the 16-bit 2723abef0e67SMarius Strobl * fields of the VTOC8 disk label. 27248b8a9b1dSJustin T. Gibbs */ 27258b8a9b1dSJustin T. Gibbs if (scsi_da_bios_params(&start_ccb->ccg) != 0) { 27268b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.status = CAM_REQ_CMP; 27278b8a9b1dSJustin T. Gibbs break; 27288b8a9b1dSJustin T. Gibbs } 27298b8a9b1dSJustin T. Gibbs #endif 2730227d67aaSAlexander Motin goto call_sim; 2731bb6087e5SJustin T. Gibbs case XPT_ABORT: 27322cefde5fSJustin T. Gibbs { 27332cefde5fSJustin T. Gibbs union ccb* abort_ccb; 27342cefde5fSJustin T. Gibbs 27352cefde5fSJustin T. Gibbs abort_ccb = start_ccb->cab.abort_ccb; 27362cefde5fSJustin T. Gibbs if (XPT_FC_IS_DEV_QUEUED(abort_ccb)) { 273783c5d981SAlexander Motin struct cam_ed *device; 2738dda945f5SMark Johnston struct cam_devq *devq; 27392cefde5fSJustin T. Gibbs 274083c5d981SAlexander Motin device = abort_ccb->ccb_h.path->device; 2741dda945f5SMark Johnston devq = device->sim->devq; 2742dda945f5SMark Johnston 2743dda945f5SMark Johnston mtx_lock(&devq->send_mtx); 2744dda945f5SMark Johnston if (abort_ccb->ccb_h.pinfo.index > 0) { 2745dda945f5SMark Johnston cam_ccbq_remove_ccb(&device->ccbq, abort_ccb); 27462cefde5fSJustin T. Gibbs abort_ccb->ccb_h.status = 27472cefde5fSJustin T. Gibbs CAM_REQ_ABORTED|CAM_DEV_QFRZN; 2748dda945f5SMark Johnston xpt_freeze_devq_device(device, 1); 2749dda945f5SMark Johnston mtx_unlock(&devq->send_mtx); 27502cefde5fSJustin T. Gibbs xpt_done(abort_ccb); 27512cefde5fSJustin T. Gibbs start_ccb->ccb_h.status = CAM_REQ_CMP; 27522cefde5fSJustin T. Gibbs break; 27532cefde5fSJustin T. Gibbs } 2754dda945f5SMark Johnston mtx_unlock(&devq->send_mtx); 2755dda945f5SMark Johnston 27562cefde5fSJustin T. Gibbs if (abort_ccb->ccb_h.pinfo.index == CAM_UNQUEUED_INDEX 27572cefde5fSJustin T. Gibbs && (abort_ccb->ccb_h.status & CAM_SIM_QUEUED) == 0) { 27582cefde5fSJustin T. Gibbs /* 27592cefde5fSJustin T. Gibbs * We've caught this ccb en route to 27602cefde5fSJustin T. Gibbs * the SIM. Flag it for abort and the 27612cefde5fSJustin T. Gibbs * SIM will do so just before starting 27622cefde5fSJustin T. Gibbs * real work on the CCB. 27632cefde5fSJustin T. Gibbs */ 27642cefde5fSJustin T. Gibbs abort_ccb->ccb_h.status = 27652cefde5fSJustin T. Gibbs CAM_REQ_ABORTED|CAM_DEV_QFRZN; 27662cefde5fSJustin T. Gibbs xpt_freeze_devq(abort_ccb->ccb_h.path, 1); 27672cefde5fSJustin T. Gibbs start_ccb->ccb_h.status = CAM_REQ_CMP; 27682cefde5fSJustin T. Gibbs break; 27692cefde5fSJustin T. Gibbs } 27702cefde5fSJustin T. Gibbs } 27712cefde5fSJustin T. Gibbs if (XPT_FC_IS_QUEUED(abort_ccb) 27722cefde5fSJustin T. Gibbs && (abort_ccb->ccb_h.pinfo.index == CAM_DONEQ_INDEX)) { 27732cefde5fSJustin T. Gibbs /* 27742cefde5fSJustin T. Gibbs * It's already completed but waiting 27752cefde5fSJustin T. Gibbs * for our SWI to get to it. 27762cefde5fSJustin T. Gibbs */ 27772cefde5fSJustin T. Gibbs start_ccb->ccb_h.status = CAM_UA_ABORT; 27782cefde5fSJustin T. Gibbs break; 27792cefde5fSJustin T. Gibbs } 27802cefde5fSJustin T. Gibbs /* 27812cefde5fSJustin T. Gibbs * If we weren't able to take care of the abort request 27822cefde5fSJustin T. Gibbs * in the XPT, pass the request down to the SIM for processing. 27832cefde5fSJustin T. Gibbs */ 27842cefde5fSJustin T. Gibbs } 278507c6eac9SPoul-Henning Kamp /* FALLTHROUGH */ 27868b8a9b1dSJustin T. Gibbs case XPT_ACCEPT_TARGET_IO: 27878b8a9b1dSJustin T. Gibbs case XPT_EN_LUN: 27888b8a9b1dSJustin T. Gibbs case XPT_IMMED_NOTIFY: 27898b8a9b1dSJustin T. Gibbs case XPT_NOTIFY_ACK: 27908b8a9b1dSJustin T. Gibbs case XPT_RESET_BUS: 27912df76c16SMatt Jacob case XPT_IMMEDIATE_NOTIFY: 27922df76c16SMatt Jacob case XPT_NOTIFY_ACKNOWLEDGE: 2793a2531862SWarner Losh case XPT_GET_SIM_KNOB_OLD: 27942df76c16SMatt Jacob case XPT_GET_SIM_KNOB: 27952df76c16SMatt Jacob case XPT_SET_SIM_KNOB: 2796227d67aaSAlexander Motin case XPT_GET_TRAN_SETTINGS: 2797227d67aaSAlexander Motin case XPT_SET_TRAN_SETTINGS: 279887cfaf0eSJustin T. Gibbs case XPT_PATH_INQ: 2799227d67aaSAlexander Motin call_sim: 2800da396db2SAlexander Motin sim = path->bus->sim; 2801401ed17aSAlexander Motin mtx = sim->mtx; 2802401ed17aSAlexander Motin if (mtx && !mtx_owned(mtx)) 2803401ed17aSAlexander Motin mtx_lock(mtx); 2804401ed17aSAlexander Motin else 2805401ed17aSAlexander Motin mtx = NULL; 2806a94a63f0SWarner Losh 280782727824SWarner Losh CAM_DEBUG(path, CAM_DEBUG_TRACE, 2808a94a63f0SWarner Losh ("Calling sim->sim_action(): func=%#x\n", start_ccb->ccb_h.func_code)); 280987cfaf0eSJustin T. Gibbs (*(sim->sim_action))(sim, start_ccb); 281082727824SWarner Losh CAM_DEBUG(path, CAM_DEBUG_TRACE, 2811a94a63f0SWarner Losh ("sim->sim_action returned: status=%#x\n", start_ccb->ccb_h.status)); 2812401ed17aSAlexander Motin if (mtx) 2813401ed17aSAlexander Motin mtx_unlock(mtx); 281487cfaf0eSJustin T. Gibbs break; 281587cfaf0eSJustin T. Gibbs case XPT_PATH_STATS: 2816da396db2SAlexander Motin start_ccb->cpis.last_reset = path->bus->last_reset; 281787cfaf0eSJustin T. Gibbs start_ccb->ccb_h.status = CAM_REQ_CMP; 281887cfaf0eSJustin T. Gibbs break; 28198b8a9b1dSJustin T. Gibbs case XPT_GDEV_TYPE: 2820a5479bc5SJustin T. Gibbs { 282187cfaf0eSJustin T. Gibbs struct cam_ed *dev; 2822a5479bc5SJustin T. Gibbs 2823da396db2SAlexander Motin dev = path->device; 282487cfaf0eSJustin T. Gibbs if ((dev->flags & CAM_DEV_UNCONFIGURED) != 0) { 28258b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.status = CAM_DEV_NOT_THERE; 28268b8a9b1dSJustin T. Gibbs } else { 28278b8a9b1dSJustin T. Gibbs struct ccb_getdev *cgd; 28288b8a9b1dSJustin T. Gibbs 28298b8a9b1dSJustin T. Gibbs cgd = &start_ccb->cgd; 283052c9ce25SScott Long cgd->protocol = dev->protocol; 28318b8a9b1dSJustin T. Gibbs cgd->inq_data = dev->inq_data; 283252c9ce25SScott Long cgd->ident_data = dev->ident_data; 283330a4094fSAlexander Motin cgd->inq_flags = dev->inq_flags; 28348b8a9b1dSJustin T. Gibbs cgd->ccb_h.status = CAM_REQ_CMP; 28358b8a9b1dSJustin T. Gibbs cgd->serial_num_len = dev->serial_num_len; 28368b8a9b1dSJustin T. Gibbs if ((dev->serial_num_len > 0) 28378b8a9b1dSJustin T. Gibbs && (dev->serial_num != NULL)) 28388b8a9b1dSJustin T. Gibbs bcopy(dev->serial_num, cgd->serial_num, 28398b8a9b1dSJustin T. Gibbs dev->serial_num_len); 28408b8a9b1dSJustin T. Gibbs } 28418b8a9b1dSJustin T. Gibbs break; 2842a5479bc5SJustin T. Gibbs } 284387cfaf0eSJustin T. Gibbs case XPT_GDEV_STATS: 284487cfaf0eSJustin T. Gibbs { 28452ef6e7aeSAlexander Motin struct ccb_getdevstats *cgds = &start_ccb->cgds; 28462ef6e7aeSAlexander Motin struct cam_ed *dev = path->device; 28472ef6e7aeSAlexander Motin struct cam_eb *bus = path->bus; 28482ef6e7aeSAlexander Motin struct cam_et *tar = path->target; 28492ef6e7aeSAlexander Motin struct cam_devq *devq = bus->sim->devq; 285087cfaf0eSJustin T. Gibbs 2851959ec258SAlexander Motin mtx_lock(&devq->send_mtx); 285287cfaf0eSJustin T. Gibbs cgds->dev_openings = dev->ccbq.dev_openings; 285387cfaf0eSJustin T. Gibbs cgds->dev_active = dev->ccbq.dev_active; 2854959ec258SAlexander Motin cgds->allocated = dev->ccbq.allocated; 2855959ec258SAlexander Motin cgds->queued = cam_ccbq_pending_ccb_count(&dev->ccbq); 28562ef6e7aeSAlexander Motin cgds->held = cgds->allocated - cgds->dev_active - cgds->queued; 285787cfaf0eSJustin T. Gibbs cgds->last_reset = tar->last_reset; 285852c9ce25SScott Long cgds->maxtags = dev->maxtags; 285952c9ce25SScott Long cgds->mintags = dev->mintags; 286087cfaf0eSJustin T. Gibbs if (timevalcmp(&tar->last_reset, &bus->last_reset, <)) 286187cfaf0eSJustin T. Gibbs cgds->last_reset = bus->last_reset; 2862959ec258SAlexander Motin mtx_unlock(&devq->send_mtx); 286387cfaf0eSJustin T. Gibbs cgds->ccb_h.status = CAM_REQ_CMP; 286487cfaf0eSJustin T. Gibbs break; 286587cfaf0eSJustin T. Gibbs } 28668b8a9b1dSJustin T. Gibbs case XPT_GDEVLIST: 28678b8a9b1dSJustin T. Gibbs { 28688b8a9b1dSJustin T. Gibbs struct cam_periph *nperiph; 28698b8a9b1dSJustin T. Gibbs struct periph_list *periph_head; 28708b8a9b1dSJustin T. Gibbs struct ccb_getdevlist *cgdl; 28713393f8daSKenneth D. Merry u_int i; 28728b8a9b1dSJustin T. Gibbs struct cam_ed *device; 28738b8a9b1dSJustin T. Gibbs int found; 28748b8a9b1dSJustin T. Gibbs 28758b8a9b1dSJustin T. Gibbs 28768b8a9b1dSJustin T. Gibbs found = 0; 28778b8a9b1dSJustin T. Gibbs 28788b8a9b1dSJustin T. Gibbs /* 28798b8a9b1dSJustin T. Gibbs * Don't want anyone mucking with our data. 28808b8a9b1dSJustin T. Gibbs */ 2881da396db2SAlexander Motin device = path->device; 28828b8a9b1dSJustin T. Gibbs periph_head = &device->periphs; 28838b8a9b1dSJustin T. Gibbs cgdl = &start_ccb->cgdl; 28848b8a9b1dSJustin T. Gibbs 28858b8a9b1dSJustin T. Gibbs /* 28868b8a9b1dSJustin T. Gibbs * Check and see if the list has changed since the user 28878b8a9b1dSJustin T. Gibbs * last requested a list member. If so, tell them that the 28888b8a9b1dSJustin T. Gibbs * list has changed, and therefore they need to start over 28898b8a9b1dSJustin T. Gibbs * from the beginning. 28908b8a9b1dSJustin T. Gibbs */ 28918b8a9b1dSJustin T. Gibbs if ((cgdl->index != 0) && 28928b8a9b1dSJustin T. Gibbs (cgdl->generation != device->generation)) { 28938b8a9b1dSJustin T. Gibbs cgdl->status = CAM_GDEVLIST_LIST_CHANGED; 28948b8a9b1dSJustin T. Gibbs break; 28958b8a9b1dSJustin T. Gibbs } 28968b8a9b1dSJustin T. Gibbs 28978b8a9b1dSJustin T. Gibbs /* 28988b8a9b1dSJustin T. Gibbs * Traverse the list of peripherals and attempt to find 28998b8a9b1dSJustin T. Gibbs * the requested peripheral. 29008b8a9b1dSJustin T. Gibbs */ 2901fc2ffbe6SPoul-Henning Kamp for (nperiph = SLIST_FIRST(periph_head), i = 0; 29028b8a9b1dSJustin T. Gibbs (nperiph != NULL) && (i <= cgdl->index); 2903fc2ffbe6SPoul-Henning Kamp nperiph = SLIST_NEXT(nperiph, periph_links), i++) { 29048b8a9b1dSJustin T. Gibbs if (i == cgdl->index) { 2905b0f662feSAlan Somers strlcpy(cgdl->periph_name, 29068b8a9b1dSJustin T. Gibbs nperiph->periph_name, 2907b0f662feSAlan Somers sizeof(cgdl->periph_name)); 29088b8a9b1dSJustin T. Gibbs cgdl->unit_number = nperiph->unit_number; 29098b8a9b1dSJustin T. Gibbs found = 1; 29108b8a9b1dSJustin T. Gibbs } 29118b8a9b1dSJustin T. Gibbs } 29128b8a9b1dSJustin T. Gibbs if (found == 0) { 29138b8a9b1dSJustin T. Gibbs cgdl->status = CAM_GDEVLIST_ERROR; 29148b8a9b1dSJustin T. Gibbs break; 29158b8a9b1dSJustin T. Gibbs } 29168b8a9b1dSJustin T. Gibbs 29178b8a9b1dSJustin T. Gibbs if (nperiph == NULL) 29188b8a9b1dSJustin T. Gibbs cgdl->status = CAM_GDEVLIST_LAST_DEVICE; 29198b8a9b1dSJustin T. Gibbs else 29208b8a9b1dSJustin T. Gibbs cgdl->status = CAM_GDEVLIST_MORE_DEVS; 29218b8a9b1dSJustin T. Gibbs 29228b8a9b1dSJustin T. Gibbs cgdl->index++; 29238b8a9b1dSJustin T. Gibbs cgdl->generation = device->generation; 29248b8a9b1dSJustin T. Gibbs 29258b8a9b1dSJustin T. Gibbs cgdl->ccb_h.status = CAM_REQ_CMP; 29268b8a9b1dSJustin T. Gibbs break; 29278b8a9b1dSJustin T. Gibbs } 29288b8a9b1dSJustin T. Gibbs case XPT_DEV_MATCH: 29298b8a9b1dSJustin T. Gibbs { 29308b8a9b1dSJustin T. Gibbs dev_pos_type position_type; 29318b8a9b1dSJustin T. Gibbs struct ccb_dev_match *cdm; 29328b8a9b1dSJustin T. Gibbs 29338b8a9b1dSJustin T. Gibbs cdm = &start_ccb->cdm; 29348b8a9b1dSJustin T. Gibbs 29358b8a9b1dSJustin T. Gibbs /* 29368b8a9b1dSJustin T. Gibbs * There are two ways of getting at information in the EDT. 29378b8a9b1dSJustin T. Gibbs * The first way is via the primary EDT tree. It starts 2938db4fcadfSConrad Meyer * with a list of buses, then a list of targets on a bus, 29398b8a9b1dSJustin T. Gibbs * then devices/luns on a target, and then peripherals on a 29408b8a9b1dSJustin T. Gibbs * device/lun. The "other" way is by the peripheral driver 29418b8a9b1dSJustin T. Gibbs * lists. The peripheral driver lists are organized by 29428b8a9b1dSJustin T. Gibbs * peripheral driver. (obviously) So it makes sense to 29438b8a9b1dSJustin T. Gibbs * use the peripheral driver list if the user is looking 29448b8a9b1dSJustin T. Gibbs * for something like "da1", or all "da" devices. If the 29458b8a9b1dSJustin T. Gibbs * user is looking for something on a particular bus/target 29468b8a9b1dSJustin T. Gibbs * or lun, it's generally better to go through the EDT tree. 29478b8a9b1dSJustin T. Gibbs */ 29488b8a9b1dSJustin T. Gibbs 29498b8a9b1dSJustin T. Gibbs if (cdm->pos.position_type != CAM_DEV_POS_NONE) 29508b8a9b1dSJustin T. Gibbs position_type = cdm->pos.position_type; 29518b8a9b1dSJustin T. Gibbs else { 29523393f8daSKenneth D. Merry u_int i; 29538b8a9b1dSJustin T. Gibbs 29548b8a9b1dSJustin T. Gibbs position_type = CAM_DEV_POS_NONE; 29558b8a9b1dSJustin T. Gibbs 29568b8a9b1dSJustin T. Gibbs for (i = 0; i < cdm->num_patterns; i++) { 29578b8a9b1dSJustin T. Gibbs if ((cdm->patterns[i].type == DEV_MATCH_BUS) 29588b8a9b1dSJustin T. Gibbs ||(cdm->patterns[i].type == DEV_MATCH_DEVICE)){ 29598b8a9b1dSJustin T. Gibbs position_type = CAM_DEV_POS_EDT; 29608b8a9b1dSJustin T. Gibbs break; 29618b8a9b1dSJustin T. Gibbs } 29628b8a9b1dSJustin T. Gibbs } 29638b8a9b1dSJustin T. Gibbs 29648b8a9b1dSJustin T. Gibbs if (cdm->num_patterns == 0) 29658b8a9b1dSJustin T. Gibbs position_type = CAM_DEV_POS_EDT; 29668b8a9b1dSJustin T. Gibbs else if (position_type == CAM_DEV_POS_NONE) 29678b8a9b1dSJustin T. Gibbs position_type = CAM_DEV_POS_PDRV; 29688b8a9b1dSJustin T. Gibbs } 29698b8a9b1dSJustin T. Gibbs 29708b8a9b1dSJustin T. Gibbs switch(position_type & CAM_DEV_POS_TYPEMASK) { 29718b8a9b1dSJustin T. Gibbs case CAM_DEV_POS_EDT: 297207c6eac9SPoul-Henning Kamp xptedtmatch(cdm); 29738b8a9b1dSJustin T. Gibbs break; 29748b8a9b1dSJustin T. Gibbs case CAM_DEV_POS_PDRV: 297507c6eac9SPoul-Henning Kamp xptperiphlistmatch(cdm); 29768b8a9b1dSJustin T. Gibbs break; 29778b8a9b1dSJustin T. Gibbs default: 29788b8a9b1dSJustin T. Gibbs cdm->status = CAM_DEV_MATCH_ERROR; 29798b8a9b1dSJustin T. Gibbs break; 29808b8a9b1dSJustin T. Gibbs } 29818b8a9b1dSJustin T. Gibbs 29828b8a9b1dSJustin T. Gibbs if (cdm->status == CAM_DEV_MATCH_ERROR) 29838b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.status = CAM_REQ_CMP_ERR; 29848b8a9b1dSJustin T. Gibbs else 29858b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.status = CAM_REQ_CMP; 29868b8a9b1dSJustin T. Gibbs 29878b8a9b1dSJustin T. Gibbs break; 29888b8a9b1dSJustin T. Gibbs } 29898b8a9b1dSJustin T. Gibbs case XPT_SASYNC_CB: 29908b8a9b1dSJustin T. Gibbs { 299184f82481SScott Long struct ccb_setasync *csa; 299284f82481SScott Long struct async_node *cur_entry; 299384f82481SScott Long struct async_list *async_head; 299484f82481SScott Long u_int32_t added; 299584f82481SScott Long 299684f82481SScott Long csa = &start_ccb->csa; 299784f82481SScott Long added = csa->event_enable; 2998da396db2SAlexander Motin async_head = &path->device->asyncs; 299984f82481SScott Long 300084f82481SScott Long /* 300184f82481SScott Long * If there is already an entry for us, simply 300284f82481SScott Long * update it. 300384f82481SScott Long */ 300484f82481SScott Long cur_entry = SLIST_FIRST(async_head); 300584f82481SScott Long while (cur_entry != NULL) { 300684f82481SScott Long if ((cur_entry->callback_arg == csa->callback_arg) 300784f82481SScott Long && (cur_entry->callback == csa->callback)) 300884f82481SScott Long break; 300984f82481SScott Long cur_entry = SLIST_NEXT(cur_entry, links); 301084f82481SScott Long } 301184f82481SScott Long 301284f82481SScott Long if (cur_entry != NULL) { 301384f82481SScott Long /* 301484f82481SScott Long * If the request has no flags set, 301584f82481SScott Long * remove the entry. 301684f82481SScott Long */ 301784f82481SScott Long added &= ~cur_entry->event_enable; 301884f82481SScott Long if (csa->event_enable == 0) { 301984f82481SScott Long SLIST_REMOVE(async_head, cur_entry, 302084f82481SScott Long async_node, links); 3021da396db2SAlexander Motin xpt_release_device(path->device); 302284f82481SScott Long free(cur_entry, M_CAMXPT); 302384f82481SScott Long } else { 302484f82481SScott Long cur_entry->event_enable = csa->event_enable; 302584f82481SScott Long } 30267685edecSAlexander Motin csa->event_enable = added; 302784f82481SScott Long } else { 302884f82481SScott Long cur_entry = malloc(sizeof(*cur_entry), M_CAMXPT, 302984f82481SScott Long M_NOWAIT); 303084f82481SScott Long if (cur_entry == NULL) { 303184f82481SScott Long csa->ccb_h.status = CAM_RESRC_UNAVAIL; 303284f82481SScott Long break; 303384f82481SScott Long } 303484f82481SScott Long cur_entry->event_enable = csa->event_enable; 3035401ed17aSAlexander Motin cur_entry->event_lock = (path->bus->sim->mtx && 3036401ed17aSAlexander Motin mtx_owned(path->bus->sim->mtx)) ? 1 : 0; 303784f82481SScott Long cur_entry->callback_arg = csa->callback_arg; 303884f82481SScott Long cur_entry->callback = csa->callback; 303984f82481SScott Long SLIST_INSERT_HEAD(async_head, cur_entry, links); 3040da396db2SAlexander Motin xpt_acquire_device(path->device); 304184f82481SScott Long } 30428b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.status = CAM_REQ_CMP; 30438b8a9b1dSJustin T. Gibbs break; 30448b8a9b1dSJustin T. Gibbs } 30458b8a9b1dSJustin T. Gibbs case XPT_REL_SIMQ: 30468b8a9b1dSJustin T. Gibbs { 30478b8a9b1dSJustin T. Gibbs struct ccb_relsim *crs; 30488b8a9b1dSJustin T. Gibbs struct cam_ed *dev; 30498b8a9b1dSJustin T. Gibbs 30508b8a9b1dSJustin T. Gibbs crs = &start_ccb->crs; 3051da396db2SAlexander Motin dev = path->device; 30528b8a9b1dSJustin T. Gibbs if (dev == NULL) { 30538b8a9b1dSJustin T. Gibbs 30548b8a9b1dSJustin T. Gibbs crs->ccb_h.status = CAM_DEV_NOT_THERE; 30558b8a9b1dSJustin T. Gibbs break; 30568b8a9b1dSJustin T. Gibbs } 30578b8a9b1dSJustin T. Gibbs 30588b8a9b1dSJustin T. Gibbs if ((crs->release_flags & RELSIM_ADJUST_OPENINGS) != 0) { 30598b8a9b1dSJustin T. Gibbs 30608b8a9b1dSJustin T. Gibbs /* Don't ever go below one opening */ 30618b8a9b1dSJustin T. Gibbs if (crs->openings > 0) { 30627dc3213dSAlexander Motin xpt_dev_ccbq_resize(path, crs->openings); 306379ccc199SJordan K. Hubbard if (bootverbose) { 3064da396db2SAlexander Motin xpt_print(path, 30657dc3213dSAlexander Motin "number of openings is now %d\n", 30668b8a9b1dSJustin T. Gibbs crs->openings); 30678b8a9b1dSJustin T. Gibbs } 30688b8a9b1dSJustin T. Gibbs } 30698b8a9b1dSJustin T. Gibbs } 30708b8a9b1dSJustin T. Gibbs 3071227d67aaSAlexander Motin mtx_lock(&dev->sim->devq->send_mtx); 30728b8a9b1dSJustin T. Gibbs if ((crs->release_flags & RELSIM_RELEASE_AFTER_TIMEOUT) != 0) { 30738b8a9b1dSJustin T. Gibbs 30748b8a9b1dSJustin T. Gibbs if ((dev->flags & CAM_DEV_REL_TIMEOUT_PENDING) != 0) { 30758b8a9b1dSJustin T. Gibbs 30768b8a9b1dSJustin T. Gibbs /* 30778b8a9b1dSJustin T. Gibbs * Just extend the old timeout and decrement 30788b8a9b1dSJustin T. Gibbs * the freeze count so that a single timeout 30798b8a9b1dSJustin T. Gibbs * is sufficient for releasing the queue. 30808b8a9b1dSJustin T. Gibbs */ 30818b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.flags &= ~CAM_DEV_QFREEZE; 30822b83592fSScott Long callout_stop(&dev->callout); 30838b8a9b1dSJustin T. Gibbs } else { 30848b8a9b1dSJustin T. Gibbs 30858b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.flags |= CAM_DEV_QFREEZE; 30868b8a9b1dSJustin T. Gibbs } 30878b8a9b1dSJustin T. Gibbs 308885c9dd9dSSteven Hartland callout_reset_sbt(&dev->callout, 308985c9dd9dSSteven Hartland SBT_1MS * crs->release_timeout, 0, 309085c9dd9dSSteven Hartland xpt_release_devq_timeout, dev, 0); 30918b8a9b1dSJustin T. Gibbs 30928b8a9b1dSJustin T. Gibbs dev->flags |= CAM_DEV_REL_TIMEOUT_PENDING; 30938b8a9b1dSJustin T. Gibbs 30948b8a9b1dSJustin T. Gibbs } 30958b8a9b1dSJustin T. Gibbs 30968b8a9b1dSJustin T. Gibbs if ((crs->release_flags & RELSIM_RELEASE_AFTER_CMDCMPLT) != 0) { 30978b8a9b1dSJustin T. Gibbs 30988b8a9b1dSJustin T. Gibbs if ((dev->flags & CAM_DEV_REL_ON_COMPLETE) != 0) { 30998b8a9b1dSJustin T. Gibbs /* 31008b8a9b1dSJustin T. Gibbs * Decrement the freeze count so that a single 31018b8a9b1dSJustin T. Gibbs * completion is still sufficient to unfreeze 31028b8a9b1dSJustin T. Gibbs * the queue. 31038b8a9b1dSJustin T. Gibbs */ 31048b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.flags &= ~CAM_DEV_QFREEZE; 31058b8a9b1dSJustin T. Gibbs } else { 31068b8a9b1dSJustin T. Gibbs 31078b8a9b1dSJustin T. Gibbs dev->flags |= CAM_DEV_REL_ON_COMPLETE; 31088b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.flags |= CAM_DEV_QFREEZE; 31098b8a9b1dSJustin T. Gibbs } 31108b8a9b1dSJustin T. Gibbs } 31118b8a9b1dSJustin T. Gibbs 31128b8a9b1dSJustin T. Gibbs if ((crs->release_flags & RELSIM_RELEASE_AFTER_QEMPTY) != 0) { 31138b8a9b1dSJustin T. Gibbs 31148b8a9b1dSJustin T. Gibbs if ((dev->flags & CAM_DEV_REL_ON_QUEUE_EMPTY) != 0 31158b8a9b1dSJustin T. Gibbs || (dev->ccbq.dev_active == 0)) { 31168b8a9b1dSJustin T. Gibbs 31178b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.flags &= ~CAM_DEV_QFREEZE; 31188b8a9b1dSJustin T. Gibbs } else { 31198b8a9b1dSJustin T. Gibbs 31208b8a9b1dSJustin T. Gibbs dev->flags |= CAM_DEV_REL_ON_QUEUE_EMPTY; 31218b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.flags |= CAM_DEV_QFREEZE; 31228b8a9b1dSJustin T. Gibbs } 31238b8a9b1dSJustin T. Gibbs } 3124227d67aaSAlexander Motin mtx_unlock(&dev->sim->devq->send_mtx); 31258b8a9b1dSJustin T. Gibbs 3126cccf4220SAlexander Motin if ((start_ccb->ccb_h.flags & CAM_DEV_QFREEZE) == 0) 3127cccf4220SAlexander Motin xpt_release_devq(path, /*count*/1, /*run_queue*/TRUE); 3128cccf4220SAlexander Motin start_ccb->crs.qfrozen_cnt = dev->ccbq.queue.qfrozen_cnt; 31298b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.status = CAM_REQ_CMP; 31308b8a9b1dSJustin T. Gibbs break; 31318b8a9b1dSJustin T. Gibbs } 31328b8a9b1dSJustin T. Gibbs case XPT_DEBUG: { 313380d6987cSAlexander Motin struct cam_path *oldpath; 313480d6987cSAlexander Motin 3135f0f25b9cSAlexander Motin /* Check that all request bits are supported. */ 313622c7d606SAlexander Motin if (start_ccb->cdbg.flags & ~(CAM_DEBUG_COMPILE)) { 3137f0f25b9cSAlexander Motin start_ccb->ccb_h.status = CAM_FUNC_NOTAVAIL; 3138f0f25b9cSAlexander Motin break; 3139f0f25b9cSAlexander Motin } 3140f0f25b9cSAlexander Motin 314180d6987cSAlexander Motin cam_dflags = CAM_DEBUG_NONE; 31428b8a9b1dSJustin T. Gibbs if (cam_dpath != NULL) { 314380d6987cSAlexander Motin oldpath = cam_dpath; 31448b8a9b1dSJustin T. Gibbs cam_dpath = NULL; 314580d6987cSAlexander Motin xpt_free_path(oldpath); 31468b8a9b1dSJustin T. Gibbs } 314780d6987cSAlexander Motin if (start_ccb->cdbg.flags != CAM_DEBUG_NONE) { 3148e5dfa058SAlexander Motin if (xpt_create_path(&cam_dpath, NULL, 31498b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.path_id, 31508b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.target_id, 31518b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.target_lun) != 31528b8a9b1dSJustin T. Gibbs CAM_REQ_CMP) { 31538b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.status = CAM_RESRC_UNAVAIL; 3154aa872be6SMatt Jacob } else { 315580d6987cSAlexander Motin cam_dflags = start_ccb->cdbg.flags; 31568b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.status = CAM_REQ_CMP; 3157f0d9af51SMatt Jacob xpt_print(cam_dpath, "debugging flags now %x\n", 3158f0d9af51SMatt Jacob cam_dflags); 3159aa872be6SMatt Jacob } 316080d6987cSAlexander Motin } else 31618b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.status = CAM_REQ_CMP; 31628b8a9b1dSJustin T. Gibbs break; 31638b8a9b1dSJustin T. Gibbs } 31648b8a9b1dSJustin T. Gibbs case XPT_NOOP: 316587cfaf0eSJustin T. Gibbs if ((start_ccb->ccb_h.flags & CAM_DEV_QFREEZE) != 0) 3166da396db2SAlexander Motin xpt_freeze_devq(path, 1); 31678b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.status = CAM_REQ_CMP; 31688b8a9b1dSJustin T. Gibbs break; 3169d68fae58SEdward Tomasz Napierala case XPT_REPROBE_LUN: 3170d68fae58SEdward Tomasz Napierala xpt_async(AC_INQ_CHANGED, path, NULL); 3171d68fae58SEdward Tomasz Napierala start_ccb->ccb_h.status = CAM_REQ_CMP; 3172d68fae58SEdward Tomasz Napierala xpt_done(start_ccb); 3173d68fae58SEdward Tomasz Napierala break; 31748b8a9b1dSJustin T. Gibbs default: 31758b8a9b1dSJustin T. Gibbs case XPT_SDEV_TYPE: 31768b8a9b1dSJustin T. Gibbs case XPT_TERM_IO: 31778b8a9b1dSJustin T. Gibbs case XPT_ENG_INQ: 31788b8a9b1dSJustin T. Gibbs /* XXX Implement */ 3179bf1a8895SScott Long xpt_print(start_ccb->ccb_h.path, 3180bf1a8895SScott Long "%s: CCB type %#x %s not supported\n", __func__, 3181b24ced67SWarner Losh start_ccb->ccb_h.func_code, 3182b24ced67SWarner Losh xpt_action_name(start_ccb->ccb_h.func_code)); 31838b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.status = CAM_PROVIDE_FAIL; 3184b882a6d3SMatt Jacob if (start_ccb->ccb_h.func_code & XPT_FC_DEV_QUEUED) { 3185b882a6d3SMatt Jacob xpt_done(start_ccb); 3186b882a6d3SMatt Jacob } 31878b8a9b1dSJustin T. Gibbs break; 31888b8a9b1dSJustin T. Gibbs } 318969be012fSWarner Losh CAM_DEBUG(path, CAM_DEBUG_TRACE, 319069be012fSWarner Losh ("xpt_action_default: func= %#x %s status %#x\n", 319169be012fSWarner Losh start_ccb->ccb_h.func_code, 319269be012fSWarner Losh xpt_action_name(start_ccb->ccb_h.func_code), 319369be012fSWarner Losh start_ccb->ccb_h.status)); 31948b8a9b1dSJustin T. Gibbs } 31958b8a9b1dSJustin T. Gibbs 31960cc28e3cSWarner Losh /* 31970cc28e3cSWarner Losh * Call the sim poll routine to allow the sim to complete 31980cc28e3cSWarner Losh * any inflight requests, then call camisr_runqueue to 31990cc28e3cSWarner Losh * complete any CCB that the polling completed. 32000cc28e3cSWarner Losh */ 32010cc28e3cSWarner Losh void 32020cc28e3cSWarner Losh xpt_sim_poll(struct cam_sim *sim) 32030cc28e3cSWarner Losh { 32040cc28e3cSWarner Losh struct mtx *mtx; 32050cc28e3cSWarner Losh 32060cc28e3cSWarner Losh mtx = sim->mtx; 32070cc28e3cSWarner Losh if (mtx) 32080cc28e3cSWarner Losh mtx_lock(mtx); 32090cc28e3cSWarner Losh (*(sim->sim_poll))(sim); 32100cc28e3cSWarner Losh if (mtx) 32110cc28e3cSWarner Losh mtx_unlock(mtx); 32120cc28e3cSWarner Losh camisr_runqueue(); 32130cc28e3cSWarner Losh } 32140cc28e3cSWarner Losh 3215f93a843cSWarner Losh uint32_t 3216f93a843cSWarner Losh xpt_poll_setup(union ccb *start_ccb) 32178b8a9b1dSJustin T. Gibbs { 32188b8a9b1dSJustin T. Gibbs u_int32_t timeout; 32198b8a9b1dSJustin T. Gibbs struct cam_sim *sim; 32208b8a9b1dSJustin T. Gibbs struct cam_devq *devq; 32218b8a9b1dSJustin T. Gibbs struct cam_ed *dev; 32228b8a9b1dSJustin T. Gibbs 32230069293bSAlexander Motin timeout = start_ccb->ccb_h.timeout * 10; 32248b8a9b1dSJustin T. Gibbs sim = start_ccb->ccb_h.path->bus->sim; 32258b8a9b1dSJustin T. Gibbs devq = sim->devq; 32268b8a9b1dSJustin T. Gibbs dev = start_ccb->ccb_h.path->device; 32278b8a9b1dSJustin T. Gibbs 32288b8a9b1dSJustin T. Gibbs /* 32298b8a9b1dSJustin T. Gibbs * Steal an opening so that no other queued requests 32308b8a9b1dSJustin T. Gibbs * can get it before us while we simulate interrupts. 32318b8a9b1dSJustin T. Gibbs */ 3232227d67aaSAlexander Motin mtx_lock(&devq->send_mtx); 32338b8a9b1dSJustin T. Gibbs dev->ccbq.dev_openings--; 3234227d67aaSAlexander Motin while((devq->send_openings <= 0 || dev->ccbq.dev_openings < 0) && 3235227d67aaSAlexander Motin (--timeout > 0)) { 3236227d67aaSAlexander Motin mtx_unlock(&devq->send_mtx); 32370069293bSAlexander Motin DELAY(100); 32380cc28e3cSWarner Losh xpt_sim_poll(sim); 3239227d67aaSAlexander Motin mtx_lock(&devq->send_mtx); 32408b8a9b1dSJustin T. Gibbs } 32418b8a9b1dSJustin T. Gibbs dev->ccbq.dev_openings++; 3242227d67aaSAlexander Motin mtx_unlock(&devq->send_mtx); 32438b8a9b1dSJustin T. Gibbs 3244f93a843cSWarner Losh return (timeout); 3245f93a843cSWarner Losh } 3246f93a843cSWarner Losh 3247f93a843cSWarner Losh void 3248f93a843cSWarner Losh xpt_pollwait(union ccb *start_ccb, uint32_t timeout) 3249f93a843cSWarner Losh { 3250f93a843cSWarner Losh 32518b8a9b1dSJustin T. Gibbs while (--timeout > 0) { 32520cc28e3cSWarner Losh xpt_sim_poll(start_ccb->ccb_h.path->bus->sim); 32538b8a9b1dSJustin T. Gibbs if ((start_ccb->ccb_h.status & CAM_STATUS_MASK) 32548b8a9b1dSJustin T. Gibbs != CAM_REQ_INPROG) 32558b8a9b1dSJustin T. Gibbs break; 32560069293bSAlexander Motin DELAY(100); 32578b8a9b1dSJustin T. Gibbs } 3258f93a843cSWarner Losh 32598b8a9b1dSJustin T. Gibbs if (timeout == 0) { 32608b8a9b1dSJustin T. Gibbs /* 32618b8a9b1dSJustin T. Gibbs * XXX Is it worth adding a sim_timeout entry 32628b8a9b1dSJustin T. Gibbs * point so we can attempt recovery? If 32638b8a9b1dSJustin T. Gibbs * this is only used for dumps, I don't think 32648b8a9b1dSJustin T. Gibbs * it is. 32658b8a9b1dSJustin T. Gibbs */ 32668b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.status = CAM_CMD_TIMEOUT; 32678b8a9b1dSJustin T. Gibbs } 3268f93a843cSWarner Losh } 3269f93a843cSWarner Losh 3270f93a843cSWarner Losh void 3271f93a843cSWarner Losh xpt_polled_action(union ccb *start_ccb) 3272f93a843cSWarner Losh { 3273f93a843cSWarner Losh uint32_t timeout; 3274f93a843cSWarner Losh struct cam_ed *dev; 3275f93a843cSWarner Losh 3276f93a843cSWarner Losh timeout = start_ccb->ccb_h.timeout * 10; 3277f93a843cSWarner Losh dev = start_ccb->ccb_h.path->device; 3278f93a843cSWarner Losh 3279f93a843cSWarner Losh mtx_unlock(&dev->device_mtx); 3280f93a843cSWarner Losh 3281f93a843cSWarner Losh timeout = xpt_poll_setup(start_ccb); 3282f93a843cSWarner Losh if (timeout > 0) { 3283f93a843cSWarner Losh xpt_action(start_ccb); 3284f93a843cSWarner Losh xpt_pollwait(start_ccb, timeout); 32858b8a9b1dSJustin T. Gibbs } else { 32868b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.status = CAM_RESRC_UNAVAIL; 32878b8a9b1dSJustin T. Gibbs } 32884a612489SAlexander Motin 3289227d67aaSAlexander Motin mtx_lock(&dev->device_mtx); 32908b8a9b1dSJustin T. Gibbs } 32918b8a9b1dSJustin T. Gibbs 32928b8a9b1dSJustin T. Gibbs /* 329321cffce5SBryan Drewery * Schedule a peripheral driver to receive a ccb when its 32948b8a9b1dSJustin T. Gibbs * target device has space for more transactions. 32958b8a9b1dSJustin T. Gibbs */ 32968b8a9b1dSJustin T. Gibbs void 3297227d67aaSAlexander Motin xpt_schedule(struct cam_periph *periph, u_int32_t new_priority) 32988b8a9b1dSJustin T. Gibbs { 32998b8a9b1dSJustin T. Gibbs 3300227d67aaSAlexander Motin CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("xpt_schedule\n")); 3301227d67aaSAlexander Motin cam_periph_assert(periph, MA_OWNED); 3302227d67aaSAlexander Motin if (new_priority < periph->scheduled_priority) { 3303227d67aaSAlexander Motin periph->scheduled_priority = new_priority; 3304227d67aaSAlexander Motin xpt_run_allocq(periph, 0); 33058b8a9b1dSJustin T. Gibbs } 33068b8a9b1dSJustin T. Gibbs } 33078b8a9b1dSJustin T. Gibbs 33088b8a9b1dSJustin T. Gibbs 33098b8a9b1dSJustin T. Gibbs /* 33108b8a9b1dSJustin T. Gibbs * Schedule a device to run on a given queue. 33118b8a9b1dSJustin T. Gibbs * If the device was inserted as a new entry on the queue, 33128b8a9b1dSJustin T. Gibbs * return 1 meaning the device queue should be run. If we 33138b8a9b1dSJustin T. Gibbs * were already queued, implying someone else has already 33148b8a9b1dSJustin T. Gibbs * started the queue, return 0 so the caller doesn't attempt 331577dc25ccSScott Long * to run the queue. 33168b8a9b1dSJustin T. Gibbs */ 3317227d67aaSAlexander Motin static int 33188b8a9b1dSJustin T. Gibbs xpt_schedule_dev(struct camq *queue, cam_pinfo *pinfo, 33198b8a9b1dSJustin T. Gibbs u_int32_t new_priority) 33208b8a9b1dSJustin T. Gibbs { 33218b8a9b1dSJustin T. Gibbs int retval; 33228b8a9b1dSJustin T. Gibbs u_int32_t old_priority; 33238b8a9b1dSJustin T. Gibbs 3324aa872be6SMatt Jacob CAM_DEBUG_PRINT(CAM_DEBUG_XPT, ("xpt_schedule_dev\n")); 33258b8a9b1dSJustin T. Gibbs 3326f93a843cSWarner Losh 33278b8a9b1dSJustin T. Gibbs old_priority = pinfo->priority; 33288b8a9b1dSJustin T. Gibbs 33298b8a9b1dSJustin T. Gibbs /* 33308b8a9b1dSJustin T. Gibbs * Are we already queued? 33318b8a9b1dSJustin T. Gibbs */ 33328b8a9b1dSJustin T. Gibbs if (pinfo->index != CAM_UNQUEUED_INDEX) { 33338b8a9b1dSJustin T. Gibbs /* Simply reorder based on new priority */ 33348b8a9b1dSJustin T. Gibbs if (new_priority < old_priority) { 33358b8a9b1dSJustin T. Gibbs camq_change_priority(queue, pinfo->index, 33368b8a9b1dSJustin T. Gibbs new_priority); 3337aa872be6SMatt Jacob CAM_DEBUG_PRINT(CAM_DEBUG_XPT, 33388b8a9b1dSJustin T. Gibbs ("changed priority to %d\n", 33398b8a9b1dSJustin T. Gibbs new_priority)); 334083c5d981SAlexander Motin retval = 1; 334183c5d981SAlexander Motin } else 33428b8a9b1dSJustin T. Gibbs retval = 0; 33438b8a9b1dSJustin T. Gibbs } else { 33448b8a9b1dSJustin T. Gibbs /* New entry on the queue */ 33458b8a9b1dSJustin T. Gibbs if (new_priority < old_priority) 33468b8a9b1dSJustin T. Gibbs pinfo->priority = new_priority; 33478b8a9b1dSJustin T. Gibbs 3348aa872be6SMatt Jacob CAM_DEBUG_PRINT(CAM_DEBUG_XPT, 33498b8a9b1dSJustin T. Gibbs ("Inserting onto queue\n")); 33508bad620dSJustin T. Gibbs pinfo->generation = ++queue->generation; 33518b8a9b1dSJustin T. Gibbs camq_insert(queue, pinfo); 33528b8a9b1dSJustin T. Gibbs retval = 1; 33538b8a9b1dSJustin T. Gibbs } 33548b8a9b1dSJustin T. Gibbs return (retval); 33558b8a9b1dSJustin T. Gibbs } 33568b8a9b1dSJustin T. Gibbs 33578b8a9b1dSJustin T. Gibbs static void 3358227d67aaSAlexander Motin xpt_run_allocq_task(void *context, int pending) 33598b8a9b1dSJustin T. Gibbs { 3360227d67aaSAlexander Motin struct cam_periph *periph = context; 33618b8a9b1dSJustin T. Gibbs 3362227d67aaSAlexander Motin cam_periph_lock(periph); 3363227d67aaSAlexander Motin periph->flags &= ~CAM_PERIPH_RUN_TASK; 3364227d67aaSAlexander Motin xpt_run_allocq(periph, 1); 3365227d67aaSAlexander Motin cam_periph_unlock(periph); 3366227d67aaSAlexander Motin cam_periph_release(periph); 3367227d67aaSAlexander Motin } 3368227d67aaSAlexander Motin 3369227d67aaSAlexander Motin static void 3370227d67aaSAlexander Motin xpt_run_allocq(struct cam_periph *periph, int sleep) 3371227d67aaSAlexander Motin { 3372227d67aaSAlexander Motin struct cam_ed *device; 3373227d67aaSAlexander Motin union ccb *ccb; 3374227d67aaSAlexander Motin uint32_t prio; 3375227d67aaSAlexander Motin 3376227d67aaSAlexander Motin cam_periph_assert(periph, MA_OWNED); 3377227d67aaSAlexander Motin if (periph->periph_allocating) 3378cccf4220SAlexander Motin return; 33797c1374d5SScott Long cam_periph_doacquire(periph); 3380227d67aaSAlexander Motin periph->periph_allocating = 1; 3381227d67aaSAlexander Motin CAM_DEBUG_PRINT(CAM_DEBUG_XPT, ("xpt_run_allocq(%p)\n", periph)); 3382227d67aaSAlexander Motin device = periph->path->device; 3383227d67aaSAlexander Motin ccb = NULL; 3384227d67aaSAlexander Motin restart: 3385227d67aaSAlexander Motin while ((prio = min(periph->scheduled_priority, 3386227d67aaSAlexander Motin periph->immediate_priority)) != CAM_PRIORITY_NONE && 3387227d67aaSAlexander Motin (periph->periph_allocated - (ccb != NULL ? 1 : 0) < 3388227d67aaSAlexander Motin device->ccbq.total_openings || prio <= CAM_PRIORITY_OOB)) { 3389cccf4220SAlexander Motin 3390227d67aaSAlexander Motin if (ccb == NULL && 3391227d67aaSAlexander Motin (ccb = xpt_get_ccb_nowait(periph)) == NULL) { 3392227d67aaSAlexander Motin if (sleep) { 3393227d67aaSAlexander Motin ccb = xpt_get_ccb(periph); 3394227d67aaSAlexander Motin goto restart; 3395227d67aaSAlexander Motin } 33968ec5ab3fSAlexander Motin if (periph->flags & CAM_PERIPH_RUN_TASK) 33978b8a9b1dSJustin T. Gibbs break; 3398c33e4029SAlexander Motin cam_periph_doacquire(periph); 3399227d67aaSAlexander Motin periph->flags |= CAM_PERIPH_RUN_TASK; 3400227d67aaSAlexander Motin taskqueue_enqueue(xsoftc.xpt_taskq, 3401227d67aaSAlexander Motin &periph->periph_run_task); 3402227d67aaSAlexander Motin break; 34038b8a9b1dSJustin T. Gibbs } 3404227d67aaSAlexander Motin xpt_setup_ccb(&ccb->ccb_h, periph->path, prio); 3405227d67aaSAlexander Motin if (prio == periph->immediate_priority) { 3406227d67aaSAlexander Motin periph->immediate_priority = CAM_PRIORITY_NONE; 3407227d67aaSAlexander Motin CAM_DEBUG_PRINT(CAM_DEBUG_XPT, 3408227d67aaSAlexander Motin ("waking cam_periph_getccb()\n")); 3409227d67aaSAlexander Motin SLIST_INSERT_HEAD(&periph->ccb_list, &ccb->ccb_h, 3410227d67aaSAlexander Motin periph_links.sle); 3411227d67aaSAlexander Motin wakeup(&periph->ccb_list); 3412227d67aaSAlexander Motin } else { 3413227d67aaSAlexander Motin periph->scheduled_priority = CAM_PRIORITY_NONE; 3414227d67aaSAlexander Motin CAM_DEBUG_PRINT(CAM_DEBUG_XPT, 3415227d67aaSAlexander Motin ("calling periph_start()\n")); 3416227d67aaSAlexander Motin periph->periph_start(periph, ccb); 3417227d67aaSAlexander Motin } 3418227d67aaSAlexander Motin ccb = NULL; 3419227d67aaSAlexander Motin } 3420227d67aaSAlexander Motin if (ccb != NULL) 3421227d67aaSAlexander Motin xpt_release_ccb(ccb); 3422227d67aaSAlexander Motin periph->periph_allocating = 0; 34237c1374d5SScott Long cam_periph_release_locked(periph); 34248b8a9b1dSJustin T. Gibbs } 34258b8a9b1dSJustin T. Gibbs 342683c5d981SAlexander Motin static void 3427cccf4220SAlexander Motin xpt_run_devq(struct cam_devq *devq) 34288b8a9b1dSJustin T. Gibbs { 3429401ed17aSAlexander Motin struct mtx *mtx; 34308b8a9b1dSJustin T. Gibbs 3431cccf4220SAlexander Motin CAM_DEBUG_PRINT(CAM_DEBUG_XPT, ("xpt_run_devq\n")); 34328b8a9b1dSJustin T. Gibbs 3433cccf4220SAlexander Motin devq->send_queue.qfrozen_cnt++; 34348b8a9b1dSJustin T. Gibbs while ((devq->send_queue.entries > 0) 3435ec700f26SAlexander Motin && (devq->send_openings > 0) 3436cccf4220SAlexander Motin && (devq->send_queue.qfrozen_cnt <= 1)) { 34378b8a9b1dSJustin T. Gibbs struct cam_ed *device; 34388b8a9b1dSJustin T. Gibbs union ccb *work_ccb; 34398b8a9b1dSJustin T. Gibbs struct cam_sim *sim; 344008f13879SWarner Losh struct xpt_proto *proto; 34418b8a9b1dSJustin T. Gibbs 3442227d67aaSAlexander Motin device = (struct cam_ed *)camq_remove(&devq->send_queue, 34435a526431SJustin T. Gibbs CAMQ_HEAD); 3444aa872be6SMatt Jacob CAM_DEBUG_PRINT(CAM_DEBUG_XPT, 344550642f18SKenneth D. Merry ("running device %p\n", device)); 34468b8a9b1dSJustin T. Gibbs 34475a526431SJustin T. Gibbs work_ccb = cam_ccbq_peek_ccb(&device->ccbq, CAMQ_HEAD); 34488b8a9b1dSJustin T. Gibbs if (work_ccb == NULL) { 344957b89bbcSNate Lawson printf("device on run queue with no ccbs???\n"); 34508b8a9b1dSJustin T. Gibbs continue; 34518b8a9b1dSJustin T. Gibbs } 34528b8a9b1dSJustin T. Gibbs 34538b8a9b1dSJustin T. Gibbs if ((work_ccb->ccb_h.flags & CAM_HIGH_POWER) != 0) { 34548b8a9b1dSJustin T. Gibbs 3455daa5487fSAlexander Motin mtx_lock(&xsoftc.xpt_highpower_lock); 34562b83592fSScott Long if (xsoftc.num_highpower <= 0) { 34578b8a9b1dSJustin T. Gibbs /* 34588b8a9b1dSJustin T. Gibbs * We got a high power command, but we 34598b8a9b1dSJustin T. Gibbs * don't have any available slots. Freeze 34608b8a9b1dSJustin T. Gibbs * the device queue until we have a slot 34618b8a9b1dSJustin T. Gibbs * available. 34628b8a9b1dSJustin T. Gibbs */ 3463daa5487fSAlexander Motin xpt_freeze_devq_device(device, 1); 3464227d67aaSAlexander Motin STAILQ_INSERT_TAIL(&xsoftc.highpowerq, device, 3465ea541bfdSAlexander Motin highpowerq_entry); 34668b8a9b1dSJustin T. Gibbs 3467daa5487fSAlexander Motin mtx_unlock(&xsoftc.xpt_highpower_lock); 34688b8a9b1dSJustin T. Gibbs continue; 34698b8a9b1dSJustin T. Gibbs } else { 34708b8a9b1dSJustin T. Gibbs /* 34718b8a9b1dSJustin T. Gibbs * Consume a high power slot while 34728b8a9b1dSJustin T. Gibbs * this ccb runs. 34738b8a9b1dSJustin T. Gibbs */ 34742b83592fSScott Long xsoftc.num_highpower--; 34758b8a9b1dSJustin T. Gibbs } 3476daa5487fSAlexander Motin mtx_unlock(&xsoftc.xpt_highpower_lock); 34778b8a9b1dSJustin T. Gibbs } 34788b8a9b1dSJustin T. Gibbs cam_ccbq_remove_ccb(&device->ccbq, work_ccb); 34798b8a9b1dSJustin T. Gibbs cam_ccbq_send_ccb(&device->ccbq, work_ccb); 34808b8a9b1dSJustin T. Gibbs devq->send_openings--; 34818b8a9b1dSJustin T. Gibbs devq->send_active++; 3482cccf4220SAlexander Motin xpt_schedule_devq(devq, device); 3483227d67aaSAlexander Motin mtx_unlock(&devq->send_mtx); 34848b8a9b1dSJustin T. Gibbs 3485cccf4220SAlexander Motin if ((work_ccb->ccb_h.flags & CAM_DEV_QFREEZE) != 0) { 34868b8a9b1dSJustin T. Gibbs /* 34878b8a9b1dSJustin T. Gibbs * The client wants to freeze the queue 34888b8a9b1dSJustin T. Gibbs * after this CCB is sent. 34898b8a9b1dSJustin T. Gibbs */ 349083c5d981SAlexander Motin xpt_freeze_devq(work_ccb->ccb_h.path, 1); 34918b8a9b1dSJustin T. Gibbs } 34928b8a9b1dSJustin T. Gibbs 3493a4eb4f16SMatt Jacob /* In Target mode, the peripheral driver knows best... */ 3494a4eb4f16SMatt Jacob if (work_ccb->ccb_h.func_code == XPT_SCSI_IO) { 3495a4eb4f16SMatt Jacob if ((device->inq_flags & SID_CmdQue) != 0 3496a4eb4f16SMatt Jacob && work_ccb->csio.tag_action != CAM_TAG_ACTION_NONE) 34978b8a9b1dSJustin T. Gibbs work_ccb->ccb_h.flags |= CAM_TAG_ACTION_VALID; 34988b8a9b1dSJustin T. Gibbs else 34998b8a9b1dSJustin T. Gibbs /* 3500a4eb4f16SMatt Jacob * Clear this in case of a retried CCB that 3501a4eb4f16SMatt Jacob * failed due to a rejected tag. 35028b8a9b1dSJustin T. Gibbs */ 35038b8a9b1dSJustin T. Gibbs work_ccb->ccb_h.flags &= ~CAM_TAG_ACTION_VALID; 3504a4eb4f16SMatt Jacob } 35058b8a9b1dSJustin T. Gibbs 350608f13879SWarner Losh KASSERT(device == work_ccb->ccb_h.path->device, 350708f13879SWarner Losh ("device (%p) / path->device (%p) mismatch", 350808f13879SWarner Losh device, work_ccb->ccb_h.path->device)); 350908f13879SWarner Losh proto = xpt_proto_find(device->protocol); 351008f13879SWarner Losh if (proto && proto->ops->debug_out) 351108f13879SWarner Losh proto->ops->debug_out(work_ccb); 3512de9ebb68SAlexander Motin 35138b8a9b1dSJustin T. Gibbs /* 3514227d67aaSAlexander Motin * Device queues can be shared among multiple SIM instances 3515db4fcadfSConrad Meyer * that reside on different buses. Use the SIM from the 3516227d67aaSAlexander Motin * queued device, rather than the one from the calling bus. 35178b8a9b1dSJustin T. Gibbs */ 3518227d67aaSAlexander Motin sim = device->sim; 3519401ed17aSAlexander Motin mtx = sim->mtx; 3520401ed17aSAlexander Motin if (mtx && !mtx_owned(mtx)) 3521401ed17aSAlexander Motin mtx_lock(mtx); 3522401ed17aSAlexander Motin else 3523401ed17aSAlexander Motin mtx = NULL; 3524e4c9cba7SWarner Losh work_ccb->ccb_h.qos.periph_data = cam_iosched_now(); 35258b8a9b1dSJustin T. Gibbs (*(sim->sim_action))(sim, work_ccb); 3526401ed17aSAlexander Motin if (mtx) 3527401ed17aSAlexander Motin mtx_unlock(mtx); 3528227d67aaSAlexander Motin mtx_lock(&devq->send_mtx); 35298b8a9b1dSJustin T. Gibbs } 3530cccf4220SAlexander Motin devq->send_queue.qfrozen_cnt--; 35318b8a9b1dSJustin T. Gibbs } 35328b8a9b1dSJustin T. Gibbs 35338b8a9b1dSJustin T. Gibbs /* 35348b8a9b1dSJustin T. Gibbs * This function merges stuff from the slave ccb into the master ccb, while 35358b8a9b1dSJustin T. Gibbs * keeping important fields in the master ccb constant. 35368b8a9b1dSJustin T. Gibbs */ 35378b8a9b1dSJustin T. Gibbs void 35388b8a9b1dSJustin T. Gibbs xpt_merge_ccb(union ccb *master_ccb, union ccb *slave_ccb) 35398b8a9b1dSJustin T. Gibbs { 354068153f43SScott Long 35418b8a9b1dSJustin T. Gibbs /* 35428b8a9b1dSJustin T. Gibbs * Pull fields that are valid for peripheral drivers to set 35438b8a9b1dSJustin T. Gibbs * into the master CCB along with the CCB "payload". 35448b8a9b1dSJustin T. Gibbs */ 35458b8a9b1dSJustin T. Gibbs master_ccb->ccb_h.retry_count = slave_ccb->ccb_h.retry_count; 35468b8a9b1dSJustin T. Gibbs master_ccb->ccb_h.func_code = slave_ccb->ccb_h.func_code; 35478b8a9b1dSJustin T. Gibbs master_ccb->ccb_h.timeout = slave_ccb->ccb_h.timeout; 35488b8a9b1dSJustin T. Gibbs master_ccb->ccb_h.flags = slave_ccb->ccb_h.flags; 35498b8a9b1dSJustin T. Gibbs bcopy(&(&slave_ccb->ccb_h)[1], &(&master_ccb->ccb_h)[1], 35508b8a9b1dSJustin T. Gibbs sizeof(union ccb) - sizeof(struct ccb_hdr)); 35518b8a9b1dSJustin T. Gibbs } 35528b8a9b1dSJustin T. Gibbs 35538b8a9b1dSJustin T. Gibbs void 3554a9934668SKenneth D. Merry xpt_setup_ccb_flags(struct ccb_hdr *ccb_h, struct cam_path *path, 3555a9934668SKenneth D. Merry u_int32_t priority, u_int32_t flags) 35568b8a9b1dSJustin T. Gibbs { 355768153f43SScott Long 35588b8a9b1dSJustin T. Gibbs CAM_DEBUG(path, CAM_DEBUG_TRACE, ("xpt_setup_ccb\n")); 35598b8a9b1dSJustin T. Gibbs ccb_h->pinfo.priority = priority; 35608b8a9b1dSJustin T. Gibbs ccb_h->path = path; 35618b8a9b1dSJustin T. Gibbs ccb_h->path_id = path->bus->path_id; 35628b8a9b1dSJustin T. Gibbs if (path->target) 35638b8a9b1dSJustin T. Gibbs ccb_h->target_id = path->target->target_id; 35648b8a9b1dSJustin T. Gibbs else 35658b8a9b1dSJustin T. Gibbs ccb_h->target_id = CAM_TARGET_WILDCARD; 35668b8a9b1dSJustin T. Gibbs if (path->device) { 35678b8a9b1dSJustin T. Gibbs ccb_h->target_lun = path->device->lun_id; 35688bad620dSJustin T. Gibbs ccb_h->pinfo.generation = ++path->device->ccbq.queue.generation; 35698b8a9b1dSJustin T. Gibbs } else { 35708b8a9b1dSJustin T. Gibbs ccb_h->target_lun = CAM_TARGET_WILDCARD; 35718b8a9b1dSJustin T. Gibbs } 35728b8a9b1dSJustin T. Gibbs ccb_h->pinfo.index = CAM_UNQUEUED_INDEX; 3573a9934668SKenneth D. Merry ccb_h->flags = flags; 3574b5595753SNathan Whitehorn ccb_h->xflags = 0; 35758b8a9b1dSJustin T. Gibbs } 35768b8a9b1dSJustin T. Gibbs 3577a9934668SKenneth D. Merry void 3578a9934668SKenneth D. Merry xpt_setup_ccb(struct ccb_hdr *ccb_h, struct cam_path *path, u_int32_t priority) 3579a9934668SKenneth D. Merry { 3580a9934668SKenneth D. Merry xpt_setup_ccb_flags(ccb_h, path, priority, /*flags*/ 0); 3581a9934668SKenneth D. Merry } 3582a9934668SKenneth D. Merry 35838b8a9b1dSJustin T. Gibbs /* Path manipulation functions */ 35848b8a9b1dSJustin T. Gibbs cam_status 35858b8a9b1dSJustin T. Gibbs xpt_create_path(struct cam_path **new_path_ptr, struct cam_periph *perph, 35868b8a9b1dSJustin T. Gibbs path_id_t path_id, target_id_t target_id, lun_id_t lun_id) 35878b8a9b1dSJustin T. Gibbs { 35888b8a9b1dSJustin T. Gibbs struct cam_path *path; 35898b8a9b1dSJustin T. Gibbs cam_status status; 35908b8a9b1dSJustin T. Gibbs 3591596ee08fSAlexander Motin path = (struct cam_path *)malloc(sizeof(*path), M_CAMPATH, M_NOWAIT); 35928b8a9b1dSJustin T. Gibbs 35938b8a9b1dSJustin T. Gibbs if (path == NULL) { 35948b8a9b1dSJustin T. Gibbs status = CAM_RESRC_UNAVAIL; 35958b8a9b1dSJustin T. Gibbs return(status); 35968b8a9b1dSJustin T. Gibbs } 35978b8a9b1dSJustin T. Gibbs status = xpt_compile_path(path, perph, path_id, target_id, lun_id); 35988b8a9b1dSJustin T. Gibbs if (status != CAM_REQ_CMP) { 3599596ee08fSAlexander Motin free(path, M_CAMPATH); 36008b8a9b1dSJustin T. Gibbs path = NULL; 36018b8a9b1dSJustin T. Gibbs } 36028b8a9b1dSJustin T. Gibbs *new_path_ptr = path; 36038b8a9b1dSJustin T. Gibbs return (status); 36048b8a9b1dSJustin T. Gibbs } 36058b8a9b1dSJustin T. Gibbs 36062b83592fSScott Long cam_status 36072b83592fSScott Long xpt_create_path_unlocked(struct cam_path **new_path_ptr, 36082b83592fSScott Long struct cam_periph *periph, path_id_t path_id, 36092b83592fSScott Long target_id_t target_id, lun_id_t lun_id) 36102b83592fSScott Long { 36112b83592fSScott Long 3612227d67aaSAlexander Motin return (xpt_create_path(new_path_ptr, periph, path_id, target_id, 3613227d67aaSAlexander Motin lun_id)); 36142b83592fSScott Long } 36152b83592fSScott Long 361652c9ce25SScott Long cam_status 36178b8a9b1dSJustin T. Gibbs xpt_compile_path(struct cam_path *new_path, struct cam_periph *perph, 36188b8a9b1dSJustin T. Gibbs path_id_t path_id, target_id_t target_id, lun_id_t lun_id) 36198b8a9b1dSJustin T. Gibbs { 36208b8a9b1dSJustin T. Gibbs struct cam_eb *bus; 36218b8a9b1dSJustin T. Gibbs struct cam_et *target; 36228b8a9b1dSJustin T. Gibbs struct cam_ed *device; 36238b8a9b1dSJustin T. Gibbs cam_status status; 36248b8a9b1dSJustin T. Gibbs 36258b8a9b1dSJustin T. Gibbs status = CAM_REQ_CMP; /* Completed without error */ 36268b8a9b1dSJustin T. Gibbs target = NULL; /* Wildcarded */ 36278b8a9b1dSJustin T. Gibbs device = NULL; /* Wildcarded */ 3628a5479bc5SJustin T. Gibbs 3629a5479bc5SJustin T. Gibbs /* 3630a5479bc5SJustin T. Gibbs * We will potentially modify the EDT, so block interrupts 3631a5479bc5SJustin T. Gibbs * that may attempt to create cam paths. 3632a5479bc5SJustin T. Gibbs */ 36338b8a9b1dSJustin T. Gibbs bus = xpt_find_bus(path_id); 36348b8a9b1dSJustin T. Gibbs if (bus == NULL) { 36358b8a9b1dSJustin T. Gibbs status = CAM_PATH_INVALID; 3636c8bead2aSJustin T. Gibbs } else { 3637227d67aaSAlexander Motin xpt_lock_buses(); 3638227d67aaSAlexander Motin mtx_lock(&bus->eb_mtx); 36398b8a9b1dSJustin T. Gibbs target = xpt_find_target(bus, target_id); 36408b8a9b1dSJustin T. Gibbs if (target == NULL) { 36418b8a9b1dSJustin T. Gibbs /* Create one */ 36428b8a9b1dSJustin T. Gibbs struct cam_et *new_target; 36438b8a9b1dSJustin T. Gibbs 36448b8a9b1dSJustin T. Gibbs new_target = xpt_alloc_target(bus, target_id); 36458b8a9b1dSJustin T. Gibbs if (new_target == NULL) { 36468b8a9b1dSJustin T. Gibbs status = CAM_RESRC_UNAVAIL; 36478b8a9b1dSJustin T. Gibbs } else { 36488b8a9b1dSJustin T. Gibbs target = new_target; 36498b8a9b1dSJustin T. Gibbs } 36508b8a9b1dSJustin T. Gibbs } 3651227d67aaSAlexander Motin xpt_unlock_buses(); 3652c8bead2aSJustin T. Gibbs if (target != NULL) { 36538b8a9b1dSJustin T. Gibbs device = xpt_find_device(target, lun_id); 36548b8a9b1dSJustin T. Gibbs if (device == NULL) { 36558b8a9b1dSJustin T. Gibbs /* Create one */ 36568b8a9b1dSJustin T. Gibbs struct cam_ed *new_device; 36578b8a9b1dSJustin T. Gibbs 365852c9ce25SScott Long new_device = 3659ded2b706SWarner Losh (*(bus->xport->ops->alloc_device))(bus, 36608b8a9b1dSJustin T. Gibbs target, 36618b8a9b1dSJustin T. Gibbs lun_id); 36628b8a9b1dSJustin T. Gibbs if (new_device == NULL) { 36638b8a9b1dSJustin T. Gibbs status = CAM_RESRC_UNAVAIL; 36648b8a9b1dSJustin T. Gibbs } else { 36658b8a9b1dSJustin T. Gibbs device = new_device; 36668b8a9b1dSJustin T. Gibbs } 36678b8a9b1dSJustin T. Gibbs } 36688b8a9b1dSJustin T. Gibbs } 3669227d67aaSAlexander Motin mtx_unlock(&bus->eb_mtx); 36708b8a9b1dSJustin T. Gibbs } 36718b8a9b1dSJustin T. Gibbs 36728b8a9b1dSJustin T. Gibbs /* 36738b8a9b1dSJustin T. Gibbs * Only touch the user's data if we are successful. 36748b8a9b1dSJustin T. Gibbs */ 36758b8a9b1dSJustin T. Gibbs if (status == CAM_REQ_CMP) { 36768b8a9b1dSJustin T. Gibbs new_path->periph = perph; 36778b8a9b1dSJustin T. Gibbs new_path->bus = bus; 36788b8a9b1dSJustin T. Gibbs new_path->target = target; 36798b8a9b1dSJustin T. Gibbs new_path->device = device; 36808b8a9b1dSJustin T. Gibbs CAM_DEBUG(new_path, CAM_DEBUG_TRACE, ("xpt_compile_path\n")); 36818b8a9b1dSJustin T. Gibbs } else { 36828b8a9b1dSJustin T. Gibbs if (device != NULL) 3683f98d7a47SAlexander Motin xpt_release_device(device); 36848b8a9b1dSJustin T. Gibbs if (target != NULL) 3685f98d7a47SAlexander Motin xpt_release_target(target); 3686a5479bc5SJustin T. Gibbs if (bus != NULL) 3687a5479bc5SJustin T. Gibbs xpt_release_bus(bus); 36888b8a9b1dSJustin T. Gibbs } 36898b8a9b1dSJustin T. Gibbs return (status); 36908b8a9b1dSJustin T. Gibbs } 36918b8a9b1dSJustin T. Gibbs 3692227d67aaSAlexander Motin cam_status 3693227d67aaSAlexander Motin xpt_clone_path(struct cam_path **new_path_ptr, struct cam_path *path) 3694227d67aaSAlexander Motin { 3695227d67aaSAlexander Motin struct cam_path *new_path; 3696227d67aaSAlexander Motin 3697227d67aaSAlexander Motin new_path = (struct cam_path *)malloc(sizeof(*path), M_CAMPATH, M_NOWAIT); 3698227d67aaSAlexander Motin if (new_path == NULL) 3699227d67aaSAlexander Motin return(CAM_RESRC_UNAVAIL); 3700227d67aaSAlexander Motin xpt_copy_path(new_path, path); 3701227d67aaSAlexander Motin *new_path_ptr = new_path; 3702227d67aaSAlexander Motin return (CAM_REQ_CMP); 3703227d67aaSAlexander Motin } 3704227d67aaSAlexander Motin 3705227d67aaSAlexander Motin void 3706227d67aaSAlexander Motin xpt_copy_path(struct cam_path *new_path, struct cam_path *path) 3707227d67aaSAlexander Motin { 3708227d67aaSAlexander Motin 3709227d67aaSAlexander Motin *new_path = *path; 3710227d67aaSAlexander Motin if (path->bus != NULL) 3711227d67aaSAlexander Motin xpt_acquire_bus(path->bus); 3712227d67aaSAlexander Motin if (path->target != NULL) 3713227d67aaSAlexander Motin xpt_acquire_target(path->target); 3714227d67aaSAlexander Motin if (path->device != NULL) 3715227d67aaSAlexander Motin xpt_acquire_device(path->device); 3716227d67aaSAlexander Motin } 3717227d67aaSAlexander Motin 371852c9ce25SScott Long void 37198b8a9b1dSJustin T. Gibbs xpt_release_path(struct cam_path *path) 37208b8a9b1dSJustin T. Gibbs { 37218b8a9b1dSJustin T. Gibbs CAM_DEBUG(path, CAM_DEBUG_TRACE, ("xpt_release_path\n")); 37229dd03ecfSJustin T. Gibbs if (path->device != NULL) { 3723f98d7a47SAlexander Motin xpt_release_device(path->device); 37249dd03ecfSJustin T. Gibbs path->device = NULL; 37259dd03ecfSJustin T. Gibbs } 37269dd03ecfSJustin T. Gibbs if (path->target != NULL) { 3727f98d7a47SAlexander Motin xpt_release_target(path->target); 37289dd03ecfSJustin T. Gibbs path->target = NULL; 37299dd03ecfSJustin T. Gibbs } 37309dd03ecfSJustin T. Gibbs if (path->bus != NULL) { 37319dd03ecfSJustin T. Gibbs xpt_release_bus(path->bus); 37329dd03ecfSJustin T. Gibbs path->bus = NULL; 37339dd03ecfSJustin T. Gibbs } 37348b8a9b1dSJustin T. Gibbs } 37358b8a9b1dSJustin T. Gibbs 37368b8a9b1dSJustin T. Gibbs void 37378b8a9b1dSJustin T. Gibbs xpt_free_path(struct cam_path *path) 37388b8a9b1dSJustin T. Gibbs { 373968153f43SScott Long 37408b8a9b1dSJustin T. Gibbs CAM_DEBUG(path, CAM_DEBUG_TRACE, ("xpt_free_path\n")); 37418b8a9b1dSJustin T. Gibbs xpt_release_path(path); 3742596ee08fSAlexander Motin free(path, M_CAMPATH); 37438b8a9b1dSJustin T. Gibbs } 37448b8a9b1dSJustin T. Gibbs 374515975b7bSMatt Jacob void 374615975b7bSMatt Jacob xpt_path_counts(struct cam_path *path, uint32_t *bus_ref, 374715975b7bSMatt Jacob uint32_t *periph_ref, uint32_t *target_ref, uint32_t *device_ref) 374815975b7bSMatt Jacob { 374915975b7bSMatt Jacob 37509a7c2696SAlexander Motin xpt_lock_buses(); 375115975b7bSMatt Jacob if (bus_ref) { 375215975b7bSMatt Jacob if (path->bus) 375315975b7bSMatt Jacob *bus_ref = path->bus->refcount; 375415975b7bSMatt Jacob else 375515975b7bSMatt Jacob *bus_ref = 0; 375615975b7bSMatt Jacob } 375715975b7bSMatt Jacob if (periph_ref) { 375815975b7bSMatt Jacob if (path->periph) 375915975b7bSMatt Jacob *periph_ref = path->periph->refcount; 376015975b7bSMatt Jacob else 376115975b7bSMatt Jacob *periph_ref = 0; 376215975b7bSMatt Jacob } 3763dcdf6e74SAlexander Motin xpt_unlock_buses(); 376415975b7bSMatt Jacob if (target_ref) { 376515975b7bSMatt Jacob if (path->target) 376615975b7bSMatt Jacob *target_ref = path->target->refcount; 376715975b7bSMatt Jacob else 376815975b7bSMatt Jacob *target_ref = 0; 376915975b7bSMatt Jacob } 377015975b7bSMatt Jacob if (device_ref) { 377115975b7bSMatt Jacob if (path->device) 377215975b7bSMatt Jacob *device_ref = path->device->refcount; 377315975b7bSMatt Jacob else 377415975b7bSMatt Jacob *device_ref = 0; 377515975b7bSMatt Jacob } 377615975b7bSMatt Jacob } 37778b8a9b1dSJustin T. Gibbs 37788b8a9b1dSJustin T. Gibbs /* 37792cefde5fSJustin T. Gibbs * Return -1 for failure, 0 for exact match, 1 for match with wildcards 37802cefde5fSJustin T. Gibbs * in path1, 2 for match with wildcards in path2. 37818b8a9b1dSJustin T. Gibbs */ 37828b8a9b1dSJustin T. Gibbs int 37838b8a9b1dSJustin T. Gibbs xpt_path_comp(struct cam_path *path1, struct cam_path *path2) 37848b8a9b1dSJustin T. Gibbs { 37858b8a9b1dSJustin T. Gibbs int retval = 0; 37868b8a9b1dSJustin T. Gibbs 37878b8a9b1dSJustin T. Gibbs if (path1->bus != path2->bus) { 37882cefde5fSJustin T. Gibbs if (path1->bus->path_id == CAM_BUS_WILDCARD) 37898b8a9b1dSJustin T. Gibbs retval = 1; 37902cefde5fSJustin T. Gibbs else if (path2->bus->path_id == CAM_BUS_WILDCARD) 37912cefde5fSJustin T. Gibbs retval = 2; 37928b8a9b1dSJustin T. Gibbs else 37938b8a9b1dSJustin T. Gibbs return (-1); 37948b8a9b1dSJustin T. Gibbs } 37958b8a9b1dSJustin T. Gibbs if (path1->target != path2->target) { 37962cefde5fSJustin T. Gibbs if (path1->target->target_id == CAM_TARGET_WILDCARD) { 37972cefde5fSJustin T. Gibbs if (retval == 0) 37988b8a9b1dSJustin T. Gibbs retval = 1; 37992cefde5fSJustin T. Gibbs } else if (path2->target->target_id == CAM_TARGET_WILDCARD) 38002cefde5fSJustin T. Gibbs retval = 2; 38018b8a9b1dSJustin T. Gibbs else 38028b8a9b1dSJustin T. Gibbs return (-1); 38038b8a9b1dSJustin T. Gibbs } 38048b8a9b1dSJustin T. Gibbs if (path1->device != path2->device) { 38052cefde5fSJustin T. Gibbs if (path1->device->lun_id == CAM_LUN_WILDCARD) { 38062cefde5fSJustin T. Gibbs if (retval == 0) 38078b8a9b1dSJustin T. Gibbs retval = 1; 38082cefde5fSJustin T. Gibbs } else if (path2->device->lun_id == CAM_LUN_WILDCARD) 38092cefde5fSJustin T. Gibbs retval = 2; 38108b8a9b1dSJustin T. Gibbs else 38118b8a9b1dSJustin T. Gibbs return (-1); 38128b8a9b1dSJustin T. Gibbs } 38138b8a9b1dSJustin T. Gibbs return (retval); 38148b8a9b1dSJustin T. Gibbs } 38158b8a9b1dSJustin T. Gibbs 38160d4f3c31SAlexander Motin int 38170d4f3c31SAlexander Motin xpt_path_comp_dev(struct cam_path *path, struct cam_ed *dev) 38180d4f3c31SAlexander Motin { 38190d4f3c31SAlexander Motin int retval = 0; 38200d4f3c31SAlexander Motin 38210d4f3c31SAlexander Motin if (path->bus != dev->target->bus) { 38220d4f3c31SAlexander Motin if (path->bus->path_id == CAM_BUS_WILDCARD) 38230d4f3c31SAlexander Motin retval = 1; 38240d4f3c31SAlexander Motin else if (dev->target->bus->path_id == CAM_BUS_WILDCARD) 38250d4f3c31SAlexander Motin retval = 2; 38260d4f3c31SAlexander Motin else 38270d4f3c31SAlexander Motin return (-1); 38280d4f3c31SAlexander Motin } 38290d4f3c31SAlexander Motin if (path->target != dev->target) { 38300d4f3c31SAlexander Motin if (path->target->target_id == CAM_TARGET_WILDCARD) { 38310d4f3c31SAlexander Motin if (retval == 0) 38320d4f3c31SAlexander Motin retval = 1; 38330d4f3c31SAlexander Motin } else if (dev->target->target_id == CAM_TARGET_WILDCARD) 38340d4f3c31SAlexander Motin retval = 2; 38350d4f3c31SAlexander Motin else 38360d4f3c31SAlexander Motin return (-1); 38370d4f3c31SAlexander Motin } 38380d4f3c31SAlexander Motin if (path->device != dev) { 38390d4f3c31SAlexander Motin if (path->device->lun_id == CAM_LUN_WILDCARD) { 38400d4f3c31SAlexander Motin if (retval == 0) 38410d4f3c31SAlexander Motin retval = 1; 38420d4f3c31SAlexander Motin } else if (dev->lun_id == CAM_LUN_WILDCARD) 38430d4f3c31SAlexander Motin retval = 2; 38440d4f3c31SAlexander Motin else 38450d4f3c31SAlexander Motin return (-1); 38460d4f3c31SAlexander Motin } 38470d4f3c31SAlexander Motin return (retval); 38480d4f3c31SAlexander Motin } 38490d4f3c31SAlexander Motin 38508b8a9b1dSJustin T. Gibbs void 38518b8a9b1dSJustin T. Gibbs xpt_print_path(struct cam_path *path) 38528b8a9b1dSJustin T. Gibbs { 3853ab3e89f1SScott Long struct sbuf sb; 3854ab3e89f1SScott Long char buffer[XPT_PRINT_LEN]; 385568153f43SScott Long 3856ab3e89f1SScott Long sbuf_new(&sb, buffer, XPT_PRINT_LEN, SBUF_FIXEDLEN); 3857ab3e89f1SScott Long xpt_path_sbuf(path, &sb); 3858ab3e89f1SScott Long sbuf_finish(&sb); 3859ab3e89f1SScott Long printf("%s", sbuf_data(&sb)); 3860ab3e89f1SScott Long sbuf_delete(&sb); 38618b8a9b1dSJustin T. Gibbs } 38628b8a9b1dSJustin T. Gibbs 3863f0d9af51SMatt Jacob void 38640d4f3c31SAlexander Motin xpt_print_device(struct cam_ed *device) 38650d4f3c31SAlexander Motin { 38660d4f3c31SAlexander Motin 38670d4f3c31SAlexander Motin if (device == NULL) 38680d4f3c31SAlexander Motin printf("(nopath): "); 38690d4f3c31SAlexander Motin else { 3870abe83505SNathan Whitehorn printf("(noperiph:%s%d:%d:%d:%jx): ", device->sim->sim_name, 38710d4f3c31SAlexander Motin device->sim->unit_number, 38720d4f3c31SAlexander Motin device->sim->bus_id, 38730d4f3c31SAlexander Motin device->target->target_id, 3874abe83505SNathan Whitehorn (uintmax_t)device->lun_id); 38750d4f3c31SAlexander Motin } 38760d4f3c31SAlexander Motin } 38770d4f3c31SAlexander Motin 38780d4f3c31SAlexander Motin void 3879f0d9af51SMatt Jacob xpt_print(struct cam_path *path, const char *fmt, ...) 3880f0d9af51SMatt Jacob { 3881f0d9af51SMatt Jacob va_list ap; 3882ab3e89f1SScott Long struct sbuf sb; 3883a136ca54SScott Long char buffer[XPT_PRINT_LEN]; 3884ab3e89f1SScott Long 3885a136ca54SScott Long sbuf_new(&sb, buffer, XPT_PRINT_LEN, SBUF_FIXEDLEN); 3886ab3e89f1SScott Long 3887ab3e89f1SScott Long xpt_path_sbuf(path, &sb); 3888f0d9af51SMatt Jacob va_start(ap, fmt); 3889ab3e89f1SScott Long sbuf_vprintf(&sb, fmt, ap); 3890f0d9af51SMatt Jacob va_end(ap); 3891ab3e89f1SScott Long 3892ab3e89f1SScott Long sbuf_finish(&sb); 3893ab3e89f1SScott Long printf("%s", sbuf_data(&sb)); 3894ab3e89f1SScott Long sbuf_delete(&sb); 3895f0d9af51SMatt Jacob } 3896f0d9af51SMatt Jacob 38973393f8daSKenneth D. Merry int 38983393f8daSKenneth D. Merry xpt_path_string(struct cam_path *path, char *str, size_t str_len) 38993393f8daSKenneth D. Merry { 39003393f8daSKenneth D. Merry struct sbuf sb; 3901ab3e89f1SScott Long int len; 39023393f8daSKenneth D. Merry 39033393f8daSKenneth D. Merry sbuf_new(&sb, str, str_len, 0); 3904ab3e89f1SScott Long len = xpt_path_sbuf(path, &sb); 3905ab3e89f1SScott Long sbuf_finish(&sb); 3906ab3e89f1SScott Long return (len); 3907ab3e89f1SScott Long } 3908ab3e89f1SScott Long 3909ab3e89f1SScott Long int 3910ab3e89f1SScott Long xpt_path_sbuf(struct cam_path *path, struct sbuf *sb) 3911ab3e89f1SScott Long { 39123393f8daSKenneth D. Merry 39133393f8daSKenneth D. Merry if (path == NULL) 3914ab3e89f1SScott Long sbuf_printf(sb, "(nopath): "); 39153393f8daSKenneth D. Merry else { 39163393f8daSKenneth D. Merry if (path->periph != NULL) 3917ab3e89f1SScott Long sbuf_printf(sb, "(%s%d:", path->periph->periph_name, 39183393f8daSKenneth D. Merry path->periph->unit_number); 39193393f8daSKenneth D. Merry else 3920ab3e89f1SScott Long sbuf_printf(sb, "(noperiph:"); 39213393f8daSKenneth D. Merry 39223393f8daSKenneth D. Merry if (path->bus != NULL) 3923ab3e89f1SScott Long sbuf_printf(sb, "%s%d:%d:", path->bus->sim->sim_name, 39243393f8daSKenneth D. Merry path->bus->sim->unit_number, 39253393f8daSKenneth D. Merry path->bus->sim->bus_id); 39263393f8daSKenneth D. Merry else 3927ab3e89f1SScott Long sbuf_printf(sb, "nobus:"); 39283393f8daSKenneth D. Merry 39293393f8daSKenneth D. Merry if (path->target != NULL) 3930ab3e89f1SScott Long sbuf_printf(sb, "%d:", path->target->target_id); 39313393f8daSKenneth D. Merry else 3932ab3e89f1SScott Long sbuf_printf(sb, "X:"); 39333393f8daSKenneth D. Merry 39343393f8daSKenneth D. Merry if (path->device != NULL) 3935ab3e89f1SScott Long sbuf_printf(sb, "%jx): ", 3936abe83505SNathan Whitehorn (uintmax_t)path->device->lun_id); 39373393f8daSKenneth D. Merry else 3938ab3e89f1SScott Long sbuf_printf(sb, "X): "); 39393393f8daSKenneth D. Merry } 39403393f8daSKenneth D. Merry 3941ab3e89f1SScott Long return(sbuf_len(sb)); 39423393f8daSKenneth D. Merry } 39433393f8daSKenneth D. Merry 39448b8a9b1dSJustin T. Gibbs path_id_t 39458b8a9b1dSJustin T. Gibbs xpt_path_path_id(struct cam_path *path) 39468b8a9b1dSJustin T. Gibbs { 39478b8a9b1dSJustin T. Gibbs return(path->bus->path_id); 39488b8a9b1dSJustin T. Gibbs } 39498b8a9b1dSJustin T. Gibbs 39508b8a9b1dSJustin T. Gibbs target_id_t 39518b8a9b1dSJustin T. Gibbs xpt_path_target_id(struct cam_path *path) 39528b8a9b1dSJustin T. Gibbs { 39538b8a9b1dSJustin T. Gibbs if (path->target != NULL) 39548b8a9b1dSJustin T. Gibbs return (path->target->target_id); 39558b8a9b1dSJustin T. Gibbs else 39568b8a9b1dSJustin T. Gibbs return (CAM_TARGET_WILDCARD); 39578b8a9b1dSJustin T. Gibbs } 39588b8a9b1dSJustin T. Gibbs 39598b8a9b1dSJustin T. Gibbs lun_id_t 39608b8a9b1dSJustin T. Gibbs xpt_path_lun_id(struct cam_path *path) 39618b8a9b1dSJustin T. Gibbs { 39628b8a9b1dSJustin T. Gibbs if (path->device != NULL) 39638b8a9b1dSJustin T. Gibbs return (path->device->lun_id); 39648b8a9b1dSJustin T. Gibbs else 39658b8a9b1dSJustin T. Gibbs return (CAM_LUN_WILDCARD); 39668b8a9b1dSJustin T. Gibbs } 39678b8a9b1dSJustin T. Gibbs 39688b8a9b1dSJustin T. Gibbs struct cam_sim * 39698b8a9b1dSJustin T. Gibbs xpt_path_sim(struct cam_path *path) 39708b8a9b1dSJustin T. Gibbs { 397168153f43SScott Long 39728b8a9b1dSJustin T. Gibbs return (path->bus->sim); 39738b8a9b1dSJustin T. Gibbs } 39748b8a9b1dSJustin T. Gibbs 39758b8a9b1dSJustin T. Gibbs struct cam_periph* 39768b8a9b1dSJustin T. Gibbs xpt_path_periph(struct cam_path *path) 39778b8a9b1dSJustin T. Gibbs { 397868153f43SScott Long 39798b8a9b1dSJustin T. Gibbs return (path->periph); 39808b8a9b1dSJustin T. Gibbs } 39818b8a9b1dSJustin T. Gibbs 39828b8a9b1dSJustin T. Gibbs /* 39838b8a9b1dSJustin T. Gibbs * Release a CAM control block for the caller. Remit the cost of the structure 39848b8a9b1dSJustin T. Gibbs * to the device referenced by the path. If the this device had no 'credits' 39858b8a9b1dSJustin T. Gibbs * and peripheral drivers have registered async callbacks for this notification 39868b8a9b1dSJustin T. Gibbs * call them now. 39878b8a9b1dSJustin T. Gibbs */ 39888b8a9b1dSJustin T. Gibbs void 39898b8a9b1dSJustin T. Gibbs xpt_release_ccb(union ccb *free_ccb) 39908b8a9b1dSJustin T. Gibbs { 39918b8a9b1dSJustin T. Gibbs struct cam_ed *device; 3992227d67aaSAlexander Motin struct cam_periph *periph; 399368153f43SScott Long 3994aa872be6SMatt Jacob CAM_DEBUG_PRINT(CAM_DEBUG_XPT, ("xpt_release_ccb\n")); 3995227d67aaSAlexander Motin xpt_path_assert(free_ccb->ccb_h.path, MA_OWNED); 3996227d67aaSAlexander Motin device = free_ccb->ccb_h.path->device; 3997227d67aaSAlexander Motin periph = free_ccb->ccb_h.path->periph; 39982b83592fSScott Long 39998b8a9b1dSJustin T. Gibbs xpt_free_ccb(free_ccb); 4000227d67aaSAlexander Motin periph->periph_allocated--; 4001227d67aaSAlexander Motin cam_ccbq_release_opening(&device->ccbq); 4002227d67aaSAlexander Motin xpt_run_allocq(periph, 0); 40038b8a9b1dSJustin T. Gibbs } 40048b8a9b1dSJustin T. Gibbs 40058b8a9b1dSJustin T. Gibbs /* Functions accessed by SIM drivers */ 40068b8a9b1dSJustin T. Gibbs 4007ded2b706SWarner Losh static struct xpt_xport_ops xport_default_ops = { 400852c9ce25SScott Long .alloc_device = xpt_alloc_device_default, 400952c9ce25SScott Long .action = xpt_action_default, 401052c9ce25SScott Long .async = xpt_dev_async_default, 401152c9ce25SScott Long }; 4012ded2b706SWarner Losh static struct xpt_xport xport_default = { 4013ded2b706SWarner Losh .xport = XPORT_UNKNOWN, 4014ded2b706SWarner Losh .name = "unknown", 4015ded2b706SWarner Losh .ops = &xport_default_ops, 4016ded2b706SWarner Losh }; 4017ded2b706SWarner Losh 4018ded2b706SWarner Losh CAM_XPT_XPORT(xport_default); 401952c9ce25SScott Long 40208b8a9b1dSJustin T. Gibbs /* 40218b8a9b1dSJustin T. Gibbs * A sim structure, listing the SIM entry points and instance 40228b8a9b1dSJustin T. Gibbs * identification info is passed to xpt_bus_register to hook the SIM 40238b8a9b1dSJustin T. Gibbs * into the CAM framework. xpt_bus_register creates a cam_eb entry 4024db4fcadfSConrad Meyer * for this new bus and places it in the array of buses and assigns 40258b8a9b1dSJustin T. Gibbs * it a path_id. The path_id may be influenced by "hard wiring" 40268b8a9b1dSJustin T. Gibbs * information specified by the user. Once interrupt services are 402702caf36eSEdward Tomasz Napierala * available, the bus will be probed. 40288b8a9b1dSJustin T. Gibbs */ 40298b8a9b1dSJustin T. Gibbs int32_t 4030b50569b7SScott Long xpt_bus_register(struct cam_sim *sim, device_t parent, u_int32_t bus) 40318b8a9b1dSJustin T. Gibbs { 40328b8a9b1dSJustin T. Gibbs struct cam_eb *new_bus; 4033434bbf6eSJustin T. Gibbs struct cam_eb *old_bus; 40348b8a9b1dSJustin T. Gibbs struct ccb_pathinq cpi; 403583c5d981SAlexander Motin struct cam_path *path; 403652c9ce25SScott Long cam_status status; 40378b8a9b1dSJustin T. Gibbs 40388b8a9b1dSJustin T. Gibbs sim->bus_id = bus; 40398b8a9b1dSJustin T. Gibbs new_bus = (struct cam_eb *)malloc(sizeof(*new_bus), 4040227d67aaSAlexander Motin M_CAMXPT, M_NOWAIT|M_ZERO); 40418b8a9b1dSJustin T. Gibbs if (new_bus == NULL) { 40428b8a9b1dSJustin T. Gibbs /* Couldn't satisfy request */ 40438b8a9b1dSJustin T. Gibbs return (CAM_RESRC_UNAVAIL); 40448b8a9b1dSJustin T. Gibbs } 40458b8a9b1dSJustin T. Gibbs 4046227d67aaSAlexander Motin mtx_init(&new_bus->eb_mtx, "CAM bus lock", NULL, MTX_DEF); 4047434bbf6eSJustin T. Gibbs TAILQ_INIT(&new_bus->et_entries); 4048fa6099fdSEdward Tomasz Napierala cam_sim_hold(sim); 40498b8a9b1dSJustin T. Gibbs new_bus->sim = sim; 405087cfaf0eSJustin T. Gibbs timevalclear(&new_bus->last_reset); 4051434bbf6eSJustin T. Gibbs new_bus->flags = 0; 4052a5479bc5SJustin T. Gibbs new_bus->refcount = 1; /* Held until a bus_deregister event */ 4053434bbf6eSJustin T. Gibbs new_bus->generation = 0; 405452c9ce25SScott Long 40559a7c2696SAlexander Motin xpt_lock_buses(); 40566dfc67e3SAlexander Motin sim->path_id = new_bus->path_id = 40576dfc67e3SAlexander Motin xptpathid(sim->sim_name, sim->unit_number, sim->bus_id); 40582b83592fSScott Long old_bus = TAILQ_FIRST(&xsoftc.xpt_busses); 4059434bbf6eSJustin T. Gibbs while (old_bus != NULL 4060434bbf6eSJustin T. Gibbs && old_bus->path_id < new_bus->path_id) 4061434bbf6eSJustin T. Gibbs old_bus = TAILQ_NEXT(old_bus, links); 4062434bbf6eSJustin T. Gibbs if (old_bus != NULL) 4063434bbf6eSJustin T. Gibbs TAILQ_INSERT_BEFORE(old_bus, new_bus, links); 4064434bbf6eSJustin T. Gibbs else 40652b83592fSScott Long TAILQ_INSERT_TAIL(&xsoftc.xpt_busses, new_bus, links); 40662b83592fSScott Long xsoftc.bus_generation++; 40679a7c2696SAlexander Motin xpt_unlock_buses(); 40688b8a9b1dSJustin T. Gibbs 406952c9ce25SScott Long /* 407052c9ce25SScott Long * Set a default transport so that a PATH_INQ can be issued to 407152c9ce25SScott Long * the SIM. This will then allow for probing and attaching of 407252c9ce25SScott Long * a more appropriate transport. 407352c9ce25SScott Long */ 407452c9ce25SScott Long new_bus->xport = &xport_default; 40758b8a9b1dSJustin T. Gibbs 407632aa80a6SAlexander Motin status = xpt_create_path(&path, /*periph*/NULL, sim->path_id, 40778b8a9b1dSJustin T. Gibbs CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD); 4078627995dcSAlexander Motin if (status != CAM_REQ_CMP) { 4079627995dcSAlexander Motin xpt_release_bus(new_bus); 4080627995dcSAlexander Motin return (CAM_RESRC_UNAVAIL); 4081627995dcSAlexander Motin } 408252c9ce25SScott Long 4083762a7f4fSWarner Losh xpt_path_inq(&cpi, path); 408452c9ce25SScott Long 408552c9ce25SScott Long if (cpi.ccb_h.status == CAM_REQ_CMP) { 4086ded2b706SWarner Losh struct xpt_xport **xpt; 4087ded2b706SWarner Losh 4088ded2b706SWarner Losh SET_FOREACH(xpt, cam_xpt_xport_set) { 4089ded2b706SWarner Losh if ((*xpt)->xport == cpi.transport) { 4090ded2b706SWarner Losh new_bus->xport = *xpt; 409152c9ce25SScott Long break; 4092ded2b706SWarner Losh } 4093ded2b706SWarner Losh } 4094ded2b706SWarner Losh if (new_bus->xport == NULL) { 4095bf1a8895SScott Long xpt_print(path, 4096bf1a8895SScott Long "No transport found for %d\n", cpi.transport); 4097ded2b706SWarner Losh xpt_release_bus(new_bus); 4098ded2b706SWarner Losh free(path, M_CAMXPT); 4099ded2b706SWarner Losh return (CAM_RESRC_UNAVAIL); 41008b8a9b1dSJustin T. Gibbs } 410152c9ce25SScott Long } 410252c9ce25SScott Long 410352c9ce25SScott Long /* Notify interested parties */ 410452c9ce25SScott Long if (sim->path_id != CAM_XPT_PATH_ID) { 410583c5d981SAlexander Motin 410683c5d981SAlexander Motin xpt_async(AC_PATH_REGISTERED, path, &cpi); 4107b01773b0SKenneth D. Merry if ((cpi.hba_misc & PIM_NOSCAN) == 0) { 4108b01773b0SKenneth D. Merry union ccb *scan_ccb; 4109b01773b0SKenneth D. Merry 411083c5d981SAlexander Motin /* Initiate bus rescan. */ 411183c5d981SAlexander Motin scan_ccb = xpt_alloc_ccb_nowait(); 4112e5736ac8SAlexander Motin if (scan_ccb != NULL) { 411383c5d981SAlexander Motin scan_ccb->ccb_h.path = path; 411483c5d981SAlexander Motin scan_ccb->ccb_h.func_code = XPT_SCAN_BUS; 411583c5d981SAlexander Motin scan_ccb->crcn.flags = 0; 411683c5d981SAlexander Motin xpt_rescan(scan_ccb); 41177f7aacb4SAlexander Motin } else { 4118b01773b0SKenneth D. Merry xpt_print(path, 4119b01773b0SKenneth D. Merry "Can't allocate CCB to scan bus\n"); 41207f7aacb4SAlexander Motin xpt_free_path(path); 41217f7aacb4SAlexander Motin } 4122b01773b0SKenneth D. Merry } else 4123b01773b0SKenneth D. Merry xpt_free_path(path); 4124e5736ac8SAlexander Motin } else 412583c5d981SAlexander Motin xpt_free_path(path); 41268b8a9b1dSJustin T. Gibbs return (CAM_SUCCESS); 41278b8a9b1dSJustin T. Gibbs } 41288b8a9b1dSJustin T. Gibbs 4129434bbf6eSJustin T. Gibbs int32_t 4130434bbf6eSJustin T. Gibbs xpt_bus_deregister(path_id_t pathid) 41318b8a9b1dSJustin T. Gibbs { 4132434bbf6eSJustin T. Gibbs struct cam_path bus_path; 4133434bbf6eSJustin T. Gibbs cam_status status; 4134434bbf6eSJustin T. Gibbs 4135434bbf6eSJustin T. Gibbs status = xpt_compile_path(&bus_path, NULL, pathid, 4136434bbf6eSJustin T. Gibbs CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD); 4137434bbf6eSJustin T. Gibbs if (status != CAM_REQ_CMP) 4138434bbf6eSJustin T. Gibbs return (status); 4139434bbf6eSJustin T. Gibbs 4140434bbf6eSJustin T. Gibbs xpt_async(AC_LOST_DEVICE, &bus_path, NULL); 4141434bbf6eSJustin T. Gibbs xpt_async(AC_PATH_DEREGISTERED, &bus_path, NULL); 4142434bbf6eSJustin T. Gibbs 4143434bbf6eSJustin T. Gibbs /* Release the reference count held while registered. */ 4144434bbf6eSJustin T. Gibbs xpt_release_bus(bus_path.bus); 4145434bbf6eSJustin T. Gibbs xpt_release_path(&bus_path); 4146434bbf6eSJustin T. Gibbs 4147434bbf6eSJustin T. Gibbs return (CAM_REQ_CMP); 4148434bbf6eSJustin T. Gibbs } 4149434bbf6eSJustin T. Gibbs 4150434bbf6eSJustin T. Gibbs static path_id_t 4151434bbf6eSJustin T. Gibbs xptnextfreepathid(void) 4152434bbf6eSJustin T. Gibbs { 4153434bbf6eSJustin T. Gibbs struct cam_eb *bus; 4154434bbf6eSJustin T. Gibbs path_id_t pathid; 41552398f0cdSPeter Wemm const char *strval; 41568b8a9b1dSJustin T. Gibbs 41576dfc67e3SAlexander Motin mtx_assert(&xsoftc.xpt_topo_lock, MA_OWNED); 4158434bbf6eSJustin T. Gibbs pathid = 0; 41592b83592fSScott Long bus = TAILQ_FIRST(&xsoftc.xpt_busses); 4160434bbf6eSJustin T. Gibbs retry: 4161434bbf6eSJustin T. Gibbs /* Find an unoccupied pathid */ 41629e6461a2SMatt Jacob while (bus != NULL && bus->path_id <= pathid) { 4163434bbf6eSJustin T. Gibbs if (bus->path_id == pathid) 4164434bbf6eSJustin T. Gibbs pathid++; 4165434bbf6eSJustin T. Gibbs bus = TAILQ_NEXT(bus, links); 4166434bbf6eSJustin T. Gibbs } 4167434bbf6eSJustin T. Gibbs 4168434bbf6eSJustin T. Gibbs /* 4169434bbf6eSJustin T. Gibbs * Ensure that this pathid is not reserved for 4170434bbf6eSJustin T. Gibbs * a bus that may be registered in the future. 4171434bbf6eSJustin T. Gibbs */ 417275f51904SPeter Wemm if (resource_string_value("scbus", pathid, "at", &strval) == 0) { 4173434bbf6eSJustin T. Gibbs ++pathid; 41748b8a9b1dSJustin T. Gibbs /* Start the search over */ 4175434bbf6eSJustin T. Gibbs goto retry; 41768b8a9b1dSJustin T. Gibbs } 4177434bbf6eSJustin T. Gibbs return (pathid); 41788b8a9b1dSJustin T. Gibbs } 41798b8a9b1dSJustin T. Gibbs 4180434bbf6eSJustin T. Gibbs static path_id_t 4181434bbf6eSJustin T. Gibbs xptpathid(const char *sim_name, int sim_unit, int sim_bus) 41828b8a9b1dSJustin T. Gibbs { 41838b8a9b1dSJustin T. Gibbs path_id_t pathid; 418475f51904SPeter Wemm int i, dunit, val; 4185642f0c46SPeter Wemm char buf[32]; 41862398f0cdSPeter Wemm const char *dname; 41878b8a9b1dSJustin T. Gibbs 41888b8a9b1dSJustin T. Gibbs pathid = CAM_XPT_PATH_ID; 418975f51904SPeter Wemm snprintf(buf, sizeof(buf), "%s%d", sim_name, sim_unit); 41906dfc67e3SAlexander Motin if (strcmp(buf, "xpt0") == 0 && sim_bus == 0) 41916dfc67e3SAlexander Motin return (pathid); 41922398f0cdSPeter Wemm i = 0; 41932398f0cdSPeter Wemm while ((resource_find_match(&i, &dname, &dunit, "at", buf)) == 0) { 41942398f0cdSPeter Wemm if (strcmp(dname, "scbus")) { 4195642f0c46SPeter Wemm /* Avoid a bit of foot shooting. */ 4196642f0c46SPeter Wemm continue; 4197642f0c46SPeter Wemm } 419875f51904SPeter Wemm if (dunit < 0) /* unwired?! */ 41998b8a9b1dSJustin T. Gibbs continue; 420075f51904SPeter Wemm if (resource_int_value("scbus", dunit, "bus", &val) == 0) { 420175f51904SPeter Wemm if (sim_bus == val) { 420275f51904SPeter Wemm pathid = dunit; 42038b8a9b1dSJustin T. Gibbs break; 42048b8a9b1dSJustin T. Gibbs } 42058b8a9b1dSJustin T. Gibbs } else if (sim_bus == 0) { 42068b8a9b1dSJustin T. Gibbs /* Unspecified matches bus 0 */ 420775f51904SPeter Wemm pathid = dunit; 42088b8a9b1dSJustin T. Gibbs break; 42098b8a9b1dSJustin T. Gibbs } else { 42108b8a9b1dSJustin T. Gibbs printf("Ambiguous scbus configuration for %s%d " 42118b8a9b1dSJustin T. Gibbs "bus %d, cannot wire down. The kernel " 42128b8a9b1dSJustin T. Gibbs "config entry for scbus%d should " 42138b8a9b1dSJustin T. Gibbs "specify a controller bus.\n" 42148b8a9b1dSJustin T. Gibbs "Scbus will be assigned dynamically.\n", 421575f51904SPeter Wemm sim_name, sim_unit, sim_bus, dunit); 42168b8a9b1dSJustin T. Gibbs break; 42178b8a9b1dSJustin T. Gibbs } 42188b8a9b1dSJustin T. Gibbs } 42198b8a9b1dSJustin T. Gibbs 4220434bbf6eSJustin T. Gibbs if (pathid == CAM_XPT_PATH_ID) 4221434bbf6eSJustin T. Gibbs pathid = xptnextfreepathid(); 42228b8a9b1dSJustin T. Gibbs return (pathid); 42238b8a9b1dSJustin T. Gibbs } 42248b8a9b1dSJustin T. Gibbs 422522c7d606SAlexander Motin static const char * 422622c7d606SAlexander Motin xpt_async_string(u_int32_t async_code) 422722c7d606SAlexander Motin { 422822c7d606SAlexander Motin 422922c7d606SAlexander Motin switch (async_code) { 423022c7d606SAlexander Motin case AC_BUS_RESET: return ("AC_BUS_RESET"); 423122c7d606SAlexander Motin case AC_UNSOL_RESEL: return ("AC_UNSOL_RESEL"); 423222c7d606SAlexander Motin case AC_SCSI_AEN: return ("AC_SCSI_AEN"); 423322c7d606SAlexander Motin case AC_SENT_BDR: return ("AC_SENT_BDR"); 423422c7d606SAlexander Motin case AC_PATH_REGISTERED: return ("AC_PATH_REGISTERED"); 423522c7d606SAlexander Motin case AC_PATH_DEREGISTERED: return ("AC_PATH_DEREGISTERED"); 423622c7d606SAlexander Motin case AC_FOUND_DEVICE: return ("AC_FOUND_DEVICE"); 423722c7d606SAlexander Motin case AC_LOST_DEVICE: return ("AC_LOST_DEVICE"); 423822c7d606SAlexander Motin case AC_TRANSFER_NEG: return ("AC_TRANSFER_NEG"); 423922c7d606SAlexander Motin case AC_INQ_CHANGED: return ("AC_INQ_CHANGED"); 424022c7d606SAlexander Motin case AC_GETDEV_CHANGED: return ("AC_GETDEV_CHANGED"); 424122c7d606SAlexander Motin case AC_CONTRACT: return ("AC_CONTRACT"); 424222c7d606SAlexander Motin case AC_ADVINFO_CHANGED: return ("AC_ADVINFO_CHANGED"); 42433631c638SAlexander Motin case AC_UNIT_ATTENTION: return ("AC_UNIT_ATTENTION"); 424422c7d606SAlexander Motin } 424522c7d606SAlexander Motin return ("AC_UNKNOWN"); 424622c7d606SAlexander Motin } 424722c7d606SAlexander Motin 4248227d67aaSAlexander Motin static int 4249227d67aaSAlexander Motin xpt_async_size(u_int32_t async_code) 42508b8a9b1dSJustin T. Gibbs { 42518b8a9b1dSJustin T. Gibbs 4252227d67aaSAlexander Motin switch (async_code) { 4253227d67aaSAlexander Motin case AC_BUS_RESET: return (0); 4254227d67aaSAlexander Motin case AC_UNSOL_RESEL: return (0); 4255227d67aaSAlexander Motin case AC_SCSI_AEN: return (0); 4256227d67aaSAlexander Motin case AC_SENT_BDR: return (0); 4257227d67aaSAlexander Motin case AC_PATH_REGISTERED: return (sizeof(struct ccb_pathinq)); 4258227d67aaSAlexander Motin case AC_PATH_DEREGISTERED: return (0); 4259227d67aaSAlexander Motin case AC_FOUND_DEVICE: return (sizeof(struct ccb_getdev)); 4260227d67aaSAlexander Motin case AC_LOST_DEVICE: return (0); 4261227d67aaSAlexander Motin case AC_TRANSFER_NEG: return (sizeof(struct ccb_trans_settings)); 4262227d67aaSAlexander Motin case AC_INQ_CHANGED: return (0); 4263227d67aaSAlexander Motin case AC_GETDEV_CHANGED: return (0); 4264227d67aaSAlexander Motin case AC_CONTRACT: return (sizeof(struct ac_contract)); 4265227d67aaSAlexander Motin case AC_ADVINFO_CHANGED: return (-1); 4266227d67aaSAlexander Motin case AC_UNIT_ATTENTION: return (sizeof(struct ccb_scsiio)); 4267227d67aaSAlexander Motin } 4268227d67aaSAlexander Motin return (0); 4269227d67aaSAlexander Motin } 4270227d67aaSAlexander Motin 4271227d67aaSAlexander Motin static int 4272227d67aaSAlexander Motin xpt_async_process_dev(struct cam_ed *device, void *arg) 4273227d67aaSAlexander Motin { 4274227d67aaSAlexander Motin union ccb *ccb = arg; 4275227d67aaSAlexander Motin struct cam_path *path = ccb->ccb_h.path; 4276227d67aaSAlexander Motin void *async_arg = ccb->casync.async_arg_ptr; 4277227d67aaSAlexander Motin u_int32_t async_code = ccb->casync.async_code; 4278227d67aaSAlexander Motin int relock; 4279227d67aaSAlexander Motin 4280227d67aaSAlexander Motin if (path->device != device 4281227d67aaSAlexander Motin && path->device->lun_id != CAM_LUN_WILDCARD 4282227d67aaSAlexander Motin && device->lun_id != CAM_LUN_WILDCARD) 4283227d67aaSAlexander Motin return (1); 42848b8a9b1dSJustin T. Gibbs 4285a5479bc5SJustin T. Gibbs /* 4286227d67aaSAlexander Motin * The async callback could free the device. 4287227d67aaSAlexander Motin * If it is a broadcast async, it doesn't hold 4288227d67aaSAlexander Motin * device reference, so take our own reference. 4289a5479bc5SJustin T. Gibbs */ 4290227d67aaSAlexander Motin xpt_acquire_device(device); 42918b8a9b1dSJustin T. Gibbs 4292227d67aaSAlexander Motin /* 4293227d67aaSAlexander Motin * If async for specific device is to be delivered to 4294227d67aaSAlexander Motin * the wildcard client, take the specific device lock. 4295227d67aaSAlexander Motin * XXX: We may need a way for client to specify it. 4296227d67aaSAlexander Motin */ 4297227d67aaSAlexander Motin if ((device->lun_id == CAM_LUN_WILDCARD && 4298227d67aaSAlexander Motin path->device->lun_id != CAM_LUN_WILDCARD) || 4299227d67aaSAlexander Motin (device->target->target_id == CAM_TARGET_WILDCARD && 4300227d67aaSAlexander Motin path->target->target_id != CAM_TARGET_WILDCARD) || 4301227d67aaSAlexander Motin (device->target->bus->path_id == CAM_BUS_WILDCARD && 4302227d67aaSAlexander Motin path->target->bus->path_id != CAM_BUS_WILDCARD)) { 4303227d67aaSAlexander Motin mtx_unlock(&device->device_mtx); 4304227d67aaSAlexander Motin xpt_path_lock(path); 4305227d67aaSAlexander Motin relock = 1; 4306227d67aaSAlexander Motin } else 4307227d67aaSAlexander Motin relock = 0; 4308227d67aaSAlexander Motin 4309ded2b706SWarner Losh (*(device->target->bus->xport->ops->async))(async_code, 4310227d67aaSAlexander Motin device->target->bus, device->target, device, async_arg); 4311227d67aaSAlexander Motin xpt_async_bcast(&device->asyncs, async_code, path, async_arg); 4312227d67aaSAlexander Motin 4313227d67aaSAlexander Motin if (relock) { 4314227d67aaSAlexander Motin xpt_path_unlock(path); 4315227d67aaSAlexander Motin mtx_lock(&device->device_mtx); 4316227d67aaSAlexander Motin } 4317227d67aaSAlexander Motin xpt_release_device(device); 4318227d67aaSAlexander Motin return (1); 4319227d67aaSAlexander Motin } 4320227d67aaSAlexander Motin 4321227d67aaSAlexander Motin static int 4322227d67aaSAlexander Motin xpt_async_process_tgt(struct cam_et *target, void *arg) 4323227d67aaSAlexander Motin { 4324227d67aaSAlexander Motin union ccb *ccb = arg; 4325227d67aaSAlexander Motin struct cam_path *path = ccb->ccb_h.path; 4326227d67aaSAlexander Motin 4327227d67aaSAlexander Motin if (path->target != target 4328227d67aaSAlexander Motin && path->target->target_id != CAM_TARGET_WILDCARD 4329227d67aaSAlexander Motin && target->target_id != CAM_TARGET_WILDCARD) 4330227d67aaSAlexander Motin return (1); 4331227d67aaSAlexander Motin 4332227d67aaSAlexander Motin if (ccb->casync.async_code == AC_SENT_BDR) { 4333227d67aaSAlexander Motin /* Update our notion of when the last reset occurred */ 4334227d67aaSAlexander Motin microtime(&target->last_reset); 4335227d67aaSAlexander Motin } 4336227d67aaSAlexander Motin 4337227d67aaSAlexander Motin return (xptdevicetraverse(target, NULL, xpt_async_process_dev, ccb)); 4338227d67aaSAlexander Motin } 4339227d67aaSAlexander Motin 4340227d67aaSAlexander Motin static void 4341227d67aaSAlexander Motin xpt_async_process(struct cam_periph *periph, union ccb *ccb) 4342227d67aaSAlexander Motin { 4343227d67aaSAlexander Motin struct cam_eb *bus; 4344227d67aaSAlexander Motin struct cam_path *path; 4345227d67aaSAlexander Motin void *async_arg; 4346227d67aaSAlexander Motin u_int32_t async_code; 4347227d67aaSAlexander Motin 4348227d67aaSAlexander Motin path = ccb->ccb_h.path; 4349227d67aaSAlexander Motin async_code = ccb->casync.async_code; 4350227d67aaSAlexander Motin async_arg = ccb->casync.async_arg_ptr; 4351227d67aaSAlexander Motin CAM_DEBUG(path, CAM_DEBUG_TRACE | CAM_DEBUG_INFO, 4352227d67aaSAlexander Motin ("xpt_async(%s)\n", xpt_async_string(async_code))); 43538b8a9b1dSJustin T. Gibbs bus = path->bus; 43548b8a9b1dSJustin T. Gibbs 43558b8a9b1dSJustin T. Gibbs if (async_code == AC_BUS_RESET) { 435687cfaf0eSJustin T. Gibbs /* Update our notion of when the last reset occurred */ 435787cfaf0eSJustin T. Gibbs microtime(&bus->last_reset); 43588b8a9b1dSJustin T. Gibbs } 43598b8a9b1dSJustin T. Gibbs 4360227d67aaSAlexander Motin xpttargettraverse(bus, NULL, xpt_async_process_tgt, ccb); 4361c8bead2aSJustin T. Gibbs 4362c8bead2aSJustin T. Gibbs /* 4363c8bead2aSJustin T. Gibbs * If this wasn't a fully wildcarded async, tell all 4364c8bead2aSJustin T. Gibbs * clients that want all async events. 4365c8bead2aSJustin T. Gibbs */ 4366227d67aaSAlexander Motin if (bus != xpt_periph->path->bus) { 4367227d67aaSAlexander Motin xpt_path_lock(xpt_periph->path); 4368227d67aaSAlexander Motin xpt_async_process_dev(xpt_periph->path->device, ccb); 4369227d67aaSAlexander Motin xpt_path_unlock(xpt_periph->path); 4370227d67aaSAlexander Motin } 4371227d67aaSAlexander Motin 4372227d67aaSAlexander Motin if (path->device != NULL && path->device->lun_id != CAM_LUN_WILDCARD) 4373227d67aaSAlexander Motin xpt_release_devq(path, 1, TRUE); 4374227d67aaSAlexander Motin else 4375227d67aaSAlexander Motin xpt_release_simq(path->bus->sim, TRUE); 4376227d67aaSAlexander Motin if (ccb->casync.async_arg_size > 0) 4377227d67aaSAlexander Motin free(async_arg, M_CAMXPT); 4378227d67aaSAlexander Motin xpt_free_path(path); 4379227d67aaSAlexander Motin xpt_free_ccb(ccb); 43808b8a9b1dSJustin T. Gibbs } 43818b8a9b1dSJustin T. Gibbs 43828b8a9b1dSJustin T. Gibbs static void 43838b8a9b1dSJustin T. Gibbs xpt_async_bcast(struct async_list *async_head, 43848b8a9b1dSJustin T. Gibbs u_int32_t async_code, 43858b8a9b1dSJustin T. Gibbs struct cam_path *path, void *async_arg) 43868b8a9b1dSJustin T. Gibbs { 43878b8a9b1dSJustin T. Gibbs struct async_node *cur_entry; 4388331d00baSAlexander Motin struct mtx *mtx; 43898b8a9b1dSJustin T. Gibbs 43908b8a9b1dSJustin T. Gibbs cur_entry = SLIST_FIRST(async_head); 43918b8a9b1dSJustin T. Gibbs while (cur_entry != NULL) { 43928b8a9b1dSJustin T. Gibbs struct async_node *next_entry; 43938b8a9b1dSJustin T. Gibbs /* 43948b8a9b1dSJustin T. Gibbs * Grab the next list entry before we call the current 43958b8a9b1dSJustin T. Gibbs * entry's callback. This is because the callback function 43968b8a9b1dSJustin T. Gibbs * can delete its async callback entry. 43978b8a9b1dSJustin T. Gibbs */ 43988b8a9b1dSJustin T. Gibbs next_entry = SLIST_NEXT(cur_entry, links); 4399227d67aaSAlexander Motin if ((cur_entry->event_enable & async_code) != 0) { 4400331d00baSAlexander Motin mtx = cur_entry->event_lock ? 4401331d00baSAlexander Motin path->device->sim->mtx : NULL; 4402331d00baSAlexander Motin if (mtx) 4403331d00baSAlexander Motin mtx_lock(mtx); 44048b8a9b1dSJustin T. Gibbs cur_entry->callback(cur_entry->callback_arg, 44058b8a9b1dSJustin T. Gibbs async_code, path, 44068b8a9b1dSJustin T. Gibbs async_arg); 4407331d00baSAlexander Motin if (mtx) 4408331d00baSAlexander Motin mtx_unlock(mtx); 4409227d67aaSAlexander Motin } 44108b8a9b1dSJustin T. Gibbs cur_entry = next_entry; 44118b8a9b1dSJustin T. Gibbs } 44128b8a9b1dSJustin T. Gibbs } 44138b8a9b1dSJustin T. Gibbs 4414227d67aaSAlexander Motin void 4415227d67aaSAlexander Motin xpt_async(u_int32_t async_code, struct cam_path *path, void *async_arg) 4416227d67aaSAlexander Motin { 4417227d67aaSAlexander Motin union ccb *ccb; 4418227d67aaSAlexander Motin int size; 4419227d67aaSAlexander Motin 4420227d67aaSAlexander Motin ccb = xpt_alloc_ccb_nowait(); 4421227d67aaSAlexander Motin if (ccb == NULL) { 4422227d67aaSAlexander Motin xpt_print(path, "Can't allocate CCB to send %s\n", 4423227d67aaSAlexander Motin xpt_async_string(async_code)); 4424227d67aaSAlexander Motin return; 4425227d67aaSAlexander Motin } 4426227d67aaSAlexander Motin 4427227d67aaSAlexander Motin if (xpt_clone_path(&ccb->ccb_h.path, path) != CAM_REQ_CMP) { 4428227d67aaSAlexander Motin xpt_print(path, "Can't allocate path to send %s\n", 4429227d67aaSAlexander Motin xpt_async_string(async_code)); 4430227d67aaSAlexander Motin xpt_free_ccb(ccb); 4431227d67aaSAlexander Motin return; 4432227d67aaSAlexander Motin } 4433227d67aaSAlexander Motin ccb->ccb_h.path->periph = NULL; 4434227d67aaSAlexander Motin ccb->ccb_h.func_code = XPT_ASYNC; 4435227d67aaSAlexander Motin ccb->ccb_h.cbfcnp = xpt_async_process; 4436227d67aaSAlexander Motin ccb->ccb_h.flags |= CAM_UNLOCKED; 4437227d67aaSAlexander Motin ccb->casync.async_code = async_code; 4438227d67aaSAlexander Motin ccb->casync.async_arg_size = 0; 4439227d67aaSAlexander Motin size = xpt_async_size(async_code); 444069be012fSWarner Losh CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE, 444169be012fSWarner Losh ("xpt_async: func %#x %s aync_code %d %s\n", 444269be012fSWarner Losh ccb->ccb_h.func_code, 444369be012fSWarner Losh xpt_action_name(ccb->ccb_h.func_code), 444469be012fSWarner Losh async_code, 444569be012fSWarner Losh xpt_async_string(async_code))); 4446227d67aaSAlexander Motin if (size > 0 && async_arg != NULL) { 4447227d67aaSAlexander Motin ccb->casync.async_arg_ptr = malloc(size, M_CAMXPT, M_NOWAIT); 4448227d67aaSAlexander Motin if (ccb->casync.async_arg_ptr == NULL) { 4449227d67aaSAlexander Motin xpt_print(path, "Can't allocate argument to send %s\n", 4450227d67aaSAlexander Motin xpt_async_string(async_code)); 4451227d67aaSAlexander Motin xpt_free_path(ccb->ccb_h.path); 4452227d67aaSAlexander Motin xpt_free_ccb(ccb); 4453227d67aaSAlexander Motin return; 4454227d67aaSAlexander Motin } 4455227d67aaSAlexander Motin memcpy(ccb->casync.async_arg_ptr, async_arg, size); 4456227d67aaSAlexander Motin ccb->casync.async_arg_size = size; 4457738fd166SAlan Somers } else if (size < 0) { 4458738fd166SAlan Somers ccb->casync.async_arg_ptr = async_arg; 4459227d67aaSAlexander Motin ccb->casync.async_arg_size = size; 4460738fd166SAlan Somers } 4461227d67aaSAlexander Motin if (path->device != NULL && path->device->lun_id != CAM_LUN_WILDCARD) 4462227d67aaSAlexander Motin xpt_freeze_devq(path, 1); 4463227d67aaSAlexander Motin else 4464227d67aaSAlexander Motin xpt_freeze_simq(path->bus->sim, 1); 4465227d67aaSAlexander Motin xpt_done(ccb); 4466227d67aaSAlexander Motin } 4467227d67aaSAlexander Motin 44682f22d08dSJustin T. Gibbs static void 446952c9ce25SScott Long xpt_dev_async_default(u_int32_t async_code, struct cam_eb *bus, 447052c9ce25SScott Long struct cam_et *target, struct cam_ed *device, 447152c9ce25SScott Long void *async_arg) 44722f22d08dSJustin T. Gibbs { 4473227d67aaSAlexander Motin 4474227d67aaSAlexander Motin /* 4475227d67aaSAlexander Motin * We only need to handle events for real devices. 4476227d67aaSAlexander Motin */ 4477227d67aaSAlexander Motin if (target->target_id == CAM_TARGET_WILDCARD 4478227d67aaSAlexander Motin || device->lun_id == CAM_LUN_WILDCARD) 4479227d67aaSAlexander Motin return; 4480227d67aaSAlexander Motin 4481b882a6d3SMatt Jacob printf("%s called\n", __func__); 44822f22d08dSJustin T. Gibbs } 44832f22d08dSJustin T. Gibbs 4484daa5487fSAlexander Motin static uint32_t 4485daa5487fSAlexander Motin xpt_freeze_devq_device(struct cam_ed *dev, u_int count) 4486daa5487fSAlexander Motin { 4487daa5487fSAlexander Motin struct cam_devq *devq; 4488daa5487fSAlexander Motin uint32_t freeze; 4489daa5487fSAlexander Motin 4490daa5487fSAlexander Motin devq = dev->sim->devq; 4491daa5487fSAlexander Motin mtx_assert(&devq->send_mtx, MA_OWNED); 4492daa5487fSAlexander Motin CAM_DEBUG_DEV(dev, CAM_DEBUG_TRACE, 4493daa5487fSAlexander Motin ("xpt_freeze_devq_device(%d) %u->%u\n", count, 4494daa5487fSAlexander Motin dev->ccbq.queue.qfrozen_cnt, dev->ccbq.queue.qfrozen_cnt + count)); 4495daa5487fSAlexander Motin freeze = (dev->ccbq.queue.qfrozen_cnt += count); 4496daa5487fSAlexander Motin /* Remove frozen device from sendq. */ 4497daa5487fSAlexander Motin if (device_is_queued(dev)) 4498daa5487fSAlexander Motin camq_remove(&devq->send_queue, dev->devq_entry.index); 4499daa5487fSAlexander Motin return (freeze); 4500daa5487fSAlexander Motin } 4501daa5487fSAlexander Motin 45028b8a9b1dSJustin T. Gibbs u_int32_t 4503cccf4220SAlexander Motin xpt_freeze_devq(struct cam_path *path, u_int count) 450483c5d981SAlexander Motin { 450583c5d981SAlexander Motin struct cam_ed *dev = path->device; 4506227d67aaSAlexander Motin struct cam_devq *devq; 4507227d67aaSAlexander Motin uint32_t freeze; 450883c5d981SAlexander Motin 4509227d67aaSAlexander Motin devq = dev->sim->devq; 4510227d67aaSAlexander Motin mtx_lock(&devq->send_mtx); 4511daa5487fSAlexander Motin CAM_DEBUG(path, CAM_DEBUG_TRACE, ("xpt_freeze_devq(%d)\n", count)); 4512daa5487fSAlexander Motin freeze = xpt_freeze_devq_device(dev, count); 4513227d67aaSAlexander Motin mtx_unlock(&devq->send_mtx); 4514227d67aaSAlexander Motin return (freeze); 45158b8a9b1dSJustin T. Gibbs } 45168b8a9b1dSJustin T. Gibbs 45178b8a9b1dSJustin T. Gibbs u_int32_t 45188b8a9b1dSJustin T. Gibbs xpt_freeze_simq(struct cam_sim *sim, u_int count) 45198b8a9b1dSJustin T. Gibbs { 4520227d67aaSAlexander Motin struct cam_devq *devq; 4521227d67aaSAlexander Motin uint32_t freeze; 4522ec700f26SAlexander Motin 4523227d67aaSAlexander Motin devq = sim->devq; 4524227d67aaSAlexander Motin mtx_lock(&devq->send_mtx); 4525227d67aaSAlexander Motin freeze = (devq->send_queue.qfrozen_cnt += count); 4526227d67aaSAlexander Motin mtx_unlock(&devq->send_mtx); 4527227d67aaSAlexander Motin return (freeze); 45288b8a9b1dSJustin T. Gibbs } 45298b8a9b1dSJustin T. Gibbs 45308b8a9b1dSJustin T. Gibbs static void 45318b8a9b1dSJustin T. Gibbs xpt_release_devq_timeout(void *arg) 45328b8a9b1dSJustin T. Gibbs { 4533227d67aaSAlexander Motin struct cam_ed *dev; 4534227d67aaSAlexander Motin struct cam_devq *devq; 45358b8a9b1dSJustin T. Gibbs 4536227d67aaSAlexander Motin dev = (struct cam_ed *)arg; 4537227d67aaSAlexander Motin CAM_DEBUG_DEV(dev, CAM_DEBUG_TRACE, ("xpt_release_devq_timeout\n")); 4538227d67aaSAlexander Motin devq = dev->sim->devq; 4539227d67aaSAlexander Motin mtx_assert(&devq->send_mtx, MA_OWNED); 4540227d67aaSAlexander Motin if (xpt_release_devq_device(dev, /*count*/1, /*run_queue*/TRUE)) 4541227d67aaSAlexander Motin xpt_run_devq(devq); 45428b8a9b1dSJustin T. Gibbs } 45438b8a9b1dSJustin T. Gibbs 45448b8a9b1dSJustin T. Gibbs void 45452cefde5fSJustin T. Gibbs xpt_release_devq(struct cam_path *path, u_int count, int run_queue) 45462cefde5fSJustin T. Gibbs { 4547227d67aaSAlexander Motin struct cam_ed *dev; 4548227d67aaSAlexander Motin struct cam_devq *devq; 454968153f43SScott Long 45500d4f3c31SAlexander Motin CAM_DEBUG(path, CAM_DEBUG_TRACE, ("xpt_release_devq(%d, %d)\n", 45510d4f3c31SAlexander Motin count, run_queue)); 4552227d67aaSAlexander Motin dev = path->device; 4553227d67aaSAlexander Motin devq = dev->sim->devq; 4554227d67aaSAlexander Motin mtx_lock(&devq->send_mtx); 4555227d67aaSAlexander Motin if (xpt_release_devq_device(dev, count, run_queue)) 4556227d67aaSAlexander Motin xpt_run_devq(dev->sim->devq); 4557227d67aaSAlexander Motin mtx_unlock(&devq->send_mtx); 455883c5d981SAlexander Motin } 455983c5d981SAlexander Motin 4560227d67aaSAlexander Motin static int 4561cccf4220SAlexander Motin xpt_release_devq_device(struct cam_ed *dev, u_int count, int run_queue) 45628b8a9b1dSJustin T. Gibbs { 45638b8a9b1dSJustin T. Gibbs 4564227d67aaSAlexander Motin mtx_assert(&dev->sim->devq->send_mtx, MA_OWNED); 45650d4f3c31SAlexander Motin CAM_DEBUG_DEV(dev, CAM_DEBUG_TRACE, 45660d4f3c31SAlexander Motin ("xpt_release_devq_device(%d, %d) %u->%u\n", count, run_queue, 45670d4f3c31SAlexander Motin dev->ccbq.queue.qfrozen_cnt, dev->ccbq.queue.qfrozen_cnt - count)); 4568cccf4220SAlexander Motin if (count > dev->ccbq.queue.qfrozen_cnt) { 456983c5d981SAlexander Motin #ifdef INVARIANTS 4570cccf4220SAlexander Motin printf("xpt_release_devq(): requested %u > present %u\n", 4571cccf4220SAlexander Motin count, dev->ccbq.queue.qfrozen_cnt); 457283c5d981SAlexander Motin #endif 4573cccf4220SAlexander Motin count = dev->ccbq.queue.qfrozen_cnt; 457483c5d981SAlexander Motin } 4575cccf4220SAlexander Motin dev->ccbq.queue.qfrozen_cnt -= count; 4576cccf4220SAlexander Motin if (dev->ccbq.queue.qfrozen_cnt == 0) { 45778b8a9b1dSJustin T. Gibbs /* 45788b8a9b1dSJustin T. Gibbs * No longer need to wait for a successful 45798b8a9b1dSJustin T. Gibbs * command completion. 45808b8a9b1dSJustin T. Gibbs */ 45818b8a9b1dSJustin T. Gibbs dev->flags &= ~CAM_DEV_REL_ON_COMPLETE; 45828b8a9b1dSJustin T. Gibbs /* 45838b8a9b1dSJustin T. Gibbs * Remove any timeouts that might be scheduled 45848b8a9b1dSJustin T. Gibbs * to release this queue. 45858b8a9b1dSJustin T. Gibbs */ 45868b8a9b1dSJustin T. Gibbs if ((dev->flags & CAM_DEV_REL_TIMEOUT_PENDING) != 0) { 45872b83592fSScott Long callout_stop(&dev->callout); 45888b8a9b1dSJustin T. Gibbs dev->flags &= ~CAM_DEV_REL_TIMEOUT_PENDING; 45898b8a9b1dSJustin T. Gibbs } 45908b8a9b1dSJustin T. Gibbs /* 45918b8a9b1dSJustin T. Gibbs * Now that we are unfrozen schedule the 45928b8a9b1dSJustin T. Gibbs * device so any pending transactions are 45938b8a9b1dSJustin T. Gibbs * run. 45948b8a9b1dSJustin T. Gibbs */ 4595227d67aaSAlexander Motin xpt_schedule_devq(dev->sim->devq, dev); 4596227d67aaSAlexander Motin } else 4597227d67aaSAlexander Motin run_queue = 0; 4598227d67aaSAlexander Motin return (run_queue); 459983c5d981SAlexander Motin } 46008b8a9b1dSJustin T. Gibbs 46018b8a9b1dSJustin T. Gibbs void 46028b8a9b1dSJustin T. Gibbs xpt_release_simq(struct cam_sim *sim, int run_queue) 46038b8a9b1dSJustin T. Gibbs { 4604227d67aaSAlexander Motin struct cam_devq *devq; 46058b8a9b1dSJustin T. Gibbs 4606227d67aaSAlexander Motin devq = sim->devq; 4607227d67aaSAlexander Motin mtx_lock(&devq->send_mtx); 4608227d67aaSAlexander Motin if (devq->send_queue.qfrozen_cnt <= 0) { 460983c5d981SAlexander Motin #ifdef INVARIANTS 461083c5d981SAlexander Motin printf("xpt_release_simq: requested 1 > present %u\n", 4611227d67aaSAlexander Motin devq->send_queue.qfrozen_cnt); 461283c5d981SAlexander Motin #endif 461383c5d981SAlexander Motin } else 4614227d67aaSAlexander Motin devq->send_queue.qfrozen_cnt--; 4615227d67aaSAlexander Motin if (devq->send_queue.qfrozen_cnt == 0) { 46168b8a9b1dSJustin T. Gibbs /* 46178b8a9b1dSJustin T. Gibbs * If there is a timeout scheduled to release this 46188b8a9b1dSJustin T. Gibbs * sim queue, remove it. The queue frozen count is 46198b8a9b1dSJustin T. Gibbs * already at 0. 46208b8a9b1dSJustin T. Gibbs */ 46218b8a9b1dSJustin T. Gibbs if ((sim->flags & CAM_SIM_REL_TIMEOUT_PENDING) != 0){ 46222b83592fSScott Long callout_stop(&sim->callout); 46238b8a9b1dSJustin T. Gibbs sim->flags &= ~CAM_SIM_REL_TIMEOUT_PENDING; 46248b8a9b1dSJustin T. Gibbs } 46258b8a9b1dSJustin T. Gibbs if (run_queue) { 46268b8a9b1dSJustin T. Gibbs /* 46278b8a9b1dSJustin T. Gibbs * Now that we are unfrozen run the send queue. 46288b8a9b1dSJustin T. Gibbs */ 4629cccf4220SAlexander Motin xpt_run_devq(sim->devq); 463077dc25ccSScott Long } 463177dc25ccSScott Long } 4632227d67aaSAlexander Motin mtx_unlock(&devq->send_mtx); 46338b8a9b1dSJustin T. Gibbs } 46348b8a9b1dSJustin T. Gibbs 46352b83592fSScott Long /* 46362b83592fSScott Long * XXX Appears to be unused. 46372b83592fSScott Long */ 46388b8a9b1dSJustin T. Gibbs static void 46398b8a9b1dSJustin T. Gibbs xpt_release_simq_timeout(void *arg) 46408b8a9b1dSJustin T. Gibbs { 46418b8a9b1dSJustin T. Gibbs struct cam_sim *sim; 46428b8a9b1dSJustin T. Gibbs 46438b8a9b1dSJustin T. Gibbs sim = (struct cam_sim *)arg; 46448b8a9b1dSJustin T. Gibbs xpt_release_simq(sim, /* run_queue */ TRUE); 46458b8a9b1dSJustin T. Gibbs } 46468b8a9b1dSJustin T. Gibbs 46478b8a9b1dSJustin T. Gibbs void 4648a5479bc5SJustin T. Gibbs xpt_done(union ccb *done_ccb) 46498b8a9b1dSJustin T. Gibbs { 4650227d67aaSAlexander Motin struct cam_doneq *queue; 4651227d67aaSAlexander Motin int run, hash; 46528b8a9b1dSJustin T. Gibbs 46538532d381SConrad Meyer #if defined(BUF_TRACKING) || defined(FULL_BUF_TRACKING) 46548532d381SConrad Meyer if (done_ccb->ccb_h.func_code == XPT_SCSI_IO && 46558532d381SConrad Meyer done_ccb->csio.bio != NULL) 46568532d381SConrad Meyer biotrack(done_ccb->csio.bio, __func__); 46578532d381SConrad Meyer #endif 46588532d381SConrad Meyer 465969be012fSWarner Losh CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_TRACE, 466069be012fSWarner Losh ("xpt_done: func= %#x %s status %#x\n", 466169be012fSWarner Losh done_ccb->ccb_h.func_code, 466269be012fSWarner Losh xpt_action_name(done_ccb->ccb_h.func_code), 466369be012fSWarner Losh done_ccb->ccb_h.status)); 4664227d67aaSAlexander Motin if ((done_ccb->ccb_h.func_code & XPT_FC_QUEUED) == 0) 4665227d67aaSAlexander Motin return; 4666227d67aaSAlexander Motin 4667a6e0c5daSWarner Losh /* Store the time the ccb was in the sim */ 4668e4c9cba7SWarner Losh done_ccb->ccb_h.qos.periph_data = cam_iosched_delta_t(done_ccb->ccb_h.qos.periph_data); 4669227d67aaSAlexander Motin hash = (done_ccb->ccb_h.path_id + done_ccb->ccb_h.target_id + 4670227d67aaSAlexander Motin done_ccb->ccb_h.target_lun) % cam_num_doneqs; 4671227d67aaSAlexander Motin queue = &cam_doneqs[hash]; 4672227d67aaSAlexander Motin mtx_lock(&queue->cam_doneq_mtx); 4673227d67aaSAlexander Motin run = (queue->cam_doneq_sleep && STAILQ_EMPTY(&queue->cam_doneq)); 4674227d67aaSAlexander Motin STAILQ_INSERT_TAIL(&queue->cam_doneq, &done_ccb->ccb_h, sim_links.stqe); 46758b8a9b1dSJustin T. Gibbs done_ccb->ccb_h.pinfo.index = CAM_DONEQ_INDEX; 4676227d67aaSAlexander Motin mtx_unlock(&queue->cam_doneq_mtx); 4677227d67aaSAlexander Motin if (run) 4678227d67aaSAlexander Motin wakeup(&queue->cam_doneq); 46798b8a9b1dSJustin T. Gibbs } 46808b8a9b1dSJustin T. Gibbs 4681711f6613SAlexander Motin void 4682227d67aaSAlexander Motin xpt_done_direct(union ccb *done_ccb) 4683711f6613SAlexander Motin { 4684711f6613SAlexander Motin 468569be012fSWarner Losh CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_TRACE, 468669be012fSWarner Losh ("xpt_done_direct: status %#x\n", done_ccb->ccb_h.status)); 4687227d67aaSAlexander Motin if ((done_ccb->ccb_h.func_code & XPT_FC_QUEUED) == 0) 4688227d67aaSAlexander Motin return; 4689711f6613SAlexander Motin 4690a6e0c5daSWarner Losh /* Store the time the ccb was in the sim */ 4691e4c9cba7SWarner Losh done_ccb->ccb_h.qos.periph_data = cam_iosched_delta_t(done_ccb->ccb_h.qos.periph_data); 4692227d67aaSAlexander Motin xpt_done_process(&done_ccb->ccb_h); 4693711f6613SAlexander Motin } 4694711f6613SAlexander Motin 46958b8a9b1dSJustin T. Gibbs union ccb * 46968008a935SScott Long xpt_alloc_ccb() 46978b8a9b1dSJustin T. Gibbs { 46988b8a9b1dSJustin T. Gibbs union ccb *new_ccb; 46998b8a9b1dSJustin T. Gibbs 4700596ee08fSAlexander Motin new_ccb = malloc(sizeof(*new_ccb), M_CAMCCB, M_ZERO|M_WAITOK); 4701362abc44STai-hwa Liang return (new_ccb); 4702362abc44STai-hwa Liang } 4703362abc44STai-hwa Liang 4704362abc44STai-hwa Liang union ccb * 47058008a935SScott Long xpt_alloc_ccb_nowait() 4706362abc44STai-hwa Liang { 4707362abc44STai-hwa Liang union ccb *new_ccb; 4708362abc44STai-hwa Liang 4709596ee08fSAlexander Motin new_ccb = malloc(sizeof(*new_ccb), M_CAMCCB, M_ZERO|M_NOWAIT); 47108b8a9b1dSJustin T. Gibbs return (new_ccb); 47118b8a9b1dSJustin T. Gibbs } 47128b8a9b1dSJustin T. Gibbs 47138b8a9b1dSJustin T. Gibbs void 47148b8a9b1dSJustin T. Gibbs xpt_free_ccb(union ccb *free_ccb) 47158b8a9b1dSJustin T. Gibbs { 4716596ee08fSAlexander Motin free(free_ccb, M_CAMCCB); 47178b8a9b1dSJustin T. Gibbs } 47188b8a9b1dSJustin T. Gibbs 47198b8a9b1dSJustin T. Gibbs 47208b8a9b1dSJustin T. Gibbs 47218b8a9b1dSJustin T. Gibbs /* Private XPT functions */ 47228b8a9b1dSJustin T. Gibbs 47238b8a9b1dSJustin T. Gibbs /* 47248b8a9b1dSJustin T. Gibbs * Get a CAM control block for the caller. Charge the structure to the device 4725227d67aaSAlexander Motin * referenced by the path. If we don't have sufficient resources to allocate 4726227d67aaSAlexander Motin * more ccbs, we return NULL. 47278b8a9b1dSJustin T. Gibbs */ 47288b8a9b1dSJustin T. Gibbs static union ccb * 4729227d67aaSAlexander Motin xpt_get_ccb_nowait(struct cam_periph *periph) 47308b8a9b1dSJustin T. Gibbs { 47318b8a9b1dSJustin T. Gibbs union ccb *new_ccb; 47328b8a9b1dSJustin T. Gibbs 4733d3995fddSBenno Rice new_ccb = malloc(sizeof(*new_ccb), M_CAMCCB, M_ZERO|M_NOWAIT); 4734227d67aaSAlexander Motin if (new_ccb == NULL) 47358b8a9b1dSJustin T. Gibbs return (NULL); 4736227d67aaSAlexander Motin periph->periph_allocated++; 4737227d67aaSAlexander Motin cam_ccbq_take_opening(&periph->path->device->ccbq); 47388b8a9b1dSJustin T. Gibbs return (new_ccb); 47398b8a9b1dSJustin T. Gibbs } 47408b8a9b1dSJustin T. Gibbs 4741227d67aaSAlexander Motin static union ccb * 4742227d67aaSAlexander Motin xpt_get_ccb(struct cam_periph *periph) 4743227d67aaSAlexander Motin { 4744227d67aaSAlexander Motin union ccb *new_ccb; 4745227d67aaSAlexander Motin 4746227d67aaSAlexander Motin cam_periph_unlock(periph); 4747d3995fddSBenno Rice new_ccb = malloc(sizeof(*new_ccb), M_CAMCCB, M_ZERO|M_WAITOK); 4748227d67aaSAlexander Motin cam_periph_lock(periph); 4749227d67aaSAlexander Motin periph->periph_allocated++; 4750227d67aaSAlexander Motin cam_ccbq_take_opening(&periph->path->device->ccbq); 4751227d67aaSAlexander Motin return (new_ccb); 4752227d67aaSAlexander Motin } 4753227d67aaSAlexander Motin 4754227d67aaSAlexander Motin union ccb * 4755227d67aaSAlexander Motin cam_periph_getccb(struct cam_periph *periph, u_int32_t priority) 4756227d67aaSAlexander Motin { 4757227d67aaSAlexander Motin struct ccb_hdr *ccb_h; 4758227d67aaSAlexander Motin 4759227d67aaSAlexander Motin CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("cam_periph_getccb\n")); 4760227d67aaSAlexander Motin cam_periph_assert(periph, MA_OWNED); 4761227d67aaSAlexander Motin while ((ccb_h = SLIST_FIRST(&periph->ccb_list)) == NULL || 4762227d67aaSAlexander Motin ccb_h->pinfo.priority != priority) { 4763227d67aaSAlexander Motin if (priority < periph->immediate_priority) { 4764227d67aaSAlexander Motin periph->immediate_priority = priority; 4765227d67aaSAlexander Motin xpt_run_allocq(periph, 0); 4766227d67aaSAlexander Motin } else 4767227d67aaSAlexander Motin cam_periph_sleep(periph, &periph->ccb_list, PRIBIO, 4768227d67aaSAlexander Motin "cgticb", 0); 4769227d67aaSAlexander Motin } 4770227d67aaSAlexander Motin SLIST_REMOVE_HEAD(&periph->ccb_list, periph_links.sle); 4771227d67aaSAlexander Motin return ((union ccb *)ccb_h); 4772227d67aaSAlexander Motin } 4773227d67aaSAlexander Motin 4774227d67aaSAlexander Motin static void 4775227d67aaSAlexander Motin xpt_acquire_bus(struct cam_eb *bus) 4776227d67aaSAlexander Motin { 4777227d67aaSAlexander Motin 4778227d67aaSAlexander Motin xpt_lock_buses(); 4779227d67aaSAlexander Motin bus->refcount++; 4780227d67aaSAlexander Motin xpt_unlock_buses(); 4781227d67aaSAlexander Motin } 4782227d67aaSAlexander Motin 4783a5479bc5SJustin T. Gibbs static void 4784a5479bc5SJustin T. Gibbs xpt_release_bus(struct cam_eb *bus) 4785a5479bc5SJustin T. Gibbs { 4786a5479bc5SJustin T. Gibbs 47879a7c2696SAlexander Motin xpt_lock_buses(); 478815975b7bSMatt Jacob KASSERT(bus->refcount >= 1, ("bus->refcount >= 1")); 4789dcdf6e74SAlexander Motin if (--bus->refcount > 0) { 4790dcdf6e74SAlexander Motin xpt_unlock_buses(); 4791dcdf6e74SAlexander Motin return; 4792dcdf6e74SAlexander Motin } 47932b83592fSScott Long TAILQ_REMOVE(&xsoftc.xpt_busses, bus, links); 47942b83592fSScott Long xsoftc.bus_generation++; 47959a7c2696SAlexander Motin xpt_unlock_buses(); 4796227d67aaSAlexander Motin KASSERT(TAILQ_EMPTY(&bus->et_entries), 4797227d67aaSAlexander Motin ("destroying bus, but target list is not empty")); 4798fa6099fdSEdward Tomasz Napierala cam_sim_release(bus->sim); 4799227d67aaSAlexander Motin mtx_destroy(&bus->eb_mtx); 4800362abc44STai-hwa Liang free(bus, M_CAMXPT); 4801a5479bc5SJustin T. Gibbs } 48028b8a9b1dSJustin T. Gibbs 48038b8a9b1dSJustin T. Gibbs static struct cam_et * 48048b8a9b1dSJustin T. Gibbs xpt_alloc_target(struct cam_eb *bus, target_id_t target_id) 48058b8a9b1dSJustin T. Gibbs { 4806dcdf6e74SAlexander Motin struct cam_et *cur_target, *target; 48078b8a9b1dSJustin T. Gibbs 4808227d67aaSAlexander Motin mtx_assert(&xsoftc.xpt_topo_lock, MA_OWNED); 4809227d67aaSAlexander Motin mtx_assert(&bus->eb_mtx, MA_OWNED); 48103501942bSJustin T. Gibbs target = (struct cam_et *)malloc(sizeof(*target), M_CAMXPT, 48113501942bSJustin T. Gibbs M_NOWAIT|M_ZERO); 4812dcdf6e74SAlexander Motin if (target == NULL) 4813dcdf6e74SAlexander Motin return (NULL); 48148b8a9b1dSJustin T. Gibbs 4815434bbf6eSJustin T. Gibbs TAILQ_INIT(&target->ed_entries); 48168b8a9b1dSJustin T. Gibbs target->bus = bus; 48178b8a9b1dSJustin T. Gibbs target->target_id = target_id; 48188b8a9b1dSJustin T. Gibbs target->refcount = 1; 4819434bbf6eSJustin T. Gibbs target->generation = 0; 482082b361b1SMatt Jacob target->luns = NULL; 4821227d67aaSAlexander Motin mtx_init(&target->luns_mtx, "CAM LUNs lock", NULL, MTX_DEF); 4822434bbf6eSJustin T. Gibbs timevalclear(&target->last_reset); 4823a5479bc5SJustin T. Gibbs /* 4824a5479bc5SJustin T. Gibbs * Hold a reference to our parent bus so it 4825a5479bc5SJustin T. Gibbs * will not go away before we do. 4826a5479bc5SJustin T. Gibbs */ 4827a5479bc5SJustin T. Gibbs bus->refcount++; 48288b8a9b1dSJustin T. Gibbs 48298b8a9b1dSJustin T. Gibbs /* Insertion sort into our bus's target list */ 48308b8a9b1dSJustin T. Gibbs cur_target = TAILQ_FIRST(&bus->et_entries); 48318b8a9b1dSJustin T. Gibbs while (cur_target != NULL && cur_target->target_id < target_id) 48328b8a9b1dSJustin T. Gibbs cur_target = TAILQ_NEXT(cur_target, links); 48338b8a9b1dSJustin T. Gibbs if (cur_target != NULL) { 48348b8a9b1dSJustin T. Gibbs TAILQ_INSERT_BEFORE(cur_target, target, links); 48358b8a9b1dSJustin T. Gibbs } else { 48368b8a9b1dSJustin T. Gibbs TAILQ_INSERT_TAIL(&bus->et_entries, target, links); 48378b8a9b1dSJustin T. Gibbs } 4838a5479bc5SJustin T. Gibbs bus->generation++; 48398b8a9b1dSJustin T. Gibbs return (target); 48408b8a9b1dSJustin T. Gibbs } 48418b8a9b1dSJustin T. Gibbs 4842a5479bc5SJustin T. Gibbs static void 4843227d67aaSAlexander Motin xpt_acquire_target(struct cam_et *target) 4844227d67aaSAlexander Motin { 4845227d67aaSAlexander Motin struct cam_eb *bus = target->bus; 4846227d67aaSAlexander Motin 4847227d67aaSAlexander Motin mtx_lock(&bus->eb_mtx); 4848227d67aaSAlexander Motin target->refcount++; 4849227d67aaSAlexander Motin mtx_unlock(&bus->eb_mtx); 4850227d67aaSAlexander Motin } 4851227d67aaSAlexander Motin 4852227d67aaSAlexander Motin static void 4853f98d7a47SAlexander Motin xpt_release_target(struct cam_et *target) 48548b8a9b1dSJustin T. Gibbs { 4855227d67aaSAlexander Motin struct cam_eb *bus = target->bus; 4856a5479bc5SJustin T. Gibbs 4857227d67aaSAlexander Motin mtx_lock(&bus->eb_mtx); 4858227d67aaSAlexander Motin if (--target->refcount > 0) { 4859227d67aaSAlexander Motin mtx_unlock(&bus->eb_mtx); 4860dcdf6e74SAlexander Motin return; 4861227d67aaSAlexander Motin } 4862227d67aaSAlexander Motin TAILQ_REMOVE(&bus->et_entries, target, links); 4863227d67aaSAlexander Motin bus->generation++; 4864227d67aaSAlexander Motin mtx_unlock(&bus->eb_mtx); 4865dcdf6e74SAlexander Motin KASSERT(TAILQ_EMPTY(&target->ed_entries), 4866227d67aaSAlexander Motin ("destroying target, but device list is not empty")); 4867227d67aaSAlexander Motin xpt_release_bus(bus); 4868227d67aaSAlexander Motin mtx_destroy(&target->luns_mtx); 486982b361b1SMatt Jacob if (target->luns) 487082b361b1SMatt Jacob free(target->luns, M_CAMXPT); 4871362abc44STai-hwa Liang free(target, M_CAMXPT); 487277dc25ccSScott Long } 48738b8a9b1dSJustin T. Gibbs 48748b8a9b1dSJustin T. Gibbs static struct cam_ed * 487552c9ce25SScott Long xpt_alloc_device_default(struct cam_eb *bus, struct cam_et *target, 487652c9ce25SScott Long lun_id_t lun_id) 487752c9ce25SScott Long { 4878dcdf6e74SAlexander Motin struct cam_ed *device; 487952c9ce25SScott Long 488052c9ce25SScott Long device = xpt_alloc_device(bus, target, lun_id); 488152c9ce25SScott Long if (device == NULL) 488252c9ce25SScott Long return (NULL); 488352c9ce25SScott Long 488452c9ce25SScott Long device->mintags = 1; 488552c9ce25SScott Long device->maxtags = 1; 488652c9ce25SScott Long return (device); 488752c9ce25SScott Long } 488852c9ce25SScott Long 4889227d67aaSAlexander Motin static void 4890227d67aaSAlexander Motin xpt_destroy_device(void *context, int pending) 4891227d67aaSAlexander Motin { 4892227d67aaSAlexander Motin struct cam_ed *device = context; 4893227d67aaSAlexander Motin 4894227d67aaSAlexander Motin mtx_lock(&device->device_mtx); 4895227d67aaSAlexander Motin mtx_destroy(&device->device_mtx); 4896227d67aaSAlexander Motin free(device, M_CAMDEV); 4897227d67aaSAlexander Motin } 4898227d67aaSAlexander Motin 489952c9ce25SScott Long struct cam_ed * 49008b8a9b1dSJustin T. Gibbs xpt_alloc_device(struct cam_eb *bus, struct cam_et *target, lun_id_t lun_id) 49018b8a9b1dSJustin T. Gibbs { 4902dcdf6e74SAlexander Motin struct cam_ed *cur_device, *device; 49038b8a9b1dSJustin T. Gibbs struct cam_devq *devq; 4904a5479bc5SJustin T. Gibbs cam_status status; 49058b8a9b1dSJustin T. Gibbs 4906227d67aaSAlexander Motin mtx_assert(&bus->eb_mtx, MA_OWNED); 49078b8a9b1dSJustin T. Gibbs /* Make space for us in the device queue on our bus */ 49088b8a9b1dSJustin T. Gibbs devq = bus->sim->devq; 4909227d67aaSAlexander Motin mtx_lock(&devq->send_mtx); 4910cccf4220SAlexander Motin status = cam_devq_resize(devq, devq->send_queue.array_size + 1); 4911227d67aaSAlexander Motin mtx_unlock(&devq->send_mtx); 4912dcdf6e74SAlexander Motin if (status != CAM_REQ_CMP) 4913dcdf6e74SAlexander Motin return (NULL); 49148b8a9b1dSJustin T. Gibbs 49158b8a9b1dSJustin T. Gibbs device = (struct cam_ed *)malloc(sizeof(*device), 4916596ee08fSAlexander Motin M_CAMDEV, M_NOWAIT|M_ZERO); 4917dcdf6e74SAlexander Motin if (device == NULL) 4918dcdf6e74SAlexander Motin return (NULL); 49198b8a9b1dSJustin T. Gibbs 4920227d67aaSAlexander Motin cam_init_pinfo(&device->devq_entry); 49218b8a9b1dSJustin T. Gibbs device->target = target; 49228b8a9b1dSJustin T. Gibbs device->lun_id = lun_id; 49232b83592fSScott Long device->sim = bus->sim; 49248b8a9b1dSJustin T. Gibbs if (cam_ccbq_init(&device->ccbq, 49258b8a9b1dSJustin T. Gibbs bus->sim->max_dev_openings) != 0) { 4926596ee08fSAlexander Motin free(device, M_CAMDEV); 49278b8a9b1dSJustin T. Gibbs return (NULL); 49288b8a9b1dSJustin T. Gibbs } 4929434bbf6eSJustin T. Gibbs SLIST_INIT(&device->asyncs); 4930434bbf6eSJustin T. Gibbs SLIST_INIT(&device->periphs); 4931434bbf6eSJustin T. Gibbs device->generation = 0; 4932434bbf6eSJustin T. Gibbs device->flags = CAM_DEV_UNCONFIGURED; 4933434bbf6eSJustin T. Gibbs device->tag_delay_count = 0; 4934df8f9080SJustin T. Gibbs device->tag_saved_openings = 0; 4935434bbf6eSJustin T. Gibbs device->refcount = 1; 4936227d67aaSAlexander Motin mtx_init(&device->device_mtx, "CAM device lock", NULL, MTX_DEF); 4937227d67aaSAlexander Motin callout_init_mtx(&device->callout, &devq->send_mtx, 0); 4938227d67aaSAlexander Motin TASK_INIT(&device->device_destroy_task, 0, xpt_destroy_device, device); 4939227d67aaSAlexander Motin /* 4940227d67aaSAlexander Motin * Hold a reference to our parent bus so it 4941227d67aaSAlexander Motin * will not go away before we do. 4942227d67aaSAlexander Motin */ 4943227d67aaSAlexander Motin target->refcount++; 4944434bbf6eSJustin T. Gibbs 4945dcdf6e74SAlexander Motin cur_device = TAILQ_FIRST(&target->ed_entries); 4946dcdf6e74SAlexander Motin while (cur_device != NULL && cur_device->lun_id < lun_id) 4947dcdf6e74SAlexander Motin cur_device = TAILQ_NEXT(cur_device, links); 4948dcdf6e74SAlexander Motin if (cur_device != NULL) 4949dcdf6e74SAlexander Motin TAILQ_INSERT_BEFORE(cur_device, device, links); 4950dcdf6e74SAlexander Motin else 4951dcdf6e74SAlexander Motin TAILQ_INSERT_TAIL(&target->ed_entries, device, links); 4952dcdf6e74SAlexander Motin target->generation++; 49538b8a9b1dSJustin T. Gibbs return (device); 49548b8a9b1dSJustin T. Gibbs } 49558b8a9b1dSJustin T. Gibbs 4956f98d7a47SAlexander Motin void 4957f98d7a47SAlexander Motin xpt_acquire_device(struct cam_ed *device) 49588b8a9b1dSJustin T. Gibbs { 4959227d67aaSAlexander Motin struct cam_eb *bus = device->target->bus; 49608b8a9b1dSJustin T. Gibbs 4961227d67aaSAlexander Motin mtx_lock(&bus->eb_mtx); 4962f98d7a47SAlexander Motin device->refcount++; 4963227d67aaSAlexander Motin mtx_unlock(&bus->eb_mtx); 4964f98d7a47SAlexander Motin } 4965f98d7a47SAlexander Motin 4966f98d7a47SAlexander Motin void 4967f98d7a47SAlexander Motin xpt_release_device(struct cam_ed *device) 4968f98d7a47SAlexander Motin { 4969227d67aaSAlexander Motin struct cam_eb *bus = device->target->bus; 49708b8a9b1dSJustin T. Gibbs struct cam_devq *devq; 49718b8a9b1dSJustin T. Gibbs 4972227d67aaSAlexander Motin mtx_lock(&bus->eb_mtx); 4973227d67aaSAlexander Motin if (--device->refcount > 0) { 4974227d67aaSAlexander Motin mtx_unlock(&bus->eb_mtx); 4975dcdf6e74SAlexander Motin return; 4976227d67aaSAlexander Motin } 4977227d67aaSAlexander Motin 4978227d67aaSAlexander Motin TAILQ_REMOVE(&device->target->ed_entries, device,links); 4979227d67aaSAlexander Motin device->target->generation++; 4980227d67aaSAlexander Motin mtx_unlock(&bus->eb_mtx); 4981227d67aaSAlexander Motin 4982227d67aaSAlexander Motin /* Release our slot in the devq */ 4983227d67aaSAlexander Motin devq = bus->sim->devq; 4984227d67aaSAlexander Motin mtx_lock(&devq->send_mtx); 4985227d67aaSAlexander Motin cam_devq_resize(devq, devq->send_queue.array_size - 1); 4986227d67aaSAlexander Motin mtx_unlock(&devq->send_mtx); 4987dcdf6e74SAlexander Motin 4988dcdf6e74SAlexander Motin KASSERT(SLIST_EMPTY(&device->periphs), 4989227d67aaSAlexander Motin ("destroying device, but periphs list is not empty")); 4990227d67aaSAlexander Motin KASSERT(device->devq_entry.index == CAM_UNQUEUED_INDEX, 4991227d67aaSAlexander Motin ("destroying device while still queued for ccbs")); 49922cefde5fSJustin T. Gibbs 49932cefde5fSJustin T. Gibbs if ((device->flags & CAM_DEV_REL_TIMEOUT_PENDING) != 0) 49942b83592fSScott Long callout_stop(&device->callout); 49952cefde5fSJustin T. Gibbs 4996227d67aaSAlexander Motin xpt_release_target(device->target); 4997227d67aaSAlexander Motin 499820a7933fSAlexander Motin cam_ccbq_fini(&device->ccbq); 4999e6bd5983SKenneth D. Merry /* 5000e6bd5983SKenneth D. Merry * Free allocated memory. free(9) does nothing if the 5001e6bd5983SKenneth D. Merry * supplied pointer is NULL, so it is safe to call without 5002e6bd5983SKenneth D. Merry * checking. 5003e6bd5983SKenneth D. Merry */ 5004e6bd5983SKenneth D. Merry free(device->supported_vpds, M_CAMXPT); 5005e6bd5983SKenneth D. Merry free(device->device_id, M_CAMXPT); 50063bba3152SKenneth D. Merry free(device->ext_inq, M_CAMXPT); 5007e6bd5983SKenneth D. Merry free(device->physpath, M_CAMXPT); 5008e6bd5983SKenneth D. Merry free(device->rcap_buf, M_CAMXPT); 5009e6bd5983SKenneth D. Merry free(device->serial_num, M_CAMXPT); 5010f439e3a4SAlexander Motin free(device->nvme_data, M_CAMXPT); 5011f439e3a4SAlexander Motin free(device->nvme_cdata, M_CAMXPT); 5012227d67aaSAlexander Motin taskqueue_enqueue(xsoftc.xpt_taskq, &device->device_destroy_task); 50138b8a9b1dSJustin T. Gibbs } 50148b8a9b1dSJustin T. Gibbs 501552c9ce25SScott Long u_int32_t 50168b8a9b1dSJustin T. Gibbs xpt_dev_ccbq_resize(struct cam_path *path, int newopenings) 50178b8a9b1dSJustin T. Gibbs { 50188b8a9b1dSJustin T. Gibbs int result; 50198b8a9b1dSJustin T. Gibbs struct cam_ed *dev; 50208b8a9b1dSJustin T. Gibbs 50218b8a9b1dSJustin T. Gibbs dev = path->device; 5022227d67aaSAlexander Motin mtx_lock(&dev->sim->devq->send_mtx); 50238b8a9b1dSJustin T. Gibbs result = cam_ccbq_resize(&dev->ccbq, newopenings); 5024227d67aaSAlexander Motin mtx_unlock(&dev->sim->devq->send_mtx); 5025df8f9080SJustin T. Gibbs if ((dev->flags & CAM_DEV_TAG_AFTER_COUNT) != 0 5026df8f9080SJustin T. Gibbs || (dev->inq_flags & SID_CmdQue) != 0) 5027df8f9080SJustin T. Gibbs dev->tag_saved_openings = newopenings; 50288b8a9b1dSJustin T. Gibbs return (result); 50298b8a9b1dSJustin T. Gibbs } 50308b8a9b1dSJustin T. Gibbs 50318b8a9b1dSJustin T. Gibbs static struct cam_eb * 50328b8a9b1dSJustin T. Gibbs xpt_find_bus(path_id_t path_id) 50338b8a9b1dSJustin T. Gibbs { 50348b8a9b1dSJustin T. Gibbs struct cam_eb *bus; 50358b8a9b1dSJustin T. Gibbs 50369a7c2696SAlexander Motin xpt_lock_buses(); 50372b83592fSScott Long for (bus = TAILQ_FIRST(&xsoftc.xpt_busses); 50388b8a9b1dSJustin T. Gibbs bus != NULL; 50398b8a9b1dSJustin T. Gibbs bus = TAILQ_NEXT(bus, links)) { 5040a5479bc5SJustin T. Gibbs if (bus->path_id == path_id) { 5041a5479bc5SJustin T. Gibbs bus->refcount++; 50428b8a9b1dSJustin T. Gibbs break; 50438b8a9b1dSJustin T. Gibbs } 5044a5479bc5SJustin T. Gibbs } 50459a7c2696SAlexander Motin xpt_unlock_buses(); 50468b8a9b1dSJustin T. Gibbs return (bus); 50478b8a9b1dSJustin T. Gibbs } 50488b8a9b1dSJustin T. Gibbs 50498b8a9b1dSJustin T. Gibbs static struct cam_et * 50508b8a9b1dSJustin T. Gibbs xpt_find_target(struct cam_eb *bus, target_id_t target_id) 50518b8a9b1dSJustin T. Gibbs { 50528b8a9b1dSJustin T. Gibbs struct cam_et *target; 50538b8a9b1dSJustin T. Gibbs 5054227d67aaSAlexander Motin mtx_assert(&bus->eb_mtx, MA_OWNED); 50558b8a9b1dSJustin T. Gibbs for (target = TAILQ_FIRST(&bus->et_entries); 50568b8a9b1dSJustin T. Gibbs target != NULL; 50578b8a9b1dSJustin T. Gibbs target = TAILQ_NEXT(target, links)) { 50588b8a9b1dSJustin T. Gibbs if (target->target_id == target_id) { 50598b8a9b1dSJustin T. Gibbs target->refcount++; 50608b8a9b1dSJustin T. Gibbs break; 50618b8a9b1dSJustin T. Gibbs } 50628b8a9b1dSJustin T. Gibbs } 50638b8a9b1dSJustin T. Gibbs return (target); 50648b8a9b1dSJustin T. Gibbs } 50658b8a9b1dSJustin T. Gibbs 50668b8a9b1dSJustin T. Gibbs static struct cam_ed * 50678b8a9b1dSJustin T. Gibbs xpt_find_device(struct cam_et *target, lun_id_t lun_id) 50688b8a9b1dSJustin T. Gibbs { 50698b8a9b1dSJustin T. Gibbs struct cam_ed *device; 50708b8a9b1dSJustin T. Gibbs 5071227d67aaSAlexander Motin mtx_assert(&target->bus->eb_mtx, MA_OWNED); 50728b8a9b1dSJustin T. Gibbs for (device = TAILQ_FIRST(&target->ed_entries); 50738b8a9b1dSJustin T. Gibbs device != NULL; 50748b8a9b1dSJustin T. Gibbs device = TAILQ_NEXT(device, links)) { 50758b8a9b1dSJustin T. Gibbs if (device->lun_id == lun_id) { 50768b8a9b1dSJustin T. Gibbs device->refcount++; 50778b8a9b1dSJustin T. Gibbs break; 50788b8a9b1dSJustin T. Gibbs } 50798b8a9b1dSJustin T. Gibbs } 50808b8a9b1dSJustin T. Gibbs return (device); 50818b8a9b1dSJustin T. Gibbs } 50828b8a9b1dSJustin T. Gibbs 508330a4094fSAlexander Motin void 5084f0adc790SJustin T. Gibbs xpt_start_tags(struct cam_path *path) 5085f0adc790SJustin T. Gibbs { 5086fd21cc5eSJustin T. Gibbs struct ccb_relsim crs; 5087fd21cc5eSJustin T. Gibbs struct cam_ed *device; 5088fd21cc5eSJustin T. Gibbs struct cam_sim *sim; 5089fd21cc5eSJustin T. Gibbs int newopenings; 5090fd21cc5eSJustin T. Gibbs 5091fd21cc5eSJustin T. Gibbs device = path->device; 5092fd21cc5eSJustin T. Gibbs sim = path->bus->sim; 5093fd21cc5eSJustin T. Gibbs device->flags &= ~CAM_DEV_TAG_AFTER_COUNT; 5094fd21cc5eSJustin T. Gibbs xpt_freeze_devq(path, /*count*/1); 5095fd21cc5eSJustin T. Gibbs device->inq_flags |= SID_CmdQue; 5096df8f9080SJustin T. Gibbs if (device->tag_saved_openings != 0) 5097df8f9080SJustin T. Gibbs newopenings = device->tag_saved_openings; 5098df8f9080SJustin T. Gibbs else 509952c9ce25SScott Long newopenings = min(device->maxtags, 5100df8f9080SJustin T. Gibbs sim->max_tagged_dev_openings); 5101f0adc790SJustin T. Gibbs xpt_dev_ccbq_resize(path, newopenings); 5102581b2e78SAlexander Motin xpt_async(AC_GETDEV_CHANGED, path, NULL); 5103bbfa4aa1SAlexander Motin xpt_setup_ccb(&crs.ccb_h, path, CAM_PRIORITY_NORMAL); 5104fd21cc5eSJustin T. Gibbs crs.ccb_h.func_code = XPT_REL_SIMQ; 5105fd21cc5eSJustin T. Gibbs crs.release_flags = RELSIM_RELEASE_AFTER_QEMPTY; 5106fd21cc5eSJustin T. Gibbs crs.openings 5107fd21cc5eSJustin T. Gibbs = crs.release_timeout 5108fd21cc5eSJustin T. Gibbs = crs.qfrozen_cnt 5109fd21cc5eSJustin T. Gibbs = 0; 5110fd21cc5eSJustin T. Gibbs xpt_action((union ccb *)&crs); 5111fd21cc5eSJustin T. Gibbs } 5112fd21cc5eSJustin T. Gibbs 511330a4094fSAlexander Motin void 511430a4094fSAlexander Motin xpt_stop_tags(struct cam_path *path) 511530a4094fSAlexander Motin { 511630a4094fSAlexander Motin struct ccb_relsim crs; 511730a4094fSAlexander Motin struct cam_ed *device; 511830a4094fSAlexander Motin struct cam_sim *sim; 511930a4094fSAlexander Motin 512030a4094fSAlexander Motin device = path->device; 512130a4094fSAlexander Motin sim = path->bus->sim; 512230a4094fSAlexander Motin device->flags &= ~CAM_DEV_TAG_AFTER_COUNT; 512330a4094fSAlexander Motin device->tag_delay_count = 0; 512430a4094fSAlexander Motin xpt_freeze_devq(path, /*count*/1); 512530a4094fSAlexander Motin device->inq_flags &= ~SID_CmdQue; 512630a4094fSAlexander Motin xpt_dev_ccbq_resize(path, sim->max_dev_openings); 5127581b2e78SAlexander Motin xpt_async(AC_GETDEV_CHANGED, path, NULL); 512830a4094fSAlexander Motin xpt_setup_ccb(&crs.ccb_h, path, CAM_PRIORITY_NORMAL); 512930a4094fSAlexander Motin crs.ccb_h.func_code = XPT_REL_SIMQ; 513030a4094fSAlexander Motin crs.release_flags = RELSIM_RELEASE_AFTER_QEMPTY; 513130a4094fSAlexander Motin crs.openings 513230a4094fSAlexander Motin = crs.release_timeout 513330a4094fSAlexander Motin = crs.qfrozen_cnt 513430a4094fSAlexander Motin = 0; 513530a4094fSAlexander Motin xpt_action((union ccb *)&crs); 513630a4094fSAlexander Motin } 513730a4094fSAlexander Motin 5138a4876fbfSAlexander Motin /* 5139a4876fbfSAlexander Motin * Assume all possible buses are detected by this time, so allow boot 5140a4876fbfSAlexander Motin * as soon as they all are scanned. 5141a4876fbfSAlexander Motin */ 514283c5d981SAlexander Motin static void 514383c5d981SAlexander Motin xpt_boot_delay(void *arg) 51448b8a9b1dSJustin T. Gibbs { 51452b83592fSScott Long 514683c5d981SAlexander Motin xpt_release_boot(); 51478b8a9b1dSJustin T. Gibbs } 51488b8a9b1dSJustin T. Gibbs 5149a4876fbfSAlexander Motin /* 5150a4876fbfSAlexander Motin * Now that all config hooks have completed, start boot_delay timer, 5151a4876fbfSAlexander Motin * waiting for possibly still undetected buses (USB) to appear. 5152a4876fbfSAlexander Motin */ 51538b8a9b1dSJustin T. Gibbs static void 5154a4876fbfSAlexander Motin xpt_ch_done(void *arg) 51558b8a9b1dSJustin T. Gibbs { 5156a4876fbfSAlexander Motin 5157a4876fbfSAlexander Motin callout_init(&xsoftc.boot_callout, 1); 5158a4876fbfSAlexander Motin callout_reset_sbt(&xsoftc.boot_callout, SBT_1MS * xsoftc.boot_delay, 0, 5159a4876fbfSAlexander Motin xpt_boot_delay, NULL, 0); 5160a4876fbfSAlexander Motin } 5161a4876fbfSAlexander Motin SYSINIT(xpt_hw_delay, SI_SUB_INT_CONFIG_HOOKS, SI_ORDER_ANY, xpt_ch_done, NULL); 5162a4876fbfSAlexander Motin 51633393f8daSKenneth D. Merry /* 51643393f8daSKenneth D. Merry * Now that interrupts are enabled, go find our devices 51653393f8daSKenneth D. Merry */ 5166a4876fbfSAlexander Motin static void 5167a4876fbfSAlexander Motin xpt_config(void *arg) 5168a4876fbfSAlexander Motin { 5169227d67aaSAlexander Motin if (taskqueue_start_threads(&xsoftc.xpt_taskq, 1, PRIBIO, "CAM taskq")) 5170227d67aaSAlexander Motin printf("xpt_config: failed to create taskqueue thread.\n"); 51718b8a9b1dSJustin T. Gibbs 5172f0f25b9cSAlexander Motin /* Setup debugging path */ 51738b8a9b1dSJustin T. Gibbs if (cam_dflags != CAM_DEBUG_NONE) { 5174227d67aaSAlexander Motin if (xpt_create_path(&cam_dpath, NULL, 51758b8a9b1dSJustin T. Gibbs CAM_DEBUG_BUS, CAM_DEBUG_TARGET, 51768b8a9b1dSJustin T. Gibbs CAM_DEBUG_LUN) != CAM_REQ_CMP) { 51778b8a9b1dSJustin T. Gibbs printf("xpt_config: xpt_create_path() failed for debug" 51788b8a9b1dSJustin T. Gibbs " target %d:%d:%d, debugging disabled\n", 51798b8a9b1dSJustin T. Gibbs CAM_DEBUG_BUS, CAM_DEBUG_TARGET, CAM_DEBUG_LUN); 51808b8a9b1dSJustin T. Gibbs cam_dflags = CAM_DEBUG_NONE; 51818b8a9b1dSJustin T. Gibbs } 51828b8a9b1dSJustin T. Gibbs } else 51838b8a9b1dSJustin T. Gibbs cam_dpath = NULL; 51848b8a9b1dSJustin T. Gibbs 518583c5d981SAlexander Motin periphdriver_init(1); 518683c5d981SAlexander Motin xpt_hold_boot(); 5187a4876fbfSAlexander Motin 518883c5d981SAlexander Motin /* Fire up rescan thread. */ 5189227d67aaSAlexander Motin if (kproc_kthread_add(xpt_scanner_thread, NULL, &cam_proc, NULL, 0, 0, 5190227d67aaSAlexander Motin "cam", "scanner")) { 51916f15a274SAlexander Motin printf("xpt_config: failed to create rescan thread.\n"); 51921e637ba6SAlexander Motin } 519383c5d981SAlexander Motin } 51948b8a9b1dSJustin T. Gibbs 519583c5d981SAlexander Motin void 5196a4876fbfSAlexander Motin xpt_hold_boot_locked(void) 5197a4876fbfSAlexander Motin { 5198a4876fbfSAlexander Motin 5199a4876fbfSAlexander Motin if (xsoftc.buses_to_config++ == 0) 5200a4876fbfSAlexander Motin root_mount_hold_token("CAM", &xsoftc.xpt_rootmount); 5201a4876fbfSAlexander Motin } 5202a4876fbfSAlexander Motin 5203a4876fbfSAlexander Motin void 520483c5d981SAlexander Motin xpt_hold_boot(void) 520583c5d981SAlexander Motin { 5206a4876fbfSAlexander Motin 520783c5d981SAlexander Motin xpt_lock_buses(); 5208a4876fbfSAlexander Motin xpt_hold_boot_locked(); 520983c5d981SAlexander Motin xpt_unlock_buses(); 521083c5d981SAlexander Motin } 521183c5d981SAlexander Motin 521283c5d981SAlexander Motin void 521383c5d981SAlexander Motin xpt_release_boot(void) 521483c5d981SAlexander Motin { 521583c5d981SAlexander Motin 5216a4876fbfSAlexander Motin xpt_lock_buses(); 5217a4876fbfSAlexander Motin if (--xsoftc.buses_to_config == 0) { 5218a4876fbfSAlexander Motin if (xsoftc.buses_config_done == 0) { 521983c5d981SAlexander Motin xsoftc.buses_config_done = 1; 5220a4876fbfSAlexander Motin xsoftc.buses_to_config++; 5221a4876fbfSAlexander Motin TASK_INIT(&xsoftc.boot_task, 0, xpt_finishconfig_task, 5222a4876fbfSAlexander Motin NULL); 5223a4876fbfSAlexander Motin taskqueue_enqueue(taskqueue_thread, &xsoftc.boot_task); 522483c5d981SAlexander Motin } else 5225a4876fbfSAlexander Motin root_mount_rel(&xsoftc.xpt_rootmount); 5226a4876fbfSAlexander Motin } 522783c5d981SAlexander Motin xpt_unlock_buses(); 52282863f7b1SJustin T. Gibbs } 52298b8a9b1dSJustin T. Gibbs 52308b8a9b1dSJustin T. Gibbs /* 52318b8a9b1dSJustin T. Gibbs * If the given device only has one peripheral attached to it, and if that 52328b8a9b1dSJustin T. Gibbs * peripheral is the passthrough driver, announce it. This insures that the 52338b8a9b1dSJustin T. Gibbs * user sees some sort of announcement for every peripheral in their system. 52348b8a9b1dSJustin T. Gibbs */ 52358b8a9b1dSJustin T. Gibbs static int 52368b8a9b1dSJustin T. Gibbs xptpassannouncefunc(struct cam_ed *device, void *arg) 52378b8a9b1dSJustin T. Gibbs { 52388b8a9b1dSJustin T. Gibbs struct cam_periph *periph; 52398b8a9b1dSJustin T. Gibbs int i; 52408b8a9b1dSJustin T. Gibbs 52418b8a9b1dSJustin T. Gibbs for (periph = SLIST_FIRST(&device->periphs), i = 0; periph != NULL; 52428b8a9b1dSJustin T. Gibbs periph = SLIST_NEXT(periph, periph_links), i++); 52438b8a9b1dSJustin T. Gibbs 52448b8a9b1dSJustin T. Gibbs periph = SLIST_FIRST(&device->periphs); 52458b8a9b1dSJustin T. Gibbs if ((i == 1) 52468b8a9b1dSJustin T. Gibbs && (strncmp(periph->periph_name, "pass", 4) == 0)) 52478b8a9b1dSJustin T. Gibbs xpt_announce_periph(periph, NULL); 52488b8a9b1dSJustin T. Gibbs 52498b8a9b1dSJustin T. Gibbs return(1); 52508b8a9b1dSJustin T. Gibbs } 52518b8a9b1dSJustin T. Gibbs 52528b8a9b1dSJustin T. Gibbs static void 52532b83592fSScott Long xpt_finishconfig_task(void *context, int pending) 52548b8a9b1dSJustin T. Gibbs { 52558b8a9b1dSJustin T. Gibbs 525683c5d981SAlexander Motin periphdriver_init(2); 52572b83592fSScott Long /* 52582b83592fSScott Long * Check for devices with no "standard" peripheral driver 52592b83592fSScott Long * attached. For any devices like that, announce the 52602b83592fSScott Long * passthrough driver so the user will see something. 52612b83592fSScott Long */ 52623089bb2eSAlexander Motin if (!bootverbose) 52632b83592fSScott Long xpt_for_all_devices(xptpassannouncefunc, NULL); 52642b83592fSScott Long 5265a4876fbfSAlexander Motin xpt_release_boot(); 52662b83592fSScott Long } 52672b83592fSScott Long 526885d92640SScott Long cam_status 526985d92640SScott Long xpt_register_async(int event, ac_callback_t *cbfunc, void *cbarg, 527085d92640SScott Long struct cam_path *path) 527185d92640SScott Long { 527285d92640SScott Long struct ccb_setasync csa; 527385d92640SScott Long cam_status status; 527485d92640SScott Long int xptpath = 0; 527585d92640SScott Long 527685d92640SScott Long if (path == NULL) { 527785d92640SScott Long status = xpt_create_path(&path, /*periph*/NULL, CAM_XPT_PATH_ID, 527885d92640SScott Long CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD); 5279227d67aaSAlexander Motin if (status != CAM_REQ_CMP) 528085d92640SScott Long return (status); 5281227d67aaSAlexander Motin xpt_path_lock(path); 528285d92640SScott Long xptpath = 1; 528385d92640SScott Long } 528485d92640SScott Long 528583c5d981SAlexander Motin xpt_setup_ccb(&csa.ccb_h, path, CAM_PRIORITY_NORMAL); 528685d92640SScott Long csa.ccb_h.func_code = XPT_SASYNC_CB; 528785d92640SScott Long csa.event_enable = event; 528885d92640SScott Long csa.callback = cbfunc; 528985d92640SScott Long csa.callback_arg = cbarg; 529085d92640SScott Long xpt_action((union ccb *)&csa); 529185d92640SScott Long status = csa.ccb_h.status; 52923501942bSJustin T. Gibbs 529369be012fSWarner Losh CAM_DEBUG(csa.ccb_h.path, CAM_DEBUG_TRACE, 529469be012fSWarner Losh ("xpt_register_async: func %p\n", cbfunc)); 529569be012fSWarner Losh 529685d92640SScott Long if (xptpath) { 5297227d67aaSAlexander Motin xpt_path_unlock(path); 529885d92640SScott Long xpt_free_path(path); 52993501942bSJustin T. Gibbs } 53007685edecSAlexander Motin 53017685edecSAlexander Motin if ((status == CAM_REQ_CMP) && 53027685edecSAlexander Motin (csa.event_enable & AC_FOUND_DEVICE)) { 53037685edecSAlexander Motin /* 53047685edecSAlexander Motin * Get this peripheral up to date with all 53057685edecSAlexander Motin * the currently existing devices. 53067685edecSAlexander Motin */ 53077685edecSAlexander Motin xpt_for_all_devices(xptsetasyncfunc, &csa); 53087685edecSAlexander Motin } 53097685edecSAlexander Motin if ((status == CAM_REQ_CMP) && 53107685edecSAlexander Motin (csa.event_enable & AC_PATH_REGISTERED)) { 53117685edecSAlexander Motin /* 53127685edecSAlexander Motin * Get this peripheral up to date with all 5313db4fcadfSConrad Meyer * the currently existing buses. 53147685edecSAlexander Motin */ 53157685edecSAlexander Motin xpt_for_all_busses(xptsetasyncbusfunc, &csa); 53167685edecSAlexander Motin } 53173501942bSJustin T. Gibbs 531885d92640SScott Long return (status); 531985d92640SScott Long } 532085d92640SScott Long 53218b8a9b1dSJustin T. Gibbs static void 53228b8a9b1dSJustin T. Gibbs xptaction(struct cam_sim *sim, union ccb *work_ccb) 53238b8a9b1dSJustin T. Gibbs { 53248b8a9b1dSJustin T. Gibbs CAM_DEBUG(work_ccb->ccb_h.path, CAM_DEBUG_TRACE, ("xptaction\n")); 53258b8a9b1dSJustin T. Gibbs 53268b8a9b1dSJustin T. Gibbs switch (work_ccb->ccb_h.func_code) { 53278b8a9b1dSJustin T. Gibbs /* Common cases first */ 53288b8a9b1dSJustin T. Gibbs case XPT_PATH_INQ: /* Path routing inquiry */ 53298b8a9b1dSJustin T. Gibbs { 53308b8a9b1dSJustin T. Gibbs struct ccb_pathinq *cpi; 53318b8a9b1dSJustin T. Gibbs 53328b8a9b1dSJustin T. Gibbs cpi = &work_ccb->cpi; 53338b8a9b1dSJustin T. Gibbs cpi->version_num = 1; /* XXX??? */ 53348b8a9b1dSJustin T. Gibbs cpi->hba_inquiry = 0; 53358b8a9b1dSJustin T. Gibbs cpi->target_sprt = 0; 53368b8a9b1dSJustin T. Gibbs cpi->hba_misc = 0; 53378b8a9b1dSJustin T. Gibbs cpi->hba_eng_cnt = 0; 53388b8a9b1dSJustin T. Gibbs cpi->max_target = 0; 53398b8a9b1dSJustin T. Gibbs cpi->max_lun = 0; 53408b8a9b1dSJustin T. Gibbs cpi->initiator_id = 0; 53414195c7deSAlan Somers strlcpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN); 53424195c7deSAlan Somers strlcpy(cpi->hba_vid, "", HBA_IDLEN); 53434195c7deSAlan Somers strlcpy(cpi->dev_name, sim->sim_name, DEV_IDLEN); 53448b8a9b1dSJustin T. Gibbs cpi->unit_number = sim->unit_number; 53458b8a9b1dSJustin T. Gibbs cpi->bus_id = sim->bus_id; 53469deea857SKenneth D. Merry cpi->base_transfer_speed = 0; 53473393f8daSKenneth D. Merry cpi->protocol = PROTO_UNSPECIFIED; 53483393f8daSKenneth D. Merry cpi->protocol_version = PROTO_VERSION_UNSPECIFIED; 53493393f8daSKenneth D. Merry cpi->transport = XPORT_UNSPECIFIED; 53503393f8daSKenneth D. Merry cpi->transport_version = XPORT_VERSION_UNSPECIFIED; 53518b8a9b1dSJustin T. Gibbs cpi->ccb_h.status = CAM_REQ_CMP; 53528b8a9b1dSJustin T. Gibbs xpt_done(work_ccb); 53538b8a9b1dSJustin T. Gibbs break; 53548b8a9b1dSJustin T. Gibbs } 53558b8a9b1dSJustin T. Gibbs default: 53568b8a9b1dSJustin T. Gibbs work_ccb->ccb_h.status = CAM_REQ_INVALID; 53578b8a9b1dSJustin T. Gibbs xpt_done(work_ccb); 53588b8a9b1dSJustin T. Gibbs break; 53598b8a9b1dSJustin T. Gibbs } 53608b8a9b1dSJustin T. Gibbs } 53618b8a9b1dSJustin T. Gibbs 53628b8a9b1dSJustin T. Gibbs /* 5363434bbf6eSJustin T. Gibbs * The xpt as a "controller" has no interrupt sources, so polling 5364434bbf6eSJustin T. Gibbs * is a no-op. 5365434bbf6eSJustin T. Gibbs */ 5366434bbf6eSJustin T. Gibbs static void 5367434bbf6eSJustin T. Gibbs xptpoll(struct cam_sim *sim) 5368434bbf6eSJustin T. Gibbs { 5369434bbf6eSJustin T. Gibbs } 5370434bbf6eSJustin T. Gibbs 53712b83592fSScott Long void 53722b83592fSScott Long xpt_lock_buses(void) 53732b83592fSScott Long { 53742b83592fSScott Long mtx_lock(&xsoftc.xpt_topo_lock); 53752b83592fSScott Long } 53762b83592fSScott Long 53772b83592fSScott Long void 53782b83592fSScott Long xpt_unlock_buses(void) 53792b83592fSScott Long { 53802b83592fSScott Long mtx_unlock(&xsoftc.xpt_topo_lock); 53812b83592fSScott Long } 53822b83592fSScott Long 5383227d67aaSAlexander Motin struct mtx * 5384227d67aaSAlexander Motin xpt_path_mtx(struct cam_path *path) 53858b8a9b1dSJustin T. Gibbs { 5386227d67aaSAlexander Motin 5387227d67aaSAlexander Motin return (&path->device->device_mtx); 5388227d67aaSAlexander Motin } 5389227d67aaSAlexander Motin 5390227d67aaSAlexander Motin static void 5391227d67aaSAlexander Motin xpt_done_process(struct ccb_hdr *ccb_h) 5392227d67aaSAlexander Motin { 5393de64cba2SWarner Losh struct cam_sim *sim = NULL; 5394de64cba2SWarner Losh struct cam_devq *devq = NULL; 5395227d67aaSAlexander Motin struct mtx *mtx = NULL; 53968b8a9b1dSJustin T. Gibbs 53978532d381SConrad Meyer #if defined(BUF_TRACKING) || defined(FULL_BUF_TRACKING) 53988532d381SConrad Meyer struct ccb_scsiio *csio; 53998532d381SConrad Meyer 54008532d381SConrad Meyer if (ccb_h->func_code == XPT_SCSI_IO) { 54018532d381SConrad Meyer csio = &((union ccb *)ccb_h)->csio; 54028532d381SConrad Meyer if (csio->bio != NULL) 54038532d381SConrad Meyer biotrack(csio->bio, __func__); 54048532d381SConrad Meyer } 54058532d381SConrad Meyer #endif 54068532d381SConrad Meyer 54078b8a9b1dSJustin T. Gibbs if (ccb_h->flags & CAM_HIGH_POWER) { 54088b8a9b1dSJustin T. Gibbs struct highpowerlist *hphead; 5409ea541bfdSAlexander Motin struct cam_ed *device; 54108b8a9b1dSJustin T. Gibbs 5411daa5487fSAlexander Motin mtx_lock(&xsoftc.xpt_highpower_lock); 54122b83592fSScott Long hphead = &xsoftc.highpowerq; 54138b8a9b1dSJustin T. Gibbs 5414ea541bfdSAlexander Motin device = STAILQ_FIRST(hphead); 54158b8a9b1dSJustin T. Gibbs 54168b8a9b1dSJustin T. Gibbs /* 54178b8a9b1dSJustin T. Gibbs * Increment the count since this command is done. 54188b8a9b1dSJustin T. Gibbs */ 54192b83592fSScott Long xsoftc.num_highpower++; 54208b8a9b1dSJustin T. Gibbs 54218b8a9b1dSJustin T. Gibbs /* 54228b8a9b1dSJustin T. Gibbs * Any high powered commands queued up? 54238b8a9b1dSJustin T. Gibbs */ 5424ea541bfdSAlexander Motin if (device != NULL) { 54258b8a9b1dSJustin T. Gibbs 5426ea541bfdSAlexander Motin STAILQ_REMOVE_HEAD(hphead, highpowerq_entry); 5427daa5487fSAlexander Motin mtx_unlock(&xsoftc.xpt_highpower_lock); 54288b8a9b1dSJustin T. Gibbs 5429227d67aaSAlexander Motin mtx_lock(&device->sim->devq->send_mtx); 5430ea541bfdSAlexander Motin xpt_release_devq_device(device, 54312cefde5fSJustin T. Gibbs /*count*/1, /*runqueue*/TRUE); 5432227d67aaSAlexander Motin mtx_unlock(&device->sim->devq->send_mtx); 54332b83592fSScott Long } else 5434daa5487fSAlexander Motin mtx_unlock(&xsoftc.xpt_highpower_lock); 54358b8a9b1dSJustin T. Gibbs } 54362b83592fSScott Long 5437de64cba2SWarner Losh /* 5438a73b2e25SWarner Losh * Insulate against a race where the periph is destroyed but CCBs are 5439a73b2e25SWarner Losh * still not all processed. This shouldn't happen, but allows us better 5440a73b2e25SWarner Losh * bug diagnostic when it does. 5441de64cba2SWarner Losh */ 5442de64cba2SWarner Losh if (ccb_h->path->bus) 5443227d67aaSAlexander Motin sim = ccb_h->path->bus->sim; 5444227d67aaSAlexander Motin 5445227d67aaSAlexander Motin if (ccb_h->status & CAM_RELEASE_SIMQ) { 5446de64cba2SWarner Losh KASSERT(sim, ("sim missing for CAM_RELEASE_SIMQ request")); 5447227d67aaSAlexander Motin xpt_release_simq(sim, /*run_queue*/FALSE); 5448227d67aaSAlexander Motin ccb_h->status &= ~CAM_RELEASE_SIMQ; 5449227d67aaSAlexander Motin } 5450227d67aaSAlexander Motin 5451227d67aaSAlexander Motin if ((ccb_h->flags & CAM_DEV_QFRZDIS) 5452227d67aaSAlexander Motin && (ccb_h->status & CAM_DEV_QFRZN)) { 5453d718926bSAlexander Motin xpt_release_devq(ccb_h->path, /*count*/1, /*run_queue*/TRUE); 5454227d67aaSAlexander Motin ccb_h->status &= ~CAM_DEV_QFRZN; 5455227d67aaSAlexander Motin } 5456227d67aaSAlexander Motin 54579deea857SKenneth D. Merry if ((ccb_h->func_code & XPT_FC_USER_CCB) == 0) { 5458227d67aaSAlexander Motin struct cam_ed *dev = ccb_h->path->device; 54598b8a9b1dSJustin T. Gibbs 5460de64cba2SWarner Losh if (sim) 5461de64cba2SWarner Losh devq = sim->devq; 5462a73b2e25SWarner Losh KASSERT(devq, ("Periph disappeared with request pending.")); 5463de64cba2SWarner Losh 5464227d67aaSAlexander Motin mtx_lock(&devq->send_mtx); 5465227d67aaSAlexander Motin devq->send_active--; 5466227d67aaSAlexander Motin devq->send_openings++; 54678b8a9b1dSJustin T. Gibbs cam_ccbq_ccb_done(&dev->ccbq, (union ccb *)ccb_h); 54688b8a9b1dSJustin T. Gibbs 5469b9c473b2SAlexander Motin if (((dev->flags & CAM_DEV_REL_ON_QUEUE_EMPTY) != 0 54708b8a9b1dSJustin T. Gibbs && (dev->ccbq.dev_active == 0))) { 5471b9c473b2SAlexander Motin dev->flags &= ~CAM_DEV_REL_ON_QUEUE_EMPTY; 5472227d67aaSAlexander Motin xpt_release_devq_device(dev, /*count*/1, 5473b9c473b2SAlexander Motin /*run_queue*/FALSE); 5474b9c473b2SAlexander Motin } 5475b9c473b2SAlexander Motin 5476b9c473b2SAlexander Motin if (((dev->flags & CAM_DEV_REL_ON_COMPLETE) != 0 5477b9c473b2SAlexander Motin && (ccb_h->status&CAM_STATUS_MASK) != CAM_REQUEUE_REQ)) { 5478b9c473b2SAlexander Motin dev->flags &= ~CAM_DEV_REL_ON_COMPLETE; 5479227d67aaSAlexander Motin xpt_release_devq_device(dev, /*count*/1, 548083c5d981SAlexander Motin /*run_queue*/FALSE); 54818b8a9b1dSJustin T. Gibbs } 54828b8a9b1dSJustin T. Gibbs 5483227d67aaSAlexander Motin if (!device_is_queued(dev)) 5484227d67aaSAlexander Motin (void)xpt_schedule_devq(devq, dev); 5485d718926bSAlexander Motin xpt_run_devq(devq); 5486227d67aaSAlexander Motin mtx_unlock(&devq->send_mtx); 5487227d67aaSAlexander Motin 5488227d67aaSAlexander Motin if ((dev->flags & CAM_DEV_TAG_AFTER_COUNT) != 0) { 5489227d67aaSAlexander Motin mtx = xpt_path_mtx(ccb_h->path); 5490227d67aaSAlexander Motin mtx_lock(mtx); 5491227d67aaSAlexander Motin 5492fd21cc5eSJustin T. Gibbs if ((dev->flags & CAM_DEV_TAG_AFTER_COUNT) != 0 5493fd21cc5eSJustin T. Gibbs && (--dev->tag_delay_count == 0)) 5494fd21cc5eSJustin T. Gibbs xpt_start_tags(ccb_h->path); 54953501942bSJustin T. Gibbs } 54968b8a9b1dSJustin T. Gibbs } 54978b8a9b1dSJustin T. Gibbs 5498227d67aaSAlexander Motin if ((ccb_h->flags & CAM_UNLOCKED) == 0) { 5499227d67aaSAlexander Motin if (mtx == NULL) { 5500227d67aaSAlexander Motin mtx = xpt_path_mtx(ccb_h->path); 5501227d67aaSAlexander Motin mtx_lock(mtx); 5502434bbf6eSJustin T. Gibbs } 5503227d67aaSAlexander Motin } else { 5504227d67aaSAlexander Motin if (mtx != NULL) { 5505227d67aaSAlexander Motin mtx_unlock(mtx); 5506227d67aaSAlexander Motin mtx = NULL; 5507227d67aaSAlexander Motin } 55088b8a9b1dSJustin T. Gibbs } 55098b8a9b1dSJustin T. Gibbs 55108b8a9b1dSJustin T. Gibbs /* Call the peripheral driver's callback */ 5511f1486b51SAlexander Motin ccb_h->pinfo.index = CAM_UNQUEUED_INDEX; 5512434bbf6eSJustin T. Gibbs (*ccb_h->cbfcnp)(ccb_h->path->periph, (union ccb *)ccb_h); 5513227d67aaSAlexander Motin if (mtx != NULL) 5514227d67aaSAlexander Motin mtx_unlock(mtx); 5515227d67aaSAlexander Motin } 5516227d67aaSAlexander Motin 5517227d67aaSAlexander Motin void 5518227d67aaSAlexander Motin xpt_done_td(void *arg) 5519227d67aaSAlexander Motin { 5520227d67aaSAlexander Motin struct cam_doneq *queue = arg; 5521227d67aaSAlexander Motin struct ccb_hdr *ccb_h; 5522227d67aaSAlexander Motin STAILQ_HEAD(, ccb_hdr) doneq; 5523227d67aaSAlexander Motin 5524227d67aaSAlexander Motin STAILQ_INIT(&doneq); 5525227d67aaSAlexander Motin mtx_lock(&queue->cam_doneq_mtx); 5526227d67aaSAlexander Motin while (1) { 5527227d67aaSAlexander Motin while (STAILQ_EMPTY(&queue->cam_doneq)) { 5528227d67aaSAlexander Motin queue->cam_doneq_sleep = 1; 5529227d67aaSAlexander Motin msleep(&queue->cam_doneq, &queue->cam_doneq_mtx, 5530227d67aaSAlexander Motin PRIBIO, "-", 0); 5531227d67aaSAlexander Motin queue->cam_doneq_sleep = 0; 5532227d67aaSAlexander Motin } 5533227d67aaSAlexander Motin STAILQ_CONCAT(&doneq, &queue->cam_doneq); 5534227d67aaSAlexander Motin mtx_unlock(&queue->cam_doneq_mtx); 5535227d67aaSAlexander Motin 5536227d67aaSAlexander Motin THREAD_NO_SLEEPING(); 5537227d67aaSAlexander Motin while ((ccb_h = STAILQ_FIRST(&doneq)) != NULL) { 5538227d67aaSAlexander Motin STAILQ_REMOVE_HEAD(&doneq, sim_links.stqe); 5539227d67aaSAlexander Motin xpt_done_process(ccb_h); 5540227d67aaSAlexander Motin } 5541227d67aaSAlexander Motin THREAD_SLEEPING_OK(); 5542227d67aaSAlexander Motin 5543227d67aaSAlexander Motin mtx_lock(&queue->cam_doneq_mtx); 5544227d67aaSAlexander Motin } 5545227d67aaSAlexander Motin } 5546227d67aaSAlexander Motin 5547227d67aaSAlexander Motin static void 5548227d67aaSAlexander Motin camisr_runqueue(void) 5549227d67aaSAlexander Motin { 5550227d67aaSAlexander Motin struct ccb_hdr *ccb_h; 5551227d67aaSAlexander Motin struct cam_doneq *queue; 5552227d67aaSAlexander Motin int i; 5553227d67aaSAlexander Motin 5554227d67aaSAlexander Motin /* Process global queues. */ 5555227d67aaSAlexander Motin for (i = 0; i < cam_num_doneqs; i++) { 5556227d67aaSAlexander Motin queue = &cam_doneqs[i]; 5557227d67aaSAlexander Motin mtx_lock(&queue->cam_doneq_mtx); 5558227d67aaSAlexander Motin while ((ccb_h = STAILQ_FIRST(&queue->cam_doneq)) != NULL) { 5559227d67aaSAlexander Motin STAILQ_REMOVE_HEAD(&queue->cam_doneq, sim_links.stqe); 5560227d67aaSAlexander Motin mtx_unlock(&queue->cam_doneq_mtx); 5561227d67aaSAlexander Motin xpt_done_process(ccb_h); 5562227d67aaSAlexander Motin mtx_lock(&queue->cam_doneq_mtx); 5563227d67aaSAlexander Motin } 5564227d67aaSAlexander Motin mtx_unlock(&queue->cam_doneq_mtx); 55658b8a9b1dSJustin T. Gibbs } 55668b8a9b1dSJustin T. Gibbs } 556769be012fSWarner Losh 556869be012fSWarner Losh struct kv 556969be012fSWarner Losh { 557069be012fSWarner Losh uint32_t v; 557169be012fSWarner Losh const char *name; 557269be012fSWarner Losh }; 557369be012fSWarner Losh 557469be012fSWarner Losh static struct kv map[] = { 557569be012fSWarner Losh { XPT_NOOP, "XPT_NOOP" }, 557669be012fSWarner Losh { XPT_SCSI_IO, "XPT_SCSI_IO" }, 557769be012fSWarner Losh { XPT_GDEV_TYPE, "XPT_GDEV_TYPE" }, 557869be012fSWarner Losh { XPT_GDEVLIST, "XPT_GDEVLIST" }, 557969be012fSWarner Losh { XPT_PATH_INQ, "XPT_PATH_INQ" }, 558069be012fSWarner Losh { XPT_REL_SIMQ, "XPT_REL_SIMQ" }, 558169be012fSWarner Losh { XPT_SASYNC_CB, "XPT_SASYNC_CB" }, 558269be012fSWarner Losh { XPT_SDEV_TYPE, "XPT_SDEV_TYPE" }, 558369be012fSWarner Losh { XPT_SCAN_BUS, "XPT_SCAN_BUS" }, 558469be012fSWarner Losh { XPT_DEV_MATCH, "XPT_DEV_MATCH" }, 558569be012fSWarner Losh { XPT_DEBUG, "XPT_DEBUG" }, 558669be012fSWarner Losh { XPT_PATH_STATS, "XPT_PATH_STATS" }, 558769be012fSWarner Losh { XPT_GDEV_STATS, "XPT_GDEV_STATS" }, 558869be012fSWarner Losh { XPT_DEV_ADVINFO, "XPT_DEV_ADVINFO" }, 558969be012fSWarner Losh { XPT_ASYNC, "XPT_ASYNC" }, 559069be012fSWarner Losh { XPT_ABORT, "XPT_ABORT" }, 559169be012fSWarner Losh { XPT_RESET_BUS, "XPT_RESET_BUS" }, 559269be012fSWarner Losh { XPT_RESET_DEV, "XPT_RESET_DEV" }, 559369be012fSWarner Losh { XPT_TERM_IO, "XPT_TERM_IO" }, 559469be012fSWarner Losh { XPT_SCAN_LUN, "XPT_SCAN_LUN" }, 559569be012fSWarner Losh { XPT_GET_TRAN_SETTINGS, "XPT_GET_TRAN_SETTINGS" }, 559669be012fSWarner Losh { XPT_SET_TRAN_SETTINGS, "XPT_SET_TRAN_SETTINGS" }, 559769be012fSWarner Losh { XPT_CALC_GEOMETRY, "XPT_CALC_GEOMETRY" }, 559869be012fSWarner Losh { XPT_ATA_IO, "XPT_ATA_IO" }, 559969be012fSWarner Losh { XPT_GET_SIM_KNOB, "XPT_GET_SIM_KNOB" }, 560069be012fSWarner Losh { XPT_SET_SIM_KNOB, "XPT_SET_SIM_KNOB" }, 56017b05c3e3SWarner Losh { XPT_NVME_IO, "XPT_NVME_IO" }, 5602a94a63f0SWarner Losh { XPT_MMC_IO, "XPT_MMC_IO" }, 560369be012fSWarner Losh { XPT_SMP_IO, "XPT_SMP_IO" }, 560469be012fSWarner Losh { XPT_SCAN_TGT, "XPT_SCAN_TGT" }, 5605df424515SWarner Losh { XPT_NVME_ADMIN, "XPT_NVME_ADMIN" }, 560669be012fSWarner Losh { XPT_ENG_INQ, "XPT_ENG_INQ" }, 560769be012fSWarner Losh { XPT_ENG_EXEC, "XPT_ENG_EXEC" }, 560869be012fSWarner Losh { XPT_EN_LUN, "XPT_EN_LUN" }, 560969be012fSWarner Losh { XPT_TARGET_IO, "XPT_TARGET_IO" }, 561069be012fSWarner Losh { XPT_ACCEPT_TARGET_IO, "XPT_ACCEPT_TARGET_IO" }, 561169be012fSWarner Losh { XPT_CONT_TARGET_IO, "XPT_CONT_TARGET_IO" }, 561269be012fSWarner Losh { XPT_IMMED_NOTIFY, "XPT_IMMED_NOTIFY" }, 561369be012fSWarner Losh { XPT_NOTIFY_ACK, "XPT_NOTIFY_ACK" }, 561469be012fSWarner Losh { XPT_IMMEDIATE_NOTIFY, "XPT_IMMEDIATE_NOTIFY" }, 561569be012fSWarner Losh { XPT_NOTIFY_ACKNOWLEDGE, "XPT_NOTIFY_ACKNOWLEDGE" }, 561669be012fSWarner Losh { 0, 0 } 561769be012fSWarner Losh }; 561869be012fSWarner Losh 5619a94a63f0SWarner Losh const char * 562069be012fSWarner Losh xpt_action_name(uint32_t action) 562169be012fSWarner Losh { 562269be012fSWarner Losh static char buffer[32]; /* Only for unknown messages -- racy */ 562369be012fSWarner Losh struct kv *walker = map; 562469be012fSWarner Losh 562569be012fSWarner Losh while (walker->name != NULL) { 562669be012fSWarner Losh if (walker->v == action) 562769be012fSWarner Losh return (walker->name); 562869be012fSWarner Losh walker++; 562969be012fSWarner Losh } 563069be012fSWarner Losh 563169be012fSWarner Losh snprintf(buffer, sizeof(buffer), "%#x", action); 563269be012fSWarner Losh return (buffer); 563369be012fSWarner Losh } 5634