18b8a9b1dSJustin T. Gibbs /* 28b8a9b1dSJustin T. Gibbs * Implementation of the Common Access Method Transport (XPT) layer. 38b8a9b1dSJustin T. Gibbs * 48b8a9b1dSJustin T. Gibbs * Copyright (c) 1997, 1998 Justin T. Gibbs. 58b8a9b1dSJustin T. Gibbs * Copyright (c) 1997, 1998 Kenneth D. Merry. 68b8a9b1dSJustin T. Gibbs * All rights reserved. 78b8a9b1dSJustin T. Gibbs * 88b8a9b1dSJustin T. Gibbs * Redistribution and use in source and binary forms, with or without 98b8a9b1dSJustin T. Gibbs * modification, are permitted provided that the following conditions 108b8a9b1dSJustin T. Gibbs * are met: 118b8a9b1dSJustin T. Gibbs * 1. Redistributions of source code must retain the above copyright 128b8a9b1dSJustin T. Gibbs * notice, this list of conditions, and the following disclaimer, 138b8a9b1dSJustin T. Gibbs * without modification, immediately at the beginning of the file. 148b8a9b1dSJustin T. Gibbs * 2. The name of the author may not be used to endorse or promote products 158b8a9b1dSJustin T. Gibbs * derived from this software without specific prior written permission. 168b8a9b1dSJustin T. Gibbs * 178b8a9b1dSJustin T. Gibbs * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 188b8a9b1dSJustin T. Gibbs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 198b8a9b1dSJustin T. Gibbs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 208b8a9b1dSJustin T. Gibbs * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 218b8a9b1dSJustin T. Gibbs * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 228b8a9b1dSJustin T. Gibbs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 238b8a9b1dSJustin T. Gibbs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 248b8a9b1dSJustin T. Gibbs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 258b8a9b1dSJustin T. Gibbs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 268b8a9b1dSJustin T. Gibbs * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 278b8a9b1dSJustin T. Gibbs * SUCH DAMAGE. 288b8a9b1dSJustin T. Gibbs * 299bc66b83SJustin T. Gibbs * $Id: cam_xpt.c,v 1.3 1998/09/16 00:11:33 ken Exp $ 308b8a9b1dSJustin T. Gibbs */ 318b8a9b1dSJustin T. Gibbs #include <sys/param.h> 328b8a9b1dSJustin T. Gibbs #include <sys/systm.h> 338b8a9b1dSJustin T. Gibbs #include <sys/types.h> 348b8a9b1dSJustin T. Gibbs #include <sys/malloc.h> 358b8a9b1dSJustin T. Gibbs #include <sys/device.h> 368b8a9b1dSJustin T. Gibbs #include <sys/kernel.h> 378b8a9b1dSJustin T. Gibbs #include <sys/conf.h> 388b8a9b1dSJustin T. Gibbs #include <sys/fcntl.h> 398b8a9b1dSJustin T. Gibbs #include <sys/md5.h> 408b8a9b1dSJustin T. Gibbs #include <sys/devicestat.h> 418b8a9b1dSJustin T. Gibbs 428b8a9b1dSJustin T. Gibbs #ifdef PC98 438b8a9b1dSJustin T. Gibbs #include <pc98/pc98/pc98_machdep.h> /* geometry translation */ 448b8a9b1dSJustin T. Gibbs #endif 458b8a9b1dSJustin T. Gibbs 468b8a9b1dSJustin T. Gibbs #include <machine/clock.h> 478b8a9b1dSJustin T. Gibbs #include <machine/ipl.h> 488b8a9b1dSJustin T. Gibbs 498b8a9b1dSJustin T. Gibbs #include <cam/cam.h> 508b8a9b1dSJustin T. Gibbs #include <cam/cam_conf.h> 518b8a9b1dSJustin T. Gibbs #include <cam/cam_ccb.h> 528b8a9b1dSJustin T. Gibbs #include <cam/cam_periph.h> 538b8a9b1dSJustin T. Gibbs #include <cam/cam_sim.h> 548b8a9b1dSJustin T. Gibbs #include <cam/cam_xpt.h> 558b8a9b1dSJustin T. Gibbs #include <cam/cam_xpt_sim.h> 568b8a9b1dSJustin T. Gibbs #include <cam/cam_xpt_periph.h> 578b8a9b1dSJustin T. Gibbs #include <cam/cam_debug.h> 588b8a9b1dSJustin T. Gibbs 598b8a9b1dSJustin T. Gibbs #include <cam/scsi/scsi_all.h> 608b8a9b1dSJustin T. Gibbs #include <cam/scsi/scsi_message.h> 618b8a9b1dSJustin T. Gibbs #include <cam/scsi/scsi_pass.h> 628b8a9b1dSJustin T. Gibbs #include "opt_cam.h" 638b8a9b1dSJustin T. Gibbs #include "opt_scsi.h" 648b8a9b1dSJustin T. Gibbs 658b8a9b1dSJustin T. Gibbs extern void (*ihandlers[32]) __P((void)); 668b8a9b1dSJustin T. Gibbs 678b8a9b1dSJustin T. Gibbs /* Datastructures internal to the xpt layer */ 688b8a9b1dSJustin T. Gibbs 698b8a9b1dSJustin T. Gibbs /* 708b8a9b1dSJustin T. Gibbs * Definition of an async handler callback block. These are used to add 718b8a9b1dSJustin T. Gibbs * SIMs and peripherals to the async callback lists. 728b8a9b1dSJustin T. Gibbs */ 738b8a9b1dSJustin T. Gibbs struct async_node { 748b8a9b1dSJustin T. Gibbs SLIST_ENTRY(async_node) links; 758b8a9b1dSJustin T. Gibbs u_int32_t event_enable; /* Async Event enables */ 768b8a9b1dSJustin T. Gibbs void (*callback)(void *arg, u_int32_t code, 778b8a9b1dSJustin T. Gibbs struct cam_path *path, void *args); 788b8a9b1dSJustin T. Gibbs void *callback_arg; 798b8a9b1dSJustin T. Gibbs }; 808b8a9b1dSJustin T. Gibbs 818b8a9b1dSJustin T. Gibbs SLIST_HEAD(async_list, async_node); 828b8a9b1dSJustin T. Gibbs SLIST_HEAD(periph_list, cam_periph); 838b8a9b1dSJustin T. Gibbs STAILQ_HEAD(highpowerlist, ccb_hdr) highpowerq; 848b8a9b1dSJustin T. Gibbs 858b8a9b1dSJustin T. Gibbs /* 868b8a9b1dSJustin T. Gibbs * This is the maximum number of high powered commands (e.g. start unit) 878b8a9b1dSJustin T. Gibbs * that can be outstanding at a particular time. 888b8a9b1dSJustin T. Gibbs */ 898b8a9b1dSJustin T. Gibbs #ifndef CAM_MAX_HIGHPOWER 908b8a9b1dSJustin T. Gibbs #define CAM_MAX_HIGHPOWER 4 918b8a9b1dSJustin T. Gibbs #endif 928b8a9b1dSJustin T. Gibbs 938b8a9b1dSJustin T. Gibbs /* 948b8a9b1dSJustin T. Gibbs * This is the number of seconds we wait for devices to settle after a SCSI 958b8a9b1dSJustin T. Gibbs * bus reset. 968b8a9b1dSJustin T. Gibbs */ 978b8a9b1dSJustin T. Gibbs #ifndef SCSI_DELAY 988b8a9b1dSJustin T. Gibbs #define SCSI_DELAY 2000 998b8a9b1dSJustin T. Gibbs #endif 1008b8a9b1dSJustin T. Gibbs #if (SCSI_DELAY < 100) 1018b8a9b1dSJustin T. Gibbs #error "SCSI_DELAY is in milliseconds, not seconds! Please use a larger value" 1028b8a9b1dSJustin T. Gibbs #endif 1038b8a9b1dSJustin T. Gibbs 1048b8a9b1dSJustin T. Gibbs /* number of high powered commands that can go through right now */ 1058b8a9b1dSJustin T. Gibbs static int num_highpower = CAM_MAX_HIGHPOWER; 1068b8a9b1dSJustin T. Gibbs 1078b8a9b1dSJustin T. Gibbs /* 1088b8a9b1dSJustin T. Gibbs * Structure for queueing a device in a run queue. 1098b8a9b1dSJustin T. Gibbs * There is one run queue for allocating new ccbs, 1108b8a9b1dSJustin T. Gibbs * and another for sending ccbs to the controller. 1118b8a9b1dSJustin T. Gibbs */ 1128b8a9b1dSJustin T. Gibbs struct cam_ed_qinfo { 1138b8a9b1dSJustin T. Gibbs cam_pinfo pinfo; 1148b8a9b1dSJustin T. Gibbs struct cam_ed *device; 1158b8a9b1dSJustin T. Gibbs }; 1168b8a9b1dSJustin T. Gibbs 1178b8a9b1dSJustin T. Gibbs /* 1188b8a9b1dSJustin T. Gibbs * The CAM EDT (Existing Device Table) contains the device information for 1198b8a9b1dSJustin T. Gibbs * all devices for all busses in the system. The table contains a 1208b8a9b1dSJustin T. Gibbs * cam_ed structure for each device on the bus. 1218b8a9b1dSJustin T. Gibbs */ 1228b8a9b1dSJustin T. Gibbs struct cam_ed { 1238b8a9b1dSJustin T. Gibbs TAILQ_ENTRY(cam_ed) links; 1248b8a9b1dSJustin T. Gibbs struct cam_ed_qinfo alloc_ccb_entry; 1258b8a9b1dSJustin T. Gibbs struct cam_ed_qinfo send_ccb_entry; 1268b8a9b1dSJustin T. Gibbs struct cam_et *target; 1278b8a9b1dSJustin T. Gibbs lun_id_t lun_id; 1288b8a9b1dSJustin T. Gibbs struct camq drvq; /* 1298b8a9b1dSJustin T. Gibbs * Queue of type drivers wanting to do 1308b8a9b1dSJustin T. Gibbs * work on this device. 1318b8a9b1dSJustin T. Gibbs */ 1328b8a9b1dSJustin T. Gibbs struct cam_ccbq ccbq; /* Queue of pending ccbs */ 1338b8a9b1dSJustin T. Gibbs struct async_list asyncs; /* Async callback info for this B/T/L */ 1348b8a9b1dSJustin T. Gibbs struct periph_list periphs; /* All attached devices */ 1358b8a9b1dSJustin T. Gibbs u_int generation; /* Generation number */ 1368b8a9b1dSJustin T. Gibbs struct cam_periph *owner; /* Peripheral driver's ownership tag */ 1378b8a9b1dSJustin T. Gibbs struct xpt_quirk_entry *quirk; /* Oddities about this device */ 1388b8a9b1dSJustin T. Gibbs /* Storage for the inquiry data */ 1398b8a9b1dSJustin T. Gibbs struct scsi_inquiry_data inq_data; 1408b8a9b1dSJustin T. Gibbs u_int8_t inq_flags; /* 1418b8a9b1dSJustin T. Gibbs * Current settings for inquiry flags. 1428b8a9b1dSJustin T. Gibbs * This allows us to override settings 1438b8a9b1dSJustin T. Gibbs * like disconnection and tagged 1448b8a9b1dSJustin T. Gibbs * queuing for a device. 1458b8a9b1dSJustin T. Gibbs */ 1468b8a9b1dSJustin T. Gibbs u_int8_t queue_flags; /* Queue flags from the control page */ 1478b8a9b1dSJustin T. Gibbs u_int8_t *serial_num; 1488b8a9b1dSJustin T. Gibbs u_int8_t serial_num_len; 1498b8a9b1dSJustin T. Gibbs u_int32_t qfrozen_cnt; 1508b8a9b1dSJustin T. Gibbs u_int32_t flags; 1518b8a9b1dSJustin T. Gibbs #define CAM_DEV_UNCONFIGURED 0x01 1528b8a9b1dSJustin T. Gibbs #define CAM_DEV_REL_TIMEOUT_PENDING 0x02 1538b8a9b1dSJustin T. Gibbs #define CAM_DEV_REL_ON_COMPLETE 0x04 1548b8a9b1dSJustin T. Gibbs #define CAM_DEV_REL_ON_QUEUE_EMPTY 0x08 1558b8a9b1dSJustin T. Gibbs #define CAM_DEV_RESIZE_QUEUE_NEEDED 0x10 1568b8a9b1dSJustin T. Gibbs u_int32_t refcount; 1578b8a9b1dSJustin T. Gibbs struct callout_handle c_handle; 1588b8a9b1dSJustin T. Gibbs }; 1598b8a9b1dSJustin T. Gibbs 1608b8a9b1dSJustin T. Gibbs /* 1618b8a9b1dSJustin T. Gibbs * Each target is represented by an ET (Existing Target). These 1628b8a9b1dSJustin T. Gibbs * entries are created when a target is successfully probed with an 1638b8a9b1dSJustin T. Gibbs * identify, and removed when a device fails to respond after a number 1648b8a9b1dSJustin T. Gibbs * of retries, or a bus rescan finds the device missing. 1658b8a9b1dSJustin T. Gibbs */ 1668b8a9b1dSJustin T. Gibbs struct cam_et { 1678b8a9b1dSJustin T. Gibbs TAILQ_HEAD(, cam_ed) ed_entries; 1688b8a9b1dSJustin T. Gibbs TAILQ_ENTRY(cam_et) links; 1698b8a9b1dSJustin T. Gibbs struct cam_eb *bus; 1708b8a9b1dSJustin T. Gibbs target_id_t target_id; 1718b8a9b1dSJustin T. Gibbs u_int32_t refcount; 1728b8a9b1dSJustin T. Gibbs u_int generation; 1738b8a9b1dSJustin T. Gibbs }; 1748b8a9b1dSJustin T. Gibbs 1758b8a9b1dSJustin T. Gibbs /* 1768b8a9b1dSJustin T. Gibbs * Each bus is represented by an EB (Existing Bus). These entries 1778b8a9b1dSJustin T. Gibbs * are created by calls to xpt_bus_register and deleted by calls to 1788b8a9b1dSJustin T. Gibbs * xpt_bus_deregister. 1798b8a9b1dSJustin T. Gibbs */ 1808b8a9b1dSJustin T. Gibbs struct cam_eb { 1818b8a9b1dSJustin T. Gibbs TAILQ_HEAD(, cam_et) et_entries; 1828b8a9b1dSJustin T. Gibbs TAILQ_ENTRY(cam_eb) links; 1838b8a9b1dSJustin T. Gibbs struct async_list asyncs; /* Async callback info for this B/T/L */ 1848b8a9b1dSJustin T. Gibbs path_id_t path_id; 1858b8a9b1dSJustin T. Gibbs struct cam_sim *sim; 1868b8a9b1dSJustin T. Gibbs u_int32_t flags; 1878b8a9b1dSJustin T. Gibbs #define CAM_EB_RUNQ_SCHEDULED 0x01 1888b8a9b1dSJustin T. Gibbs u_int generation; 1898b8a9b1dSJustin T. Gibbs }; 1908b8a9b1dSJustin T. Gibbs 1918b8a9b1dSJustin T. Gibbs struct cam_path { 1928b8a9b1dSJustin T. Gibbs struct cam_periph *periph; 1938b8a9b1dSJustin T. Gibbs struct cam_eb *bus; 1948b8a9b1dSJustin T. Gibbs struct cam_et *target; 1958b8a9b1dSJustin T. Gibbs struct cam_ed *device; 1968b8a9b1dSJustin T. Gibbs }; 1978b8a9b1dSJustin T. Gibbs 1988b8a9b1dSJustin T. Gibbs struct xpt_quirk_entry { 1998b8a9b1dSJustin T. Gibbs struct scsi_inquiry_pattern inq_pat; 2008b8a9b1dSJustin T. Gibbs u_int8_t quirks; 2018b8a9b1dSJustin T. Gibbs #define CAM_QUIRK_NOLUNS 0x01 2028b8a9b1dSJustin T. Gibbs #define CAM_QUIRK_NOSERIAL 0x02 2038b8a9b1dSJustin T. Gibbs u_int8_t mintags; 2048b8a9b1dSJustin T. Gibbs u_int8_t maxtags; 2058b8a9b1dSJustin T. Gibbs }; 2068b8a9b1dSJustin T. Gibbs 2078b8a9b1dSJustin T. Gibbs typedef enum { 2088b8a9b1dSJustin T. Gibbs XPT_FLAG_OPEN = 0x01 2098b8a9b1dSJustin T. Gibbs } xpt_flags; 2108b8a9b1dSJustin T. Gibbs 2118b8a9b1dSJustin T. Gibbs struct xpt_softc { 2128b8a9b1dSJustin T. Gibbs xpt_flags flags; 2138b8a9b1dSJustin T. Gibbs u_int32_t generation; 2148b8a9b1dSJustin T. Gibbs #ifdef DEVFS 2158b8a9b1dSJustin T. Gibbs void *xpt_devfs_token; 2168b8a9b1dSJustin T. Gibbs void *ctl_devfs_token; 2178b8a9b1dSJustin T. Gibbs #endif 2188b8a9b1dSJustin T. Gibbs }; 2198b8a9b1dSJustin T. Gibbs 2208b8a9b1dSJustin T. Gibbs static const char quantum[] = "QUANTUM"; 2218b8a9b1dSJustin T. Gibbs 2228b8a9b1dSJustin T. Gibbs static struct xpt_quirk_entry xpt_quirk_table[] = 2238b8a9b1dSJustin T. Gibbs { 2248b8a9b1dSJustin T. Gibbs { 2258b8a9b1dSJustin T. Gibbs /* Reports QUEUE FULL for temporary resource shortages */ 2268b8a9b1dSJustin T. Gibbs { T_DIRECT, SIP_MEDIA_FIXED, quantum, "XP39100?", "*" }, 2278b8a9b1dSJustin T. Gibbs /*quirks*/0, /*mintags*/24, /*maxtags*/32 2288b8a9b1dSJustin T. Gibbs }, 2298b8a9b1dSJustin T. Gibbs { 2308b8a9b1dSJustin T. Gibbs /* Reports QUEUE FULL for temporary resource shortages */ 2318b8a9b1dSJustin T. Gibbs { T_DIRECT, SIP_MEDIA_FIXED, quantum, "XP34550?", "*" }, 2328b8a9b1dSJustin T. Gibbs /*quirks*/0, /*mintags*/24, /*maxtags*/32 2338b8a9b1dSJustin T. Gibbs }, 2348b8a9b1dSJustin T. Gibbs { 2358b8a9b1dSJustin T. Gibbs /* Broken tagged queuing drive */ 2368b8a9b1dSJustin T. Gibbs { T_DIRECT, SIP_MEDIA_FIXED, "HP", "C372*", "*" }, 2378b8a9b1dSJustin T. Gibbs /*quirks*/0, /*mintags*/0, /*maxtags*/0 2388b8a9b1dSJustin T. Gibbs }, 2398b8a9b1dSJustin T. Gibbs { 2408b8a9b1dSJustin T. Gibbs /* Broken tagged queuing drive */ 2418b8a9b1dSJustin T. Gibbs { T_DIRECT, SIP_MEDIA_FIXED, "MICROP", "3391*", "x43h" }, 2428b8a9b1dSJustin T. Gibbs /*quirks*/0, /*mintags*/0, /*maxtags*/0 2438b8a9b1dSJustin T. Gibbs }, 2448b8a9b1dSJustin T. Gibbs { 2458b8a9b1dSJustin T. Gibbs /* Broken tagged queuing drive */ 2468b8a9b1dSJustin T. Gibbs { T_DIRECT, SIP_MEDIA_REMOVABLE, "iomega", "jaz*", "*" }, 2478b8a9b1dSJustin T. Gibbs /*quirks*/0, /*mintags*/0, /*maxtags*/0 2488b8a9b1dSJustin T. Gibbs }, 2498b8a9b1dSJustin T. Gibbs { 2508b8a9b1dSJustin T. Gibbs /* Doesn't understand EVP Serial Requests */ 2518b8a9b1dSJustin T. Gibbs { 2528b8a9b1dSJustin T. Gibbs T_CDROM, SIP_MEDIA_REMOVABLE, 2538b8a9b1dSJustin T. Gibbs "TOSHIBA", "CD-ROM XM-3401TA", "1094" 2548b8a9b1dSJustin T. Gibbs }, 2558b8a9b1dSJustin T. Gibbs CAM_QUIRK_NOSERIAL, /*mintags*/0, /*maxtags*/0 2568b8a9b1dSJustin T. Gibbs }, 2578b8a9b1dSJustin T. Gibbs { 2588b8a9b1dSJustin T. Gibbs /* 2598b8a9b1dSJustin T. Gibbs * Hack until multiple-luns are supported by 2608b8a9b1dSJustin T. Gibbs * the target mode code. 2618b8a9b1dSJustin T. Gibbs */ 2628b8a9b1dSJustin T. Gibbs { 2638b8a9b1dSJustin T. Gibbs T_PROCESSOR, SIP_MEDIA_REMOVABLE|SIP_MEDIA_FIXED, 2648b8a9b1dSJustin T. Gibbs "FreeBSD", "TM-PT", "*" 2658b8a9b1dSJustin T. Gibbs }, 2668b8a9b1dSJustin T. Gibbs CAM_QUIRK_NOLUNS, /*mintags*/0, /*maxtags*/0 2678b8a9b1dSJustin T. Gibbs }, 2688b8a9b1dSJustin T. Gibbs { 2698b8a9b1dSJustin T. Gibbs /* Really only one LUN */ 2708b8a9b1dSJustin T. Gibbs { 2718b8a9b1dSJustin T. Gibbs T_ENCLOSURE, SIP_MEDIA_FIXED, "SUN", "SENA*", "*" }, 2728b8a9b1dSJustin T. Gibbs CAM_QUIRK_NOLUNS, /*mintags*/0, /*maxtags*/0 2738b8a9b1dSJustin T. Gibbs }, 2748b8a9b1dSJustin T. Gibbs { 2758b8a9b1dSJustin T. Gibbs /* Default tagged queuing parameters for all devices */ 2768b8a9b1dSJustin T. Gibbs { 2778b8a9b1dSJustin T. Gibbs T_ANY, SIP_MEDIA_REMOVABLE|SIP_MEDIA_FIXED, 2788b8a9b1dSJustin T. Gibbs /*vendor*/"*", /*product*/"*", /*revision*/"*" 2798b8a9b1dSJustin T. Gibbs }, 2808b8a9b1dSJustin T. Gibbs /*quirks*/0, /*mintags*/2, /*maxtags*/64 2818b8a9b1dSJustin T. Gibbs }, 2828b8a9b1dSJustin T. Gibbs }; 2838b8a9b1dSJustin T. Gibbs typedef enum { 2848b8a9b1dSJustin T. Gibbs DM_RET_COPY = 0x01, 2858b8a9b1dSJustin T. Gibbs DM_RET_FLAG_MASK = 0x0f, 2868b8a9b1dSJustin T. Gibbs DM_RET_NONE = 0x00, 2878b8a9b1dSJustin T. Gibbs DM_RET_STOP = 0x10, 2888b8a9b1dSJustin T. Gibbs DM_RET_DESCEND = 0x20, 2898b8a9b1dSJustin T. Gibbs DM_RET_ERROR = 0x30, 2908b8a9b1dSJustin T. Gibbs DM_RET_ACTION_MASK = 0xf0 2918b8a9b1dSJustin T. Gibbs } dev_match_ret; 2928b8a9b1dSJustin T. Gibbs 2938b8a9b1dSJustin T. Gibbs typedef enum { 2948b8a9b1dSJustin T. Gibbs XPT_DEPTH_BUS, 2958b8a9b1dSJustin T. Gibbs XPT_DEPTH_TARGET, 2968b8a9b1dSJustin T. Gibbs XPT_DEPTH_DEVICE, 2978b8a9b1dSJustin T. Gibbs XPT_DEPTH_PERIPH 2988b8a9b1dSJustin T. Gibbs } xpt_traverse_depth; 2998b8a9b1dSJustin T. Gibbs 3008b8a9b1dSJustin T. Gibbs struct xpt_traverse_config { 3018b8a9b1dSJustin T. Gibbs xpt_traverse_depth depth; 3028b8a9b1dSJustin T. Gibbs void *tr_func; 3038b8a9b1dSJustin T. Gibbs void *tr_arg; 3048b8a9b1dSJustin T. Gibbs }; 3058b8a9b1dSJustin T. Gibbs 3068b8a9b1dSJustin T. Gibbs typedef int xpt_busfunc_t (struct cam_eb *bus, void *arg); 3078b8a9b1dSJustin T. Gibbs typedef int xpt_targetfunc_t (struct cam_et *target, void *arg); 3088b8a9b1dSJustin T. Gibbs typedef int xpt_devicefunc_t (struct cam_ed *device, void *arg); 3098b8a9b1dSJustin T. Gibbs typedef int xpt_periphfunc_t (struct cam_periph *periph, void *arg); 3108b8a9b1dSJustin T. Gibbs typedef int xpt_pdrvfunc_t (struct periph_driver **pdrv, void *arg); 3118b8a9b1dSJustin T. Gibbs 3128b8a9b1dSJustin T. Gibbs /* Transport layer configuration information */ 3138b8a9b1dSJustin T. Gibbs static struct xpt_softc xsoftc; 3148b8a9b1dSJustin T. Gibbs 3158b8a9b1dSJustin T. Gibbs /* Queues for our software interrupt handler */ 3168b8a9b1dSJustin T. Gibbs typedef TAILQ_HEAD(cam_isrq, ccb_hdr) cam_isrq_t; 3178b8a9b1dSJustin T. Gibbs static cam_isrq_t cam_bioq; 3188b8a9b1dSJustin T. Gibbs static cam_isrq_t cam_netq; 3198b8a9b1dSJustin T. Gibbs 3208b8a9b1dSJustin T. Gibbs /* "Pool" of inactive ccbs managed by xpt_alloc_ccb and xpt_free_ccb */ 3218b8a9b1dSJustin T. Gibbs SLIST_HEAD(,ccb_hdr) ccb_freeq; 3228b8a9b1dSJustin T. Gibbs static u_int xpt_max_ccbs; /* 3238b8a9b1dSJustin T. Gibbs * Maximum size of ccb pool. Modified as 3248b8a9b1dSJustin T. Gibbs * devices are added/removed or have their 3258b8a9b1dSJustin T. Gibbs * opening counts changed. 3268b8a9b1dSJustin T. Gibbs */ 3278b8a9b1dSJustin T. Gibbs static u_int xpt_ccb_count; /* Current count of allocated ccbs */ 3288b8a9b1dSJustin T. Gibbs 3298b8a9b1dSJustin T. Gibbs static struct cam_periph *xpt_periph; 3308b8a9b1dSJustin T. Gibbs 3318b8a9b1dSJustin T. Gibbs static periph_init_t xpt_periph_init; 3328b8a9b1dSJustin T. Gibbs 3338b8a9b1dSJustin T. Gibbs static periph_init_t probe_periph_init; 3348b8a9b1dSJustin T. Gibbs 3358b8a9b1dSJustin T. Gibbs static struct periph_driver xpt_driver = 3368b8a9b1dSJustin T. Gibbs { 3378b8a9b1dSJustin T. Gibbs xpt_periph_init, "xpt", 3388b8a9b1dSJustin T. Gibbs TAILQ_HEAD_INITIALIZER(xpt_driver.units) 3398b8a9b1dSJustin T. Gibbs }; 3408b8a9b1dSJustin T. Gibbs 3418b8a9b1dSJustin T. Gibbs static struct periph_driver probe_driver = 3428b8a9b1dSJustin T. Gibbs { 3438b8a9b1dSJustin T. Gibbs probe_periph_init, "probe", 3448b8a9b1dSJustin T. Gibbs TAILQ_HEAD_INITIALIZER(probe_driver.units) 3458b8a9b1dSJustin T. Gibbs }; 3468b8a9b1dSJustin T. Gibbs 3478b8a9b1dSJustin T. Gibbs DATA_SET(periphdriver_set, xpt_driver); 3488b8a9b1dSJustin T. Gibbs DATA_SET(periphdriver_set, probe_driver); 3498b8a9b1dSJustin T. Gibbs 3508b8a9b1dSJustin T. Gibbs #define XPT_CDEV_MAJOR 104 3518b8a9b1dSJustin T. Gibbs 3528b8a9b1dSJustin T. Gibbs static d_open_t xptopen; 3538b8a9b1dSJustin T. Gibbs static d_close_t xptclose; 3548b8a9b1dSJustin T. Gibbs static d_ioctl_t xptioctl; 3558b8a9b1dSJustin T. Gibbs 3568b8a9b1dSJustin T. Gibbs static struct cdevsw xpt_cdevsw = 3578b8a9b1dSJustin T. Gibbs { 3588b8a9b1dSJustin T. Gibbs /*d_open*/ xptopen, 3598b8a9b1dSJustin T. Gibbs /*d_close*/ xptclose, 3608b8a9b1dSJustin T. Gibbs /*d_read*/ noread, 3618b8a9b1dSJustin T. Gibbs /*d_write*/ nowrite, 3628b8a9b1dSJustin T. Gibbs /*d_ioctl*/ xptioctl, 3638b8a9b1dSJustin T. Gibbs /*d_stop*/ nostop, 3648b8a9b1dSJustin T. Gibbs /*d_reset*/ noreset, 3658b8a9b1dSJustin T. Gibbs /*d_devtotty*/ nodevtotty, 3668b8a9b1dSJustin T. Gibbs /*d_poll*/ NULL, 3678b8a9b1dSJustin T. Gibbs /*d_mmap*/ nommap, 3688b8a9b1dSJustin T. Gibbs /*d_strategy*/ nostrategy, 3698b8a9b1dSJustin T. Gibbs /*d_name*/ "xpt", 3708b8a9b1dSJustin T. Gibbs /*d_spare*/ NULL, 3718b8a9b1dSJustin T. Gibbs /*d_maj*/ -1, 3728b8a9b1dSJustin T. Gibbs /*d_dump*/ nodump, 3738b8a9b1dSJustin T. Gibbs /*d_psize*/ nopsize, 3748b8a9b1dSJustin T. Gibbs /*d_flags*/ 0, 3758b8a9b1dSJustin T. Gibbs /*d_maxio*/ 0, 3768b8a9b1dSJustin T. Gibbs /*b_maj*/ -1 3778b8a9b1dSJustin T. Gibbs }; 3788b8a9b1dSJustin T. Gibbs 3798b8a9b1dSJustin T. Gibbs static struct intr_config_hook *xpt_config_hook; 3808b8a9b1dSJustin T. Gibbs 3818b8a9b1dSJustin T. Gibbs /* Registered busses */ 3828b8a9b1dSJustin T. Gibbs TAILQ_HEAD(,cam_eb) xpt_busses; 3838b8a9b1dSJustin T. Gibbs static u_int bus_generation; 3848b8a9b1dSJustin T. Gibbs 3858b8a9b1dSJustin T. Gibbs /* Storage for debugging datastructures */ 3868b8a9b1dSJustin T. Gibbs #ifdef CAMDEBUG 3878b8a9b1dSJustin T. Gibbs struct cam_path *cam_dpath; 3888b8a9b1dSJustin T. Gibbs u_int32_t cam_dflags; 3898b8a9b1dSJustin T. Gibbs #endif 3908b8a9b1dSJustin T. Gibbs 3918b8a9b1dSJustin T. Gibbs #if defined(CAM_DEBUG_FLAGS) && !defined(CAMDEBUG) 3928b8a9b1dSJustin T. Gibbs #error "You must have options CAMDEBUG to use options CAM_DEBUG_FLAGS" 3938b8a9b1dSJustin T. Gibbs #endif 3948b8a9b1dSJustin T. Gibbs 3958b8a9b1dSJustin T. Gibbs /* 3968b8a9b1dSJustin T. Gibbs * In order to enable the CAM_DEBUG_* options, the user must have CAMDEBUG 3978b8a9b1dSJustin T. Gibbs * enabled. Also, the user must have either none, or all of CAM_DEBUG_BUS, 3988b8a9b1dSJustin T. Gibbs * CAM_DEBUG_TARGET, and CAM_DEBUG_LUN specified. 3998b8a9b1dSJustin T. Gibbs */ 4008b8a9b1dSJustin T. Gibbs #if defined(CAM_DEBUG_BUS) || defined(CAM_DEBUG_TARGET) \ 4018b8a9b1dSJustin T. Gibbs || defined(CAM_DEBUG_LUN) 4028b8a9b1dSJustin T. Gibbs #ifdef CAMDEBUG 4038b8a9b1dSJustin T. Gibbs #if !defined(CAM_DEBUG_BUS) || !defined(CAM_DEBUG_TARGET) \ 4048b8a9b1dSJustin T. Gibbs || !defined(CAM_DEBUG_LUN) 4058b8a9b1dSJustin T. Gibbs #error "You must define all or none of CAM_DEBUG_BUS, CAM_DEBUG_TARGET \ 4068b8a9b1dSJustin T. Gibbs and CAM_DEBUG_LUN" 4078b8a9b1dSJustin T. Gibbs #endif /* !CAM_DEBUG_BUS || !CAM_DEBUG_TARGET || !CAM_DEBUG_LUN */ 4088b8a9b1dSJustin T. Gibbs #else /* !CAMDEBUG */ 4098b8a9b1dSJustin T. Gibbs #error "You must use options CAMDEBUG if you use the CAM_DEBUG_* options" 4108b8a9b1dSJustin T. Gibbs #endif /* CAMDEBUG */ 4118b8a9b1dSJustin T. Gibbs #endif /* CAM_DEBUG_BUS || CAM_DEBUG_TARGET || CAM_DEBUG_LUN */ 4128b8a9b1dSJustin T. Gibbs 4138b8a9b1dSJustin T. Gibbs /* Forward declarations for private functions */ 4148b8a9b1dSJustin T. Gibbs void xpt_init(void); 4158b8a9b1dSJustin T. Gibbs 4168b8a9b1dSJustin T. Gibbs static cam_status xpt_compile_path(struct cam_path *new_path, 4178b8a9b1dSJustin T. Gibbs struct cam_periph *perph, 4188b8a9b1dSJustin T. Gibbs path_id_t path_id, 4198b8a9b1dSJustin T. Gibbs target_id_t target_id, 4208b8a9b1dSJustin T. Gibbs lun_id_t lun_id); 4218b8a9b1dSJustin T. Gibbs 4228b8a9b1dSJustin T. Gibbs static void xpt_release_path(struct cam_path *path); 4238b8a9b1dSJustin T. Gibbs 4248b8a9b1dSJustin T. Gibbs static void xpt_async_bcast(struct async_list *async_head, 4258b8a9b1dSJustin T. Gibbs u_int32_t async_code, 4268b8a9b1dSJustin T. Gibbs struct cam_path *path, 4278b8a9b1dSJustin T. Gibbs void *async_arg); 4288b8a9b1dSJustin T. Gibbs static int xptnextfreebus(path_id_t startbus); 4298b8a9b1dSJustin T. Gibbs static int xptpathid(const char *sim_name, int sim_unit, int sim_bus, 4308b8a9b1dSJustin T. Gibbs path_id_t *nextpath); 4318b8a9b1dSJustin T. Gibbs static union ccb *xpt_get_ccb(struct cam_ed *device); 4328b8a9b1dSJustin T. Gibbs static int xpt_schedule_dev(struct camq *queue, cam_pinfo *dev_pinfo, 4338b8a9b1dSJustin T. Gibbs u_int32_t new_priority); 4348b8a9b1dSJustin T. Gibbs static void xpt_run_dev_allocq(struct cam_eb *bus); 4358b8a9b1dSJustin T. Gibbs static void xpt_run_dev_sendq(struct cam_eb *bus); 4368b8a9b1dSJustin T. Gibbs static timeout_t xpt_release_devq_timeout; 4378b8a9b1dSJustin T. Gibbs static timeout_t xpt_release_simq_timeout; 4388b8a9b1dSJustin T. Gibbs static struct cam_et* 4398b8a9b1dSJustin T. Gibbs xpt_alloc_target(struct cam_eb *bus, target_id_t target_id); 4408b8a9b1dSJustin T. Gibbs static void xpt_release_target(struct cam_eb *bus, struct cam_et *target); 4418b8a9b1dSJustin T. Gibbs static struct cam_ed* 4428b8a9b1dSJustin T. Gibbs xpt_alloc_device(struct cam_eb *bus, struct cam_et *target, 4438b8a9b1dSJustin T. Gibbs lun_id_t lun_id); 4448b8a9b1dSJustin T. Gibbs static void xpt_release_device(struct cam_eb *bus, struct cam_et *target, 4458b8a9b1dSJustin T. Gibbs struct cam_ed *device); 4468b8a9b1dSJustin T. Gibbs static u_int32_t xpt_dev_ccbq_resize(struct cam_path *path, int newopenings); 4478b8a9b1dSJustin T. Gibbs static struct cam_eb* 4488b8a9b1dSJustin T. Gibbs xpt_find_bus(path_id_t path_id); 4498b8a9b1dSJustin T. Gibbs static struct cam_et* 4508b8a9b1dSJustin T. Gibbs xpt_find_target(struct cam_eb *bus, target_id_t target_id); 4518b8a9b1dSJustin T. Gibbs static struct cam_ed* 4528b8a9b1dSJustin T. Gibbs xpt_find_device(struct cam_et *target, lun_id_t lun_id); 4538b8a9b1dSJustin T. Gibbs static void xpt_scan_bus(struct cam_periph *periph, union ccb *ccb); 4548b8a9b1dSJustin T. Gibbs static void xpt_scan_lun(struct cam_periph *periph, 4558b8a9b1dSJustin T. Gibbs struct cam_path *path, cam_flags flags, 4568b8a9b1dSJustin T. Gibbs union ccb *ccb); 4578b8a9b1dSJustin T. Gibbs static void xptscandone(struct cam_periph *periph, union ccb *done_ccb); 4588b8a9b1dSJustin T. Gibbs static xpt_busfunc_t xptconfigbuscountfunc; 4598b8a9b1dSJustin T. Gibbs static xpt_busfunc_t xptconfigfunc; 4608b8a9b1dSJustin T. Gibbs static void xpt_config(void *arg); 4618b8a9b1dSJustin T. Gibbs static xpt_devicefunc_t xptfinishconfigfunc; 4628b8a9b1dSJustin T. Gibbs static xpt_devicefunc_t xptpassannouncefunc; 4638b8a9b1dSJustin T. Gibbs static void xpt_finishconfig(struct cam_periph *periph, union ccb *ccb); 4648b8a9b1dSJustin T. Gibbs static void xptaction(struct cam_sim *sim, union ccb *work_ccb); 4658b8a9b1dSJustin T. Gibbs void swi_camnet(void); 4668b8a9b1dSJustin T. Gibbs void swi_cambio(void); 4678b8a9b1dSJustin T. Gibbs static void camisr(cam_isrq_t *queue); 4688b8a9b1dSJustin T. Gibbs #if 0 4698b8a9b1dSJustin T. Gibbs static void xptstart(struct cam_periph *periph, union ccb *work_ccb); 4708b8a9b1dSJustin T. Gibbs static void xptasync(struct cam_periph *periph, 4718b8a9b1dSJustin T. Gibbs u_int32_t code, cam_path *path); 4728b8a9b1dSJustin T. Gibbs #endif 4738b8a9b1dSJustin T. Gibbs static dev_match_ret xptbusmatch(struct dev_match_pattern *patterns, 4748b8a9b1dSJustin T. Gibbs int num_patterns, struct cam_eb *bus); 4758b8a9b1dSJustin T. Gibbs static dev_match_ret xptdevicematch(struct dev_match_pattern *patterns, 4768b8a9b1dSJustin T. Gibbs int num_patterns, struct cam_ed *device); 4778b8a9b1dSJustin T. Gibbs static dev_match_ret xptperiphmatch(struct dev_match_pattern *patterns, 4788b8a9b1dSJustin T. Gibbs int num_patterns, 4798b8a9b1dSJustin T. Gibbs struct cam_periph *periph); 4808b8a9b1dSJustin T. Gibbs static xpt_busfunc_t xptedtbusfunc; 4818b8a9b1dSJustin T. Gibbs static xpt_targetfunc_t xptedttargetfunc; 4828b8a9b1dSJustin T. Gibbs static xpt_devicefunc_t xptedtdevicefunc; 4838b8a9b1dSJustin T. Gibbs static xpt_periphfunc_t xptedtperiphfunc; 4848b8a9b1dSJustin T. Gibbs static xpt_pdrvfunc_t xptplistpdrvfunc; 4858b8a9b1dSJustin T. Gibbs static xpt_periphfunc_t xptplistperiphfunc; 4868b8a9b1dSJustin T. Gibbs static int xptedtmatch(struct ccb_dev_match *cdm); 4878b8a9b1dSJustin T. Gibbs static int xptperiphlistmatch(struct ccb_dev_match *cdm); 4888b8a9b1dSJustin T. Gibbs static int xptbustraverse(struct cam_eb *start_bus, 4898b8a9b1dSJustin T. Gibbs xpt_busfunc_t *tr_func, void *arg); 4908b8a9b1dSJustin T. Gibbs static int xpttargettraverse(struct cam_eb *bus, 4918b8a9b1dSJustin T. Gibbs struct cam_et *start_target, 4928b8a9b1dSJustin T. Gibbs xpt_targetfunc_t *tr_func, void *arg); 4938b8a9b1dSJustin T. Gibbs static int xptdevicetraverse(struct cam_et *target, 4948b8a9b1dSJustin T. Gibbs struct cam_ed *start_device, 4958b8a9b1dSJustin T. Gibbs xpt_devicefunc_t *tr_func, void *arg); 4968b8a9b1dSJustin T. Gibbs static int xptperiphtraverse(struct cam_ed *device, 4978b8a9b1dSJustin T. Gibbs struct cam_periph *start_periph, 4988b8a9b1dSJustin T. Gibbs xpt_periphfunc_t *tr_func, void *arg); 4998b8a9b1dSJustin T. Gibbs static int xptpdrvtraverse(struct periph_driver **start_pdrv, 5008b8a9b1dSJustin T. Gibbs xpt_pdrvfunc_t *tr_func, void *arg); 5018b8a9b1dSJustin T. Gibbs static int xptpdperiphtraverse(struct periph_driver **pdrv, 5028b8a9b1dSJustin T. Gibbs struct cam_periph *start_periph, 5038b8a9b1dSJustin T. Gibbs xpt_periphfunc_t *tr_func, 5048b8a9b1dSJustin T. Gibbs void *arg); 5058b8a9b1dSJustin T. Gibbs static xpt_busfunc_t xptdefbusfunc; 5068b8a9b1dSJustin T. Gibbs static xpt_targetfunc_t xptdeftargetfunc; 5078b8a9b1dSJustin T. Gibbs static xpt_devicefunc_t xptdefdevicefunc; 5088b8a9b1dSJustin T. Gibbs static xpt_periphfunc_t xptdefperiphfunc; 5098b8a9b1dSJustin T. Gibbs static int xpt_for_all_busses(xpt_busfunc_t *tr_func, void *arg); 5108b8a9b1dSJustin T. Gibbs static int xpt_for_all_targets(xpt_targetfunc_t *tr_func, 5118b8a9b1dSJustin T. Gibbs void *arg); 5128b8a9b1dSJustin T. Gibbs static int xpt_for_all_devices(xpt_devicefunc_t *tr_func, 5138b8a9b1dSJustin T. Gibbs void *arg); 5148b8a9b1dSJustin T. Gibbs static int xpt_for_all_periphs(xpt_periphfunc_t *tr_func, 5158b8a9b1dSJustin T. Gibbs void *arg); 5168b8a9b1dSJustin T. Gibbs static xpt_devicefunc_t xptsetasyncfunc; 5178b8a9b1dSJustin T. Gibbs static xpt_busfunc_t xptsetasyncbusfunc; 5188b8a9b1dSJustin T. Gibbs static cam_status xptregister(struct cam_periph *periph, 5198b8a9b1dSJustin T. Gibbs void *arg); 5208b8a9b1dSJustin T. Gibbs static cam_status proberegister(struct cam_periph *periph, 5218b8a9b1dSJustin T. Gibbs void *arg); 5228b8a9b1dSJustin T. Gibbs static void probeschedule(struct cam_periph *probe_periph); 5238b8a9b1dSJustin T. Gibbs static void probestart(struct cam_periph *periph, union ccb *start_ccb); 5248b8a9b1dSJustin T. Gibbs static void probedone(struct cam_periph *periph, union ccb *done_ccb); 5258b8a9b1dSJustin T. Gibbs static void probecleanup(struct cam_periph *periph); 5268b8a9b1dSJustin T. Gibbs static void xpt_find_quirk(struct cam_ed *device); 5278b8a9b1dSJustin T. Gibbs static void xpt_set_transfer_settings(struct ccb_trans_settings *cts, 5288b8a9b1dSJustin T. Gibbs int async_update); 5298b8a9b1dSJustin T. Gibbs static __inline int xpt_schedule_dev_allocq(struct cam_eb *bus, 5308b8a9b1dSJustin T. Gibbs struct cam_ed *dev); 5318b8a9b1dSJustin T. Gibbs static __inline int xpt_schedule_dev_sendq(struct cam_eb *bus, 5328b8a9b1dSJustin T. Gibbs struct cam_ed *dev); 5338b8a9b1dSJustin T. Gibbs static __inline int periph_is_queued(struct cam_periph *periph); 5348b8a9b1dSJustin T. Gibbs static __inline int device_is_alloc_queued(struct cam_ed *device); 5358b8a9b1dSJustin T. Gibbs static __inline int device_is_send_queued(struct cam_ed *device); 5368b8a9b1dSJustin T. Gibbs static __inline int dev_allocq_is_runnable(struct cam_devq *devq); 5378b8a9b1dSJustin T. Gibbs 5388b8a9b1dSJustin T. Gibbs static __inline int 5398b8a9b1dSJustin T. Gibbs xpt_schedule_dev_allocq(struct cam_eb *bus, struct cam_ed *dev) 5408b8a9b1dSJustin T. Gibbs { 5418b8a9b1dSJustin T. Gibbs int retval; 5428b8a9b1dSJustin T. Gibbs 5438b8a9b1dSJustin T. Gibbs if (dev->ccbq.devq_openings > 0) { 5448b8a9b1dSJustin T. Gibbs if ((dev->flags & CAM_DEV_RESIZE_QUEUE_NEEDED) != 0) { 5458b8a9b1dSJustin T. Gibbs cam_ccbq_resize(&dev->ccbq, 5468b8a9b1dSJustin T. Gibbs dev->ccbq.dev_openings 5478b8a9b1dSJustin T. Gibbs + dev->ccbq.dev_active); 5488b8a9b1dSJustin T. Gibbs dev->flags &= ~CAM_DEV_RESIZE_QUEUE_NEEDED; 5498b8a9b1dSJustin T. Gibbs } 5508b8a9b1dSJustin T. Gibbs retval = xpt_schedule_dev(&bus->sim->devq->alloc_queue, 5518b8a9b1dSJustin T. Gibbs &dev->alloc_ccb_entry.pinfo, 5528b8a9b1dSJustin T. Gibbs dev->drvq.queue_array[0]->priority); 5538b8a9b1dSJustin T. Gibbs } else { 5548b8a9b1dSJustin T. Gibbs retval = 0; 5558b8a9b1dSJustin T. Gibbs } 5568b8a9b1dSJustin T. Gibbs 5578b8a9b1dSJustin T. Gibbs return (retval); 5588b8a9b1dSJustin T. Gibbs } 5598b8a9b1dSJustin T. Gibbs 5608b8a9b1dSJustin T. Gibbs static __inline int 5618b8a9b1dSJustin T. Gibbs xpt_schedule_dev_sendq(struct cam_eb *bus, struct cam_ed *dev) 5628b8a9b1dSJustin T. Gibbs { 5638b8a9b1dSJustin T. Gibbs int retval; 5648b8a9b1dSJustin T. Gibbs 5658b8a9b1dSJustin T. Gibbs if (dev->ccbq.dev_openings > 0) { 5668b8a9b1dSJustin T. Gibbs retval = xpt_schedule_dev(&bus->sim->devq->send_queue, 5678b8a9b1dSJustin T. Gibbs &dev->send_ccb_entry.pinfo, 5688b8a9b1dSJustin T. Gibbs dev->ccbq.queue.queue_array[0]->priority); 5698b8a9b1dSJustin T. Gibbs } else { 5708b8a9b1dSJustin T. Gibbs retval = 0; 5718b8a9b1dSJustin T. Gibbs } 5728b8a9b1dSJustin T. Gibbs return (retval); 5738b8a9b1dSJustin T. Gibbs } 5748b8a9b1dSJustin T. Gibbs 5758b8a9b1dSJustin T. Gibbs static __inline int 5768b8a9b1dSJustin T. Gibbs periph_is_queued(struct cam_periph *periph) 5778b8a9b1dSJustin T. Gibbs { 5788b8a9b1dSJustin T. Gibbs return (periph->pinfo.index != CAM_UNQUEUED_INDEX); 5798b8a9b1dSJustin T. Gibbs } 5808b8a9b1dSJustin T. Gibbs 5818b8a9b1dSJustin T. Gibbs static __inline int 5828b8a9b1dSJustin T. Gibbs device_is_alloc_queued(struct cam_ed *device) 5838b8a9b1dSJustin T. Gibbs { 5848b8a9b1dSJustin T. Gibbs return (device->alloc_ccb_entry.pinfo.index != CAM_UNQUEUED_INDEX); 5858b8a9b1dSJustin T. Gibbs } 5868b8a9b1dSJustin T. Gibbs 5878b8a9b1dSJustin T. Gibbs static __inline int 5888b8a9b1dSJustin T. Gibbs device_is_send_queued(struct cam_ed *device) 5898b8a9b1dSJustin T. Gibbs { 5908b8a9b1dSJustin T. Gibbs return (device->send_ccb_entry.pinfo.index != CAM_UNQUEUED_INDEX); 5918b8a9b1dSJustin T. Gibbs } 5928b8a9b1dSJustin T. Gibbs 5938b8a9b1dSJustin T. Gibbs static __inline int 5948b8a9b1dSJustin T. Gibbs dev_allocq_is_runnable(struct cam_devq *devq) 5958b8a9b1dSJustin T. Gibbs { 5968b8a9b1dSJustin T. Gibbs /* 5978b8a9b1dSJustin T. Gibbs * Have work to do. 5988b8a9b1dSJustin T. Gibbs * Have space to do more work. 5998b8a9b1dSJustin T. Gibbs * Allowed to do work. 6008b8a9b1dSJustin T. Gibbs */ 6018b8a9b1dSJustin T. Gibbs return ((devq->alloc_queue.qfrozen_cnt == 0) 6028b8a9b1dSJustin T. Gibbs && (devq->alloc_queue.entries > 0) 6038b8a9b1dSJustin T. Gibbs && (devq->alloc_openings > 0)); 6048b8a9b1dSJustin T. Gibbs } 6058b8a9b1dSJustin T. Gibbs 6068b8a9b1dSJustin T. Gibbs static void 6078b8a9b1dSJustin T. Gibbs xpt_periph_init() 6088b8a9b1dSJustin T. Gibbs { 6098b8a9b1dSJustin T. Gibbs dev_t dev; 6108b8a9b1dSJustin T. Gibbs 6118b8a9b1dSJustin T. Gibbs dev = makedev(XPT_CDEV_MAJOR, 0); 6128b8a9b1dSJustin T. Gibbs cdevsw_add(&dev, &xpt_cdevsw, NULL); 6138b8a9b1dSJustin T. Gibbs } 6148b8a9b1dSJustin T. Gibbs 6158b8a9b1dSJustin T. Gibbs static void 6168b8a9b1dSJustin T. Gibbs probe_periph_init() 6178b8a9b1dSJustin T. Gibbs { 6188b8a9b1dSJustin T. Gibbs } 6198b8a9b1dSJustin T. Gibbs 6208b8a9b1dSJustin T. Gibbs 6218b8a9b1dSJustin T. Gibbs static void 6228b8a9b1dSJustin T. Gibbs xptdone(struct cam_periph *periph, union ccb *done_ccb) 6238b8a9b1dSJustin T. Gibbs { 6248b8a9b1dSJustin T. Gibbs /* Caller will release the CCB */ 6258b8a9b1dSJustin T. Gibbs wakeup(&done_ccb->ccb_h.cbfcnp); 6268b8a9b1dSJustin T. Gibbs } 6278b8a9b1dSJustin T. Gibbs 6288b8a9b1dSJustin T. Gibbs static int 6298b8a9b1dSJustin T. Gibbs xptopen(dev_t dev, int flags, int fmt, struct proc *p) 6308b8a9b1dSJustin T. Gibbs { 6318b8a9b1dSJustin T. Gibbs int unit; 6328b8a9b1dSJustin T. Gibbs 6338b8a9b1dSJustin T. Gibbs unit = minor(dev) & 0xff; 6348b8a9b1dSJustin T. Gibbs 6358b8a9b1dSJustin T. Gibbs /* 63666a0780eSKenneth D. Merry * Only allow read-write access. 63766a0780eSKenneth D. Merry */ 63866a0780eSKenneth D. Merry if (((flags & FWRITE) == 0) || ((flags & FREAD) == 0)) 63966a0780eSKenneth D. Merry return(EPERM); 64066a0780eSKenneth D. Merry 64166a0780eSKenneth D. Merry /* 6428b8a9b1dSJustin T. Gibbs * We don't allow nonblocking access. 6438b8a9b1dSJustin T. Gibbs */ 6448b8a9b1dSJustin T. Gibbs if ((flags & O_NONBLOCK) != 0) { 6458b8a9b1dSJustin T. Gibbs printf("xpt%d: can't do nonblocking accesss\n", unit); 6468b8a9b1dSJustin T. Gibbs return(ENODEV); 6478b8a9b1dSJustin T. Gibbs } 6488b8a9b1dSJustin T. Gibbs 6498b8a9b1dSJustin T. Gibbs /* 6508b8a9b1dSJustin T. Gibbs * We only have one transport layer right now. If someone accesses 6518b8a9b1dSJustin T. Gibbs * us via something other than minor number 1, point out their 6528b8a9b1dSJustin T. Gibbs * mistake. 6538b8a9b1dSJustin T. Gibbs */ 6548b8a9b1dSJustin T. Gibbs if (unit != 0) { 6558b8a9b1dSJustin T. Gibbs printf("xptopen: got invalid xpt unit %d\n", unit); 6568b8a9b1dSJustin T. Gibbs return(ENXIO); 6578b8a9b1dSJustin T. Gibbs } 6588b8a9b1dSJustin T. Gibbs 6598b8a9b1dSJustin T. Gibbs /* Mark ourselves open */ 6608b8a9b1dSJustin T. Gibbs xsoftc.flags |= XPT_FLAG_OPEN; 6618b8a9b1dSJustin T. Gibbs 6628b8a9b1dSJustin T. Gibbs return(0); 6638b8a9b1dSJustin T. Gibbs } 6648b8a9b1dSJustin T. Gibbs 6658b8a9b1dSJustin T. Gibbs static int 6668b8a9b1dSJustin T. Gibbs xptclose(dev_t dev, int flag, int fmt, struct proc *p) 6678b8a9b1dSJustin T. Gibbs { 6688b8a9b1dSJustin T. Gibbs int unit; 6698b8a9b1dSJustin T. Gibbs 6708b8a9b1dSJustin T. Gibbs unit = minor(dev) & 0xff; 6718b8a9b1dSJustin T. Gibbs 6728b8a9b1dSJustin T. Gibbs /* 6738b8a9b1dSJustin T. Gibbs * We only have one transport layer right now. If someone accesses 6748b8a9b1dSJustin T. Gibbs * us via something other than minor number 1, point out their 6758b8a9b1dSJustin T. Gibbs * mistake. 6768b8a9b1dSJustin T. Gibbs */ 6778b8a9b1dSJustin T. Gibbs if (unit != 0) { 6788b8a9b1dSJustin T. Gibbs printf("xptclose: got invalid xpt unit %d\n", unit); 6798b8a9b1dSJustin T. Gibbs return(ENXIO); 6808b8a9b1dSJustin T. Gibbs } 6818b8a9b1dSJustin T. Gibbs 6828b8a9b1dSJustin T. Gibbs /* Mark ourselves closed */ 6838b8a9b1dSJustin T. Gibbs xsoftc.flags &= ~XPT_FLAG_OPEN; 6848b8a9b1dSJustin T. Gibbs 6858b8a9b1dSJustin T. Gibbs return(0); 6868b8a9b1dSJustin T. Gibbs } 6878b8a9b1dSJustin T. Gibbs 6888b8a9b1dSJustin T. Gibbs static int 6898b8a9b1dSJustin T. Gibbs xptioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p) 6908b8a9b1dSJustin T. Gibbs { 6918b8a9b1dSJustin T. Gibbs int unit, error; 6928b8a9b1dSJustin T. Gibbs 6938b8a9b1dSJustin T. Gibbs error = 0; 6948b8a9b1dSJustin T. Gibbs unit = minor(dev) & 0xff; 6958b8a9b1dSJustin T. Gibbs 6968b8a9b1dSJustin T. Gibbs /* 6978b8a9b1dSJustin T. Gibbs * We only have one transport layer right now. If someone accesses 6988b8a9b1dSJustin T. Gibbs * us via something other than minor number 1, point out their 6998b8a9b1dSJustin T. Gibbs * mistake. 7008b8a9b1dSJustin T. Gibbs */ 7018b8a9b1dSJustin T. Gibbs if (unit != 0) { 7028b8a9b1dSJustin T. Gibbs printf("xptioctl: got invalid xpt unit %d\n", unit); 7038b8a9b1dSJustin T. Gibbs return(ENXIO); 7048b8a9b1dSJustin T. Gibbs } 7058b8a9b1dSJustin T. Gibbs 7068b8a9b1dSJustin T. Gibbs switch(cmd) { 7078b8a9b1dSJustin T. Gibbs /* 7088b8a9b1dSJustin T. Gibbs * For the transport layer CAMIOCOMMAND ioctl, we really only want 7098b8a9b1dSJustin T. Gibbs * to accept CCB types that don't quite make sense to send through a 7108b8a9b1dSJustin T. Gibbs * passthrough driver. 7118b8a9b1dSJustin T. Gibbs */ 7128b8a9b1dSJustin T. Gibbs case CAMIOCOMMAND: { 7138b8a9b1dSJustin T. Gibbs union ccb *ccb; 7148b8a9b1dSJustin T. Gibbs union ccb *inccb; 7158b8a9b1dSJustin T. Gibbs 7168b8a9b1dSJustin T. Gibbs inccb = (union ccb *)addr; 7178b8a9b1dSJustin T. Gibbs 7188b8a9b1dSJustin T. Gibbs switch(inccb->ccb_h.func_code) { 7198b8a9b1dSJustin T. Gibbs case XPT_SCAN_BUS: 7208b8a9b1dSJustin T. Gibbs case XPT_RESET_BUS: 7218b8a9b1dSJustin T. Gibbs if ((inccb->ccb_h.target_id != CAM_TARGET_WILDCARD) 7228b8a9b1dSJustin T. Gibbs || (inccb->ccb_h.target_lun != CAM_LUN_WILDCARD)) { 7238b8a9b1dSJustin T. Gibbs error = EINVAL; 7248b8a9b1dSJustin T. Gibbs break; 7258b8a9b1dSJustin T. Gibbs } 7268b8a9b1dSJustin T. Gibbs /* FALLTHROUGH */ 7278b8a9b1dSJustin T. Gibbs case XPT_SCAN_LUN: 7288b8a9b1dSJustin T. Gibbs case XPT_ENG_INQ: /* XXX not implemented yet */ 7298b8a9b1dSJustin T. Gibbs case XPT_ENG_EXEC: 7308b8a9b1dSJustin T. Gibbs 7318b8a9b1dSJustin T. Gibbs ccb = xpt_alloc_ccb(); 7328b8a9b1dSJustin T. Gibbs 7338b8a9b1dSJustin T. Gibbs /* 7348b8a9b1dSJustin T. Gibbs * Create a path using the bus, target, and lun the 7358b8a9b1dSJustin T. Gibbs * user passed in. 7368b8a9b1dSJustin T. Gibbs */ 7378b8a9b1dSJustin T. Gibbs if (xpt_create_path(&ccb->ccb_h.path, xpt_periph, 7388b8a9b1dSJustin T. Gibbs inccb->ccb_h.path_id, 7398b8a9b1dSJustin T. Gibbs inccb->ccb_h.target_id, 7408b8a9b1dSJustin T. Gibbs inccb->ccb_h.target_lun) != 7418b8a9b1dSJustin T. Gibbs CAM_REQ_CMP){ 7428b8a9b1dSJustin T. Gibbs error = EINVAL; 7438b8a9b1dSJustin T. Gibbs xpt_free_ccb(ccb); 7448b8a9b1dSJustin T. Gibbs break; 7458b8a9b1dSJustin T. Gibbs } 7468b8a9b1dSJustin T. Gibbs /* Ensure all of our fields are correct */ 7478b8a9b1dSJustin T. Gibbs xpt_setup_ccb(&ccb->ccb_h, ccb->ccb_h.path, 7488b8a9b1dSJustin T. Gibbs inccb->ccb_h.pinfo.priority); 7498b8a9b1dSJustin T. Gibbs xpt_merge_ccb(ccb, inccb); 7508b8a9b1dSJustin T. Gibbs ccb->ccb_h.cbfcnp = xptdone; 7518b8a9b1dSJustin T. Gibbs cam_periph_runccb(ccb, NULL, 0, 0, NULL); 7528b8a9b1dSJustin T. Gibbs bcopy(ccb, inccb, sizeof(union ccb)); 7538b8a9b1dSJustin T. Gibbs xpt_free_path(ccb->ccb_h.path); 7548b8a9b1dSJustin T. Gibbs xpt_free_ccb(ccb); 7558b8a9b1dSJustin T. Gibbs break; 7568b8a9b1dSJustin T. Gibbs 7578b8a9b1dSJustin T. Gibbs case XPT_DEBUG: { 7588b8a9b1dSJustin T. Gibbs union ccb ccb; 7598b8a9b1dSJustin T. Gibbs 7608b8a9b1dSJustin T. Gibbs /* 7618b8a9b1dSJustin T. Gibbs * This is an immedaite CCB, so it's okay to 7628b8a9b1dSJustin T. Gibbs * allocate it on the stack. 7638b8a9b1dSJustin T. Gibbs */ 7648b8a9b1dSJustin T. Gibbs 7658b8a9b1dSJustin T. Gibbs /* 7668b8a9b1dSJustin T. Gibbs * Create a path using the bus, target, and lun the 7678b8a9b1dSJustin T. Gibbs * user passed in. 7688b8a9b1dSJustin T. Gibbs */ 7698b8a9b1dSJustin T. Gibbs if (xpt_create_path(&ccb.ccb_h.path, xpt_periph, 7708b8a9b1dSJustin T. Gibbs inccb->ccb_h.path_id, 7718b8a9b1dSJustin T. Gibbs inccb->ccb_h.target_id, 7728b8a9b1dSJustin T. Gibbs inccb->ccb_h.target_lun) != 7738b8a9b1dSJustin T. Gibbs CAM_REQ_CMP){ 7748b8a9b1dSJustin T. Gibbs error = EINVAL; 7758b8a9b1dSJustin T. Gibbs break; 7768b8a9b1dSJustin T. Gibbs } 7778b8a9b1dSJustin T. Gibbs /* Ensure all of our fields are correct */ 7788b8a9b1dSJustin T. Gibbs xpt_setup_ccb(&ccb.ccb_h, ccb.ccb_h.path, 7798b8a9b1dSJustin T. Gibbs inccb->ccb_h.pinfo.priority); 7808b8a9b1dSJustin T. Gibbs xpt_merge_ccb(&ccb, inccb); 7818b8a9b1dSJustin T. Gibbs ccb.ccb_h.cbfcnp = xptdone; 7828b8a9b1dSJustin T. Gibbs xpt_action(&ccb); 7838b8a9b1dSJustin T. Gibbs bcopy(&ccb, inccb, sizeof(union ccb)); 7848b8a9b1dSJustin T. Gibbs xpt_free_path(ccb.ccb_h.path); 7858b8a9b1dSJustin T. Gibbs break; 7868b8a9b1dSJustin T. Gibbs 7878b8a9b1dSJustin T. Gibbs } 7888b8a9b1dSJustin T. Gibbs case XPT_DEV_MATCH: { 7898b8a9b1dSJustin T. Gibbs struct cam_periph_map_info mapinfo; 7908b8a9b1dSJustin T. Gibbs 7918b8a9b1dSJustin T. Gibbs /* 7928b8a9b1dSJustin T. Gibbs * We can't deal with physical addresses for this 7938b8a9b1dSJustin T. Gibbs * type of transaction. 7948b8a9b1dSJustin T. Gibbs */ 7958b8a9b1dSJustin T. Gibbs if (inccb->ccb_h.flags & CAM_DATA_PHYS) { 7968b8a9b1dSJustin T. Gibbs error = EINVAL; 7978b8a9b1dSJustin T. Gibbs break; 7988b8a9b1dSJustin T. Gibbs } 7998b8a9b1dSJustin T. Gibbs bzero(&mapinfo, sizeof(mapinfo)); 8008b8a9b1dSJustin T. Gibbs 8018b8a9b1dSJustin T. Gibbs /* 8028b8a9b1dSJustin T. Gibbs * Map the pattern and match buffers into kernel 8038b8a9b1dSJustin T. Gibbs * virtual address space. 8048b8a9b1dSJustin T. Gibbs */ 8058b8a9b1dSJustin T. Gibbs error = cam_periph_mapmem(inccb, &mapinfo); 8068b8a9b1dSJustin T. Gibbs 8078b8a9b1dSJustin T. Gibbs if (error) 8088b8a9b1dSJustin T. Gibbs break; 8098b8a9b1dSJustin T. Gibbs 8108b8a9b1dSJustin T. Gibbs /* 8118b8a9b1dSJustin T. Gibbs * This is an immediate CCB, we can send it on directly. 8128b8a9b1dSJustin T. Gibbs */ 8138b8a9b1dSJustin T. Gibbs xpt_action(inccb); 8148b8a9b1dSJustin T. Gibbs 8158b8a9b1dSJustin T. Gibbs /* 8168b8a9b1dSJustin T. Gibbs * Map the buffers back into user space. 8178b8a9b1dSJustin T. Gibbs */ 8188b8a9b1dSJustin T. Gibbs cam_periph_unmapmem(inccb, &mapinfo); 8198b8a9b1dSJustin T. Gibbs 8208b8a9b1dSJustin T. Gibbs error = 0; 8218b8a9b1dSJustin T. Gibbs break; 8228b8a9b1dSJustin T. Gibbs } 8238b8a9b1dSJustin T. Gibbs default: 8248b8a9b1dSJustin T. Gibbs error = EINVAL; 8258b8a9b1dSJustin T. Gibbs break; 8268b8a9b1dSJustin T. Gibbs } 8278b8a9b1dSJustin T. Gibbs break; 8288b8a9b1dSJustin T. Gibbs } 8298b8a9b1dSJustin T. Gibbs /* 8308b8a9b1dSJustin T. Gibbs * This is the getpassthru ioctl. It takes a XPT_GDEVLIST ccb as input, 8318b8a9b1dSJustin T. Gibbs * with the periphal driver name and unit name filled in. The other 8328b8a9b1dSJustin T. Gibbs * fields don't really matter as input. The passthrough driver name 8338b8a9b1dSJustin T. Gibbs * ("pass"), and unit number are passed back in the ccb. The current 8348b8a9b1dSJustin T. Gibbs * device generation number, and the index into the device peripheral 8358b8a9b1dSJustin T. Gibbs * driver list, and the status are also passed back. Note that 8368b8a9b1dSJustin T. Gibbs * since we do everything in one pass, unlike the XPT_GDEVLIST ccb, 8378b8a9b1dSJustin T. Gibbs * we never return a status of CAM_GDEVLIST_LIST_CHANGED. It is 8388b8a9b1dSJustin T. Gibbs * (or rather should be) impossible for the device peripheral driver 8398b8a9b1dSJustin T. Gibbs * list to change since we look at the whole thing in one pass, and 8408b8a9b1dSJustin T. Gibbs * we do it with splsoftcam protection. 8418b8a9b1dSJustin T. Gibbs * 8428b8a9b1dSJustin T. Gibbs */ 8438b8a9b1dSJustin T. Gibbs case CAMGETPASSTHRU: { 8448b8a9b1dSJustin T. Gibbs union ccb *ccb; 8458b8a9b1dSJustin T. Gibbs struct cam_periph *periph; 8468b8a9b1dSJustin T. Gibbs struct periph_driver **p_drv; 8478b8a9b1dSJustin T. Gibbs char *name; 8488b8a9b1dSJustin T. Gibbs int unit; 8498b8a9b1dSJustin T. Gibbs int cur_generation; 8508b8a9b1dSJustin T. Gibbs int splbreaknum; 8518b8a9b1dSJustin T. Gibbs int s; 8528b8a9b1dSJustin T. Gibbs int i; 8538b8a9b1dSJustin T. Gibbs 8548b8a9b1dSJustin T. Gibbs ccb = (union ccb *)addr; 8558b8a9b1dSJustin T. Gibbs unit = ccb->cgdl.unit_number; 8568b8a9b1dSJustin T. Gibbs name = ccb->cgdl.periph_name; 8578b8a9b1dSJustin T. Gibbs /* 8588b8a9b1dSJustin T. Gibbs * Every 100 devices, we want to drop our spl protection to 8598b8a9b1dSJustin T. Gibbs * give the software interrupt handler a chance to run. 8608b8a9b1dSJustin T. Gibbs * Most systems won't run into this check, but this should 8618b8a9b1dSJustin T. Gibbs * avoid starvation in the software interrupt handler in 8628b8a9b1dSJustin T. Gibbs * large systems. 8638b8a9b1dSJustin T. Gibbs */ 8648b8a9b1dSJustin T. Gibbs splbreaknum = 100; 8658b8a9b1dSJustin T. Gibbs 8668b8a9b1dSJustin T. Gibbs ccb = (union ccb *)addr; 8678b8a9b1dSJustin T. Gibbs 8688b8a9b1dSJustin T. Gibbs /* 8698b8a9b1dSJustin T. Gibbs * Sanity check -- make sure we don't get a null peripheral 8708b8a9b1dSJustin T. Gibbs * driver name. 8718b8a9b1dSJustin T. Gibbs */ 8728b8a9b1dSJustin T. Gibbs if (*ccb->cgdl.periph_name == '\0') { 8738b8a9b1dSJustin T. Gibbs error = EINVAL; 8748b8a9b1dSJustin T. Gibbs break; 8758b8a9b1dSJustin T. Gibbs } 8768b8a9b1dSJustin T. Gibbs 8778b8a9b1dSJustin T. Gibbs /* Keep the list from changing while we traverse it */ 8788b8a9b1dSJustin T. Gibbs s = splsoftcam(); 8798b8a9b1dSJustin T. Gibbs ptstartover: 8808b8a9b1dSJustin T. Gibbs cur_generation = xsoftc.generation; 8818b8a9b1dSJustin T. Gibbs 8828b8a9b1dSJustin T. Gibbs /* first find our driver in the list of drivers */ 8838b8a9b1dSJustin T. Gibbs for (p_drv = (struct periph_driver **)periphdriver_set.ls_items; 8848b8a9b1dSJustin T. Gibbs *p_drv != NULL; p_drv++) 8858b8a9b1dSJustin T. Gibbs if (strcmp((*p_drv)->driver_name, name) == 0) 8868b8a9b1dSJustin T. Gibbs break; 8878b8a9b1dSJustin T. Gibbs 8888b8a9b1dSJustin T. Gibbs if (*p_drv == NULL) { 8898b8a9b1dSJustin T. Gibbs splx(s); 8908b8a9b1dSJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_CMP_ERR; 8918b8a9b1dSJustin T. Gibbs ccb->cgdl.status = CAM_GDEVLIST_ERROR; 8928b8a9b1dSJustin T. Gibbs *ccb->cgdl.periph_name = '\0'; 8938b8a9b1dSJustin T. Gibbs ccb->cgdl.unit_number = 0; 8948b8a9b1dSJustin T. Gibbs error = ENOENT; 8958b8a9b1dSJustin T. Gibbs break; 8968b8a9b1dSJustin T. Gibbs } 8978b8a9b1dSJustin T. Gibbs 8988b8a9b1dSJustin T. Gibbs /* 8998b8a9b1dSJustin T. Gibbs * Run through every peripheral instance of this driver 9008b8a9b1dSJustin T. Gibbs * and check to see whether it matches the unit passed 9018b8a9b1dSJustin T. Gibbs * in by the user. If it does, get out of the loops and 9028b8a9b1dSJustin T. Gibbs * find the passthrough driver associated with that 9038b8a9b1dSJustin T. Gibbs * peripheral driver. 9048b8a9b1dSJustin T. Gibbs */ 9058b8a9b1dSJustin T. Gibbs for (periph = TAILQ_FIRST(&(*p_drv)->units); periph != NULL; 9068b8a9b1dSJustin T. Gibbs periph = TAILQ_NEXT(periph, unit_links)) { 9078b8a9b1dSJustin T. Gibbs 9088b8a9b1dSJustin T. Gibbs if (periph->unit_number == unit) { 9098b8a9b1dSJustin T. Gibbs break; 9108b8a9b1dSJustin T. Gibbs } else if (--splbreaknum == 0) { 9118b8a9b1dSJustin T. Gibbs splx(s); 9128b8a9b1dSJustin T. Gibbs s = splsoftcam(); 9138b8a9b1dSJustin T. Gibbs splbreaknum = 100; 9148b8a9b1dSJustin T. Gibbs if (cur_generation != xsoftc.generation) 9158b8a9b1dSJustin T. Gibbs goto ptstartover; 9168b8a9b1dSJustin T. Gibbs } 9178b8a9b1dSJustin T. Gibbs } 9188b8a9b1dSJustin T. Gibbs /* 9198b8a9b1dSJustin T. Gibbs * If we found the peripheral driver that the user passed 9208b8a9b1dSJustin T. Gibbs * in, go through all of the peripheral drivers for that 9218b8a9b1dSJustin T. Gibbs * particular device and look for a passthrough driver. 9228b8a9b1dSJustin T. Gibbs */ 9238b8a9b1dSJustin T. Gibbs if (periph != NULL) { 9248b8a9b1dSJustin T. Gibbs struct cam_ed *device; 9258b8a9b1dSJustin T. Gibbs int i; 9268b8a9b1dSJustin T. Gibbs 9278b8a9b1dSJustin T. Gibbs device = periph->path->device; 9288b8a9b1dSJustin T. Gibbs for (i = 0, periph = device->periphs.slh_first; 9298b8a9b1dSJustin T. Gibbs periph != NULL; 9308b8a9b1dSJustin T. Gibbs periph = periph->periph_links.sle_next, i++) { 9318b8a9b1dSJustin T. Gibbs /* 9328b8a9b1dSJustin T. Gibbs * Check to see whether we have a 9338b8a9b1dSJustin T. Gibbs * passthrough device or not. 9348b8a9b1dSJustin T. Gibbs */ 9358b8a9b1dSJustin T. Gibbs if (strcmp(periph->periph_name, "pass") == 0) { 9368b8a9b1dSJustin T. Gibbs /* 9378b8a9b1dSJustin T. Gibbs * Fill in the getdevlist fields. 9388b8a9b1dSJustin T. Gibbs */ 9398b8a9b1dSJustin T. Gibbs strcpy(ccb->cgdl.periph_name, 9408b8a9b1dSJustin T. Gibbs periph->periph_name); 9418b8a9b1dSJustin T. Gibbs ccb->cgdl.unit_number = 9428b8a9b1dSJustin T. Gibbs periph->unit_number; 9438b8a9b1dSJustin T. Gibbs if (periph->periph_links.sle_next) 9448b8a9b1dSJustin T. Gibbs ccb->cgdl.status = 9458b8a9b1dSJustin T. Gibbs CAM_GDEVLIST_MORE_DEVS; 9468b8a9b1dSJustin T. Gibbs else 9478b8a9b1dSJustin T. Gibbs ccb->cgdl.status = 9488b8a9b1dSJustin T. Gibbs CAM_GDEVLIST_LAST_DEVICE; 9498b8a9b1dSJustin T. Gibbs ccb->cgdl.generation = 9508b8a9b1dSJustin T. Gibbs device->generation; 9518b8a9b1dSJustin T. Gibbs ccb->cgdl.index = i; 9528b8a9b1dSJustin T. Gibbs /* 9538b8a9b1dSJustin T. Gibbs * Fill in some CCB header fields 9548b8a9b1dSJustin T. Gibbs * that the user may want. 9558b8a9b1dSJustin T. Gibbs */ 9568b8a9b1dSJustin T. Gibbs ccb->ccb_h.path_id = 9578b8a9b1dSJustin T. Gibbs periph->path->bus->path_id; 9588b8a9b1dSJustin T. Gibbs ccb->ccb_h.target_id = 9598b8a9b1dSJustin T. Gibbs periph->path->target->target_id; 9608b8a9b1dSJustin T. Gibbs ccb->ccb_h.target_lun = 9618b8a9b1dSJustin T. Gibbs periph->path->device->lun_id; 9628b8a9b1dSJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_CMP; 9638b8a9b1dSJustin T. Gibbs break; 9648b8a9b1dSJustin T. Gibbs } 9658b8a9b1dSJustin T. Gibbs } 9668b8a9b1dSJustin T. Gibbs } 9678b8a9b1dSJustin T. Gibbs 9688b8a9b1dSJustin T. Gibbs /* 9698b8a9b1dSJustin T. Gibbs * If the periph is null here, one of two things has 9708b8a9b1dSJustin T. Gibbs * happened. The first possibility is that we couldn't 9718b8a9b1dSJustin T. Gibbs * find the unit number of the particular peripheral driver 9728b8a9b1dSJustin T. Gibbs * that the user is asking about. e.g. the user asks for 9738b8a9b1dSJustin T. Gibbs * the passthrough driver for "da11". We find the list of 9748b8a9b1dSJustin T. Gibbs * "da" peripherals all right, but there is no unit 11. 9758b8a9b1dSJustin T. Gibbs * The other possibility is that we went through the list 9768b8a9b1dSJustin T. Gibbs * of peripheral drivers attached to the device structure, 9778b8a9b1dSJustin T. Gibbs * but didn't find one with the name "pass". Either way, 9788b8a9b1dSJustin T. Gibbs * we return ENOENT, since we couldn't find something. 9798b8a9b1dSJustin T. Gibbs */ 9808b8a9b1dSJustin T. Gibbs if (periph == NULL) { 9818b8a9b1dSJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_CMP_ERR; 9828b8a9b1dSJustin T. Gibbs ccb->cgdl.status = CAM_GDEVLIST_ERROR; 9838b8a9b1dSJustin T. Gibbs *ccb->cgdl.periph_name = '\0'; 9848b8a9b1dSJustin T. Gibbs ccb->cgdl.unit_number = 0; 9858b8a9b1dSJustin T. Gibbs error = ENOENT; 9868b8a9b1dSJustin T. Gibbs } 9878b8a9b1dSJustin T. Gibbs splx(s); 9888b8a9b1dSJustin T. Gibbs break; 9898b8a9b1dSJustin T. Gibbs } 9908b8a9b1dSJustin T. Gibbs default: 9918b8a9b1dSJustin T. Gibbs error = ENOTTY; 9928b8a9b1dSJustin T. Gibbs break; 9938b8a9b1dSJustin T. Gibbs } 9948b8a9b1dSJustin T. Gibbs 9958b8a9b1dSJustin T. Gibbs return(error); 9968b8a9b1dSJustin T. Gibbs } 9978b8a9b1dSJustin T. Gibbs 9988b8a9b1dSJustin T. Gibbs /* Functions accessed by the peripheral drivers */ 9998b8a9b1dSJustin T. Gibbs void 10008b8a9b1dSJustin T. Gibbs xpt_init() 10018b8a9b1dSJustin T. Gibbs { 10028b8a9b1dSJustin T. Gibbs struct cam_sim *xpt_sim; 10038b8a9b1dSJustin T. Gibbs struct cam_path *path; 10048b8a9b1dSJustin T. Gibbs struct cam_devq; 10058b8a9b1dSJustin T. Gibbs cam_status status; 10068b8a9b1dSJustin T. Gibbs 10078b8a9b1dSJustin T. Gibbs TAILQ_INIT(&xpt_busses); 10088b8a9b1dSJustin T. Gibbs TAILQ_INIT(&cam_bioq); 10098b8a9b1dSJustin T. Gibbs TAILQ_INIT(&cam_netq); 10108b8a9b1dSJustin T. Gibbs SLIST_INIT(&ccb_freeq); 10118b8a9b1dSJustin T. Gibbs STAILQ_INIT(&highpowerq); 10128b8a9b1dSJustin T. Gibbs 10138b8a9b1dSJustin T. Gibbs /* 10148b8a9b1dSJustin T. Gibbs * The xpt layer is, itself, the equivelent of a SIM. 10158b8a9b1dSJustin T. Gibbs * Allow 16 ccbs in the ccb pool for it. This should 10168b8a9b1dSJustin T. Gibbs * give decent parallelism when we probe busses and 10178b8a9b1dSJustin T. Gibbs * perform other XPT functions. 10188b8a9b1dSJustin T. Gibbs */ 10198b8a9b1dSJustin T. Gibbs xpt_sim = (struct cam_sim *)malloc(sizeof(*xpt_sim), 10208b8a9b1dSJustin T. Gibbs M_DEVBUF, M_WAITOK); 10218b8a9b1dSJustin T. Gibbs xpt_sim->sim_action = xptaction; 10228b8a9b1dSJustin T. Gibbs xpt_sim->sim_name = "xpt"; 10238b8a9b1dSJustin T. Gibbs xpt_sim->path_id = CAM_XPT_PATH_ID; 10248b8a9b1dSJustin T. Gibbs xpt_sim->bus_id = 0; 10258b8a9b1dSJustin T. Gibbs xpt_sim->max_tagged_dev_openings = 0; 10268b8a9b1dSJustin T. Gibbs xpt_sim->max_dev_openings = 0; 10278b8a9b1dSJustin T. Gibbs xpt_sim->devq = cam_simq_alloc(16); 10288b8a9b1dSJustin T. Gibbs xpt_max_ccbs = 16; 10298b8a9b1dSJustin T. Gibbs 10308b8a9b1dSJustin T. Gibbs xpt_bus_register(xpt_sim, 0); 10318b8a9b1dSJustin T. Gibbs 10328b8a9b1dSJustin T. Gibbs /* 10338b8a9b1dSJustin T. Gibbs * Looking at the XPT from the SIM layer, the XPT is 10348b8a9b1dSJustin T. Gibbs * the equivelent of a peripheral driver. Allocate 10358b8a9b1dSJustin T. Gibbs * a peripheral driver entry for us. 10368b8a9b1dSJustin T. Gibbs */ 10378b8a9b1dSJustin T. Gibbs if ((status = xpt_create_path(&path, NULL, CAM_XPT_PATH_ID, 10388b8a9b1dSJustin T. Gibbs CAM_TARGET_WILDCARD, 10398b8a9b1dSJustin T. Gibbs CAM_LUN_WILDCARD)) != CAM_REQ_CMP) { 10408b8a9b1dSJustin T. Gibbs printf("xpt_init: xpt_create_path failed with status %#x," 10418b8a9b1dSJustin T. Gibbs " failing attach\n", status); 10428b8a9b1dSJustin T. Gibbs return; 10438b8a9b1dSJustin T. Gibbs } 10448b8a9b1dSJustin T. Gibbs 10458b8a9b1dSJustin T. Gibbs cam_periph_alloc(xptregister, NULL, NULL, "xpt", CAM_PERIPH_BIO, 10468b8a9b1dSJustin T. Gibbs path, NULL, 0, NULL); 10478b8a9b1dSJustin T. Gibbs xpt_free_path(path); 10488b8a9b1dSJustin T. Gibbs 10498b8a9b1dSJustin T. Gibbs xpt_sim->softc = xpt_periph; 10508b8a9b1dSJustin T. Gibbs 10518b8a9b1dSJustin T. Gibbs /* 10528b8a9b1dSJustin T. Gibbs * Register a callback for when interrupts are enabled. 10538b8a9b1dSJustin T. Gibbs */ 10548b8a9b1dSJustin T. Gibbs xpt_config_hook = 10558b8a9b1dSJustin T. Gibbs (struct intr_config_hook *)malloc(sizeof(struct intr_config_hook), 10568b8a9b1dSJustin T. Gibbs M_TEMP, M_NOWAIT); 10578b8a9b1dSJustin T. Gibbs if (xpt_config_hook == NULL) { 10588b8a9b1dSJustin T. Gibbs printf("xpt_init: Cannot malloc config hook " 10598b8a9b1dSJustin T. Gibbs "- failing attach\n"); 10608b8a9b1dSJustin T. Gibbs return; 10618b8a9b1dSJustin T. Gibbs } 10628b8a9b1dSJustin T. Gibbs bzero(xpt_config_hook, sizeof(*xpt_config_hook)); 10638b8a9b1dSJustin T. Gibbs 10648b8a9b1dSJustin T. Gibbs xpt_config_hook->ich_func = xpt_config; 10658b8a9b1dSJustin T. Gibbs if (config_intrhook_establish(xpt_config_hook) != 0) { 10668b8a9b1dSJustin T. Gibbs free (xpt_config_hook, M_TEMP); 10678b8a9b1dSJustin T. Gibbs printf("xpt_init: config_intrhook_establish failed " 10688b8a9b1dSJustin T. Gibbs "- failing attach\n"); 10698b8a9b1dSJustin T. Gibbs } 10708b8a9b1dSJustin T. Gibbs 10718b8a9b1dSJustin T. Gibbs /* Install our software interrupt handlers */ 10728b8a9b1dSJustin T. Gibbs /* XXX Should call some MI function to do this */ 10738b8a9b1dSJustin T. Gibbs ihandlers[SWI_CAMNET] = swi_camnet; 10748b8a9b1dSJustin T. Gibbs ihandlers[SWI_CAMBIO] = swi_cambio; 10758b8a9b1dSJustin T. Gibbs } 10768b8a9b1dSJustin T. Gibbs 10778b8a9b1dSJustin T. Gibbs static cam_status 10788b8a9b1dSJustin T. Gibbs xptregister(struct cam_periph *periph, void *arg) 10798b8a9b1dSJustin T. Gibbs { 10808b8a9b1dSJustin T. Gibbs if (periph == NULL) { 10818b8a9b1dSJustin T. Gibbs printf("xptregister: periph was NULL!!\n"); 10828b8a9b1dSJustin T. Gibbs return(CAM_REQ_CMP_ERR); 10838b8a9b1dSJustin T. Gibbs } 10848b8a9b1dSJustin T. Gibbs 10858b8a9b1dSJustin T. Gibbs periph->softc = NULL; 10868b8a9b1dSJustin T. Gibbs 10878b8a9b1dSJustin T. Gibbs xpt_periph = periph; 10888b8a9b1dSJustin T. Gibbs 10898b8a9b1dSJustin T. Gibbs return(CAM_REQ_CMP); 10908b8a9b1dSJustin T. Gibbs } 10918b8a9b1dSJustin T. Gibbs 10928b8a9b1dSJustin T. Gibbs int32_t 10938b8a9b1dSJustin T. Gibbs xpt_add_periph(struct cam_periph *periph) 10948b8a9b1dSJustin T. Gibbs { 10958b8a9b1dSJustin T. Gibbs struct cam_ed *device; 10968b8a9b1dSJustin T. Gibbs int32_t status; 10978b8a9b1dSJustin T. Gibbs struct periph_list *periph_head; 10988b8a9b1dSJustin T. Gibbs 10998b8a9b1dSJustin T. Gibbs device = periph->path->device; 11008b8a9b1dSJustin T. Gibbs 11018b8a9b1dSJustin T. Gibbs periph_head = &device->periphs; 11028b8a9b1dSJustin T. Gibbs 11038b8a9b1dSJustin T. Gibbs status = CAM_REQ_CMP; 11048b8a9b1dSJustin T. Gibbs 11058b8a9b1dSJustin T. Gibbs if (device != NULL) { 11068b8a9b1dSJustin T. Gibbs int s; 11078b8a9b1dSJustin T. Gibbs 11088b8a9b1dSJustin T. Gibbs /* 11098b8a9b1dSJustin T. Gibbs * Make room for this peripheral 11108b8a9b1dSJustin T. Gibbs * so it will fit in the queue 11118b8a9b1dSJustin T. Gibbs * when it's scheduled to run 11128b8a9b1dSJustin T. Gibbs */ 11138b8a9b1dSJustin T. Gibbs s = splsoftcam(); 11148b8a9b1dSJustin T. Gibbs status = camq_resize(&device->drvq, 11158b8a9b1dSJustin T. Gibbs device->drvq.array_size + 1); 11168b8a9b1dSJustin T. Gibbs 11178b8a9b1dSJustin T. Gibbs device->generation++; 11188b8a9b1dSJustin T. Gibbs 11198b8a9b1dSJustin T. Gibbs SLIST_INSERT_HEAD(periph_head, periph, periph_links); 11208b8a9b1dSJustin T. Gibbs 11218b8a9b1dSJustin T. Gibbs splx(s); 11228b8a9b1dSJustin T. Gibbs } 11238b8a9b1dSJustin T. Gibbs 11248b8a9b1dSJustin T. Gibbs xsoftc.generation++; 11258b8a9b1dSJustin T. Gibbs 11268b8a9b1dSJustin T. Gibbs return (status); 11278b8a9b1dSJustin T. Gibbs } 11288b8a9b1dSJustin T. Gibbs 11298b8a9b1dSJustin T. Gibbs void 11308b8a9b1dSJustin T. Gibbs xpt_remove_periph(struct cam_periph *periph) 11318b8a9b1dSJustin T. Gibbs { 11328b8a9b1dSJustin T. Gibbs struct cam_ed *device; 11338b8a9b1dSJustin T. Gibbs 11348b8a9b1dSJustin T. Gibbs device = periph->path->device; 11358b8a9b1dSJustin T. Gibbs 11368b8a9b1dSJustin T. Gibbs if (device != NULL) { 11378b8a9b1dSJustin T. Gibbs int s; 11388b8a9b1dSJustin T. Gibbs struct periph_list *periph_head; 11398b8a9b1dSJustin T. Gibbs 11408b8a9b1dSJustin T. Gibbs periph_head = &device->periphs; 11418b8a9b1dSJustin T. Gibbs 11428b8a9b1dSJustin T. Gibbs /* Release the slot for this peripheral */ 11438b8a9b1dSJustin T. Gibbs s = splsoftcam(); 11448b8a9b1dSJustin T. Gibbs camq_resize(&device->drvq, device->drvq.array_size - 1); 11458b8a9b1dSJustin T. Gibbs 11468b8a9b1dSJustin T. Gibbs device->generation++; 11478b8a9b1dSJustin T. Gibbs 11488b8a9b1dSJustin T. Gibbs SLIST_REMOVE(periph_head, periph, cam_periph, periph_links); 11498b8a9b1dSJustin T. Gibbs 11508b8a9b1dSJustin T. Gibbs splx(s); 11518b8a9b1dSJustin T. Gibbs } 11528b8a9b1dSJustin T. Gibbs 11538b8a9b1dSJustin T. Gibbs xsoftc.generation++; 11548b8a9b1dSJustin T. Gibbs 11558b8a9b1dSJustin T. Gibbs } 11568b8a9b1dSJustin T. Gibbs 11578b8a9b1dSJustin T. Gibbs void 11588b8a9b1dSJustin T. Gibbs xpt_announce_periph(struct cam_periph *periph, char *announce_string) 11598b8a9b1dSJustin T. Gibbs { 11608b8a9b1dSJustin T. Gibbs int s; 11618b8a9b1dSJustin T. Gibbs u_int mb; 11628b8a9b1dSJustin T. Gibbs struct cam_path *path; 11638b8a9b1dSJustin T. Gibbs struct ccb_trans_settings cts; 11648b8a9b1dSJustin T. Gibbs 11658b8a9b1dSJustin T. Gibbs path = periph->path; 11668b8a9b1dSJustin T. Gibbs /* 11678b8a9b1dSJustin T. Gibbs * To ensure that this is printed in one piece, 11688b8a9b1dSJustin T. Gibbs * mask out CAM interrupts. 11698b8a9b1dSJustin T. Gibbs */ 11708b8a9b1dSJustin T. Gibbs s = splsoftcam(); 11718b8a9b1dSJustin T. Gibbs printf("%s%d at %s%d bus %d target %d lun %d\n", 11728b8a9b1dSJustin T. Gibbs periph->periph_name, periph->unit_number, 11738b8a9b1dSJustin T. Gibbs path->bus->sim->sim_name, 11748b8a9b1dSJustin T. Gibbs path->bus->sim->unit_number, 11758b8a9b1dSJustin T. Gibbs path->bus->sim->bus_id, 11768b8a9b1dSJustin T. Gibbs path->target->target_id, 11778b8a9b1dSJustin T. Gibbs path->device->lun_id); 11788b8a9b1dSJustin T. Gibbs printf("%s%d: ", periph->periph_name, periph->unit_number); 11798b8a9b1dSJustin T. Gibbs scsi_print_inquiry(&path->device->inq_data); 11808b8a9b1dSJustin T. Gibbs if ((bootverbose) 11818b8a9b1dSJustin T. Gibbs && (path->device->serial_num_len > 0)) { 11828b8a9b1dSJustin T. Gibbs /* Don't wrap the screen - print only the first 60 chars */ 11838b8a9b1dSJustin T. Gibbs printf("%s%d: Serial Number %.60s\n", periph->periph_name, 11848b8a9b1dSJustin T. Gibbs periph->unit_number, path->device->serial_num); 11858b8a9b1dSJustin T. Gibbs } 11868b8a9b1dSJustin T. Gibbs xpt_setup_ccb(&cts.ccb_h, path, /*priority*/1); 11878b8a9b1dSJustin T. Gibbs cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS; 11888b8a9b1dSJustin T. Gibbs cts.flags = CCB_TRANS_CURRENT_SETTINGS; 11898b8a9b1dSJustin T. Gibbs xpt_action((union ccb*)&cts); 11908b8a9b1dSJustin T. Gibbs if (cts.ccb_h.status == CAM_REQ_CMP) { 11918b8a9b1dSJustin T. Gibbs u_int speed; 11928b8a9b1dSJustin T. Gibbs u_int freq; 11938b8a9b1dSJustin T. Gibbs 11948b8a9b1dSJustin T. Gibbs if ((cts.valid & CCB_TRANS_SYNC_OFFSET_VALID) != 0 11958b8a9b1dSJustin T. Gibbs && cts.sync_offset != 0) { 11968b8a9b1dSJustin T. Gibbs freq = scsi_calc_syncsrate(cts.sync_period); 11978b8a9b1dSJustin T. Gibbs speed = freq; 11988b8a9b1dSJustin T. Gibbs } else { 11998b8a9b1dSJustin T. Gibbs freq = 0; 12008b8a9b1dSJustin T. Gibbs speed = path->bus->sim->base_transfer_speed; 12018b8a9b1dSJustin T. Gibbs } 12028b8a9b1dSJustin T. Gibbs if ((cts.valid & CCB_TRANS_BUS_WIDTH_VALID) != 0) 12038b8a9b1dSJustin T. Gibbs speed *= (0x01 << cts.bus_width); 12048b8a9b1dSJustin T. Gibbs mb = speed / 1000; 12058b8a9b1dSJustin T. Gibbs if (mb > 0) 12068b8a9b1dSJustin T. Gibbs printf("%s%d: %d.%dMB/s transfers", periph->periph_name, 12078b8a9b1dSJustin T. Gibbs periph->unit_number, mb, speed % 1000); 12088b8a9b1dSJustin T. Gibbs else 12098b8a9b1dSJustin T. Gibbs printf("%s%d: %dKB/s transfers", periph->periph_name, 12108b8a9b1dSJustin T. Gibbs periph->unit_number, (speed % 1000) * 1000); 12118b8a9b1dSJustin T. Gibbs if ((cts.valid & CCB_TRANS_SYNC_OFFSET_VALID) != 0 12128b8a9b1dSJustin T. Gibbs && cts.sync_offset != 0) { 12138b8a9b1dSJustin T. Gibbs printf(" (%d.%dMHz, offset %d", freq / 1000, 12148b8a9b1dSJustin T. Gibbs freq % 1000, cts.sync_offset); 12158b8a9b1dSJustin T. Gibbs } 12168b8a9b1dSJustin T. Gibbs if ((cts.valid & CCB_TRANS_BUS_WIDTH_VALID) != 0 12178b8a9b1dSJustin T. Gibbs && cts.bus_width > 0) { 12188b8a9b1dSJustin T. Gibbs if ((cts.valid & CCB_TRANS_SYNC_OFFSET_VALID) != 0 12198b8a9b1dSJustin T. Gibbs && cts.sync_offset != 0) { 12208b8a9b1dSJustin T. Gibbs printf(", "); 12218b8a9b1dSJustin T. Gibbs } else { 12228b8a9b1dSJustin T. Gibbs printf(" ("); 12238b8a9b1dSJustin T. Gibbs } 12248b8a9b1dSJustin T. Gibbs printf("%dbit)", 8 * (0x01 << cts.bus_width)); 12258b8a9b1dSJustin T. Gibbs } else if ((cts.valid & CCB_TRANS_SYNC_OFFSET_VALID) != 0 12268b8a9b1dSJustin T. Gibbs && cts.sync_offset != 0) { 12278b8a9b1dSJustin T. Gibbs printf(")"); 12288b8a9b1dSJustin T. Gibbs } 12298b8a9b1dSJustin T. Gibbs if (path->device->inq_flags & SID_CmdQue) { 12308b8a9b1dSJustin T. Gibbs printf(", Tagged Queueing Enabled"); 12318b8a9b1dSJustin T. Gibbs } 12328b8a9b1dSJustin T. Gibbs 12338b8a9b1dSJustin T. Gibbs printf("\n"); 12348b8a9b1dSJustin T. Gibbs } else if (path->device->inq_flags & SID_CmdQue) { 12358b8a9b1dSJustin T. Gibbs printf("%s%d: Tagged Queueing Enabled\n", 12368b8a9b1dSJustin T. Gibbs periph->periph_name, periph->unit_number); 12378b8a9b1dSJustin T. Gibbs } 12388b8a9b1dSJustin T. Gibbs 12398b8a9b1dSJustin T. Gibbs /* 12408b8a9b1dSJustin T. Gibbs * We only want to print the caller's announce string if they've 12418b8a9b1dSJustin T. Gibbs * passed one in.. 12428b8a9b1dSJustin T. Gibbs */ 12438b8a9b1dSJustin T. Gibbs if (announce_string != NULL) 12448b8a9b1dSJustin T. Gibbs printf("%s%d: %s\n", periph->periph_name, 12458b8a9b1dSJustin T. Gibbs periph->unit_number, announce_string); 12468b8a9b1dSJustin T. Gibbs splx(s); 12478b8a9b1dSJustin T. Gibbs } 12488b8a9b1dSJustin T. Gibbs 12498b8a9b1dSJustin T. Gibbs 12508b8a9b1dSJustin T. Gibbs static dev_match_ret 12518b8a9b1dSJustin T. Gibbs xptbusmatch(struct dev_match_pattern *patterns, int num_patterns, 12528b8a9b1dSJustin T. Gibbs struct cam_eb *bus) 12538b8a9b1dSJustin T. Gibbs { 12548b8a9b1dSJustin T. Gibbs dev_match_ret retval; 12558b8a9b1dSJustin T. Gibbs int i; 12568b8a9b1dSJustin T. Gibbs 12578b8a9b1dSJustin T. Gibbs retval = DM_RET_NONE; 12588b8a9b1dSJustin T. Gibbs 12598b8a9b1dSJustin T. Gibbs /* 12608b8a9b1dSJustin T. Gibbs * If we aren't given something to match against, that's an error. 12618b8a9b1dSJustin T. Gibbs */ 12628b8a9b1dSJustin T. Gibbs if (bus == NULL) 12638b8a9b1dSJustin T. Gibbs return(DM_RET_ERROR); 12648b8a9b1dSJustin T. Gibbs 12658b8a9b1dSJustin T. Gibbs /* 12668b8a9b1dSJustin T. Gibbs * If there are no match entries, then this bus matches no 12678b8a9b1dSJustin T. Gibbs * matter what. 12688b8a9b1dSJustin T. Gibbs */ 12698b8a9b1dSJustin T. Gibbs if ((patterns == NULL) || (num_patterns == 0)) 12708b8a9b1dSJustin T. Gibbs return(DM_RET_DESCEND | DM_RET_COPY); 12718b8a9b1dSJustin T. Gibbs 12728b8a9b1dSJustin T. Gibbs for (i = 0; i < num_patterns; i++) { 12738b8a9b1dSJustin T. Gibbs struct bus_match_pattern *cur_pattern; 12748b8a9b1dSJustin T. Gibbs 12758b8a9b1dSJustin T. Gibbs /* 12768b8a9b1dSJustin T. Gibbs * If the pattern in question isn't for a bus node, we 12778b8a9b1dSJustin T. Gibbs * aren't interested. However, we do indicate to the 12788b8a9b1dSJustin T. Gibbs * calling routine that we should continue descending the 12798b8a9b1dSJustin T. Gibbs * tree, since the user wants to match against lower-level 12808b8a9b1dSJustin T. Gibbs * EDT elements. 12818b8a9b1dSJustin T. Gibbs */ 12828b8a9b1dSJustin T. Gibbs if (patterns[i].type != DEV_MATCH_BUS) { 12838b8a9b1dSJustin T. Gibbs if ((retval & DM_RET_ACTION_MASK) == DM_RET_NONE) 12848b8a9b1dSJustin T. Gibbs retval |= DM_RET_DESCEND; 12858b8a9b1dSJustin T. Gibbs continue; 12868b8a9b1dSJustin T. Gibbs } 12878b8a9b1dSJustin T. Gibbs 12888b8a9b1dSJustin T. Gibbs cur_pattern = &patterns[i].pattern.bus_pattern; 12898b8a9b1dSJustin T. Gibbs 12908b8a9b1dSJustin T. Gibbs /* 12918b8a9b1dSJustin T. Gibbs * If they want to match any bus node, we give them any 12928b8a9b1dSJustin T. Gibbs * device node. 12938b8a9b1dSJustin T. Gibbs */ 12948b8a9b1dSJustin T. Gibbs if (cur_pattern->flags == BUS_MATCH_ANY) { 12958b8a9b1dSJustin T. Gibbs /* set the copy flag */ 12968b8a9b1dSJustin T. Gibbs retval |= DM_RET_COPY; 12978b8a9b1dSJustin T. Gibbs 12988b8a9b1dSJustin T. Gibbs /* 12998b8a9b1dSJustin T. Gibbs * If we've already decided on an action, go ahead 13008b8a9b1dSJustin T. Gibbs * and return. 13018b8a9b1dSJustin T. Gibbs */ 13028b8a9b1dSJustin T. Gibbs if ((retval & DM_RET_ACTION_MASK) != DM_RET_NONE) 13038b8a9b1dSJustin T. Gibbs return(retval); 13048b8a9b1dSJustin T. Gibbs } 13058b8a9b1dSJustin T. Gibbs 13068b8a9b1dSJustin T. Gibbs /* 13078b8a9b1dSJustin T. Gibbs * Not sure why someone would do this... 13088b8a9b1dSJustin T. Gibbs */ 13098b8a9b1dSJustin T. Gibbs if (cur_pattern->flags == BUS_MATCH_NONE) 13108b8a9b1dSJustin T. Gibbs continue; 13118b8a9b1dSJustin T. Gibbs 13128b8a9b1dSJustin T. Gibbs if (((cur_pattern->flags & BUS_MATCH_PATH) != 0) 13138b8a9b1dSJustin T. Gibbs && (cur_pattern->path_id != bus->path_id)) 13148b8a9b1dSJustin T. Gibbs continue; 13158b8a9b1dSJustin T. Gibbs 13168b8a9b1dSJustin T. Gibbs if (((cur_pattern->flags & BUS_MATCH_BUS_ID) != 0) 13178b8a9b1dSJustin T. Gibbs && (cur_pattern->bus_id != bus->sim->bus_id)) 13188b8a9b1dSJustin T. Gibbs continue; 13198b8a9b1dSJustin T. Gibbs 13208b8a9b1dSJustin T. Gibbs if (((cur_pattern->flags & BUS_MATCH_UNIT) != 0) 13218b8a9b1dSJustin T. Gibbs && (cur_pattern->unit_number != bus->sim->unit_number)) 13228b8a9b1dSJustin T. Gibbs continue; 13238b8a9b1dSJustin T. Gibbs 13248b8a9b1dSJustin T. Gibbs if (((cur_pattern->flags & BUS_MATCH_NAME) != 0) 13258b8a9b1dSJustin T. Gibbs && (strncmp(cur_pattern->dev_name, bus->sim->sim_name, 13268b8a9b1dSJustin T. Gibbs DEV_IDLEN) != 0)) 13278b8a9b1dSJustin T. Gibbs continue; 13288b8a9b1dSJustin T. Gibbs 13298b8a9b1dSJustin T. Gibbs /* 13308b8a9b1dSJustin T. Gibbs * If we get to this point, the user definitely wants 13318b8a9b1dSJustin T. Gibbs * information on this bus. So tell the caller to copy the 13328b8a9b1dSJustin T. Gibbs * data out. 13338b8a9b1dSJustin T. Gibbs */ 13348b8a9b1dSJustin T. Gibbs retval |= DM_RET_COPY; 13358b8a9b1dSJustin T. Gibbs 13368b8a9b1dSJustin T. Gibbs /* 13378b8a9b1dSJustin T. Gibbs * If the return action has been set to descend, then we 13388b8a9b1dSJustin T. Gibbs * know that we've already seen a non-bus matching 13398b8a9b1dSJustin T. Gibbs * expression, therefore we need to further descend the tree. 13408b8a9b1dSJustin T. Gibbs * This won't change by continuing around the loop, so we 13418b8a9b1dSJustin T. Gibbs * go ahead and return. If we haven't seen a non-bus 13428b8a9b1dSJustin T. Gibbs * matching expression, we keep going around the loop until 13438b8a9b1dSJustin T. Gibbs * we exhaust the matching expressions. We'll set the stop 13448b8a9b1dSJustin T. Gibbs * flag once we fall out of the loop. 13458b8a9b1dSJustin T. Gibbs */ 13468b8a9b1dSJustin T. Gibbs if ((retval & DM_RET_ACTION_MASK) == DM_RET_DESCEND) 13478b8a9b1dSJustin T. Gibbs return(retval); 13488b8a9b1dSJustin T. Gibbs } 13498b8a9b1dSJustin T. Gibbs 13508b8a9b1dSJustin T. Gibbs /* 13518b8a9b1dSJustin T. Gibbs * If the return action hasn't been set to descend yet, that means 13528b8a9b1dSJustin T. Gibbs * we haven't seen anything other than bus matching patterns. So 13538b8a9b1dSJustin T. Gibbs * tell the caller to stop descending the tree -- the user doesn't 13548b8a9b1dSJustin T. Gibbs * want to match against lower level tree elements. 13558b8a9b1dSJustin T. Gibbs */ 13568b8a9b1dSJustin T. Gibbs if ((retval & DM_RET_ACTION_MASK) == DM_RET_NONE) 13578b8a9b1dSJustin T. Gibbs retval |= DM_RET_STOP; 13588b8a9b1dSJustin T. Gibbs 13598b8a9b1dSJustin T. Gibbs return(retval); 13608b8a9b1dSJustin T. Gibbs } 13618b8a9b1dSJustin T. Gibbs 13628b8a9b1dSJustin T. Gibbs static dev_match_ret 13638b8a9b1dSJustin T. Gibbs xptdevicematch(struct dev_match_pattern *patterns, int num_patterns, 13648b8a9b1dSJustin T. Gibbs struct cam_ed *device) 13658b8a9b1dSJustin T. Gibbs { 13668b8a9b1dSJustin T. Gibbs dev_match_ret retval; 13678b8a9b1dSJustin T. Gibbs int i; 13688b8a9b1dSJustin T. Gibbs 13698b8a9b1dSJustin T. Gibbs retval = DM_RET_NONE; 13708b8a9b1dSJustin T. Gibbs 13718b8a9b1dSJustin T. Gibbs /* 13728b8a9b1dSJustin T. Gibbs * If we aren't given something to match against, that's an error. 13738b8a9b1dSJustin T. Gibbs */ 13748b8a9b1dSJustin T. Gibbs if (device == NULL) 13758b8a9b1dSJustin T. Gibbs return(DM_RET_ERROR); 13768b8a9b1dSJustin T. Gibbs 13778b8a9b1dSJustin T. Gibbs /* 13788b8a9b1dSJustin T. Gibbs * If there are no match entries, then this device matches no 13798b8a9b1dSJustin T. Gibbs * matter what. 13808b8a9b1dSJustin T. Gibbs */ 13818b8a9b1dSJustin T. Gibbs if ((patterns == NULL) || (patterns == 0)) 13828b8a9b1dSJustin T. Gibbs return(DM_RET_DESCEND | DM_RET_COPY); 13838b8a9b1dSJustin T. Gibbs 13848b8a9b1dSJustin T. Gibbs for (i = 0; i < num_patterns; i++) { 13858b8a9b1dSJustin T. Gibbs struct device_match_pattern *cur_pattern; 13868b8a9b1dSJustin T. Gibbs 13878b8a9b1dSJustin T. Gibbs /* 13888b8a9b1dSJustin T. Gibbs * If the pattern in question isn't for a device node, we 13898b8a9b1dSJustin T. Gibbs * aren't interested. 13908b8a9b1dSJustin T. Gibbs */ 13918b8a9b1dSJustin T. Gibbs if (patterns[i].type != DEV_MATCH_DEVICE) { 13928b8a9b1dSJustin T. Gibbs if ((patterns[i].type == DEV_MATCH_PERIPH) 13938b8a9b1dSJustin T. Gibbs && ((retval & DM_RET_ACTION_MASK) == DM_RET_NONE)) 13948b8a9b1dSJustin T. Gibbs retval |= DM_RET_DESCEND; 13958b8a9b1dSJustin T. Gibbs continue; 13968b8a9b1dSJustin T. Gibbs } 13978b8a9b1dSJustin T. Gibbs 13988b8a9b1dSJustin T. Gibbs cur_pattern = &patterns[i].pattern.device_pattern; 13998b8a9b1dSJustin T. Gibbs 14008b8a9b1dSJustin T. Gibbs /* 14018b8a9b1dSJustin T. Gibbs * If they want to match any device node, we give them any 14028b8a9b1dSJustin T. Gibbs * device node. 14038b8a9b1dSJustin T. Gibbs */ 14048b8a9b1dSJustin T. Gibbs if (cur_pattern->flags == DEV_MATCH_ANY) { 14058b8a9b1dSJustin T. Gibbs /* set the copy flag */ 14068b8a9b1dSJustin T. Gibbs retval |= DM_RET_COPY; 14078b8a9b1dSJustin T. Gibbs 14088b8a9b1dSJustin T. Gibbs 14098b8a9b1dSJustin T. Gibbs /* 14108b8a9b1dSJustin T. Gibbs * If we've already decided on an action, go ahead 14118b8a9b1dSJustin T. Gibbs * and return. 14128b8a9b1dSJustin T. Gibbs */ 14138b8a9b1dSJustin T. Gibbs if ((retval & DM_RET_ACTION_MASK) != DM_RET_NONE) 14148b8a9b1dSJustin T. Gibbs return(retval); 14158b8a9b1dSJustin T. Gibbs } 14168b8a9b1dSJustin T. Gibbs 14178b8a9b1dSJustin T. Gibbs /* 14188b8a9b1dSJustin T. Gibbs * Not sure why someone would do this... 14198b8a9b1dSJustin T. Gibbs */ 14208b8a9b1dSJustin T. Gibbs if (cur_pattern->flags == DEV_MATCH_NONE) 14218b8a9b1dSJustin T. Gibbs continue; 14228b8a9b1dSJustin T. Gibbs 14238b8a9b1dSJustin T. Gibbs if (((cur_pattern->flags & DEV_MATCH_PATH) != 0) 14248b8a9b1dSJustin T. Gibbs && (cur_pattern->path_id != device->target->bus->path_id)) 14258b8a9b1dSJustin T. Gibbs continue; 14268b8a9b1dSJustin T. Gibbs 14278b8a9b1dSJustin T. Gibbs if (((cur_pattern->flags & DEV_MATCH_TARGET) != 0) 14288b8a9b1dSJustin T. Gibbs && (cur_pattern->target_id != device->target->target_id)) 14298b8a9b1dSJustin T. Gibbs continue; 14308b8a9b1dSJustin T. Gibbs 14318b8a9b1dSJustin T. Gibbs if (((cur_pattern->flags & DEV_MATCH_LUN) != 0) 14328b8a9b1dSJustin T. Gibbs && (cur_pattern->target_lun != device->lun_id)) 14338b8a9b1dSJustin T. Gibbs continue; 14348b8a9b1dSJustin T. Gibbs 14358b8a9b1dSJustin T. Gibbs if (((cur_pattern->flags & DEV_MATCH_INQUIRY) != 0) 14368b8a9b1dSJustin T. Gibbs && (cam_quirkmatch((caddr_t)&device->inq_data, 14378b8a9b1dSJustin T. Gibbs (caddr_t)&cur_pattern->inq_pat, 14388b8a9b1dSJustin T. Gibbs 1, sizeof(cur_pattern->inq_pat), 14398b8a9b1dSJustin T. Gibbs scsi_static_inquiry_match) == NULL)) 14408b8a9b1dSJustin T. Gibbs continue; 14418b8a9b1dSJustin T. Gibbs 14428b8a9b1dSJustin T. Gibbs /* 14438b8a9b1dSJustin T. Gibbs * If we get to this point, the user definitely wants 14448b8a9b1dSJustin T. Gibbs * information on this device. So tell the caller to copy 14458b8a9b1dSJustin T. Gibbs * the data out. 14468b8a9b1dSJustin T. Gibbs */ 14478b8a9b1dSJustin T. Gibbs retval |= DM_RET_COPY; 14488b8a9b1dSJustin T. Gibbs 14498b8a9b1dSJustin T. Gibbs /* 14508b8a9b1dSJustin T. Gibbs * If the return action has been set to descend, then we 14518b8a9b1dSJustin T. Gibbs * know that we've already seen a peripheral matching 14528b8a9b1dSJustin T. Gibbs * expression, therefore we need to further descend the tree. 14538b8a9b1dSJustin T. Gibbs * This won't change by continuing around the loop, so we 14548b8a9b1dSJustin T. Gibbs * go ahead and return. If we haven't seen a peripheral 14558b8a9b1dSJustin T. Gibbs * matching expression, we keep going around the loop until 14568b8a9b1dSJustin T. Gibbs * we exhaust the matching expressions. We'll set the stop 14578b8a9b1dSJustin T. Gibbs * flag once we fall out of the loop. 14588b8a9b1dSJustin T. Gibbs */ 14598b8a9b1dSJustin T. Gibbs if ((retval & DM_RET_ACTION_MASK) == DM_RET_DESCEND) 14608b8a9b1dSJustin T. Gibbs return(retval); 14618b8a9b1dSJustin T. Gibbs } 14628b8a9b1dSJustin T. Gibbs 14638b8a9b1dSJustin T. Gibbs /* 14648b8a9b1dSJustin T. Gibbs * If the return action hasn't been set to descend yet, that means 14658b8a9b1dSJustin T. Gibbs * we haven't seen any peripheral matching patterns. So tell the 14668b8a9b1dSJustin T. Gibbs * caller to stop descending the tree -- the user doesn't want to 14678b8a9b1dSJustin T. Gibbs * match against lower level tree elements. 14688b8a9b1dSJustin T. Gibbs */ 14698b8a9b1dSJustin T. Gibbs if ((retval & DM_RET_ACTION_MASK) == DM_RET_NONE) 14708b8a9b1dSJustin T. Gibbs retval |= DM_RET_STOP; 14718b8a9b1dSJustin T. Gibbs 14728b8a9b1dSJustin T. Gibbs return(retval); 14738b8a9b1dSJustin T. Gibbs } 14748b8a9b1dSJustin T. Gibbs 14758b8a9b1dSJustin T. Gibbs /* 14768b8a9b1dSJustin T. Gibbs * Match a single peripheral against any number of match patterns. 14778b8a9b1dSJustin T. Gibbs */ 14788b8a9b1dSJustin T. Gibbs static dev_match_ret 14798b8a9b1dSJustin T. Gibbs xptperiphmatch(struct dev_match_pattern *patterns, int num_patterns, 14808b8a9b1dSJustin T. Gibbs struct cam_periph *periph) 14818b8a9b1dSJustin T. Gibbs { 14828b8a9b1dSJustin T. Gibbs dev_match_ret retval; 14838b8a9b1dSJustin T. Gibbs int i; 14848b8a9b1dSJustin T. Gibbs 14858b8a9b1dSJustin T. Gibbs /* 14868b8a9b1dSJustin T. Gibbs * If we aren't given something to match against, that's an error. 14878b8a9b1dSJustin T. Gibbs */ 14888b8a9b1dSJustin T. Gibbs if (periph == NULL) 14898b8a9b1dSJustin T. Gibbs return(DM_RET_ERROR); 14908b8a9b1dSJustin T. Gibbs 14918b8a9b1dSJustin T. Gibbs /* 14928b8a9b1dSJustin T. Gibbs * If there are no match entries, then this peripheral matches no 14938b8a9b1dSJustin T. Gibbs * matter what. 14948b8a9b1dSJustin T. Gibbs */ 14958b8a9b1dSJustin T. Gibbs if ((patterns == NULL) || (num_patterns == 0)) 14968b8a9b1dSJustin T. Gibbs return(DM_RET_STOP | DM_RET_COPY); 14978b8a9b1dSJustin T. Gibbs 14988b8a9b1dSJustin T. Gibbs /* 14998b8a9b1dSJustin T. Gibbs * There aren't any nodes below a peripheral node, so there's no 15008b8a9b1dSJustin T. Gibbs * reason to descend the tree any further. 15018b8a9b1dSJustin T. Gibbs */ 15028b8a9b1dSJustin T. Gibbs retval = DM_RET_STOP; 15038b8a9b1dSJustin T. Gibbs 15048b8a9b1dSJustin T. Gibbs for (i = 0; i < num_patterns; i++) { 15058b8a9b1dSJustin T. Gibbs struct periph_match_pattern *cur_pattern; 15068b8a9b1dSJustin T. Gibbs 15078b8a9b1dSJustin T. Gibbs /* 15088b8a9b1dSJustin T. Gibbs * If the pattern in question isn't for a peripheral, we 15098b8a9b1dSJustin T. Gibbs * aren't interested. 15108b8a9b1dSJustin T. Gibbs */ 15118b8a9b1dSJustin T. Gibbs if (patterns[i].type != DEV_MATCH_PERIPH) 15128b8a9b1dSJustin T. Gibbs continue; 15138b8a9b1dSJustin T. Gibbs 15148b8a9b1dSJustin T. Gibbs cur_pattern = &patterns[i].pattern.periph_pattern; 15158b8a9b1dSJustin T. Gibbs 15168b8a9b1dSJustin T. Gibbs /* 15178b8a9b1dSJustin T. Gibbs * If they want to match on anything, then we will do so. 15188b8a9b1dSJustin T. Gibbs */ 15198b8a9b1dSJustin T. Gibbs if (cur_pattern->flags == PERIPH_MATCH_ANY) { 15208b8a9b1dSJustin T. Gibbs /* set the copy flag */ 15218b8a9b1dSJustin T. Gibbs retval |= DM_RET_COPY; 15228b8a9b1dSJustin T. Gibbs 15238b8a9b1dSJustin T. Gibbs /* 15248b8a9b1dSJustin T. Gibbs * We've already set the return action to stop, 15258b8a9b1dSJustin T. Gibbs * since there are no nodes below peripherals in 15268b8a9b1dSJustin T. Gibbs * the tree. 15278b8a9b1dSJustin T. Gibbs */ 15288b8a9b1dSJustin T. Gibbs return(retval); 15298b8a9b1dSJustin T. Gibbs } 15308b8a9b1dSJustin T. Gibbs 15318b8a9b1dSJustin T. Gibbs /* 15328b8a9b1dSJustin T. Gibbs * Not sure why someone would do this... 15338b8a9b1dSJustin T. Gibbs */ 15348b8a9b1dSJustin T. Gibbs if (cur_pattern->flags == PERIPH_MATCH_NONE) 15358b8a9b1dSJustin T. Gibbs continue; 15368b8a9b1dSJustin T. Gibbs 15378b8a9b1dSJustin T. Gibbs if (((cur_pattern->flags & PERIPH_MATCH_PATH) != 0) 15388b8a9b1dSJustin T. Gibbs && (cur_pattern->path_id != periph->path->bus->path_id)) 15398b8a9b1dSJustin T. Gibbs continue; 15408b8a9b1dSJustin T. Gibbs 15418b8a9b1dSJustin T. Gibbs /* 15428b8a9b1dSJustin T. Gibbs * For the target and lun id's, we have to make sure the 15438b8a9b1dSJustin T. Gibbs * target and lun pointers aren't NULL. The xpt peripheral 15448b8a9b1dSJustin T. Gibbs * has a wildcard target and device. 15458b8a9b1dSJustin T. Gibbs */ 15468b8a9b1dSJustin T. Gibbs if (((cur_pattern->flags & PERIPH_MATCH_TARGET) != 0) 15478b8a9b1dSJustin T. Gibbs && ((periph->path->target == NULL) 15488b8a9b1dSJustin T. Gibbs ||(cur_pattern->target_id != periph->path->target->target_id))) 15498b8a9b1dSJustin T. Gibbs continue; 15508b8a9b1dSJustin T. Gibbs 15518b8a9b1dSJustin T. Gibbs if (((cur_pattern->flags & PERIPH_MATCH_LUN) != 0) 15528b8a9b1dSJustin T. Gibbs && ((periph->path->device == NULL) 15538b8a9b1dSJustin T. Gibbs || (cur_pattern->target_lun != periph->path->device->lun_id))) 15548b8a9b1dSJustin T. Gibbs continue; 15558b8a9b1dSJustin T. Gibbs 15568b8a9b1dSJustin T. Gibbs if (((cur_pattern->flags & PERIPH_MATCH_UNIT) != 0) 15578b8a9b1dSJustin T. Gibbs && (cur_pattern->unit_number != periph->unit_number)) 15588b8a9b1dSJustin T. Gibbs continue; 15598b8a9b1dSJustin T. Gibbs 15608b8a9b1dSJustin T. Gibbs if (((cur_pattern->flags & PERIPH_MATCH_NAME) != 0) 15618b8a9b1dSJustin T. Gibbs && (strncmp(cur_pattern->periph_name, periph->periph_name, 15628b8a9b1dSJustin T. Gibbs DEV_IDLEN) != 0)) 15638b8a9b1dSJustin T. Gibbs continue; 15648b8a9b1dSJustin T. Gibbs 15658b8a9b1dSJustin T. Gibbs /* 15668b8a9b1dSJustin T. Gibbs * If we get to this point, the user definitely wants 15678b8a9b1dSJustin T. Gibbs * information on this peripheral. So tell the caller to 15688b8a9b1dSJustin T. Gibbs * copy the data out. 15698b8a9b1dSJustin T. Gibbs */ 15708b8a9b1dSJustin T. Gibbs retval |= DM_RET_COPY; 15718b8a9b1dSJustin T. Gibbs 15728b8a9b1dSJustin T. Gibbs /* 15738b8a9b1dSJustin T. Gibbs * The return action has already been set to stop, since 15748b8a9b1dSJustin T. Gibbs * peripherals don't have any nodes below them in the EDT. 15758b8a9b1dSJustin T. Gibbs */ 15768b8a9b1dSJustin T. Gibbs return(retval); 15778b8a9b1dSJustin T. Gibbs } 15788b8a9b1dSJustin T. Gibbs 15798b8a9b1dSJustin T. Gibbs /* 15808b8a9b1dSJustin T. Gibbs * If we get to this point, the peripheral that was passed in 15818b8a9b1dSJustin T. Gibbs * doesn't match any of the patterns. 15828b8a9b1dSJustin T. Gibbs */ 15838b8a9b1dSJustin T. Gibbs return(retval); 15848b8a9b1dSJustin T. Gibbs } 15858b8a9b1dSJustin T. Gibbs 15868b8a9b1dSJustin T. Gibbs static int 15878b8a9b1dSJustin T. Gibbs xptedtbusfunc(struct cam_eb *bus, void *arg) 15888b8a9b1dSJustin T. Gibbs { 15898b8a9b1dSJustin T. Gibbs struct ccb_dev_match *cdm; 15908b8a9b1dSJustin T. Gibbs dev_match_ret retval; 15918b8a9b1dSJustin T. Gibbs 15928b8a9b1dSJustin T. Gibbs cdm = (struct ccb_dev_match *)arg; 15938b8a9b1dSJustin T. Gibbs 15948b8a9b1dSJustin T. Gibbs /* 15958b8a9b1dSJustin T. Gibbs * If our position is for something deeper in the tree, that means 15968b8a9b1dSJustin T. Gibbs * that we've already seen this node. So, we keep going down. 15978b8a9b1dSJustin T. Gibbs */ 15988b8a9b1dSJustin T. Gibbs if ((cdm->pos.position_type & CAM_DEV_POS_BUS) 15998b8a9b1dSJustin T. Gibbs && (cdm->pos.cookie.bus == bus) 16008b8a9b1dSJustin T. Gibbs && (cdm->pos.position_type & CAM_DEV_POS_TARGET) 16018b8a9b1dSJustin T. Gibbs && (cdm->pos.cookie.target != NULL)) 16028b8a9b1dSJustin T. Gibbs retval = DM_RET_DESCEND; 16038b8a9b1dSJustin T. Gibbs else 16048b8a9b1dSJustin T. Gibbs retval = xptbusmatch(cdm->patterns, cdm->num_patterns, bus); 16058b8a9b1dSJustin T. Gibbs 16068b8a9b1dSJustin T. Gibbs /* 16078b8a9b1dSJustin T. Gibbs * If we got an error, bail out of the search. 16088b8a9b1dSJustin T. Gibbs */ 16098b8a9b1dSJustin T. Gibbs if ((retval & DM_RET_ACTION_MASK) == DM_RET_ERROR) { 16108b8a9b1dSJustin T. Gibbs cdm->status = CAM_DEV_MATCH_ERROR; 16118b8a9b1dSJustin T. Gibbs return(0); 16128b8a9b1dSJustin T. Gibbs } 16138b8a9b1dSJustin T. Gibbs 16148b8a9b1dSJustin T. Gibbs /* 16158b8a9b1dSJustin T. Gibbs * If the copy flag is set, copy this bus out. 16168b8a9b1dSJustin T. Gibbs */ 16178b8a9b1dSJustin T. Gibbs if (retval & DM_RET_COPY) { 16188b8a9b1dSJustin T. Gibbs int spaceleft, j; 16198b8a9b1dSJustin T. Gibbs 16208b8a9b1dSJustin T. Gibbs spaceleft = cdm->match_buf_len - (cdm->num_matches * 16218b8a9b1dSJustin T. Gibbs sizeof(struct dev_match_result)); 16228b8a9b1dSJustin T. Gibbs 16238b8a9b1dSJustin T. Gibbs /* 16248b8a9b1dSJustin T. Gibbs * If we don't have enough space to put in another 16258b8a9b1dSJustin T. Gibbs * match result, save our position and tell the 16268b8a9b1dSJustin T. Gibbs * user there are more devices to check. 16278b8a9b1dSJustin T. Gibbs */ 16288b8a9b1dSJustin T. Gibbs if (spaceleft < sizeof(struct dev_match_result)) { 16298b8a9b1dSJustin T. Gibbs bzero(&cdm->pos, sizeof(cdm->pos)); 16308b8a9b1dSJustin T. Gibbs cdm->pos.position_type = 16318b8a9b1dSJustin T. Gibbs CAM_DEV_POS_EDT | CAM_DEV_POS_BUS; 16328b8a9b1dSJustin T. Gibbs 16338b8a9b1dSJustin T. Gibbs cdm->pos.cookie.bus = bus; 16348b8a9b1dSJustin T. Gibbs cdm->pos.generations[CAM_BUS_GENERATION]= 16358b8a9b1dSJustin T. Gibbs bus_generation; 16368b8a9b1dSJustin T. Gibbs cdm->status = CAM_DEV_MATCH_MORE; 16378b8a9b1dSJustin T. Gibbs return(0); 16388b8a9b1dSJustin T. Gibbs } 16398b8a9b1dSJustin T. Gibbs j = cdm->num_matches; 16408b8a9b1dSJustin T. Gibbs cdm->num_matches++; 16418b8a9b1dSJustin T. Gibbs cdm->matches[j].type = DEV_MATCH_BUS; 16428b8a9b1dSJustin T. Gibbs cdm->matches[j].result.bus_result.path_id = bus->path_id; 16438b8a9b1dSJustin T. Gibbs cdm->matches[j].result.bus_result.bus_id = bus->sim->bus_id; 16448b8a9b1dSJustin T. Gibbs cdm->matches[j].result.bus_result.unit_number = 16458b8a9b1dSJustin T. Gibbs bus->sim->unit_number; 16468b8a9b1dSJustin T. Gibbs strncpy(cdm->matches[j].result.bus_result.dev_name, 16478b8a9b1dSJustin T. Gibbs bus->sim->sim_name, DEV_IDLEN); 16488b8a9b1dSJustin T. Gibbs } 16498b8a9b1dSJustin T. Gibbs 16508b8a9b1dSJustin T. Gibbs /* 16518b8a9b1dSJustin T. Gibbs * If the user is only interested in busses, there's no 16528b8a9b1dSJustin T. Gibbs * reason to descend to the next level in the tree. 16538b8a9b1dSJustin T. Gibbs */ 16548b8a9b1dSJustin T. Gibbs if ((retval & DM_RET_ACTION_MASK) == DM_RET_STOP) 16558b8a9b1dSJustin T. Gibbs return(1); 16568b8a9b1dSJustin T. Gibbs 16578b8a9b1dSJustin T. Gibbs /* 16588b8a9b1dSJustin T. Gibbs * If there is a target generation recorded, check it to 16598b8a9b1dSJustin T. Gibbs * make sure the target list hasn't changed. 16608b8a9b1dSJustin T. Gibbs */ 16618b8a9b1dSJustin T. Gibbs if ((cdm->pos.position_type & CAM_DEV_POS_BUS) 16628b8a9b1dSJustin T. Gibbs && (bus == cdm->pos.cookie.bus) 16638b8a9b1dSJustin T. Gibbs && (cdm->pos.position_type & CAM_DEV_POS_TARGET) 16648b8a9b1dSJustin T. Gibbs && (cdm->pos.generations[CAM_TARGET_GENERATION] != 0) 16658b8a9b1dSJustin T. Gibbs && (cdm->pos.generations[CAM_TARGET_GENERATION] != 16668b8a9b1dSJustin T. Gibbs bus->generation)) { 16678b8a9b1dSJustin T. Gibbs cdm->status = CAM_DEV_MATCH_LIST_CHANGED; 16688b8a9b1dSJustin T. Gibbs return(0); 16698b8a9b1dSJustin T. Gibbs } 16708b8a9b1dSJustin T. Gibbs 16718b8a9b1dSJustin T. Gibbs if ((cdm->pos.position_type & CAM_DEV_POS_BUS) 16728b8a9b1dSJustin T. Gibbs && (cdm->pos.cookie.bus == bus) 16738b8a9b1dSJustin T. Gibbs && (cdm->pos.position_type & CAM_DEV_POS_TARGET) 16748b8a9b1dSJustin T. Gibbs && (cdm->pos.cookie.target != NULL)) 16758b8a9b1dSJustin T. Gibbs return(xpttargettraverse(bus, 16768b8a9b1dSJustin T. Gibbs (struct cam_et *)cdm->pos.cookie.target, 16778b8a9b1dSJustin T. Gibbs xptedttargetfunc, arg)); 16788b8a9b1dSJustin T. Gibbs else 16798b8a9b1dSJustin T. Gibbs return(xpttargettraverse(bus, NULL, xptedttargetfunc, arg)); 16808b8a9b1dSJustin T. Gibbs } 16818b8a9b1dSJustin T. Gibbs 16828b8a9b1dSJustin T. Gibbs static int 16838b8a9b1dSJustin T. Gibbs xptedttargetfunc(struct cam_et *target, void *arg) 16848b8a9b1dSJustin T. Gibbs { 16858b8a9b1dSJustin T. Gibbs struct ccb_dev_match *cdm; 16868b8a9b1dSJustin T. Gibbs 16878b8a9b1dSJustin T. Gibbs cdm = (struct ccb_dev_match *)arg; 16888b8a9b1dSJustin T. Gibbs 16898b8a9b1dSJustin T. Gibbs /* 16908b8a9b1dSJustin T. Gibbs * If there is a device list generation recorded, check it to 16918b8a9b1dSJustin T. Gibbs * make sure the device list hasn't changed. 16928b8a9b1dSJustin T. Gibbs */ 16938b8a9b1dSJustin T. Gibbs if ((cdm->pos.position_type & CAM_DEV_POS_BUS) 16948b8a9b1dSJustin T. Gibbs && (cdm->pos.cookie.bus == target->bus) 16958b8a9b1dSJustin T. Gibbs && (cdm->pos.position_type & CAM_DEV_POS_TARGET) 16968b8a9b1dSJustin T. Gibbs && (cdm->pos.cookie.target == target) 16978b8a9b1dSJustin T. Gibbs && (cdm->pos.position_type & CAM_DEV_POS_DEVICE) 16988b8a9b1dSJustin T. Gibbs && (cdm->pos.generations[CAM_DEV_GENERATION] != 0) 16998b8a9b1dSJustin T. Gibbs && (cdm->pos.generations[CAM_DEV_GENERATION] != 17008b8a9b1dSJustin T. Gibbs target->generation)) { 17018b8a9b1dSJustin T. Gibbs cdm->status = CAM_DEV_MATCH_LIST_CHANGED; 17028b8a9b1dSJustin T. Gibbs return(0); 17038b8a9b1dSJustin T. Gibbs } 17048b8a9b1dSJustin T. Gibbs 17058b8a9b1dSJustin T. Gibbs if ((cdm->pos.position_type & CAM_DEV_POS_BUS) 17068b8a9b1dSJustin T. Gibbs && (cdm->pos.cookie.bus == target->bus) 17078b8a9b1dSJustin T. Gibbs && (cdm->pos.position_type & CAM_DEV_POS_TARGET) 17088b8a9b1dSJustin T. Gibbs && (cdm->pos.cookie.target == target) 17098b8a9b1dSJustin T. Gibbs && (cdm->pos.position_type & CAM_DEV_POS_DEVICE) 17108b8a9b1dSJustin T. Gibbs && (cdm->pos.cookie.device != NULL)) 17118b8a9b1dSJustin T. Gibbs return(xptdevicetraverse(target, 17128b8a9b1dSJustin T. Gibbs (struct cam_ed *)cdm->pos.cookie.device, 17138b8a9b1dSJustin T. Gibbs xptedtdevicefunc, arg)); 17148b8a9b1dSJustin T. Gibbs else 17158b8a9b1dSJustin T. Gibbs return(xptdevicetraverse(target, NULL, xptedtdevicefunc, arg)); 17168b8a9b1dSJustin T. Gibbs } 17178b8a9b1dSJustin T. Gibbs 17188b8a9b1dSJustin T. Gibbs static int 17198b8a9b1dSJustin T. Gibbs xptedtdevicefunc(struct cam_ed *device, void *arg) 17208b8a9b1dSJustin T. Gibbs { 17218b8a9b1dSJustin T. Gibbs 17228b8a9b1dSJustin T. Gibbs struct ccb_dev_match *cdm; 17238b8a9b1dSJustin T. Gibbs dev_match_ret retval; 17248b8a9b1dSJustin T. Gibbs u_int dev_gen; 17258b8a9b1dSJustin T. Gibbs 17268b8a9b1dSJustin T. Gibbs cdm = (struct ccb_dev_match *)arg; 17278b8a9b1dSJustin T. Gibbs 17288b8a9b1dSJustin T. Gibbs /* 17298b8a9b1dSJustin T. Gibbs * If our position is for something deeper in the tree, that means 17308b8a9b1dSJustin T. Gibbs * that we've already seen this node. So, we keep going down. 17318b8a9b1dSJustin T. Gibbs */ 17328b8a9b1dSJustin T. Gibbs if ((cdm->pos.position_type & CAM_DEV_POS_DEVICE) 17338b8a9b1dSJustin T. Gibbs && (cdm->pos.cookie.device == device) 17348b8a9b1dSJustin T. Gibbs && (cdm->pos.position_type & CAM_DEV_POS_PERIPH) 17358b8a9b1dSJustin T. Gibbs && (cdm->pos.cookie.periph != NULL)) 17368b8a9b1dSJustin T. Gibbs retval = DM_RET_DESCEND; 17378b8a9b1dSJustin T. Gibbs else 17388b8a9b1dSJustin T. Gibbs retval = xptdevicematch(cdm->patterns, cdm->num_patterns, 17398b8a9b1dSJustin T. Gibbs device); 17408b8a9b1dSJustin T. Gibbs 17418b8a9b1dSJustin T. Gibbs if ((retval & DM_RET_ACTION_MASK) == DM_RET_ERROR) { 17428b8a9b1dSJustin T. Gibbs cdm->status = CAM_DEV_MATCH_ERROR; 17438b8a9b1dSJustin T. Gibbs return(0); 17448b8a9b1dSJustin T. Gibbs } 17458b8a9b1dSJustin T. Gibbs 17468b8a9b1dSJustin T. Gibbs /* 17478b8a9b1dSJustin T. Gibbs * If the copy flag is set, copy this device out. 17488b8a9b1dSJustin T. Gibbs */ 17498b8a9b1dSJustin T. Gibbs if (retval & DM_RET_COPY) { 17508b8a9b1dSJustin T. Gibbs int spaceleft, j; 17518b8a9b1dSJustin T. Gibbs 17528b8a9b1dSJustin T. Gibbs spaceleft = cdm->match_buf_len - (cdm->num_matches * 17538b8a9b1dSJustin T. Gibbs sizeof(struct dev_match_result)); 17548b8a9b1dSJustin T. Gibbs 17558b8a9b1dSJustin T. Gibbs /* 17568b8a9b1dSJustin T. Gibbs * If we don't have enough space to put in another 17578b8a9b1dSJustin T. Gibbs * match result, save our position and tell the 17588b8a9b1dSJustin T. Gibbs * user there are more devices to check. 17598b8a9b1dSJustin T. Gibbs */ 17608b8a9b1dSJustin T. Gibbs if (spaceleft < sizeof(struct dev_match_result)) { 17618b8a9b1dSJustin T. Gibbs bzero(&cdm->pos, sizeof(cdm->pos)); 17628b8a9b1dSJustin T. Gibbs cdm->pos.position_type = 17638b8a9b1dSJustin T. Gibbs CAM_DEV_POS_EDT | CAM_DEV_POS_BUS | 17648b8a9b1dSJustin T. Gibbs CAM_DEV_POS_TARGET | CAM_DEV_POS_DEVICE; 17658b8a9b1dSJustin T. Gibbs 17668b8a9b1dSJustin T. Gibbs cdm->pos.cookie.bus = device->target->bus; 17678b8a9b1dSJustin T. Gibbs cdm->pos.generations[CAM_BUS_GENERATION]= 17688b8a9b1dSJustin T. Gibbs bus_generation; 17698b8a9b1dSJustin T. Gibbs cdm->pos.cookie.target = device->target; 17708b8a9b1dSJustin T. Gibbs cdm->pos.generations[CAM_TARGET_GENERATION] = 17718b8a9b1dSJustin T. Gibbs device->target->bus->generation; 17728b8a9b1dSJustin T. Gibbs cdm->pos.cookie.device = device; 17738b8a9b1dSJustin T. Gibbs cdm->pos.generations[CAM_DEV_GENERATION] = 17748b8a9b1dSJustin T. Gibbs device->target->generation; 17758b8a9b1dSJustin T. Gibbs cdm->status = CAM_DEV_MATCH_MORE; 17768b8a9b1dSJustin T. Gibbs return(0); 17778b8a9b1dSJustin T. Gibbs } 17788b8a9b1dSJustin T. Gibbs j = cdm->num_matches; 17798b8a9b1dSJustin T. Gibbs cdm->num_matches++; 17808b8a9b1dSJustin T. Gibbs cdm->matches[j].type = DEV_MATCH_DEVICE; 17818b8a9b1dSJustin T. Gibbs cdm->matches[j].result.device_result.path_id = 17828b8a9b1dSJustin T. Gibbs device->target->bus->path_id; 17838b8a9b1dSJustin T. Gibbs cdm->matches[j].result.device_result.target_id = 17848b8a9b1dSJustin T. Gibbs device->target->target_id; 17858b8a9b1dSJustin T. Gibbs cdm->matches[j].result.device_result.target_lun = 17868b8a9b1dSJustin T. Gibbs device->lun_id; 17878b8a9b1dSJustin T. Gibbs bcopy(&device->inq_data, 17888b8a9b1dSJustin T. Gibbs &cdm->matches[j].result.device_result.inq_data, 17898b8a9b1dSJustin T. Gibbs sizeof(struct scsi_inquiry_data)); 17908b8a9b1dSJustin T. Gibbs } 17918b8a9b1dSJustin T. Gibbs 17928b8a9b1dSJustin T. Gibbs /* 17938b8a9b1dSJustin T. Gibbs * If the user isn't interested in peripherals, don't descend 17948b8a9b1dSJustin T. Gibbs * the tree any further. 17958b8a9b1dSJustin T. Gibbs */ 17968b8a9b1dSJustin T. Gibbs if ((retval & DM_RET_ACTION_MASK) == DM_RET_STOP) 17978b8a9b1dSJustin T. Gibbs return(1); 17988b8a9b1dSJustin T. Gibbs 17998b8a9b1dSJustin T. Gibbs /* 18008b8a9b1dSJustin T. Gibbs * If there is a peripheral list generation recorded, make sure 18018b8a9b1dSJustin T. Gibbs * it hasn't changed. 18028b8a9b1dSJustin T. Gibbs */ 18038b8a9b1dSJustin T. Gibbs if ((cdm->pos.position_type & CAM_DEV_POS_BUS) 18048b8a9b1dSJustin T. Gibbs && (device->target->bus == cdm->pos.cookie.bus) 18058b8a9b1dSJustin T. Gibbs && (cdm->pos.position_type & CAM_DEV_POS_TARGET) 18068b8a9b1dSJustin T. Gibbs && (device->target == cdm->pos.cookie.target) 18078b8a9b1dSJustin T. Gibbs && (cdm->pos.position_type & CAM_DEV_POS_DEVICE) 18088b8a9b1dSJustin T. Gibbs && (device == cdm->pos.cookie.device) 18098b8a9b1dSJustin T. Gibbs && (cdm->pos.position_type & CAM_DEV_POS_PERIPH) 18108b8a9b1dSJustin T. Gibbs && (cdm->pos.generations[CAM_PERIPH_GENERATION] != 0) 18118b8a9b1dSJustin T. Gibbs && (cdm->pos.generations[CAM_PERIPH_GENERATION] != 18128b8a9b1dSJustin T. Gibbs device->generation)){ 18138b8a9b1dSJustin T. Gibbs cdm->status = CAM_DEV_MATCH_LIST_CHANGED; 18148b8a9b1dSJustin T. Gibbs return(0); 18158b8a9b1dSJustin T. Gibbs } 18168b8a9b1dSJustin T. Gibbs 18178b8a9b1dSJustin T. Gibbs if ((cdm->pos.position_type & CAM_DEV_POS_BUS) 18188b8a9b1dSJustin T. Gibbs && (cdm->pos.cookie.bus == device->target->bus) 18198b8a9b1dSJustin T. Gibbs && (cdm->pos.position_type & CAM_DEV_POS_TARGET) 18208b8a9b1dSJustin T. Gibbs && (cdm->pos.cookie.target == device->target) 18218b8a9b1dSJustin T. Gibbs && (cdm->pos.position_type & CAM_DEV_POS_DEVICE) 18228b8a9b1dSJustin T. Gibbs && (cdm->pos.cookie.device == device) 18238b8a9b1dSJustin T. Gibbs && (cdm->pos.position_type & CAM_DEV_POS_PERIPH) 18248b8a9b1dSJustin T. Gibbs && (cdm->pos.cookie.periph != NULL)) 18258b8a9b1dSJustin T. Gibbs return(xptperiphtraverse(device, 18268b8a9b1dSJustin T. Gibbs (struct cam_periph *)cdm->pos.cookie.periph, 18278b8a9b1dSJustin T. Gibbs xptedtperiphfunc, arg)); 18288b8a9b1dSJustin T. Gibbs else 18298b8a9b1dSJustin T. Gibbs return(xptperiphtraverse(device, NULL, xptedtperiphfunc, arg)); 18308b8a9b1dSJustin T. Gibbs } 18318b8a9b1dSJustin T. Gibbs 18328b8a9b1dSJustin T. Gibbs static int 18338b8a9b1dSJustin T. Gibbs xptedtperiphfunc(struct cam_periph *periph, void *arg) 18348b8a9b1dSJustin T. Gibbs { 18358b8a9b1dSJustin T. Gibbs struct ccb_dev_match *cdm; 18368b8a9b1dSJustin T. Gibbs dev_match_ret retval; 18378b8a9b1dSJustin T. Gibbs 18388b8a9b1dSJustin T. Gibbs cdm = (struct ccb_dev_match *)arg; 18398b8a9b1dSJustin T. Gibbs 18408b8a9b1dSJustin T. Gibbs retval = xptperiphmatch(cdm->patterns, cdm->num_patterns, periph); 18418b8a9b1dSJustin T. Gibbs 18428b8a9b1dSJustin T. Gibbs if ((retval & DM_RET_ACTION_MASK) == DM_RET_ERROR) { 18438b8a9b1dSJustin T. Gibbs cdm->status = CAM_DEV_MATCH_ERROR; 18448b8a9b1dSJustin T. Gibbs return(0); 18458b8a9b1dSJustin T. Gibbs } 18468b8a9b1dSJustin T. Gibbs 18478b8a9b1dSJustin T. Gibbs /* 18488b8a9b1dSJustin T. Gibbs * If the copy flag is set, copy this peripheral out. 18498b8a9b1dSJustin T. Gibbs */ 18508b8a9b1dSJustin T. Gibbs if (retval & DM_RET_COPY) { 18518b8a9b1dSJustin T. Gibbs int spaceleft, j; 18528b8a9b1dSJustin T. Gibbs 18538b8a9b1dSJustin T. Gibbs spaceleft = cdm->match_buf_len - (cdm->num_matches * 18548b8a9b1dSJustin T. Gibbs sizeof(struct dev_match_result)); 18558b8a9b1dSJustin T. Gibbs 18568b8a9b1dSJustin T. Gibbs /* 18578b8a9b1dSJustin T. Gibbs * If we don't have enough space to put in another 18588b8a9b1dSJustin T. Gibbs * match result, save our position and tell the 18598b8a9b1dSJustin T. Gibbs * user there are more devices to check. 18608b8a9b1dSJustin T. Gibbs */ 18618b8a9b1dSJustin T. Gibbs if (spaceleft < sizeof(struct dev_match_result)) { 18628b8a9b1dSJustin T. Gibbs bzero(&cdm->pos, sizeof(cdm->pos)); 18638b8a9b1dSJustin T. Gibbs cdm->pos.position_type = 18648b8a9b1dSJustin T. Gibbs CAM_DEV_POS_EDT | CAM_DEV_POS_BUS | 18658b8a9b1dSJustin T. Gibbs CAM_DEV_POS_TARGET | CAM_DEV_POS_DEVICE | 18668b8a9b1dSJustin T. Gibbs CAM_DEV_POS_PERIPH; 18678b8a9b1dSJustin T. Gibbs 18688b8a9b1dSJustin T. Gibbs cdm->pos.cookie.bus = periph->path->bus; 18698b8a9b1dSJustin T. Gibbs cdm->pos.generations[CAM_BUS_GENERATION]= 18708b8a9b1dSJustin T. Gibbs bus_generation; 18718b8a9b1dSJustin T. Gibbs cdm->pos.cookie.target = periph->path->target; 18728b8a9b1dSJustin T. Gibbs cdm->pos.generations[CAM_TARGET_GENERATION] = 18738b8a9b1dSJustin T. Gibbs periph->path->bus->generation; 18748b8a9b1dSJustin T. Gibbs cdm->pos.cookie.device = periph->path->device; 18758b8a9b1dSJustin T. Gibbs cdm->pos.generations[CAM_DEV_GENERATION] = 18768b8a9b1dSJustin T. Gibbs periph->path->target->generation; 18778b8a9b1dSJustin T. Gibbs cdm->pos.cookie.periph = periph; 18788b8a9b1dSJustin T. Gibbs cdm->pos.generations[CAM_PERIPH_GENERATION] = 18798b8a9b1dSJustin T. Gibbs periph->path->device->generation; 18808b8a9b1dSJustin T. Gibbs cdm->status = CAM_DEV_MATCH_MORE; 18818b8a9b1dSJustin T. Gibbs return(0); 18828b8a9b1dSJustin T. Gibbs } 18838b8a9b1dSJustin T. Gibbs 18848b8a9b1dSJustin T. Gibbs j = cdm->num_matches; 18858b8a9b1dSJustin T. Gibbs cdm->num_matches++; 18868b8a9b1dSJustin T. Gibbs cdm->matches[j].type = DEV_MATCH_PERIPH; 18878b8a9b1dSJustin T. Gibbs cdm->matches[j].result.periph_result.path_id = 18888b8a9b1dSJustin T. Gibbs periph->path->bus->path_id; 18898b8a9b1dSJustin T. Gibbs cdm->matches[j].result.periph_result.target_id = 18908b8a9b1dSJustin T. Gibbs periph->path->target->target_id; 18918b8a9b1dSJustin T. Gibbs cdm->matches[j].result.periph_result.target_lun = 18928b8a9b1dSJustin T. Gibbs periph->path->device->lun_id; 18938b8a9b1dSJustin T. Gibbs cdm->matches[j].result.periph_result.unit_number = 18948b8a9b1dSJustin T. Gibbs periph->unit_number; 18958b8a9b1dSJustin T. Gibbs strncpy(cdm->matches[j].result.periph_result.periph_name, 18968b8a9b1dSJustin T. Gibbs periph->periph_name, DEV_IDLEN); 18978b8a9b1dSJustin T. Gibbs } 18988b8a9b1dSJustin T. Gibbs 18998b8a9b1dSJustin T. Gibbs return(1); 19008b8a9b1dSJustin T. Gibbs } 19018b8a9b1dSJustin T. Gibbs 19028b8a9b1dSJustin T. Gibbs static int 19038b8a9b1dSJustin T. Gibbs xptedtmatch(struct ccb_dev_match *cdm) 19048b8a9b1dSJustin T. Gibbs { 19058b8a9b1dSJustin T. Gibbs int ret; 19068b8a9b1dSJustin T. Gibbs 19078b8a9b1dSJustin T. Gibbs cdm->num_matches = 0; 19088b8a9b1dSJustin T. Gibbs 19098b8a9b1dSJustin T. Gibbs /* 19108b8a9b1dSJustin T. Gibbs * Check the bus list generation. If it has changed, the user 19118b8a9b1dSJustin T. Gibbs * needs to reset everything and start over. 19128b8a9b1dSJustin T. Gibbs */ 19138b8a9b1dSJustin T. Gibbs if ((cdm->pos.position_type & CAM_DEV_POS_BUS) 19148b8a9b1dSJustin T. Gibbs && (cdm->pos.generations[CAM_BUS_GENERATION] != 0) 19158b8a9b1dSJustin T. Gibbs && (cdm->pos.generations[CAM_BUS_GENERATION] != bus_generation)) { 19168b8a9b1dSJustin T. Gibbs cdm->status = CAM_DEV_MATCH_LIST_CHANGED; 19178b8a9b1dSJustin T. Gibbs return(0); 19188b8a9b1dSJustin T. Gibbs } 19198b8a9b1dSJustin T. Gibbs 19208b8a9b1dSJustin T. Gibbs if ((cdm->pos.position_type & CAM_DEV_POS_BUS) 19218b8a9b1dSJustin T. Gibbs && (cdm->pos.cookie.bus != NULL)) 19228b8a9b1dSJustin T. Gibbs ret = xptbustraverse((struct cam_eb *)cdm->pos.cookie.bus, 19238b8a9b1dSJustin T. Gibbs xptedtbusfunc, cdm); 19248b8a9b1dSJustin T. Gibbs else 19258b8a9b1dSJustin T. Gibbs ret = xptbustraverse(NULL, xptedtbusfunc, cdm); 19268b8a9b1dSJustin T. Gibbs 19278b8a9b1dSJustin T. Gibbs /* 19288b8a9b1dSJustin T. Gibbs * If we get back 0, that means that we had to stop before fully 19298b8a9b1dSJustin T. Gibbs * traversing the EDT. It also means that one of the subroutines 19308b8a9b1dSJustin T. Gibbs * has set the status field to the proper value. If we get back 1, 19318b8a9b1dSJustin T. Gibbs * we've fully traversed the EDT and copied out any matching entries. 19328b8a9b1dSJustin T. Gibbs */ 19338b8a9b1dSJustin T. Gibbs if (ret == 1) 19348b8a9b1dSJustin T. Gibbs cdm->status = CAM_DEV_MATCH_LAST; 19358b8a9b1dSJustin T. Gibbs 19368b8a9b1dSJustin T. Gibbs return(ret); 19378b8a9b1dSJustin T. Gibbs } 19388b8a9b1dSJustin T. Gibbs 19398b8a9b1dSJustin T. Gibbs static int 19408b8a9b1dSJustin T. Gibbs xptplistpdrvfunc(struct periph_driver **pdrv, void *arg) 19418b8a9b1dSJustin T. Gibbs { 19428b8a9b1dSJustin T. Gibbs struct ccb_dev_match *cdm; 19438b8a9b1dSJustin T. Gibbs 19448b8a9b1dSJustin T. Gibbs cdm = (struct ccb_dev_match *)arg; 19458b8a9b1dSJustin T. Gibbs 19468b8a9b1dSJustin T. Gibbs if ((cdm->pos.position_type & CAM_DEV_POS_PDPTR) 19478b8a9b1dSJustin T. Gibbs && (cdm->pos.cookie.pdrv == pdrv) 19488b8a9b1dSJustin T. Gibbs && (cdm->pos.position_type & CAM_DEV_POS_PERIPH) 19498b8a9b1dSJustin T. Gibbs && (cdm->pos.generations[CAM_PERIPH_GENERATION] != 0) 19508b8a9b1dSJustin T. Gibbs && (cdm->pos.generations[CAM_PERIPH_GENERATION] != 19518b8a9b1dSJustin T. Gibbs (*pdrv)->generation)) { 19528b8a9b1dSJustin T. Gibbs cdm->status = CAM_DEV_MATCH_LIST_CHANGED; 19538b8a9b1dSJustin T. Gibbs return(0); 19548b8a9b1dSJustin T. Gibbs } 19558b8a9b1dSJustin T. Gibbs 19568b8a9b1dSJustin T. Gibbs if ((cdm->pos.position_type & CAM_DEV_POS_PDPTR) 19578b8a9b1dSJustin T. Gibbs && (cdm->pos.cookie.pdrv == pdrv) 19588b8a9b1dSJustin T. Gibbs && (cdm->pos.position_type & CAM_DEV_POS_PERIPH) 19598b8a9b1dSJustin T. Gibbs && (cdm->pos.cookie.periph != NULL)) 19608b8a9b1dSJustin T. Gibbs return(xptpdperiphtraverse(pdrv, 19618b8a9b1dSJustin T. Gibbs (struct cam_periph *)cdm->pos.cookie.periph, 19628b8a9b1dSJustin T. Gibbs xptplistperiphfunc, arg)); 19638b8a9b1dSJustin T. Gibbs else 19648b8a9b1dSJustin T. Gibbs return(xptpdperiphtraverse(pdrv, NULL,xptplistperiphfunc, arg)); 19658b8a9b1dSJustin T. Gibbs } 19668b8a9b1dSJustin T. Gibbs 19678b8a9b1dSJustin T. Gibbs static int 19688b8a9b1dSJustin T. Gibbs xptplistperiphfunc(struct cam_periph *periph, void *arg) 19698b8a9b1dSJustin T. Gibbs { 19708b8a9b1dSJustin T. Gibbs struct ccb_dev_match *cdm; 19718b8a9b1dSJustin T. Gibbs dev_match_ret retval; 19728b8a9b1dSJustin T. Gibbs 19738b8a9b1dSJustin T. Gibbs cdm = (struct ccb_dev_match *)arg; 19748b8a9b1dSJustin T. Gibbs 19758b8a9b1dSJustin T. Gibbs retval = xptperiphmatch(cdm->patterns, cdm->num_patterns, periph); 19768b8a9b1dSJustin T. Gibbs 19778b8a9b1dSJustin T. Gibbs if ((retval & DM_RET_ACTION_MASK) == DM_RET_ERROR) { 19788b8a9b1dSJustin T. Gibbs cdm->status = CAM_DEV_MATCH_ERROR; 19798b8a9b1dSJustin T. Gibbs return(0); 19808b8a9b1dSJustin T. Gibbs } 19818b8a9b1dSJustin T. Gibbs 19828b8a9b1dSJustin T. Gibbs /* 19838b8a9b1dSJustin T. Gibbs * If the copy flag is set, copy this peripheral out. 19848b8a9b1dSJustin T. Gibbs */ 19858b8a9b1dSJustin T. Gibbs if (retval & DM_RET_COPY) { 19868b8a9b1dSJustin T. Gibbs int spaceleft, j; 19878b8a9b1dSJustin T. Gibbs 19888b8a9b1dSJustin T. Gibbs spaceleft = cdm->match_buf_len - (cdm->num_matches * 19898b8a9b1dSJustin T. Gibbs sizeof(struct dev_match_result)); 19908b8a9b1dSJustin T. Gibbs 19918b8a9b1dSJustin T. Gibbs /* 19928b8a9b1dSJustin T. Gibbs * If we don't have enough space to put in another 19938b8a9b1dSJustin T. Gibbs * match result, save our position and tell the 19948b8a9b1dSJustin T. Gibbs * user there are more devices to check. 19958b8a9b1dSJustin T. Gibbs */ 19968b8a9b1dSJustin T. Gibbs if (spaceleft < sizeof(struct dev_match_result)) { 19978b8a9b1dSJustin T. Gibbs struct periph_driver **pdrv; 19988b8a9b1dSJustin T. Gibbs 19998b8a9b1dSJustin T. Gibbs pdrv = NULL; 20008b8a9b1dSJustin T. Gibbs bzero(&cdm->pos, sizeof(cdm->pos)); 20018b8a9b1dSJustin T. Gibbs cdm->pos.position_type = 20028b8a9b1dSJustin T. Gibbs CAM_DEV_POS_PDRV | CAM_DEV_POS_PDPTR | 20038b8a9b1dSJustin T. Gibbs CAM_DEV_POS_PERIPH; 20048b8a9b1dSJustin T. Gibbs 20058b8a9b1dSJustin T. Gibbs /* 20068b8a9b1dSJustin T. Gibbs * This may look a bit non-sensical, but it is 20078b8a9b1dSJustin T. Gibbs * actually quite logical. There are very few 20088b8a9b1dSJustin T. Gibbs * peripheral drivers, and bloating every peripheral 20098b8a9b1dSJustin T. Gibbs * structure with a pointer back to its parent 20108b8a9b1dSJustin T. Gibbs * peripheral driver linker set entry would cost 20118b8a9b1dSJustin T. Gibbs * more in the long run than doing this quick lookup. 20128b8a9b1dSJustin T. Gibbs */ 20138b8a9b1dSJustin T. Gibbs for (pdrv = 20148b8a9b1dSJustin T. Gibbs (struct periph_driver **)periphdriver_set.ls_items; 20158b8a9b1dSJustin T. Gibbs *pdrv != NULL; pdrv++) { 20168b8a9b1dSJustin T. Gibbs if (strcmp((*pdrv)->driver_name, 20178b8a9b1dSJustin T. Gibbs periph->periph_name) == 0) 20188b8a9b1dSJustin T. Gibbs break; 20198b8a9b1dSJustin T. Gibbs } 20208b8a9b1dSJustin T. Gibbs 20218b8a9b1dSJustin T. Gibbs if (pdrv == NULL) { 20228b8a9b1dSJustin T. Gibbs cdm->status = CAM_DEV_MATCH_ERROR; 20238b8a9b1dSJustin T. Gibbs return(0); 20248b8a9b1dSJustin T. Gibbs } 20258b8a9b1dSJustin T. Gibbs 20268b8a9b1dSJustin T. Gibbs cdm->pos.cookie.pdrv = pdrv; 20278b8a9b1dSJustin T. Gibbs /* 20288b8a9b1dSJustin T. Gibbs * The periph generation slot does double duty, as 20298b8a9b1dSJustin T. Gibbs * does the periph pointer slot. They are used for 20308b8a9b1dSJustin T. Gibbs * both edt and pdrv lookups and positioning. 20318b8a9b1dSJustin T. Gibbs */ 20328b8a9b1dSJustin T. Gibbs cdm->pos.cookie.periph = periph; 20338b8a9b1dSJustin T. Gibbs cdm->pos.generations[CAM_PERIPH_GENERATION] = 20348b8a9b1dSJustin T. Gibbs (*pdrv)->generation; 20358b8a9b1dSJustin T. Gibbs cdm->status = CAM_DEV_MATCH_MORE; 20368b8a9b1dSJustin T. Gibbs return(0); 20378b8a9b1dSJustin T. Gibbs } 20388b8a9b1dSJustin T. Gibbs 20398b8a9b1dSJustin T. Gibbs j = cdm->num_matches; 20408b8a9b1dSJustin T. Gibbs cdm->num_matches++; 20418b8a9b1dSJustin T. Gibbs cdm->matches[j].type = DEV_MATCH_PERIPH; 20428b8a9b1dSJustin T. Gibbs cdm->matches[j].result.periph_result.path_id = 20438b8a9b1dSJustin T. Gibbs periph->path->bus->path_id; 20448b8a9b1dSJustin T. Gibbs 20458b8a9b1dSJustin T. Gibbs /* 20468b8a9b1dSJustin T. Gibbs * The transport layer peripheral doesn't have a target or 20478b8a9b1dSJustin T. Gibbs * lun. 20488b8a9b1dSJustin T. Gibbs */ 20498b8a9b1dSJustin T. Gibbs if (periph->path->target) 20508b8a9b1dSJustin T. Gibbs cdm->matches[j].result.periph_result.target_id = 20518b8a9b1dSJustin T. Gibbs periph->path->target->target_id; 20528b8a9b1dSJustin T. Gibbs else 20538b8a9b1dSJustin T. Gibbs cdm->matches[j].result.periph_result.target_id = -1; 20548b8a9b1dSJustin T. Gibbs 20558b8a9b1dSJustin T. Gibbs if (periph->path->device) 20568b8a9b1dSJustin T. Gibbs cdm->matches[j].result.periph_result.target_lun = 20578b8a9b1dSJustin T. Gibbs periph->path->device->lun_id; 20588b8a9b1dSJustin T. Gibbs else 20598b8a9b1dSJustin T. Gibbs cdm->matches[j].result.periph_result.target_lun = -1; 20608b8a9b1dSJustin T. Gibbs 20618b8a9b1dSJustin T. Gibbs cdm->matches[j].result.periph_result.unit_number = 20628b8a9b1dSJustin T. Gibbs periph->unit_number; 20638b8a9b1dSJustin T. Gibbs strncpy(cdm->matches[j].result.periph_result.periph_name, 20648b8a9b1dSJustin T. Gibbs periph->periph_name, DEV_IDLEN); 20658b8a9b1dSJustin T. Gibbs } 20668b8a9b1dSJustin T. Gibbs 20678b8a9b1dSJustin T. Gibbs return(1); 20688b8a9b1dSJustin T. Gibbs } 20698b8a9b1dSJustin T. Gibbs 20708b8a9b1dSJustin T. Gibbs static int 20718b8a9b1dSJustin T. Gibbs xptperiphlistmatch(struct ccb_dev_match *cdm) 20728b8a9b1dSJustin T. Gibbs { 20738b8a9b1dSJustin T. Gibbs int ret; 20748b8a9b1dSJustin T. Gibbs 20758b8a9b1dSJustin T. Gibbs cdm->num_matches = 0; 20768b8a9b1dSJustin T. Gibbs 20778b8a9b1dSJustin T. Gibbs /* 20788b8a9b1dSJustin T. Gibbs * At this point in the edt traversal function, we check the bus 20798b8a9b1dSJustin T. Gibbs * list generation to make sure that no busses have been added or 20808b8a9b1dSJustin T. Gibbs * removed since the user last sent a XPT_DEV_MATCH ccb through. 20818b8a9b1dSJustin T. Gibbs * For the peripheral driver list traversal function, however, we 20828b8a9b1dSJustin T. Gibbs * don't have to worry about new peripheral driver types coming or 20838b8a9b1dSJustin T. Gibbs * going; they're in a linker set, and therefore can't change 20848b8a9b1dSJustin T. Gibbs * without a recompile. 20858b8a9b1dSJustin T. Gibbs */ 20868b8a9b1dSJustin T. Gibbs 20878b8a9b1dSJustin T. Gibbs if ((cdm->pos.position_type & CAM_DEV_POS_PDPTR) 20888b8a9b1dSJustin T. Gibbs && (cdm->pos.cookie.pdrv != NULL)) 20898b8a9b1dSJustin T. Gibbs ret = xptpdrvtraverse( 20908b8a9b1dSJustin T. Gibbs (struct periph_driver **)cdm->pos.cookie.pdrv, 20918b8a9b1dSJustin T. Gibbs xptplistpdrvfunc, cdm); 20928b8a9b1dSJustin T. Gibbs else 20938b8a9b1dSJustin T. Gibbs ret = xptpdrvtraverse(NULL, xptplistpdrvfunc, cdm); 20948b8a9b1dSJustin T. Gibbs 20958b8a9b1dSJustin T. Gibbs /* 20968b8a9b1dSJustin T. Gibbs * If we get back 0, that means that we had to stop before fully 20978b8a9b1dSJustin T. Gibbs * traversing the peripheral driver tree. It also means that one of 20988b8a9b1dSJustin T. Gibbs * the subroutines has set the status field to the proper value. If 20998b8a9b1dSJustin T. Gibbs * we get back 1, we've fully traversed the EDT and copied out any 21008b8a9b1dSJustin T. Gibbs * matching entries. 21018b8a9b1dSJustin T. Gibbs */ 21028b8a9b1dSJustin T. Gibbs if (ret == 1) 21038b8a9b1dSJustin T. Gibbs cdm->status = CAM_DEV_MATCH_LAST; 21048b8a9b1dSJustin T. Gibbs 21058b8a9b1dSJustin T. Gibbs return(ret); 21068b8a9b1dSJustin T. Gibbs } 21078b8a9b1dSJustin T. Gibbs 21088b8a9b1dSJustin T. Gibbs static int 21098b8a9b1dSJustin T. Gibbs xptbustraverse(struct cam_eb *start_bus, xpt_busfunc_t *tr_func, void *arg) 21108b8a9b1dSJustin T. Gibbs { 21118b8a9b1dSJustin T. Gibbs struct cam_eb *bus, *next_bus; 21128b8a9b1dSJustin T. Gibbs int retval; 21138b8a9b1dSJustin T. Gibbs 21148b8a9b1dSJustin T. Gibbs retval = 1; 21158b8a9b1dSJustin T. Gibbs 21168b8a9b1dSJustin T. Gibbs for (bus = (start_bus ? start_bus : TAILQ_FIRST(&xpt_busses)); 21178b8a9b1dSJustin T. Gibbs bus != NULL; 21188b8a9b1dSJustin T. Gibbs bus = next_bus) { 21198b8a9b1dSJustin T. Gibbs next_bus = TAILQ_NEXT(bus, links); 21208b8a9b1dSJustin T. Gibbs 21218b8a9b1dSJustin T. Gibbs retval = tr_func(bus, arg); 21228b8a9b1dSJustin T. Gibbs if (retval == 0) 21238b8a9b1dSJustin T. Gibbs return(retval); 21248b8a9b1dSJustin T. Gibbs } 21258b8a9b1dSJustin T. Gibbs 21268b8a9b1dSJustin T. Gibbs return(retval); 21278b8a9b1dSJustin T. Gibbs } 21288b8a9b1dSJustin T. Gibbs 21298b8a9b1dSJustin T. Gibbs static int 21308b8a9b1dSJustin T. Gibbs xpttargettraverse(struct cam_eb *bus, struct cam_et *start_target, 21318b8a9b1dSJustin T. Gibbs xpt_targetfunc_t *tr_func, void *arg) 21328b8a9b1dSJustin T. Gibbs { 21338b8a9b1dSJustin T. Gibbs struct cam_et *target, *next_target; 21348b8a9b1dSJustin T. Gibbs int retval; 21358b8a9b1dSJustin T. Gibbs 21368b8a9b1dSJustin T. Gibbs retval = 1; 21378b8a9b1dSJustin T. Gibbs for (target = (start_target ? start_target : 21388b8a9b1dSJustin T. Gibbs TAILQ_FIRST(&bus->et_entries)); 21398b8a9b1dSJustin T. Gibbs target != NULL; target = next_target) { 21408b8a9b1dSJustin T. Gibbs 21418b8a9b1dSJustin T. Gibbs next_target = TAILQ_NEXT(target, links); 21428b8a9b1dSJustin T. Gibbs 21438b8a9b1dSJustin T. Gibbs retval = tr_func(target, arg); 21448b8a9b1dSJustin T. Gibbs 21458b8a9b1dSJustin T. Gibbs if (retval == 0) 21468b8a9b1dSJustin T. Gibbs return(retval); 21478b8a9b1dSJustin T. Gibbs } 21488b8a9b1dSJustin T. Gibbs 21498b8a9b1dSJustin T. Gibbs return(retval); 21508b8a9b1dSJustin T. Gibbs } 21518b8a9b1dSJustin T. Gibbs 21528b8a9b1dSJustin T. Gibbs static int 21538b8a9b1dSJustin T. Gibbs xptdevicetraverse(struct cam_et *target, struct cam_ed *start_device, 21548b8a9b1dSJustin T. Gibbs xpt_devicefunc_t *tr_func, void *arg) 21558b8a9b1dSJustin T. Gibbs { 21568b8a9b1dSJustin T. Gibbs struct cam_ed *device, *next_device; 21578b8a9b1dSJustin T. Gibbs int retval; 21588b8a9b1dSJustin T. Gibbs 21598b8a9b1dSJustin T. Gibbs retval = 1; 21608b8a9b1dSJustin T. Gibbs for (device = (start_device ? start_device : 21618b8a9b1dSJustin T. Gibbs TAILQ_FIRST(&target->ed_entries)); 21628b8a9b1dSJustin T. Gibbs device != NULL; 21638b8a9b1dSJustin T. Gibbs device = next_device) { 21648b8a9b1dSJustin T. Gibbs 21658b8a9b1dSJustin T. Gibbs next_device = TAILQ_NEXT(device, links); 21668b8a9b1dSJustin T. Gibbs 21678b8a9b1dSJustin T. Gibbs retval = tr_func(device, arg); 21688b8a9b1dSJustin T. Gibbs 21698b8a9b1dSJustin T. Gibbs if (retval == 0) 21708b8a9b1dSJustin T. Gibbs return(retval); 21718b8a9b1dSJustin T. Gibbs } 21728b8a9b1dSJustin T. Gibbs 21738b8a9b1dSJustin T. Gibbs return(retval); 21748b8a9b1dSJustin T. Gibbs } 21758b8a9b1dSJustin T. Gibbs 21768b8a9b1dSJustin T. Gibbs static int 21778b8a9b1dSJustin T. Gibbs xptperiphtraverse(struct cam_ed *device, struct cam_periph *start_periph, 21788b8a9b1dSJustin T. Gibbs xpt_periphfunc_t *tr_func, void *arg) 21798b8a9b1dSJustin T. Gibbs { 21808b8a9b1dSJustin T. Gibbs struct cam_periph *periph, *next_periph; 21818b8a9b1dSJustin T. Gibbs int retval; 21828b8a9b1dSJustin T. Gibbs 21838b8a9b1dSJustin T. Gibbs retval = 1; 21848b8a9b1dSJustin T. Gibbs 21858b8a9b1dSJustin T. Gibbs for (periph = (start_periph ? start_periph : 21868b8a9b1dSJustin T. Gibbs SLIST_FIRST(&device->periphs)); 21878b8a9b1dSJustin T. Gibbs periph != NULL; 21888b8a9b1dSJustin T. Gibbs periph = next_periph) { 21898b8a9b1dSJustin T. Gibbs 21908b8a9b1dSJustin T. Gibbs next_periph = SLIST_NEXT(periph, periph_links); 21918b8a9b1dSJustin T. Gibbs 21928b8a9b1dSJustin T. Gibbs retval = tr_func(periph, arg); 21938b8a9b1dSJustin T. Gibbs if (retval == 0) 21948b8a9b1dSJustin T. Gibbs return(retval); 21958b8a9b1dSJustin T. Gibbs } 21968b8a9b1dSJustin T. Gibbs 21978b8a9b1dSJustin T. Gibbs return(retval); 21988b8a9b1dSJustin T. Gibbs } 21998b8a9b1dSJustin T. Gibbs 22008b8a9b1dSJustin T. Gibbs static int 22018b8a9b1dSJustin T. Gibbs xptpdrvtraverse(struct periph_driver **start_pdrv, 22028b8a9b1dSJustin T. Gibbs xpt_pdrvfunc_t *tr_func, void *arg) 22038b8a9b1dSJustin T. Gibbs { 22048b8a9b1dSJustin T. Gibbs struct periph_driver **pdrv; 22058b8a9b1dSJustin T. Gibbs int retval; 22068b8a9b1dSJustin T. Gibbs 22078b8a9b1dSJustin T. Gibbs retval = 1; 22088b8a9b1dSJustin T. Gibbs 22098b8a9b1dSJustin T. Gibbs /* 22108b8a9b1dSJustin T. Gibbs * We don't traverse the peripheral driver list like we do the 22118b8a9b1dSJustin T. Gibbs * other lists, because it is a linker set, and therefore cannot be 22128b8a9b1dSJustin T. Gibbs * changed during runtime. If the peripheral driver list is ever 22138b8a9b1dSJustin T. Gibbs * re-done to be something other than a linker set (i.e. it can 22148b8a9b1dSJustin T. Gibbs * change while the system is running), the list traversal should 22158b8a9b1dSJustin T. Gibbs * be modified to work like the other traversal functions. 22168b8a9b1dSJustin T. Gibbs */ 22178b8a9b1dSJustin T. Gibbs for (pdrv = (start_pdrv ? start_pdrv : 22188b8a9b1dSJustin T. Gibbs (struct periph_driver **)periphdriver_set.ls_items); 22198b8a9b1dSJustin T. Gibbs *pdrv != NULL; pdrv++) { 22208b8a9b1dSJustin T. Gibbs retval = tr_func(pdrv, arg); 22218b8a9b1dSJustin T. Gibbs 22228b8a9b1dSJustin T. Gibbs if (retval == 0) 22238b8a9b1dSJustin T. Gibbs return(retval); 22248b8a9b1dSJustin T. Gibbs } 22258b8a9b1dSJustin T. Gibbs 22268b8a9b1dSJustin T. Gibbs return(retval); 22278b8a9b1dSJustin T. Gibbs } 22288b8a9b1dSJustin T. Gibbs 22298b8a9b1dSJustin T. Gibbs static int 22308b8a9b1dSJustin T. Gibbs xptpdperiphtraverse(struct periph_driver **pdrv, 22318b8a9b1dSJustin T. Gibbs struct cam_periph *start_periph, 22328b8a9b1dSJustin T. Gibbs xpt_periphfunc_t *tr_func, void *arg) 22338b8a9b1dSJustin T. Gibbs { 22348b8a9b1dSJustin T. Gibbs struct cam_periph *periph, *next_periph; 22358b8a9b1dSJustin T. Gibbs int retval; 22368b8a9b1dSJustin T. Gibbs 22378b8a9b1dSJustin T. Gibbs retval = 1; 22388b8a9b1dSJustin T. Gibbs 22398b8a9b1dSJustin T. Gibbs for (periph = (start_periph ? start_periph : 22408b8a9b1dSJustin T. Gibbs TAILQ_FIRST(&(*pdrv)->units)); periph != NULL; 22418b8a9b1dSJustin T. Gibbs periph = next_periph) { 22428b8a9b1dSJustin T. Gibbs 22438b8a9b1dSJustin T. Gibbs next_periph = TAILQ_NEXT(periph, unit_links); 22448b8a9b1dSJustin T. Gibbs 22458b8a9b1dSJustin T. Gibbs retval = tr_func(periph, arg); 22468b8a9b1dSJustin T. Gibbs if (retval == 0) 22478b8a9b1dSJustin T. Gibbs return(retval); 22488b8a9b1dSJustin T. Gibbs } 22498b8a9b1dSJustin T. Gibbs return(retval); 22508b8a9b1dSJustin T. Gibbs } 22518b8a9b1dSJustin T. Gibbs 22528b8a9b1dSJustin T. Gibbs static int 22538b8a9b1dSJustin T. Gibbs xptdefbusfunc(struct cam_eb *bus, void *arg) 22548b8a9b1dSJustin T. Gibbs { 22558b8a9b1dSJustin T. Gibbs struct xpt_traverse_config *tr_config; 22568b8a9b1dSJustin T. Gibbs 22578b8a9b1dSJustin T. Gibbs tr_config = (struct xpt_traverse_config *)arg; 22588b8a9b1dSJustin T. Gibbs 22598b8a9b1dSJustin T. Gibbs if (tr_config->depth == XPT_DEPTH_BUS) { 22608b8a9b1dSJustin T. Gibbs xpt_busfunc_t *tr_func; 22618b8a9b1dSJustin T. Gibbs 22628b8a9b1dSJustin T. Gibbs tr_func = (xpt_busfunc_t *)tr_config->tr_func; 22638b8a9b1dSJustin T. Gibbs 22648b8a9b1dSJustin T. Gibbs return(tr_func(bus, tr_config->tr_arg)); 22658b8a9b1dSJustin T. Gibbs } else 22668b8a9b1dSJustin T. Gibbs return(xpttargettraverse(bus, NULL, xptdeftargetfunc, arg)); 22678b8a9b1dSJustin T. Gibbs } 22688b8a9b1dSJustin T. Gibbs 22698b8a9b1dSJustin T. Gibbs static int 22708b8a9b1dSJustin T. Gibbs xptdeftargetfunc(struct cam_et *target, void *arg) 22718b8a9b1dSJustin T. Gibbs { 22728b8a9b1dSJustin T. Gibbs struct xpt_traverse_config *tr_config; 22738b8a9b1dSJustin T. Gibbs 22748b8a9b1dSJustin T. Gibbs tr_config = (struct xpt_traverse_config *)arg; 22758b8a9b1dSJustin T. Gibbs 22768b8a9b1dSJustin T. Gibbs if (tr_config->depth == XPT_DEPTH_TARGET) { 22778b8a9b1dSJustin T. Gibbs xpt_targetfunc_t *tr_func; 22788b8a9b1dSJustin T. Gibbs 22798b8a9b1dSJustin T. Gibbs tr_func = (xpt_targetfunc_t *)tr_config->tr_func; 22808b8a9b1dSJustin T. Gibbs 22818b8a9b1dSJustin T. Gibbs return(tr_func(target, tr_config->tr_arg)); 22828b8a9b1dSJustin T. Gibbs } else 22838b8a9b1dSJustin T. Gibbs return(xptdevicetraverse(target, NULL, xptdefdevicefunc, arg)); 22848b8a9b1dSJustin T. Gibbs } 22858b8a9b1dSJustin T. Gibbs 22868b8a9b1dSJustin T. Gibbs static int 22878b8a9b1dSJustin T. Gibbs xptdefdevicefunc(struct cam_ed *device, void *arg) 22888b8a9b1dSJustin T. Gibbs { 22898b8a9b1dSJustin T. Gibbs struct xpt_traverse_config *tr_config; 22908b8a9b1dSJustin T. Gibbs 22918b8a9b1dSJustin T. Gibbs tr_config = (struct xpt_traverse_config *)arg; 22928b8a9b1dSJustin T. Gibbs 22938b8a9b1dSJustin T. Gibbs if (tr_config->depth == XPT_DEPTH_DEVICE) { 22948b8a9b1dSJustin T. Gibbs xpt_devicefunc_t *tr_func; 22958b8a9b1dSJustin T. Gibbs 22968b8a9b1dSJustin T. Gibbs tr_func = (xpt_devicefunc_t *)tr_config->tr_func; 22978b8a9b1dSJustin T. Gibbs 22988b8a9b1dSJustin T. Gibbs return(tr_func(device, tr_config->tr_arg)); 22998b8a9b1dSJustin T. Gibbs } else 23008b8a9b1dSJustin T. Gibbs return(xptperiphtraverse(device, NULL, xptdefperiphfunc, arg)); 23018b8a9b1dSJustin T. Gibbs } 23028b8a9b1dSJustin T. Gibbs 23038b8a9b1dSJustin T. Gibbs static int 23048b8a9b1dSJustin T. Gibbs xptdefperiphfunc(struct cam_periph *periph, void *arg) 23058b8a9b1dSJustin T. Gibbs { 23068b8a9b1dSJustin T. Gibbs struct xpt_traverse_config *tr_config; 23078b8a9b1dSJustin T. Gibbs xpt_periphfunc_t *tr_func; 23088b8a9b1dSJustin T. Gibbs 23098b8a9b1dSJustin T. Gibbs tr_config = (struct xpt_traverse_config *)arg; 23108b8a9b1dSJustin T. Gibbs 23118b8a9b1dSJustin T. Gibbs tr_func = (xpt_periphfunc_t *)tr_config->tr_func; 23128b8a9b1dSJustin T. Gibbs 23138b8a9b1dSJustin T. Gibbs /* 23148b8a9b1dSJustin T. Gibbs * Unlike the other default functions, we don't check for depth 23158b8a9b1dSJustin T. Gibbs * here. The peripheral driver level is the last level in the EDT, 23168b8a9b1dSJustin T. Gibbs * so if we're here, we should execute the function in question. 23178b8a9b1dSJustin T. Gibbs */ 23188b8a9b1dSJustin T. Gibbs return(tr_func(periph, tr_config->tr_arg)); 23198b8a9b1dSJustin T. Gibbs } 23208b8a9b1dSJustin T. Gibbs 23218b8a9b1dSJustin T. Gibbs /* 23228b8a9b1dSJustin T. Gibbs * Execute the given function for every bus in the EDT. 23238b8a9b1dSJustin T. Gibbs */ 23248b8a9b1dSJustin T. Gibbs static int 23258b8a9b1dSJustin T. Gibbs xpt_for_all_busses(xpt_busfunc_t *tr_func, void *arg) 23268b8a9b1dSJustin T. Gibbs { 23278b8a9b1dSJustin T. Gibbs struct xpt_traverse_config tr_config; 23288b8a9b1dSJustin T. Gibbs 23298b8a9b1dSJustin T. Gibbs tr_config.depth = XPT_DEPTH_BUS; 23308b8a9b1dSJustin T. Gibbs tr_config.tr_func = tr_func; 23318b8a9b1dSJustin T. Gibbs tr_config.tr_arg = arg; 23328b8a9b1dSJustin T. Gibbs 23338b8a9b1dSJustin T. Gibbs return(xptbustraverse(NULL, xptdefbusfunc, &tr_config)); 23348b8a9b1dSJustin T. Gibbs } 23358b8a9b1dSJustin T. Gibbs 23368b8a9b1dSJustin T. Gibbs /* 23378b8a9b1dSJustin T. Gibbs * Execute the given function for every target in the EDT. 23388b8a9b1dSJustin T. Gibbs */ 23398b8a9b1dSJustin T. Gibbs static int 23408b8a9b1dSJustin T. Gibbs xpt_for_all_targets(xpt_targetfunc_t *tr_func, void *arg) 23418b8a9b1dSJustin T. Gibbs { 23428b8a9b1dSJustin T. Gibbs struct xpt_traverse_config tr_config; 23438b8a9b1dSJustin T. Gibbs 23448b8a9b1dSJustin T. Gibbs tr_config.depth = XPT_DEPTH_TARGET; 23458b8a9b1dSJustin T. Gibbs tr_config.tr_func = tr_func; 23468b8a9b1dSJustin T. Gibbs tr_config.tr_arg = arg; 23478b8a9b1dSJustin T. Gibbs 23488b8a9b1dSJustin T. Gibbs return(xptbustraverse(NULL, xptdefbusfunc, &tr_config)); 23498b8a9b1dSJustin T. Gibbs } 23508b8a9b1dSJustin T. Gibbs 23518b8a9b1dSJustin T. Gibbs /* 23528b8a9b1dSJustin T. Gibbs * Execute the given function for every device in the EDT. 23538b8a9b1dSJustin T. Gibbs */ 23548b8a9b1dSJustin T. Gibbs static int 23558b8a9b1dSJustin T. Gibbs xpt_for_all_devices(xpt_devicefunc_t *tr_func, void *arg) 23568b8a9b1dSJustin T. Gibbs { 23578b8a9b1dSJustin T. Gibbs struct xpt_traverse_config tr_config; 23588b8a9b1dSJustin T. Gibbs 23598b8a9b1dSJustin T. Gibbs tr_config.depth = XPT_DEPTH_DEVICE; 23608b8a9b1dSJustin T. Gibbs tr_config.tr_func = tr_func; 23618b8a9b1dSJustin T. Gibbs tr_config.tr_arg = arg; 23628b8a9b1dSJustin T. Gibbs 23638b8a9b1dSJustin T. Gibbs return(xptbustraverse(NULL, xptdefbusfunc, &tr_config)); 23648b8a9b1dSJustin T. Gibbs } 23658b8a9b1dSJustin T. Gibbs 23668b8a9b1dSJustin T. Gibbs /* 23678b8a9b1dSJustin T. Gibbs * Execute the given function for every peripheral in the EDT. 23688b8a9b1dSJustin T. Gibbs */ 23698b8a9b1dSJustin T. Gibbs static int 23708b8a9b1dSJustin T. Gibbs xpt_for_all_periphs(xpt_periphfunc_t *tr_func, void *arg) 23718b8a9b1dSJustin T. Gibbs { 23728b8a9b1dSJustin T. Gibbs struct xpt_traverse_config tr_config; 23738b8a9b1dSJustin T. Gibbs 23748b8a9b1dSJustin T. Gibbs tr_config.depth = XPT_DEPTH_PERIPH; 23758b8a9b1dSJustin T. Gibbs tr_config.tr_func = tr_func; 23768b8a9b1dSJustin T. Gibbs tr_config.tr_arg = arg; 23778b8a9b1dSJustin T. Gibbs 23788b8a9b1dSJustin T. Gibbs return(xptbustraverse(NULL, xptdefbusfunc, &tr_config)); 23798b8a9b1dSJustin T. Gibbs } 23808b8a9b1dSJustin T. Gibbs 23818b8a9b1dSJustin T. Gibbs static int 23828b8a9b1dSJustin T. Gibbs xptsetasyncfunc(struct cam_ed *device, void *arg) 23838b8a9b1dSJustin T. Gibbs { 23848b8a9b1dSJustin T. Gibbs struct cam_path path; 23858b8a9b1dSJustin T. Gibbs struct ccb_getdev cgd; 23868b8a9b1dSJustin T. Gibbs struct async_node *cur_entry; 23878b8a9b1dSJustin T. Gibbs 23888b8a9b1dSJustin T. Gibbs cur_entry = (struct async_node *)arg; 23898b8a9b1dSJustin T. Gibbs 23908b8a9b1dSJustin T. Gibbs xpt_compile_path(&path, 23918b8a9b1dSJustin T. Gibbs NULL, 23928b8a9b1dSJustin T. Gibbs device->target->bus->path_id, 23938b8a9b1dSJustin T. Gibbs device->target->target_id, 23948b8a9b1dSJustin T. Gibbs device->lun_id); 23958b8a9b1dSJustin T. Gibbs xpt_setup_ccb(&cgd.ccb_h, &path, /*priority*/1); 23968b8a9b1dSJustin T. Gibbs cgd.ccb_h.func_code = XPT_GDEV_TYPE; 23978b8a9b1dSJustin T. Gibbs xpt_action((union ccb *)&cgd); 23988b8a9b1dSJustin T. Gibbs cur_entry->callback(cur_entry->callback_arg, 23998b8a9b1dSJustin T. Gibbs AC_FOUND_DEVICE, 24008b8a9b1dSJustin T. Gibbs &path, &cgd); 24018b8a9b1dSJustin T. Gibbs xpt_release_path(&path); 24028b8a9b1dSJustin T. Gibbs 24038b8a9b1dSJustin T. Gibbs return(1); 24048b8a9b1dSJustin T. Gibbs } 24058b8a9b1dSJustin T. Gibbs static int 24068b8a9b1dSJustin T. Gibbs xptsetasyncbusfunc(struct cam_eb *bus, void *arg) 24078b8a9b1dSJustin T. Gibbs { 24088b8a9b1dSJustin T. Gibbs struct cam_path path; 24098b8a9b1dSJustin T. Gibbs struct ccb_pathinq cpi; 24108b8a9b1dSJustin T. Gibbs struct async_node *cur_entry; 24118b8a9b1dSJustin T. Gibbs 24128b8a9b1dSJustin T. Gibbs cur_entry = (struct async_node *)arg; 24138b8a9b1dSJustin T. Gibbs 24148b8a9b1dSJustin T. Gibbs xpt_compile_path(&path, /*periph*/NULL, 24158b8a9b1dSJustin T. Gibbs bus->sim->path_id, 24168b8a9b1dSJustin T. Gibbs CAM_TARGET_WILDCARD, 24178b8a9b1dSJustin T. Gibbs CAM_LUN_WILDCARD); 24188b8a9b1dSJustin T. Gibbs xpt_setup_ccb(&cpi.ccb_h, &path, /*priority*/1); 24198b8a9b1dSJustin T. Gibbs cpi.ccb_h.func_code = XPT_PATH_INQ; 24208b8a9b1dSJustin T. Gibbs xpt_action((union ccb *)&cpi); 24218b8a9b1dSJustin T. Gibbs cur_entry->callback(cur_entry->callback_arg, 24228b8a9b1dSJustin T. Gibbs AC_PATH_REGISTERED, 24238b8a9b1dSJustin T. Gibbs &path, &cpi); 24248b8a9b1dSJustin T. Gibbs xpt_release_path(&path); 24258b8a9b1dSJustin T. Gibbs 24268b8a9b1dSJustin T. Gibbs return(1); 24278b8a9b1dSJustin T. Gibbs } 24288b8a9b1dSJustin T. Gibbs 24298b8a9b1dSJustin T. Gibbs void 24308b8a9b1dSJustin T. Gibbs xpt_action(union ccb *start_ccb) 24318b8a9b1dSJustin T. Gibbs { 24328b8a9b1dSJustin T. Gibbs CAM_DEBUG(start_ccb->ccb_h.path, CAM_DEBUG_TRACE, ("xpt_action\n")); 24338b8a9b1dSJustin T. Gibbs 24348b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.status = CAM_REQ_INPROG; 24358b8a9b1dSJustin T. Gibbs 24368b8a9b1dSJustin T. Gibbs switch (start_ccb->ccb_h.func_code) { 24378b8a9b1dSJustin T. Gibbs case XPT_SCSI_IO: 24388b8a9b1dSJustin T. Gibbs /* 24398b8a9b1dSJustin T. Gibbs * For the sake of compatibility with SCSI-1 24408b8a9b1dSJustin T. Gibbs * devices that may not understand the identify 24418b8a9b1dSJustin T. Gibbs * message, we include lun information in the 24428b8a9b1dSJustin T. Gibbs * second byte of all commands. SCSI-1 specifies 24438b8a9b1dSJustin T. Gibbs * that luns are a 3 bit value and reserves only 3 24448b8a9b1dSJustin T. Gibbs * bits for lun information in the CDB. Later 24458b8a9b1dSJustin T. Gibbs * revisions of the SCSI spec allow for more than 8 24468b8a9b1dSJustin T. Gibbs * luns, but have deprecated lun information in the 24478b8a9b1dSJustin T. Gibbs * CDB. So, if the lun won't fit, we must omit. 24488b8a9b1dSJustin T. Gibbs * 24498b8a9b1dSJustin T. Gibbs * Also be aware that during initial probing for devices, 24508b8a9b1dSJustin T. Gibbs * the inquiry information is unknown but initialized to 0. 24518b8a9b1dSJustin T. Gibbs * This means that this code will be exercised while probing 24528b8a9b1dSJustin T. Gibbs * devices with an ANSI revision greater than 2. 24538b8a9b1dSJustin T. Gibbs */ 24548b8a9b1dSJustin T. Gibbs if (SID_ANSI_REV(&start_ccb->ccb_h.path->device->inq_data) <= 2 24558b8a9b1dSJustin T. Gibbs && start_ccb->ccb_h.target_lun < 8 24568b8a9b1dSJustin T. Gibbs && (start_ccb->ccb_h.flags & CAM_CDB_POINTER) == 0) { 24578b8a9b1dSJustin T. Gibbs 24588b8a9b1dSJustin T. Gibbs start_ccb->csio.cdb_io.cdb_bytes[1] |= 24598b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.target_lun << 5; 24608b8a9b1dSJustin T. Gibbs } 24618b8a9b1dSJustin T. Gibbs start_ccb->csio.scsi_status = SCSI_STATUS_OK; 24628b8a9b1dSJustin T. Gibbs start_ccb->csio.sense_resid = 0; 24638b8a9b1dSJustin T. Gibbs start_ccb->csio.resid = 0; 24648b8a9b1dSJustin T. Gibbs /* FALLTRHOUGH */ 24658b8a9b1dSJustin T. Gibbs case XPT_TARGET_IO: 24668b8a9b1dSJustin T. Gibbs case XPT_CONT_TARGET_IO: 24678b8a9b1dSJustin T. Gibbs case XPT_ENG_EXEC: 24688b8a9b1dSJustin T. Gibbs { 24698b8a9b1dSJustin T. Gibbs struct cam_path *path; 24708b8a9b1dSJustin T. Gibbs int s; 24718b8a9b1dSJustin T. Gibbs int runq; 24728b8a9b1dSJustin T. Gibbs 24738b8a9b1dSJustin T. Gibbs path = start_ccb->ccb_h.path; 24748b8a9b1dSJustin T. Gibbs s = splsoftcam(); 24758b8a9b1dSJustin T. Gibbs 24768b8a9b1dSJustin T. Gibbs cam_ccbq_insert_ccb(&path->device->ccbq, start_ccb); 24778b8a9b1dSJustin T. Gibbs if (path->device->qfrozen_cnt == 0) 24788b8a9b1dSJustin T. Gibbs runq = xpt_schedule_dev_sendq(path->bus, path->device); 24798b8a9b1dSJustin T. Gibbs else 24808b8a9b1dSJustin T. Gibbs runq = 0; 24818b8a9b1dSJustin T. Gibbs splx(s); 24828b8a9b1dSJustin T. Gibbs if (runq != 0) 24838b8a9b1dSJustin T. Gibbs xpt_run_dev_sendq(path->bus); 24848b8a9b1dSJustin T. Gibbs break; 24858b8a9b1dSJustin T. Gibbs } 24868b8a9b1dSJustin T. Gibbs case XPT_SET_TRAN_SETTINGS: 24878b8a9b1dSJustin T. Gibbs { 24888b8a9b1dSJustin T. Gibbs xpt_set_transfer_settings(&start_ccb->cts, 24898b8a9b1dSJustin T. Gibbs /*async_update*/FALSE); 24908b8a9b1dSJustin T. Gibbs break; 24918b8a9b1dSJustin T. Gibbs } 24928b8a9b1dSJustin T. Gibbs case XPT_CALC_GEOMETRY: 24938b8a9b1dSJustin T. Gibbs /* Filter out garbage */ 24948b8a9b1dSJustin T. Gibbs if (start_ccb->ccg.block_size == 0 24958b8a9b1dSJustin T. Gibbs || start_ccb->ccg.volume_size == 0) { 24968b8a9b1dSJustin T. Gibbs start_ccb->ccg.cylinders = 0; 24978b8a9b1dSJustin T. Gibbs start_ccb->ccg.heads = 0; 24988b8a9b1dSJustin T. Gibbs start_ccb->ccg.secs_per_track = 0; 24998b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.status = CAM_REQ_CMP; 25008b8a9b1dSJustin T. Gibbs break; 25018b8a9b1dSJustin T. Gibbs } 25028b8a9b1dSJustin T. Gibbs #ifdef PC98 25038b8a9b1dSJustin T. Gibbs /* 25048b8a9b1dSJustin T. Gibbs * In a PC-98 system, geometry translation depens on 25058b8a9b1dSJustin T. Gibbs * the "real" device geometry obtained from mode page 4. 25068b8a9b1dSJustin T. Gibbs * SCSI geometry translation is performed in the 25078b8a9b1dSJustin T. Gibbs * initialization routine of the SCSI BIOS and the result 25088b8a9b1dSJustin T. Gibbs * stored in host memory. If the translation is available 25098b8a9b1dSJustin T. Gibbs * in host memory, use it. If not, rely on the default 25108b8a9b1dSJustin T. Gibbs * translation the device driver performs. 25118b8a9b1dSJustin T. Gibbs */ 25128b8a9b1dSJustin T. Gibbs if (scsi_da_bios_params(&start_ccb->ccg) != 0) { 25138b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.status = CAM_REQ_CMP; 25148b8a9b1dSJustin T. Gibbs break; 25158b8a9b1dSJustin T. Gibbs } 25168b8a9b1dSJustin T. Gibbs /* FALLTHROUGH */ 25178b8a9b1dSJustin T. Gibbs #endif 25188b8a9b1dSJustin T. Gibbs case XPT_ACCEPT_TARGET_IO: 25198b8a9b1dSJustin T. Gibbs case XPT_EN_LUN: 25208b8a9b1dSJustin T. Gibbs case XPT_IMMED_NOTIFY: 25218b8a9b1dSJustin T. Gibbs case XPT_NOTIFY_ACK: 25228b8a9b1dSJustin T. Gibbs case XPT_GET_TRAN_SETTINGS: 25238b8a9b1dSJustin T. Gibbs case XPT_PATH_INQ: 25248b8a9b1dSJustin T. Gibbs case XPT_RESET_BUS: 25258b8a9b1dSJustin T. Gibbs { 25268b8a9b1dSJustin T. Gibbs struct cam_sim *sim; 25278b8a9b1dSJustin T. Gibbs 25288b8a9b1dSJustin T. Gibbs sim = start_ccb->ccb_h.path->bus->sim; 25298b8a9b1dSJustin T. Gibbs (*(sim->sim_action))(sim, start_ccb); 25308b8a9b1dSJustin T. Gibbs break; 25318b8a9b1dSJustin T. Gibbs } 25328b8a9b1dSJustin T. Gibbs case XPT_GDEV_TYPE: 25338b8a9b1dSJustin T. Gibbs if ((start_ccb->ccb_h.path->device->flags & CAM_DEV_UNCONFIGURED) != 0) { 25348b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.status = CAM_DEV_NOT_THERE; 25358b8a9b1dSJustin T. Gibbs } else { 25368b8a9b1dSJustin T. Gibbs struct ccb_getdev *cgd; 25378b8a9b1dSJustin T. Gibbs struct cam_et *tar; 25388b8a9b1dSJustin T. Gibbs struct cam_ed *dev; 25398b8a9b1dSJustin T. Gibbs int s; 25408b8a9b1dSJustin T. Gibbs 25418b8a9b1dSJustin T. Gibbs s = splsoftcam(); 25428b8a9b1dSJustin T. Gibbs cgd = &start_ccb->cgd; 25438b8a9b1dSJustin T. Gibbs tar = cgd->ccb_h.path->target; 25448b8a9b1dSJustin T. Gibbs dev = cgd->ccb_h.path->device; 25458b8a9b1dSJustin T. Gibbs cgd->inq_data = dev->inq_data; 25468b8a9b1dSJustin T. Gibbs cgd->pd_type = SID_TYPE(&dev->inq_data); 25478b8a9b1dSJustin T. Gibbs cgd->dev_openings = dev->ccbq.dev_openings; 25488b8a9b1dSJustin T. Gibbs cgd->dev_active = dev->ccbq.dev_active; 25498b8a9b1dSJustin T. Gibbs cgd->devq_openings = dev->ccbq.devq_openings; 25508b8a9b1dSJustin T. Gibbs cgd->devq_queued = dev->ccbq.queue.entries; 25518b8a9b1dSJustin T. Gibbs cgd->held = dev->ccbq.held; 25528b8a9b1dSJustin T. Gibbs cgd->maxtags = dev->quirk->maxtags; 25538b8a9b1dSJustin T. Gibbs cgd->mintags = dev->quirk->mintags; 25548b8a9b1dSJustin T. Gibbs cgd->ccb_h.status = CAM_REQ_CMP; 25558b8a9b1dSJustin T. Gibbs cgd->serial_num_len = dev->serial_num_len; 25568b8a9b1dSJustin T. Gibbs if ((dev->serial_num_len > 0) 25578b8a9b1dSJustin T. Gibbs && (dev->serial_num != NULL)) 25588b8a9b1dSJustin T. Gibbs bcopy(dev->serial_num, cgd->serial_num, 25598b8a9b1dSJustin T. Gibbs dev->serial_num_len); 25608b8a9b1dSJustin T. Gibbs splx(s); 25618b8a9b1dSJustin T. Gibbs } 25628b8a9b1dSJustin T. Gibbs break; 25638b8a9b1dSJustin T. Gibbs case XPT_GDEVLIST: 25648b8a9b1dSJustin T. Gibbs { 25658b8a9b1dSJustin T. Gibbs struct cam_periph *nperiph; 25668b8a9b1dSJustin T. Gibbs struct periph_list *periph_head; 25678b8a9b1dSJustin T. Gibbs struct ccb_getdevlist *cgdl; 25688b8a9b1dSJustin T. Gibbs int i; 25698b8a9b1dSJustin T. Gibbs int s; 25708b8a9b1dSJustin T. Gibbs struct cam_ed *device; 25718b8a9b1dSJustin T. Gibbs int found; 25728b8a9b1dSJustin T. Gibbs 25738b8a9b1dSJustin T. Gibbs 25748b8a9b1dSJustin T. Gibbs found = 0; 25758b8a9b1dSJustin T. Gibbs 25768b8a9b1dSJustin T. Gibbs /* 25778b8a9b1dSJustin T. Gibbs * Don't want anyone mucking with our data. 25788b8a9b1dSJustin T. Gibbs */ 25798b8a9b1dSJustin T. Gibbs s = splsoftcam(); 25808b8a9b1dSJustin T. Gibbs device = start_ccb->ccb_h.path->device; 25818b8a9b1dSJustin T. Gibbs periph_head = &device->periphs; 25828b8a9b1dSJustin T. Gibbs cgdl = &start_ccb->cgdl; 25838b8a9b1dSJustin T. Gibbs 25848b8a9b1dSJustin T. Gibbs /* 25858b8a9b1dSJustin T. Gibbs * Check and see if the list has changed since the user 25868b8a9b1dSJustin T. Gibbs * last requested a list member. If so, tell them that the 25878b8a9b1dSJustin T. Gibbs * list has changed, and therefore they need to start over 25888b8a9b1dSJustin T. Gibbs * from the beginning. 25898b8a9b1dSJustin T. Gibbs */ 25908b8a9b1dSJustin T. Gibbs if ((cgdl->index != 0) && 25918b8a9b1dSJustin T. Gibbs (cgdl->generation != device->generation)) { 25928b8a9b1dSJustin T. Gibbs cgdl->status = CAM_GDEVLIST_LIST_CHANGED; 25938b8a9b1dSJustin T. Gibbs splx(s); 25948b8a9b1dSJustin T. Gibbs break; 25958b8a9b1dSJustin T. Gibbs } 25968b8a9b1dSJustin T. Gibbs 25978b8a9b1dSJustin T. Gibbs /* 25988b8a9b1dSJustin T. Gibbs * Traverse the list of peripherals and attempt to find 25998b8a9b1dSJustin T. Gibbs * the requested peripheral. 26008b8a9b1dSJustin T. Gibbs */ 26018b8a9b1dSJustin T. Gibbs for (nperiph = periph_head->slh_first, i = 0; 26028b8a9b1dSJustin T. Gibbs (nperiph != NULL) && (i <= cgdl->index); 26038b8a9b1dSJustin T. Gibbs nperiph = nperiph->periph_links.sle_next, i++) { 26048b8a9b1dSJustin T. Gibbs if (i == cgdl->index) { 26058b8a9b1dSJustin T. Gibbs strncpy(cgdl->periph_name, 26068b8a9b1dSJustin T. Gibbs nperiph->periph_name, 26078b8a9b1dSJustin T. Gibbs DEV_IDLEN); 26088b8a9b1dSJustin T. Gibbs cgdl->unit_number = nperiph->unit_number; 26098b8a9b1dSJustin T. Gibbs found = 1; 26108b8a9b1dSJustin T. Gibbs } 26118b8a9b1dSJustin T. Gibbs } 26128b8a9b1dSJustin T. Gibbs if (found == 0) { 26138b8a9b1dSJustin T. Gibbs cgdl->status = CAM_GDEVLIST_ERROR; 26148b8a9b1dSJustin T. Gibbs splx(s); 26158b8a9b1dSJustin T. Gibbs break; 26168b8a9b1dSJustin T. Gibbs } 26178b8a9b1dSJustin T. Gibbs 26188b8a9b1dSJustin T. Gibbs if (nperiph == NULL) 26198b8a9b1dSJustin T. Gibbs cgdl->status = CAM_GDEVLIST_LAST_DEVICE; 26208b8a9b1dSJustin T. Gibbs else 26218b8a9b1dSJustin T. Gibbs cgdl->status = CAM_GDEVLIST_MORE_DEVS; 26228b8a9b1dSJustin T. Gibbs 26238b8a9b1dSJustin T. Gibbs cgdl->index++; 26248b8a9b1dSJustin T. Gibbs cgdl->generation = device->generation; 26258b8a9b1dSJustin T. Gibbs 26268b8a9b1dSJustin T. Gibbs splx(s); 26278b8a9b1dSJustin T. Gibbs cgdl->ccb_h.status = CAM_REQ_CMP; 26288b8a9b1dSJustin T. Gibbs break; 26298b8a9b1dSJustin T. Gibbs } 26308b8a9b1dSJustin T. Gibbs case XPT_DEV_MATCH: 26318b8a9b1dSJustin T. Gibbs { 26328b8a9b1dSJustin T. Gibbs int s; 26338b8a9b1dSJustin T. Gibbs dev_pos_type position_type; 26348b8a9b1dSJustin T. Gibbs struct ccb_dev_match *cdm; 26358b8a9b1dSJustin T. Gibbs int ret; 26368b8a9b1dSJustin T. Gibbs 26378b8a9b1dSJustin T. Gibbs cdm = &start_ccb->cdm; 26388b8a9b1dSJustin T. Gibbs 26398b8a9b1dSJustin T. Gibbs /* 26408b8a9b1dSJustin T. Gibbs * Prevent EDT changes while we traverse it. 26418b8a9b1dSJustin T. Gibbs */ 26428b8a9b1dSJustin T. Gibbs s = splsoftcam(); 26438b8a9b1dSJustin T. Gibbs /* 26448b8a9b1dSJustin T. Gibbs * There are two ways of getting at information in the EDT. 26458b8a9b1dSJustin T. Gibbs * The first way is via the primary EDT tree. It starts 26468b8a9b1dSJustin T. Gibbs * with a list of busses, then a list of targets on a bus, 26478b8a9b1dSJustin T. Gibbs * then devices/luns on a target, and then peripherals on a 26488b8a9b1dSJustin T. Gibbs * device/lun. The "other" way is by the peripheral driver 26498b8a9b1dSJustin T. Gibbs * lists. The peripheral driver lists are organized by 26508b8a9b1dSJustin T. Gibbs * peripheral driver. (obviously) So it makes sense to 26518b8a9b1dSJustin T. Gibbs * use the peripheral driver list if the user is looking 26528b8a9b1dSJustin T. Gibbs * for something like "da1", or all "da" devices. If the 26538b8a9b1dSJustin T. Gibbs * user is looking for something on a particular bus/target 26548b8a9b1dSJustin T. Gibbs * or lun, it's generally better to go through the EDT tree. 26558b8a9b1dSJustin T. Gibbs */ 26568b8a9b1dSJustin T. Gibbs 26578b8a9b1dSJustin T. Gibbs if (cdm->pos.position_type != CAM_DEV_POS_NONE) 26588b8a9b1dSJustin T. Gibbs position_type = cdm->pos.position_type; 26598b8a9b1dSJustin T. Gibbs else { 26608b8a9b1dSJustin T. Gibbs int i; 26618b8a9b1dSJustin T. Gibbs 26628b8a9b1dSJustin T. Gibbs position_type = CAM_DEV_POS_NONE; 26638b8a9b1dSJustin T. Gibbs 26648b8a9b1dSJustin T. Gibbs for (i = 0; i < cdm->num_patterns; i++) { 26658b8a9b1dSJustin T. Gibbs if ((cdm->patterns[i].type == DEV_MATCH_BUS) 26668b8a9b1dSJustin T. Gibbs ||(cdm->patterns[i].type == DEV_MATCH_DEVICE)){ 26678b8a9b1dSJustin T. Gibbs position_type = CAM_DEV_POS_EDT; 26688b8a9b1dSJustin T. Gibbs break; 26698b8a9b1dSJustin T. Gibbs } 26708b8a9b1dSJustin T. Gibbs } 26718b8a9b1dSJustin T. Gibbs 26728b8a9b1dSJustin T. Gibbs if (cdm->num_patterns == 0) 26738b8a9b1dSJustin T. Gibbs position_type = CAM_DEV_POS_EDT; 26748b8a9b1dSJustin T. Gibbs else if (position_type == CAM_DEV_POS_NONE) 26758b8a9b1dSJustin T. Gibbs position_type = CAM_DEV_POS_PDRV; 26768b8a9b1dSJustin T. Gibbs } 26778b8a9b1dSJustin T. Gibbs 26788b8a9b1dSJustin T. Gibbs switch(position_type & CAM_DEV_POS_TYPEMASK) { 26798b8a9b1dSJustin T. Gibbs case CAM_DEV_POS_EDT: 26808b8a9b1dSJustin T. Gibbs ret = xptedtmatch(cdm); 26818b8a9b1dSJustin T. Gibbs break; 26828b8a9b1dSJustin T. Gibbs case CAM_DEV_POS_PDRV: 26838b8a9b1dSJustin T. Gibbs ret = xptperiphlistmatch(cdm); 26848b8a9b1dSJustin T. Gibbs break; 26858b8a9b1dSJustin T. Gibbs default: 26868b8a9b1dSJustin T. Gibbs cdm->status = CAM_DEV_MATCH_ERROR; 26878b8a9b1dSJustin T. Gibbs break; 26888b8a9b1dSJustin T. Gibbs } 26898b8a9b1dSJustin T. Gibbs 26908b8a9b1dSJustin T. Gibbs splx(s); 26918b8a9b1dSJustin T. Gibbs 26928b8a9b1dSJustin T. Gibbs if (cdm->status == CAM_DEV_MATCH_ERROR) 26938b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.status = CAM_REQ_CMP_ERR; 26948b8a9b1dSJustin T. Gibbs else 26958b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.status = CAM_REQ_CMP; 26968b8a9b1dSJustin T. Gibbs 26978b8a9b1dSJustin T. Gibbs break; 26988b8a9b1dSJustin T. Gibbs } 26998b8a9b1dSJustin T. Gibbs case XPT_SASYNC_CB: 27008b8a9b1dSJustin T. Gibbs { 27018b8a9b1dSJustin T. Gibbs /* 27028b8a9b1dSJustin T. Gibbs * First off, determine the list we want to 27038b8a9b1dSJustin T. Gibbs * be insterted into. 27048b8a9b1dSJustin T. Gibbs */ 27058b8a9b1dSJustin T. Gibbs struct ccb_setasync *csa; 27068b8a9b1dSJustin T. Gibbs struct async_node *cur_entry; 27078b8a9b1dSJustin T. Gibbs struct async_list *async_head; 27088b8a9b1dSJustin T. Gibbs u_int32_t added; 27098b8a9b1dSJustin T. Gibbs int s; 27108b8a9b1dSJustin T. Gibbs 27118b8a9b1dSJustin T. Gibbs csa = &start_ccb->csa; 27128b8a9b1dSJustin T. Gibbs added = csa->event_enable; 27138b8a9b1dSJustin T. Gibbs if (csa->ccb_h.path->device != NULL) { 27148b8a9b1dSJustin T. Gibbs async_head = &csa->ccb_h.path->device->asyncs; 27158b8a9b1dSJustin T. Gibbs } else { 27168b8a9b1dSJustin T. Gibbs async_head = &csa->ccb_h.path->bus->asyncs; 27178b8a9b1dSJustin T. Gibbs } 27188b8a9b1dSJustin T. Gibbs 27198b8a9b1dSJustin T. Gibbs /* 27208b8a9b1dSJustin T. Gibbs * If there is already an entry for us, simply 27218b8a9b1dSJustin T. Gibbs * update it. 27228b8a9b1dSJustin T. Gibbs */ 27238b8a9b1dSJustin T. Gibbs s = splsoftcam(); 27248b8a9b1dSJustin T. Gibbs cur_entry = SLIST_FIRST(async_head); 27258b8a9b1dSJustin T. Gibbs while (cur_entry != NULL) { 27268b8a9b1dSJustin T. Gibbs if ((cur_entry->callback_arg == csa->callback_arg) 27278b8a9b1dSJustin T. Gibbs && (cur_entry->callback == csa->callback)) 27288b8a9b1dSJustin T. Gibbs break; 27298b8a9b1dSJustin T. Gibbs cur_entry = SLIST_NEXT(cur_entry, links); 27308b8a9b1dSJustin T. Gibbs } 27318b8a9b1dSJustin T. Gibbs 27328b8a9b1dSJustin T. Gibbs if (cur_entry != NULL) { 27338b8a9b1dSJustin T. Gibbs /* 27348b8a9b1dSJustin T. Gibbs * If the request has no flags set, 27358b8a9b1dSJustin T. Gibbs * remove the entry. 27368b8a9b1dSJustin T. Gibbs */ 27378b8a9b1dSJustin T. Gibbs added &= ~cur_entry->event_enable; 27388b8a9b1dSJustin T. Gibbs if (csa->event_enable == 0) { 27398b8a9b1dSJustin T. Gibbs SLIST_REMOVE(async_head, cur_entry, 27408b8a9b1dSJustin T. Gibbs async_node, links); 27418b8a9b1dSJustin T. Gibbs free(cur_entry, M_DEVBUF); 27428b8a9b1dSJustin T. Gibbs } else { 27438b8a9b1dSJustin T. Gibbs cur_entry->event_enable = csa->event_enable; 27448b8a9b1dSJustin T. Gibbs } 27458b8a9b1dSJustin T. Gibbs } else { 27468b8a9b1dSJustin T. Gibbs cur_entry = malloc(sizeof(*cur_entry), M_DEVBUF, 27478b8a9b1dSJustin T. Gibbs M_NOWAIT); 27488b8a9b1dSJustin T. Gibbs if (cur_entry == NULL) { 27498b8a9b1dSJustin T. Gibbs splx(s); 27508b8a9b1dSJustin T. Gibbs csa->ccb_h.status = CAM_RESRC_UNAVAIL; 27518b8a9b1dSJustin T. Gibbs break; 27528b8a9b1dSJustin T. Gibbs } 27538b8a9b1dSJustin T. Gibbs cur_entry->callback_arg = csa->callback_arg; 27548b8a9b1dSJustin T. Gibbs cur_entry->callback = csa->callback; 27558b8a9b1dSJustin T. Gibbs cur_entry->event_enable = csa->event_enable; 27568b8a9b1dSJustin T. Gibbs SLIST_INSERT_HEAD(async_head, cur_entry, links); 27578b8a9b1dSJustin T. Gibbs } 27588b8a9b1dSJustin T. Gibbs 27598b8a9b1dSJustin T. Gibbs if ((added & AC_FOUND_DEVICE) != 0) { 27608b8a9b1dSJustin T. Gibbs /* 27618b8a9b1dSJustin T. Gibbs * Get this peripheral up to date with all 27628b8a9b1dSJustin T. Gibbs * the currently existing devices. 27638b8a9b1dSJustin T. Gibbs */ 27648b8a9b1dSJustin T. Gibbs xpt_for_all_devices(xptsetasyncfunc, cur_entry); 27658b8a9b1dSJustin T. Gibbs } 27668b8a9b1dSJustin T. Gibbs if ((added & AC_PATH_REGISTERED) != 0) { 27678b8a9b1dSJustin T. Gibbs /* 27688b8a9b1dSJustin T. Gibbs * Get this peripheral up to date with all 27698b8a9b1dSJustin T. Gibbs * the currently existing busses. 27708b8a9b1dSJustin T. Gibbs */ 27718b8a9b1dSJustin T. Gibbs xpt_for_all_busses(xptsetasyncbusfunc, cur_entry); 27728b8a9b1dSJustin T. Gibbs } 27738b8a9b1dSJustin T. Gibbs splx(s); 27748b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.status = CAM_REQ_CMP; 27758b8a9b1dSJustin T. Gibbs break; 27768b8a9b1dSJustin T. Gibbs } 27778b8a9b1dSJustin T. Gibbs case XPT_REL_SIMQ: 27788b8a9b1dSJustin T. Gibbs { 27798b8a9b1dSJustin T. Gibbs struct ccb_relsim *crs; 27808b8a9b1dSJustin T. Gibbs struct cam_ed *dev; 27818b8a9b1dSJustin T. Gibbs int s; 27828b8a9b1dSJustin T. Gibbs 27838b8a9b1dSJustin T. Gibbs crs = &start_ccb->crs; 27848b8a9b1dSJustin T. Gibbs dev = crs->ccb_h.path->device; 27858b8a9b1dSJustin T. Gibbs if (dev == NULL) { 27868b8a9b1dSJustin T. Gibbs 27878b8a9b1dSJustin T. Gibbs crs->ccb_h.status = CAM_DEV_NOT_THERE; 27888b8a9b1dSJustin T. Gibbs break; 27898b8a9b1dSJustin T. Gibbs } 27908b8a9b1dSJustin T. Gibbs 27918b8a9b1dSJustin T. Gibbs s = splcam(); 27928b8a9b1dSJustin T. Gibbs 27938b8a9b1dSJustin T. Gibbs if ((crs->release_flags & RELSIM_ADJUST_OPENINGS) != 0) { 27948b8a9b1dSJustin T. Gibbs 27958b8a9b1dSJustin T. Gibbs if ((dev->inq_data.flags & SID_CmdQue) != 0) { 27968b8a9b1dSJustin T. Gibbs int reduction; 27978b8a9b1dSJustin T. Gibbs 27988b8a9b1dSJustin T. Gibbs /* Don't ever go below one opening */ 27998b8a9b1dSJustin T. Gibbs if (crs->openings > 0) { 28008b8a9b1dSJustin T. Gibbs xpt_dev_ccbq_resize(crs->ccb_h.path, 28018b8a9b1dSJustin T. Gibbs crs->openings); 28028b8a9b1dSJustin T. Gibbs 28038b8a9b1dSJustin T. Gibbs if (bootverbose || 1) { 28048b8a9b1dSJustin T. Gibbs xpt_print_path(crs->ccb_h.path); 28058b8a9b1dSJustin T. Gibbs printf("tagged openings " 28068b8a9b1dSJustin T. Gibbs "now %d\n", 28078b8a9b1dSJustin T. Gibbs crs->openings); 28088b8a9b1dSJustin T. Gibbs } 28098b8a9b1dSJustin T. Gibbs } 28108b8a9b1dSJustin T. Gibbs } 28118b8a9b1dSJustin T. Gibbs } 28128b8a9b1dSJustin T. Gibbs 28138b8a9b1dSJustin T. Gibbs if ((crs->release_flags & RELSIM_RELEASE_AFTER_TIMEOUT) != 0) { 28148b8a9b1dSJustin T. Gibbs 28158b8a9b1dSJustin T. Gibbs if ((dev->flags & CAM_DEV_REL_TIMEOUT_PENDING) != 0) { 28168b8a9b1dSJustin T. Gibbs 28178b8a9b1dSJustin T. Gibbs /* 28188b8a9b1dSJustin T. Gibbs * Just extend the old timeout and decrement 28198b8a9b1dSJustin T. Gibbs * the freeze count so that a single timeout 28208b8a9b1dSJustin T. Gibbs * is sufficient for releasing the queue. 28218b8a9b1dSJustin T. Gibbs */ 28228b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.flags &= ~CAM_DEV_QFREEZE; 28238b8a9b1dSJustin T. Gibbs untimeout(xpt_release_devq_timeout, 28248b8a9b1dSJustin T. Gibbs dev, dev->c_handle); 28258b8a9b1dSJustin T. Gibbs } else { 28268b8a9b1dSJustin T. Gibbs 28278b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.flags |= CAM_DEV_QFREEZE; 28288b8a9b1dSJustin T. Gibbs } 28298b8a9b1dSJustin T. Gibbs 28308b8a9b1dSJustin T. Gibbs dev->c_handle = 28318b8a9b1dSJustin T. Gibbs timeout(xpt_release_devq_timeout, 28328b8a9b1dSJustin T. Gibbs dev, 28338b8a9b1dSJustin T. Gibbs (crs->release_timeout * hz) / 1000); 28348b8a9b1dSJustin T. Gibbs 28358b8a9b1dSJustin T. Gibbs dev->flags |= CAM_DEV_REL_TIMEOUT_PENDING; 28368b8a9b1dSJustin T. Gibbs 28378b8a9b1dSJustin T. Gibbs } 28388b8a9b1dSJustin T. Gibbs 28398b8a9b1dSJustin T. Gibbs if ((crs->release_flags & RELSIM_RELEASE_AFTER_CMDCMPLT) != 0) { 28408b8a9b1dSJustin T. Gibbs 28418b8a9b1dSJustin T. Gibbs if ((dev->flags & CAM_DEV_REL_ON_COMPLETE) != 0) { 28428b8a9b1dSJustin T. Gibbs /* 28438b8a9b1dSJustin T. Gibbs * Decrement the freeze count so that a single 28448b8a9b1dSJustin T. Gibbs * completion is still sufficient to unfreeze 28458b8a9b1dSJustin T. Gibbs * the queue. 28468b8a9b1dSJustin T. Gibbs */ 28478b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.flags &= ~CAM_DEV_QFREEZE; 28488b8a9b1dSJustin T. Gibbs } else { 28498b8a9b1dSJustin T. Gibbs 28508b8a9b1dSJustin T. Gibbs dev->flags |= CAM_DEV_REL_ON_COMPLETE; 28518b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.flags |= CAM_DEV_QFREEZE; 28528b8a9b1dSJustin T. Gibbs } 28538b8a9b1dSJustin T. Gibbs } 28548b8a9b1dSJustin T. Gibbs 28558b8a9b1dSJustin T. Gibbs if ((crs->release_flags & RELSIM_RELEASE_AFTER_QEMPTY) != 0) { 28568b8a9b1dSJustin T. Gibbs 28578b8a9b1dSJustin T. Gibbs if ((dev->flags & CAM_DEV_REL_ON_QUEUE_EMPTY) != 0 28588b8a9b1dSJustin T. Gibbs || (dev->ccbq.dev_active == 0)) { 28598b8a9b1dSJustin T. Gibbs 28608b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.flags &= ~CAM_DEV_QFREEZE; 28618b8a9b1dSJustin T. Gibbs } else { 28628b8a9b1dSJustin T. Gibbs 28638b8a9b1dSJustin T. Gibbs dev->flags |= CAM_DEV_REL_ON_QUEUE_EMPTY; 28648b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.flags |= CAM_DEV_QFREEZE; 28658b8a9b1dSJustin T. Gibbs } 28668b8a9b1dSJustin T. Gibbs } 28678b8a9b1dSJustin T. Gibbs splx(s); 28688b8a9b1dSJustin T. Gibbs 28698b8a9b1dSJustin T. Gibbs if ((start_ccb->ccb_h.flags & CAM_DEV_QFREEZE) == 0) { 28708b8a9b1dSJustin T. Gibbs 28718b8a9b1dSJustin T. Gibbs xpt_release_devq(crs->ccb_h.path->device, 28728b8a9b1dSJustin T. Gibbs /*run_queue*/TRUE); 28738b8a9b1dSJustin T. Gibbs } 28748b8a9b1dSJustin T. Gibbs start_ccb->crs.qfrozen_cnt = dev->qfrozen_cnt; 28758b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.status = CAM_REQ_CMP; 28768b8a9b1dSJustin T. Gibbs break; 28778b8a9b1dSJustin T. Gibbs } 28788b8a9b1dSJustin T. Gibbs case XPT_SCAN_BUS: 28798b8a9b1dSJustin T. Gibbs xpt_scan_bus(start_ccb->ccb_h.path->periph, start_ccb); 28808b8a9b1dSJustin T. Gibbs break; 28818b8a9b1dSJustin T. Gibbs case XPT_SCAN_LUN: 28828b8a9b1dSJustin T. Gibbs xpt_scan_lun(start_ccb->ccb_h.path->periph, 28838b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.path, start_ccb->crcn.flags, 28848b8a9b1dSJustin T. Gibbs start_ccb); 28858b8a9b1dSJustin T. Gibbs break; 28868b8a9b1dSJustin T. Gibbs case XPT_DEBUG: { 28878b8a9b1dSJustin T. Gibbs #ifdef CAMDEBUG 28888b8a9b1dSJustin T. Gibbs int s; 28898b8a9b1dSJustin T. Gibbs 28908b8a9b1dSJustin T. Gibbs s = splcam(); 28918b8a9b1dSJustin T. Gibbs cam_dflags = start_ccb->cdbg.flags; 28928b8a9b1dSJustin T. Gibbs if (cam_dpath != NULL) { 28938b8a9b1dSJustin T. Gibbs xpt_free_path(cam_dpath); 28948b8a9b1dSJustin T. Gibbs cam_dpath = NULL; 28958b8a9b1dSJustin T. Gibbs } 28968b8a9b1dSJustin T. Gibbs 28978b8a9b1dSJustin T. Gibbs if (cam_dflags != CAM_DEBUG_NONE) { 28988b8a9b1dSJustin T. Gibbs if (xpt_create_path(&cam_dpath, xpt_periph, 28998b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.path_id, 29008b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.target_id, 29018b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.target_lun) != 29028b8a9b1dSJustin T. Gibbs CAM_REQ_CMP) { 29038b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.status = CAM_RESRC_UNAVAIL; 29048b8a9b1dSJustin T. Gibbs cam_dflags = CAM_DEBUG_NONE; 29058b8a9b1dSJustin T. Gibbs } else 29068b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.status = CAM_REQ_CMP; 29078b8a9b1dSJustin T. Gibbs } else { 29088b8a9b1dSJustin T. Gibbs cam_dpath = NULL; 29098b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.status = CAM_REQ_CMP; 29108b8a9b1dSJustin T. Gibbs } 29118b8a9b1dSJustin T. Gibbs splx(s); 29128b8a9b1dSJustin T. Gibbs #else /* !CAMDEBUG */ 29138b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.status = CAM_FUNC_NOTAVAIL; 29148b8a9b1dSJustin T. Gibbs #endif /* CAMDEBUG */ 29158b8a9b1dSJustin T. Gibbs break; 29168b8a9b1dSJustin T. Gibbs } 29178b8a9b1dSJustin T. Gibbs case XPT_NOOP: 29188b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.status = CAM_REQ_CMP; 29198b8a9b1dSJustin T. Gibbs break; 29208b8a9b1dSJustin T. Gibbs default: 29218b8a9b1dSJustin T. Gibbs case XPT_SDEV_TYPE: 29228b8a9b1dSJustin T. Gibbs case XPT_ABORT: 29238b8a9b1dSJustin T. Gibbs case XPT_RESET_DEV: 29248b8a9b1dSJustin T. Gibbs case XPT_TERM_IO: 29258b8a9b1dSJustin T. Gibbs case XPT_ENG_INQ: 29268b8a9b1dSJustin T. Gibbs /* XXX Implement */ 29278b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.status = CAM_PROVIDE_FAIL; 29288b8a9b1dSJustin T. Gibbs break; 29298b8a9b1dSJustin T. Gibbs } 29308b8a9b1dSJustin T. Gibbs } 29318b8a9b1dSJustin T. Gibbs 29328b8a9b1dSJustin T. Gibbs void 29338b8a9b1dSJustin T. Gibbs xpt_polled_action(union ccb *start_ccb) 29348b8a9b1dSJustin T. Gibbs { 29358b8a9b1dSJustin T. Gibbs int s; 29368b8a9b1dSJustin T. Gibbs u_int32_t timeout; 29378b8a9b1dSJustin T. Gibbs struct cam_sim *sim; 29388b8a9b1dSJustin T. Gibbs struct cam_devq *devq; 29398b8a9b1dSJustin T. Gibbs struct cam_ed *dev; 29408b8a9b1dSJustin T. Gibbs 29418b8a9b1dSJustin T. Gibbs timeout = start_ccb->ccb_h.timeout; 29428b8a9b1dSJustin T. Gibbs sim = start_ccb->ccb_h.path->bus->sim; 29438b8a9b1dSJustin T. Gibbs devq = sim->devq; 29448b8a9b1dSJustin T. Gibbs dev = start_ccb->ccb_h.path->device; 29458b8a9b1dSJustin T. Gibbs 29468b8a9b1dSJustin T. Gibbs s = splcam(); 29478b8a9b1dSJustin T. Gibbs 29488b8a9b1dSJustin T. Gibbs /* 29498b8a9b1dSJustin T. Gibbs * Steal an opening so that no other queued requests 29508b8a9b1dSJustin T. Gibbs * can get it before us while we simulate interrupts. 29518b8a9b1dSJustin T. Gibbs */ 29528b8a9b1dSJustin T. Gibbs dev->ccbq.devq_openings--; 29538b8a9b1dSJustin T. Gibbs dev->ccbq.dev_openings--; 29548b8a9b1dSJustin T. Gibbs 29558b8a9b1dSJustin T. Gibbs while((devq->send_openings <= 0 || dev->ccbq.dev_openings < 0) 29568b8a9b1dSJustin T. Gibbs && (--timeout > 0)) { 29578b8a9b1dSJustin T. Gibbs DELAY(1000); 29588b8a9b1dSJustin T. Gibbs (*(sim->sim_poll))(sim); 29598b8a9b1dSJustin T. Gibbs swi_camnet(); 29608b8a9b1dSJustin T. Gibbs swi_cambio(); 29618b8a9b1dSJustin T. Gibbs } 29628b8a9b1dSJustin T. Gibbs 29638b8a9b1dSJustin T. Gibbs dev->ccbq.devq_openings++; 29648b8a9b1dSJustin T. Gibbs dev->ccbq.dev_openings++; 29658b8a9b1dSJustin T. Gibbs 29668b8a9b1dSJustin T. Gibbs if (timeout != 0) { 29678b8a9b1dSJustin T. Gibbs xpt_action(start_ccb); 29688b8a9b1dSJustin T. Gibbs while(--timeout > 0) { 29698b8a9b1dSJustin T. Gibbs (*(sim->sim_poll))(sim); 29708b8a9b1dSJustin T. Gibbs swi_camnet(); 29718b8a9b1dSJustin T. Gibbs swi_cambio(); 29728b8a9b1dSJustin T. Gibbs if ((start_ccb->ccb_h.status & CAM_STATUS_MASK) 29738b8a9b1dSJustin T. Gibbs != CAM_REQ_INPROG) 29748b8a9b1dSJustin T. Gibbs break; 29758b8a9b1dSJustin T. Gibbs DELAY(1000); 29768b8a9b1dSJustin T. Gibbs } 29778b8a9b1dSJustin T. Gibbs if (timeout == 0) { 29788b8a9b1dSJustin T. Gibbs /* 29798b8a9b1dSJustin T. Gibbs * XXX Is it worth adding a sim_timeout entry 29808b8a9b1dSJustin T. Gibbs * point so we can attempt recovery? If 29818b8a9b1dSJustin T. Gibbs * this is only used for dumps, I don't think 29828b8a9b1dSJustin T. Gibbs * it is. 29838b8a9b1dSJustin T. Gibbs */ 29848b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.status = CAM_CMD_TIMEOUT; 29858b8a9b1dSJustin T. Gibbs } 29868b8a9b1dSJustin T. Gibbs } else { 29878b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.status = CAM_RESRC_UNAVAIL; 29888b8a9b1dSJustin T. Gibbs } 29898b8a9b1dSJustin T. Gibbs splx(s); 29908b8a9b1dSJustin T. Gibbs } 29918b8a9b1dSJustin T. Gibbs 29928b8a9b1dSJustin T. Gibbs /* 29938b8a9b1dSJustin T. Gibbs * Schedule a peripheral driver to receive a ccb when it's 29948b8a9b1dSJustin T. Gibbs * target device has space for more transactions. 29958b8a9b1dSJustin T. Gibbs */ 29968b8a9b1dSJustin T. Gibbs void 29978b8a9b1dSJustin T. Gibbs xpt_schedule(struct cam_periph *perph, u_int32_t new_priority) 29988b8a9b1dSJustin T. Gibbs { 29998b8a9b1dSJustin T. Gibbs struct cam_ed *device; 30008b8a9b1dSJustin T. Gibbs int s; 30018b8a9b1dSJustin T. Gibbs int runq; 30028b8a9b1dSJustin T. Gibbs 30038b8a9b1dSJustin T. Gibbs CAM_DEBUG(perph->path, CAM_DEBUG_TRACE, ("xpt_schedule\n")); 30048b8a9b1dSJustin T. Gibbs device = perph->path->device; 30058b8a9b1dSJustin T. Gibbs s = splsoftcam(); 30068b8a9b1dSJustin T. Gibbs if (periph_is_queued(perph)) { 30078b8a9b1dSJustin T. Gibbs /* Simply reorder based on new priority */ 30088b8a9b1dSJustin T. Gibbs CAM_DEBUG(perph->path, CAM_DEBUG_SUBTRACE, 30098b8a9b1dSJustin T. Gibbs (" change priority to %d\n", new_priority)); 30108b8a9b1dSJustin T. Gibbs if (new_priority < perph->pinfo.priority) { 30118b8a9b1dSJustin T. Gibbs camq_change_priority(&device->drvq, 30128b8a9b1dSJustin T. Gibbs perph->pinfo.index, 30138b8a9b1dSJustin T. Gibbs new_priority); 30148b8a9b1dSJustin T. Gibbs } 30158b8a9b1dSJustin T. Gibbs runq = 0; 30168b8a9b1dSJustin T. Gibbs } else { 30178b8a9b1dSJustin T. Gibbs /* New entry on the queue */ 30188b8a9b1dSJustin T. Gibbs CAM_DEBUG(perph->path, CAM_DEBUG_SUBTRACE, 30198b8a9b1dSJustin T. Gibbs (" added periph to queue\n")); 30208b8a9b1dSJustin T. Gibbs if (device->drvq.generation++ == 0) { 30218b8a9b1dSJustin T. Gibbs /* Generation wrap, regen all entries */ 30228b8a9b1dSJustin T. Gibbs camq_regen(&device->drvq); 30238b8a9b1dSJustin T. Gibbs } 30248b8a9b1dSJustin T. Gibbs perph->pinfo.priority = new_priority; 30258b8a9b1dSJustin T. Gibbs perph->pinfo.generation = device->drvq.generation; 30268b8a9b1dSJustin T. Gibbs camq_insert(&device->drvq, &perph->pinfo); 30278b8a9b1dSJustin T. Gibbs runq = xpt_schedule_dev_allocq(perph->path->bus, device); 30288b8a9b1dSJustin T. Gibbs } 30298b8a9b1dSJustin T. Gibbs splx(s); 30308b8a9b1dSJustin T. Gibbs if (runq != 0) { 30318b8a9b1dSJustin T. Gibbs CAM_DEBUG(perph->path, CAM_DEBUG_SUBTRACE, 30328b8a9b1dSJustin T. Gibbs (" calling xpt_run_devq\n")); 30338b8a9b1dSJustin T. Gibbs xpt_run_dev_allocq(perph->path->bus); 30348b8a9b1dSJustin T. Gibbs } 30358b8a9b1dSJustin T. Gibbs } 30368b8a9b1dSJustin T. Gibbs 30378b8a9b1dSJustin T. Gibbs 30388b8a9b1dSJustin T. Gibbs /* 30398b8a9b1dSJustin T. Gibbs * Schedule a device to run on a given queue. 30408b8a9b1dSJustin T. Gibbs * If the device was inserted as a new entry on the queue, 30418b8a9b1dSJustin T. Gibbs * return 1 meaning the device queue should be run. If we 30428b8a9b1dSJustin T. Gibbs * were already queued, implying someone else has already 30438b8a9b1dSJustin T. Gibbs * started the queue, return 0 so the caller doesn't attempt 30448b8a9b1dSJustin T. Gibbs * to run the queue. Must be run at either splsoftcam 30458b8a9b1dSJustin T. Gibbs * (or splcam since that encompases splsoftcam). 30468b8a9b1dSJustin T. Gibbs */ 30478b8a9b1dSJustin T. Gibbs static int 30488b8a9b1dSJustin T. Gibbs xpt_schedule_dev(struct camq *queue, cam_pinfo *pinfo, 30498b8a9b1dSJustin T. Gibbs u_int32_t new_priority) 30508b8a9b1dSJustin T. Gibbs { 30518b8a9b1dSJustin T. Gibbs int retval; 30528b8a9b1dSJustin T. Gibbs u_int32_t old_priority; 30538b8a9b1dSJustin T. Gibbs 30548b8a9b1dSJustin T. Gibbs CAM_DEBUG_PRINT(CAM_DEBUG_TRACE, ("xpt_schedule_dev\n")); 30558b8a9b1dSJustin T. Gibbs 30568b8a9b1dSJustin T. Gibbs old_priority = pinfo->priority; 30578b8a9b1dSJustin T. Gibbs 30588b8a9b1dSJustin T. Gibbs /* 30598b8a9b1dSJustin T. Gibbs * Are we already queued? 30608b8a9b1dSJustin T. Gibbs */ 30618b8a9b1dSJustin T. Gibbs if (pinfo->index != CAM_UNQUEUED_INDEX) { 30628b8a9b1dSJustin T. Gibbs /* Simply reorder based on new priority */ 30638b8a9b1dSJustin T. Gibbs if (new_priority < old_priority) { 30648b8a9b1dSJustin T. Gibbs camq_change_priority(queue, pinfo->index, 30658b8a9b1dSJustin T. Gibbs new_priority); 30668b8a9b1dSJustin T. Gibbs CAM_DEBUG_PRINT(CAM_DEBUG_SUBTRACE, 30678b8a9b1dSJustin T. Gibbs ("changed priority to %d\n", 30688b8a9b1dSJustin T. Gibbs new_priority)); 30698b8a9b1dSJustin T. Gibbs } 30708b8a9b1dSJustin T. Gibbs retval = 0; 30718b8a9b1dSJustin T. Gibbs } else { 30728b8a9b1dSJustin T. Gibbs /* New entry on the queue */ 30738b8a9b1dSJustin T. Gibbs if (new_priority < old_priority) 30748b8a9b1dSJustin T. Gibbs pinfo->priority = new_priority; 30758b8a9b1dSJustin T. Gibbs 30768b8a9b1dSJustin T. Gibbs CAM_DEBUG_PRINT(CAM_DEBUG_SUBTRACE, 30778b8a9b1dSJustin T. Gibbs ("Inserting onto queue\n")); 30788b8a9b1dSJustin T. Gibbs if (queue->generation++ == 0) { 30798b8a9b1dSJustin T. Gibbs /* Generation wrap, regen all entries */ 30808b8a9b1dSJustin T. Gibbs camq_regen(queue); 30818b8a9b1dSJustin T. Gibbs } 30828b8a9b1dSJustin T. Gibbs pinfo->generation = queue->generation; 30838b8a9b1dSJustin T. Gibbs camq_insert(queue, pinfo); 30848b8a9b1dSJustin T. Gibbs retval = 1; 30858b8a9b1dSJustin T. Gibbs } 30868b8a9b1dSJustin T. Gibbs return (retval); 30878b8a9b1dSJustin T. Gibbs } 30888b8a9b1dSJustin T. Gibbs 30898b8a9b1dSJustin T. Gibbs static void 30908b8a9b1dSJustin T. Gibbs xpt_run_dev_allocq(struct cam_eb *bus) 30918b8a9b1dSJustin T. Gibbs { 30928b8a9b1dSJustin T. Gibbs struct cam_devq *devq; 30938b8a9b1dSJustin T. Gibbs int s; 30948b8a9b1dSJustin T. Gibbs 30958b8a9b1dSJustin T. Gibbs CAM_DEBUG_PRINT(CAM_DEBUG_TRACE, ("xpt_run_dev_allocq\n")); 30968b8a9b1dSJustin T. Gibbs devq = bus->sim->devq; 30978b8a9b1dSJustin T. Gibbs 30988b8a9b1dSJustin T. Gibbs CAM_DEBUG_PRINT(CAM_DEBUG_SUBTRACE, 30998b8a9b1dSJustin T. Gibbs (" qfrozen_cnt == 0x%x, entries == %d, " 31008b8a9b1dSJustin T. Gibbs "openings == %d, active == %d\n", 31018b8a9b1dSJustin T. Gibbs devq->alloc_queue.qfrozen_cnt, 31028b8a9b1dSJustin T. Gibbs devq->alloc_queue.entries, 31038b8a9b1dSJustin T. Gibbs devq->alloc_openings, 31048b8a9b1dSJustin T. Gibbs devq->alloc_active)); 31058b8a9b1dSJustin T. Gibbs 31068b8a9b1dSJustin T. Gibbs s = splsoftcam(); 31078b8a9b1dSJustin T. Gibbs devq->alloc_queue.qfrozen_cnt++; 31088b8a9b1dSJustin T. Gibbs while ((devq->alloc_queue.entries > 0) 31098b8a9b1dSJustin T. Gibbs && (devq->alloc_openings > 0) 31108b8a9b1dSJustin T. Gibbs && (devq->alloc_queue.qfrozen_cnt <= 1)) { 31118b8a9b1dSJustin T. Gibbs struct cam_ed_qinfo *qinfo; 31128b8a9b1dSJustin T. Gibbs struct cam_ed *device; 31138b8a9b1dSJustin T. Gibbs union ccb *work_ccb; 31148b8a9b1dSJustin T. Gibbs struct cam_periph *drv; 31158b8a9b1dSJustin T. Gibbs struct camq *drvq; 31168b8a9b1dSJustin T. Gibbs 31178b8a9b1dSJustin T. Gibbs qinfo = (struct cam_ed_qinfo *)camq_remove(&devq->alloc_queue, 31188b8a9b1dSJustin T. Gibbs /*position*/0); 31198b8a9b1dSJustin T. Gibbs device = qinfo->device; 31208b8a9b1dSJustin T. Gibbs 31218b8a9b1dSJustin T. Gibbs CAM_DEBUG_PRINT(CAM_DEBUG_SUBTRACE, 31228b8a9b1dSJustin T. Gibbs ("running device 0x%x\n", device)); 31238b8a9b1dSJustin T. Gibbs 31248b8a9b1dSJustin T. Gibbs drvq = &device->drvq; 31258b8a9b1dSJustin T. Gibbs 31268b8a9b1dSJustin T. Gibbs #ifdef CAMDEBUG 31278b8a9b1dSJustin T. Gibbs if (drvq->entries <= 0) { 31288b8a9b1dSJustin T. Gibbs panic("xpt_run_dev_allocq: " 31298b8a9b1dSJustin T. Gibbs "Device on queue without any work to do"); 31308b8a9b1dSJustin T. Gibbs } 31318b8a9b1dSJustin T. Gibbs #endif 31328b8a9b1dSJustin T. Gibbs if ((work_ccb = xpt_get_ccb(device)) != NULL) { 31338b8a9b1dSJustin T. Gibbs devq->alloc_openings--; 31348b8a9b1dSJustin T. Gibbs devq->alloc_active++; 31358b8a9b1dSJustin T. Gibbs drv = (struct cam_periph*)camq_remove(drvq, 31368b8a9b1dSJustin T. Gibbs /*pos*/0); 31378b8a9b1dSJustin T. Gibbs /* Update priority */ 31388b8a9b1dSJustin T. Gibbs if (drvq->entries > 0) { 31398b8a9b1dSJustin T. Gibbs qinfo->pinfo.priority = drvq->queue_array[0]->priority; 31408b8a9b1dSJustin T. Gibbs } else { 31418b8a9b1dSJustin T. Gibbs qinfo->pinfo.priority = CAM_PRIORITY_NONE; 31428b8a9b1dSJustin T. Gibbs } 31438b8a9b1dSJustin T. Gibbs splx(s); 31448b8a9b1dSJustin T. Gibbs xpt_setup_ccb(&work_ccb->ccb_h, drv->path, 31458b8a9b1dSJustin T. Gibbs drv->pinfo.priority); 31468b8a9b1dSJustin T. Gibbs CAM_DEBUG_PRINT(CAM_DEBUG_SUBTRACE, 31478b8a9b1dSJustin T. Gibbs ("calling periph start\n")); 31488b8a9b1dSJustin T. Gibbs drv->periph_start(drv, work_ccb); 31498b8a9b1dSJustin T. Gibbs } else { 31508b8a9b1dSJustin T. Gibbs /* 31518b8a9b1dSJustin T. Gibbs * Malloc failure in alloc_ccb 31528b8a9b1dSJustin T. Gibbs */ 31538b8a9b1dSJustin T. Gibbs /* 31548b8a9b1dSJustin T. Gibbs * XXX add us to a list to be run from free_ccb 31558b8a9b1dSJustin T. Gibbs * if we don't have any ccbs active on this 31568b8a9b1dSJustin T. Gibbs * device queue otherwise we may never get run 31578b8a9b1dSJustin T. Gibbs * again. 31588b8a9b1dSJustin T. Gibbs */ 31598b8a9b1dSJustin T. Gibbs break; 31608b8a9b1dSJustin T. Gibbs } 31618b8a9b1dSJustin T. Gibbs 31628b8a9b1dSJustin T. Gibbs /* Raise IPL for possible insertion and test at top of loop */ 31638b8a9b1dSJustin T. Gibbs s = splsoftcam(); 31648b8a9b1dSJustin T. Gibbs 31658b8a9b1dSJustin T. Gibbs if (drvq->entries > 0) { 31668b8a9b1dSJustin T. Gibbs /* We have more work. Attempt to reschedule */ 31678b8a9b1dSJustin T. Gibbs xpt_schedule_dev_allocq(bus, device); 31688b8a9b1dSJustin T. Gibbs } 31698b8a9b1dSJustin T. Gibbs } 31708b8a9b1dSJustin T. Gibbs devq->alloc_queue.qfrozen_cnt--; 31718b8a9b1dSJustin T. Gibbs splx(s); 31728b8a9b1dSJustin T. Gibbs } 31738b8a9b1dSJustin T. Gibbs 31748b8a9b1dSJustin T. Gibbs static void 31758b8a9b1dSJustin T. Gibbs xpt_run_dev_sendq(struct cam_eb *bus) 31768b8a9b1dSJustin T. Gibbs { 31778b8a9b1dSJustin T. Gibbs struct cam_devq *devq; 31788b8a9b1dSJustin T. Gibbs int s; 31798b8a9b1dSJustin T. Gibbs 31808b8a9b1dSJustin T. Gibbs CAM_DEBUG_PRINT(CAM_DEBUG_TRACE, ("xpt_run_dev_sendq\n")); 31818b8a9b1dSJustin T. Gibbs 31828b8a9b1dSJustin T. Gibbs devq = bus->sim->devq; 31838b8a9b1dSJustin T. Gibbs 31848b8a9b1dSJustin T. Gibbs s = splcam(); 31858b8a9b1dSJustin T. Gibbs devq->send_queue.qfrozen_cnt++; 31868b8a9b1dSJustin T. Gibbs splx(s); 31878b8a9b1dSJustin T. Gibbs s = splsoftcam(); 31888b8a9b1dSJustin T. Gibbs while ((devq->send_queue.entries > 0) 31898b8a9b1dSJustin T. Gibbs && (devq->send_openings > 0)) { 31908b8a9b1dSJustin T. Gibbs struct cam_ed_qinfo *qinfo; 31918b8a9b1dSJustin T. Gibbs struct cam_ed *device; 31928b8a9b1dSJustin T. Gibbs union ccb *work_ccb; 31938b8a9b1dSJustin T. Gibbs struct cam_sim *sim; 31948b8a9b1dSJustin T. Gibbs int ospl; 31958b8a9b1dSJustin T. Gibbs 31968b8a9b1dSJustin T. Gibbs ospl = splcam(); 31978b8a9b1dSJustin T. Gibbs if (devq->send_queue.qfrozen_cnt > 1) { 31988b8a9b1dSJustin T. Gibbs splx(ospl); 31998b8a9b1dSJustin T. Gibbs break; 32008b8a9b1dSJustin T. Gibbs } 32018b8a9b1dSJustin T. Gibbs 32028b8a9b1dSJustin T. Gibbs qinfo = (struct cam_ed_qinfo *)camq_remove(&devq->send_queue, 32038b8a9b1dSJustin T. Gibbs /*position*/0); 32048b8a9b1dSJustin T. Gibbs device = qinfo->device; 32058b8a9b1dSJustin T. Gibbs 32068b8a9b1dSJustin T. Gibbs /* 32078b8a9b1dSJustin T. Gibbs * If the device has been "frozen", don't attempt 32088b8a9b1dSJustin T. Gibbs * to run it. 32098b8a9b1dSJustin T. Gibbs */ 32108b8a9b1dSJustin T. Gibbs if (device->qfrozen_cnt > 0) { 32118b8a9b1dSJustin T. Gibbs splx(ospl); 32128b8a9b1dSJustin T. Gibbs continue; 32138b8a9b1dSJustin T. Gibbs } 32148b8a9b1dSJustin T. Gibbs 32158b8a9b1dSJustin T. Gibbs CAM_DEBUG_PRINT(CAM_DEBUG_SUBTRACE, 32168b8a9b1dSJustin T. Gibbs ("running device 0x%x\n", device)); 32178b8a9b1dSJustin T. Gibbs 32188b8a9b1dSJustin T. Gibbs work_ccb = cam_ccbq_peek_ccb(&device->ccbq, 0); 32198b8a9b1dSJustin T. Gibbs if (work_ccb == NULL) { 32208b8a9b1dSJustin T. Gibbs printf("device on run queue with no ccbs???"); 32218b8a9b1dSJustin T. Gibbs splx(ospl); 32228b8a9b1dSJustin T. Gibbs continue; 32238b8a9b1dSJustin T. Gibbs } 32248b8a9b1dSJustin T. Gibbs 32258b8a9b1dSJustin T. Gibbs if ((work_ccb->ccb_h.flags & CAM_HIGH_POWER) != 0) { 32268b8a9b1dSJustin T. Gibbs 32278b8a9b1dSJustin T. Gibbs if (num_highpower <= 0) { 32288b8a9b1dSJustin T. Gibbs /* 32298b8a9b1dSJustin T. Gibbs * We got a high power command, but we 32308b8a9b1dSJustin T. Gibbs * don't have any available slots. Freeze 32318b8a9b1dSJustin T. Gibbs * the device queue until we have a slot 32328b8a9b1dSJustin T. Gibbs * available. 32338b8a9b1dSJustin T. Gibbs */ 32348b8a9b1dSJustin T. Gibbs device->qfrozen_cnt++; 32358b8a9b1dSJustin T. Gibbs STAILQ_INSERT_TAIL(&highpowerq, 32368b8a9b1dSJustin T. Gibbs &work_ccb->ccb_h, 32378b8a9b1dSJustin T. Gibbs xpt_links.stqe); 32388b8a9b1dSJustin T. Gibbs 32398b8a9b1dSJustin T. Gibbs splx(ospl); 32408b8a9b1dSJustin T. Gibbs continue; 32418b8a9b1dSJustin T. Gibbs } else { 32428b8a9b1dSJustin T. Gibbs /* 32438b8a9b1dSJustin T. Gibbs * Consume a high power slot while 32448b8a9b1dSJustin T. Gibbs * this ccb runs. 32458b8a9b1dSJustin T. Gibbs */ 32468b8a9b1dSJustin T. Gibbs num_highpower--; 32478b8a9b1dSJustin T. Gibbs } 32488b8a9b1dSJustin T. Gibbs } 32498b8a9b1dSJustin T. Gibbs devq->active_dev = device; 32508b8a9b1dSJustin T. Gibbs cam_ccbq_remove_ccb(&device->ccbq, work_ccb); 32518b8a9b1dSJustin T. Gibbs 32528b8a9b1dSJustin T. Gibbs cam_ccbq_send_ccb(&device->ccbq, work_ccb); 32538b8a9b1dSJustin T. Gibbs splx(ospl); 32548b8a9b1dSJustin T. Gibbs 32558b8a9b1dSJustin T. Gibbs devq->send_openings--; 32568b8a9b1dSJustin T. Gibbs devq->send_active++; 32578b8a9b1dSJustin T. Gibbs 32588b8a9b1dSJustin T. Gibbs if (device->ccbq.queue.entries > 0) { 32598b8a9b1dSJustin T. Gibbs qinfo->pinfo.priority = 32608b8a9b1dSJustin T. Gibbs device->ccbq.queue.queue_array[0]->priority; 32618b8a9b1dSJustin T. Gibbs xpt_schedule_dev_sendq(bus, device); 32628b8a9b1dSJustin T. Gibbs } else { 32638b8a9b1dSJustin T. Gibbs qinfo->pinfo.priority = CAM_PRIORITY_NONE; 32648b8a9b1dSJustin T. Gibbs } 32658b8a9b1dSJustin T. Gibbs 32668b8a9b1dSJustin T. Gibbs if (work_ccb && (work_ccb->ccb_h.flags & CAM_DEV_QFREEZE) != 0){ 32678b8a9b1dSJustin T. Gibbs /* 32688b8a9b1dSJustin T. Gibbs * The client wants to freeze the queue 32698b8a9b1dSJustin T. Gibbs * after this CCB is sent. 32708b8a9b1dSJustin T. Gibbs */ 32718b8a9b1dSJustin T. Gibbs ospl = splcam(); 32728b8a9b1dSJustin T. Gibbs device->qfrozen_cnt++; 32738b8a9b1dSJustin T. Gibbs splx(ospl); 32748b8a9b1dSJustin T. Gibbs } 32758b8a9b1dSJustin T. Gibbs 32768b8a9b1dSJustin T. Gibbs splx(s); 32778b8a9b1dSJustin T. Gibbs 32788b8a9b1dSJustin T. Gibbs if ((device->inq_flags & SID_CmdQue) != 0) 32798b8a9b1dSJustin T. Gibbs work_ccb->ccb_h.flags |= CAM_TAG_ACTION_VALID; 32808b8a9b1dSJustin T. Gibbs else 32818b8a9b1dSJustin T. Gibbs /* 32828b8a9b1dSJustin T. Gibbs * Clear this in case of a retried CCB that failed 32838b8a9b1dSJustin T. Gibbs * due to a rejected tag. 32848b8a9b1dSJustin T. Gibbs */ 32858b8a9b1dSJustin T. Gibbs work_ccb->ccb_h.flags &= ~CAM_TAG_ACTION_VALID; 32868b8a9b1dSJustin T. Gibbs 32878b8a9b1dSJustin T. Gibbs /* 32888b8a9b1dSJustin T. Gibbs * Device queues can be shared among multiple sim instances 32898b8a9b1dSJustin T. Gibbs * that reside on different busses. Use the SIM in the queue 32908b8a9b1dSJustin T. Gibbs * CCB's path, rather than the one in the bus that was passed 32918b8a9b1dSJustin T. Gibbs * into this function. 32928b8a9b1dSJustin T. Gibbs */ 32938b8a9b1dSJustin T. Gibbs sim = work_ccb->ccb_h.path->bus->sim; 32948b8a9b1dSJustin T. Gibbs (*(sim->sim_action))(sim, work_ccb); 32958b8a9b1dSJustin T. Gibbs 32968b8a9b1dSJustin T. Gibbs ospl = splcam(); 32978b8a9b1dSJustin T. Gibbs devq->active_dev = NULL; 32988b8a9b1dSJustin T. Gibbs splx(ospl); 32998b8a9b1dSJustin T. Gibbs /* Raise IPL for possible insertion and test at top of loop */ 33008b8a9b1dSJustin T. Gibbs s = splsoftcam(); 33018b8a9b1dSJustin T. Gibbs } 33028b8a9b1dSJustin T. Gibbs splx(s); 33038b8a9b1dSJustin T. Gibbs s = splcam(); 33048b8a9b1dSJustin T. Gibbs devq->send_queue.qfrozen_cnt--; 33058b8a9b1dSJustin T. Gibbs splx(s); 33068b8a9b1dSJustin T. Gibbs } 33078b8a9b1dSJustin T. Gibbs 33088b8a9b1dSJustin T. Gibbs /* 33098b8a9b1dSJustin T. Gibbs * This function merges stuff from the slave ccb into the master ccb, while 33108b8a9b1dSJustin T. Gibbs * keeping important fields in the master ccb constant. 33118b8a9b1dSJustin T. Gibbs */ 33128b8a9b1dSJustin T. Gibbs void 33138b8a9b1dSJustin T. Gibbs xpt_merge_ccb(union ccb *master_ccb, union ccb *slave_ccb) 33148b8a9b1dSJustin T. Gibbs { 33158b8a9b1dSJustin T. Gibbs /* 33168b8a9b1dSJustin T. Gibbs * Pull fields that are valid for peripheral drivers to set 33178b8a9b1dSJustin T. Gibbs * into the master CCB along with the CCB "payload". 33188b8a9b1dSJustin T. Gibbs */ 33198b8a9b1dSJustin T. Gibbs master_ccb->ccb_h.retry_count = slave_ccb->ccb_h.retry_count; 33208b8a9b1dSJustin T. Gibbs master_ccb->ccb_h.func_code = slave_ccb->ccb_h.func_code; 33218b8a9b1dSJustin T. Gibbs master_ccb->ccb_h.timeout = slave_ccb->ccb_h.timeout; 33228b8a9b1dSJustin T. Gibbs master_ccb->ccb_h.flags = slave_ccb->ccb_h.flags; 33238b8a9b1dSJustin T. Gibbs bcopy(&(&slave_ccb->ccb_h)[1], &(&master_ccb->ccb_h)[1], 33248b8a9b1dSJustin T. Gibbs sizeof(union ccb) - sizeof(struct ccb_hdr)); 33258b8a9b1dSJustin T. Gibbs } 33268b8a9b1dSJustin T. Gibbs 33278b8a9b1dSJustin T. Gibbs void 33288b8a9b1dSJustin T. Gibbs xpt_setup_ccb(struct ccb_hdr *ccb_h, struct cam_path *path, u_int32_t priority) 33298b8a9b1dSJustin T. Gibbs { 33308b8a9b1dSJustin T. Gibbs CAM_DEBUG(path, CAM_DEBUG_TRACE, ("xpt_setup_ccb\n")); 33318b8a9b1dSJustin T. Gibbs ccb_h->pinfo.priority = priority; 33328b8a9b1dSJustin T. Gibbs ccb_h->path = path; 33338b8a9b1dSJustin T. Gibbs ccb_h->path_id = path->bus->path_id; 33348b8a9b1dSJustin T. Gibbs if (path->target) 33358b8a9b1dSJustin T. Gibbs ccb_h->target_id = path->target->target_id; 33368b8a9b1dSJustin T. Gibbs else 33378b8a9b1dSJustin T. Gibbs ccb_h->target_id = CAM_TARGET_WILDCARD; 33388b8a9b1dSJustin T. Gibbs if (path->device) { 33398b8a9b1dSJustin T. Gibbs if (path->device->ccbq.queue.generation++ == 0) { 33408b8a9b1dSJustin T. Gibbs /* Generation wrap, regen all entries */ 33418b8a9b1dSJustin T. Gibbs cam_ccbq_regen(&path->device->ccbq); 33428b8a9b1dSJustin T. Gibbs } 33438b8a9b1dSJustin T. Gibbs ccb_h->target_lun = path->device->lun_id; 33448b8a9b1dSJustin T. Gibbs ccb_h->pinfo.generation = path->device->ccbq.queue.generation; 33458b8a9b1dSJustin T. Gibbs } else { 33468b8a9b1dSJustin T. Gibbs ccb_h->target_lun = CAM_TARGET_WILDCARD; 33478b8a9b1dSJustin T. Gibbs } 33488b8a9b1dSJustin T. Gibbs ccb_h->pinfo.index = CAM_UNQUEUED_INDEX; 33498b8a9b1dSJustin T. Gibbs ccb_h->flags = 0; 33508b8a9b1dSJustin T. Gibbs } 33518b8a9b1dSJustin T. Gibbs 33528b8a9b1dSJustin T. Gibbs /* Path manipulation functions */ 33538b8a9b1dSJustin T. Gibbs cam_status 33548b8a9b1dSJustin T. Gibbs xpt_create_path(struct cam_path **new_path_ptr, struct cam_periph *perph, 33558b8a9b1dSJustin T. Gibbs path_id_t path_id, target_id_t target_id, lun_id_t lun_id) 33568b8a9b1dSJustin T. Gibbs { 33578b8a9b1dSJustin T. Gibbs struct cam_path *path; 33588b8a9b1dSJustin T. Gibbs cam_status status; 33598b8a9b1dSJustin T. Gibbs 33608b8a9b1dSJustin T. Gibbs path = (struct cam_path *)malloc(sizeof(*path), M_DEVBUF, M_NOWAIT); 33618b8a9b1dSJustin T. Gibbs 33628b8a9b1dSJustin T. Gibbs if (path == NULL) { 33638b8a9b1dSJustin T. Gibbs status = CAM_RESRC_UNAVAIL; 33648b8a9b1dSJustin T. Gibbs return(status); 33658b8a9b1dSJustin T. Gibbs } 33668b8a9b1dSJustin T. Gibbs status = xpt_compile_path(path, perph, path_id, target_id, lun_id); 33678b8a9b1dSJustin T. Gibbs if (status != CAM_REQ_CMP) { 33688b8a9b1dSJustin T. Gibbs free(path, M_DEVBUF); 33698b8a9b1dSJustin T. Gibbs path = NULL; 33708b8a9b1dSJustin T. Gibbs } 33718b8a9b1dSJustin T. Gibbs *new_path_ptr = path; 33728b8a9b1dSJustin T. Gibbs return (status); 33738b8a9b1dSJustin T. Gibbs } 33748b8a9b1dSJustin T. Gibbs 33758b8a9b1dSJustin T. Gibbs static cam_status 33768b8a9b1dSJustin T. Gibbs xpt_compile_path(struct cam_path *new_path, struct cam_periph *perph, 33778b8a9b1dSJustin T. Gibbs path_id_t path_id, target_id_t target_id, lun_id_t lun_id) 33788b8a9b1dSJustin T. Gibbs { 33798b8a9b1dSJustin T. Gibbs struct cam_eb *bus; 33808b8a9b1dSJustin T. Gibbs struct cam_et *target; 33818b8a9b1dSJustin T. Gibbs struct cam_ed *device; 33828b8a9b1dSJustin T. Gibbs cam_status status; 33838b8a9b1dSJustin T. Gibbs int s; 33848b8a9b1dSJustin T. Gibbs 33858b8a9b1dSJustin T. Gibbs status = CAM_REQ_CMP; /* Completed without error */ 33868b8a9b1dSJustin T. Gibbs target = NULL; /* Wildcarded */ 33878b8a9b1dSJustin T. Gibbs device = NULL; /* Wildcarded */ 33888b8a9b1dSJustin T. Gibbs s = splsoftcam(); 33898b8a9b1dSJustin T. Gibbs bus = xpt_find_bus(path_id); 33908b8a9b1dSJustin T. Gibbs if (bus == NULL) { 33918b8a9b1dSJustin T. Gibbs status = CAM_PATH_INVALID; 33928b8a9b1dSJustin T. Gibbs } else if (target_id != CAM_TARGET_WILDCARD) { 33938b8a9b1dSJustin T. Gibbs target = xpt_find_target(bus, target_id); 33948b8a9b1dSJustin T. Gibbs if (target == NULL) { 33958b8a9b1dSJustin T. Gibbs if (path_id == CAM_XPT_PATH_ID) { 33968b8a9b1dSJustin T. Gibbs status = CAM_TID_INVALID; 33978b8a9b1dSJustin T. Gibbs } else { 33988b8a9b1dSJustin T. Gibbs /* Create one */ 33998b8a9b1dSJustin T. Gibbs struct cam_et *new_target; 34008b8a9b1dSJustin T. Gibbs 34018b8a9b1dSJustin T. Gibbs new_target = xpt_alloc_target(bus, target_id); 34028b8a9b1dSJustin T. Gibbs if (new_target == NULL) { 34038b8a9b1dSJustin T. Gibbs status = CAM_RESRC_UNAVAIL; 34048b8a9b1dSJustin T. Gibbs } else { 34058b8a9b1dSJustin T. Gibbs target = new_target; 34068b8a9b1dSJustin T. Gibbs } 34078b8a9b1dSJustin T. Gibbs } 34088b8a9b1dSJustin T. Gibbs } 34098b8a9b1dSJustin T. Gibbs if (target != NULL && lun_id != CAM_LUN_WILDCARD) { 34108b8a9b1dSJustin T. Gibbs device = xpt_find_device(target, lun_id); 34118b8a9b1dSJustin T. Gibbs if (device == NULL) { 34128b8a9b1dSJustin T. Gibbs if (path_id == CAM_XPT_PATH_ID) { 34138b8a9b1dSJustin T. Gibbs status = CAM_LUN_INVALID; 34148b8a9b1dSJustin T. Gibbs } else { 34158b8a9b1dSJustin T. Gibbs /* Create one */ 34168b8a9b1dSJustin T. Gibbs struct cam_ed *new_device; 34178b8a9b1dSJustin T. Gibbs 34188b8a9b1dSJustin T. Gibbs new_device = xpt_alloc_device(bus, 34198b8a9b1dSJustin T. Gibbs target, 34208b8a9b1dSJustin T. Gibbs lun_id); 34218b8a9b1dSJustin T. Gibbs if (new_device == NULL) { 34228b8a9b1dSJustin T. Gibbs status = CAM_RESRC_UNAVAIL; 34238b8a9b1dSJustin T. Gibbs } else { 34248b8a9b1dSJustin T. Gibbs device = new_device; 34258b8a9b1dSJustin T. Gibbs } 34268b8a9b1dSJustin T. Gibbs } 34278b8a9b1dSJustin T. Gibbs } 34288b8a9b1dSJustin T. Gibbs } 34298b8a9b1dSJustin T. Gibbs } else if (lun_id != CAM_LUN_WILDCARD) { 34308b8a9b1dSJustin T. Gibbs /* 34318b8a9b1dSJustin T. Gibbs * Specific luns are not allowed if the 34328b8a9b1dSJustin T. Gibbs * target is wildcarded 34338b8a9b1dSJustin T. Gibbs */ 34348b8a9b1dSJustin T. Gibbs status = CAM_LUN_INVALID; 34358b8a9b1dSJustin T. Gibbs } 34368b8a9b1dSJustin T. Gibbs 34378b8a9b1dSJustin T. Gibbs /* 34388b8a9b1dSJustin T. Gibbs * Only touch the user's data if we are successful. 34398b8a9b1dSJustin T. Gibbs */ 34408b8a9b1dSJustin T. Gibbs if (status == CAM_REQ_CMP) { 34418b8a9b1dSJustin T. Gibbs new_path->periph = perph; 34428b8a9b1dSJustin T. Gibbs new_path->bus = bus; 34438b8a9b1dSJustin T. Gibbs new_path->target = target; 34448b8a9b1dSJustin T. Gibbs new_path->device = device; 34458b8a9b1dSJustin T. Gibbs CAM_DEBUG(new_path, CAM_DEBUG_TRACE, ("xpt_compile_path\n")); 34468b8a9b1dSJustin T. Gibbs } else { 34478b8a9b1dSJustin T. Gibbs if (device != NULL) 34488b8a9b1dSJustin T. Gibbs xpt_release_device(bus, target, device); 34498b8a9b1dSJustin T. Gibbs if (target != NULL) 34508b8a9b1dSJustin T. Gibbs xpt_release_target(bus, target); 34518b8a9b1dSJustin T. Gibbs } 34528b8a9b1dSJustin T. Gibbs splx(s); 34538b8a9b1dSJustin T. Gibbs return (status); 34548b8a9b1dSJustin T. Gibbs } 34558b8a9b1dSJustin T. Gibbs 34568b8a9b1dSJustin T. Gibbs static void 34578b8a9b1dSJustin T. Gibbs xpt_release_path(struct cam_path *path) 34588b8a9b1dSJustin T. Gibbs { 34598b8a9b1dSJustin T. Gibbs CAM_DEBUG(path, CAM_DEBUG_TRACE, ("xpt_release_path\n")); 34608b8a9b1dSJustin T. Gibbs if (path->device != NULL) 34618b8a9b1dSJustin T. Gibbs xpt_release_device(path->bus, path->target, path->device); 34628b8a9b1dSJustin T. Gibbs if (path->target != NULL) 34638b8a9b1dSJustin T. Gibbs xpt_release_target(path->bus, path->target); 34648b8a9b1dSJustin T. Gibbs } 34658b8a9b1dSJustin T. Gibbs 34668b8a9b1dSJustin T. Gibbs void 34678b8a9b1dSJustin T. Gibbs xpt_free_path(struct cam_path *path) 34688b8a9b1dSJustin T. Gibbs { 34698b8a9b1dSJustin T. Gibbs CAM_DEBUG(path, CAM_DEBUG_TRACE, ("xpt_free_path\n")); 34708b8a9b1dSJustin T. Gibbs xpt_release_path(path); 34718b8a9b1dSJustin T. Gibbs free(path, M_DEVBUF); 34728b8a9b1dSJustin T. Gibbs } 34738b8a9b1dSJustin T. Gibbs 34748b8a9b1dSJustin T. Gibbs 34758b8a9b1dSJustin T. Gibbs /* 34768b8a9b1dSJustin T. Gibbs * Return -1 for failure, 0 for exact match, 1 for match with wildcards. 34778b8a9b1dSJustin T. Gibbs */ 34788b8a9b1dSJustin T. Gibbs int 34798b8a9b1dSJustin T. Gibbs xpt_path_comp(struct cam_path *path1, struct cam_path *path2) 34808b8a9b1dSJustin T. Gibbs { 34818b8a9b1dSJustin T. Gibbs int retval = 0; 34828b8a9b1dSJustin T. Gibbs 34838b8a9b1dSJustin T. Gibbs if (path1->bus != path2->bus) { 34848b8a9b1dSJustin T. Gibbs if ((path1->bus == NULL) 34858b8a9b1dSJustin T. Gibbs || (path2->bus == NULL)) 34868b8a9b1dSJustin T. Gibbs retval = 1; 34878b8a9b1dSJustin T. Gibbs else 34888b8a9b1dSJustin T. Gibbs return (-1); 34898b8a9b1dSJustin T. Gibbs } 34908b8a9b1dSJustin T. Gibbs if (path1->target != path2->target) { 34918b8a9b1dSJustin T. Gibbs if ((path1->target == NULL) 34928b8a9b1dSJustin T. Gibbs || (path2->target == NULL)) 34938b8a9b1dSJustin T. Gibbs retval = 1; 34948b8a9b1dSJustin T. Gibbs else 34958b8a9b1dSJustin T. Gibbs return (-1); 34968b8a9b1dSJustin T. Gibbs } 34978b8a9b1dSJustin T. Gibbs if (path1->device != path2->device) { 34988b8a9b1dSJustin T. Gibbs if ((path1->device == NULL) 34998b8a9b1dSJustin T. Gibbs || (path2->device == NULL)) 35008b8a9b1dSJustin T. Gibbs retval = 1; 35018b8a9b1dSJustin T. Gibbs else 35028b8a9b1dSJustin T. Gibbs return (-1); 35038b8a9b1dSJustin T. Gibbs } 35048b8a9b1dSJustin T. Gibbs return (retval); 35058b8a9b1dSJustin T. Gibbs } 35068b8a9b1dSJustin T. Gibbs 35078b8a9b1dSJustin T. Gibbs void 35088b8a9b1dSJustin T. Gibbs xpt_print_path(struct cam_path *path) 35098b8a9b1dSJustin T. Gibbs { 35108b8a9b1dSJustin T. Gibbs if (path == NULL) 35118b8a9b1dSJustin T. Gibbs printf("(nopath): "); 35128b8a9b1dSJustin T. Gibbs else { 35138b8a9b1dSJustin T. Gibbs if (path->periph != NULL) 35148b8a9b1dSJustin T. Gibbs printf("(%s%d:", path->periph->periph_name, 35158b8a9b1dSJustin T. Gibbs path->periph->unit_number); 35168b8a9b1dSJustin T. Gibbs else 35178b8a9b1dSJustin T. Gibbs printf("(noperiph:"); 35188b8a9b1dSJustin T. Gibbs 35198b8a9b1dSJustin T. Gibbs if (path->bus != NULL) 35208b8a9b1dSJustin T. Gibbs printf("%s%d:%d:", path->bus->sim->sim_name, 35218b8a9b1dSJustin T. Gibbs path->bus->sim->unit_number, 35228b8a9b1dSJustin T. Gibbs path->bus->sim->bus_id); 35238b8a9b1dSJustin T. Gibbs else 35248b8a9b1dSJustin T. Gibbs printf("nobus:"); 35258b8a9b1dSJustin T. Gibbs 35268b8a9b1dSJustin T. Gibbs if (path->target != NULL) 35278b8a9b1dSJustin T. Gibbs printf("%d:", path->target->target_id); 35288b8a9b1dSJustin T. Gibbs else 35298b8a9b1dSJustin T. Gibbs printf("X:"); 35308b8a9b1dSJustin T. Gibbs 35318b8a9b1dSJustin T. Gibbs if (path->device != NULL) 35328b8a9b1dSJustin T. Gibbs printf("%d): ", path->device->lun_id); 35338b8a9b1dSJustin T. Gibbs else 35348b8a9b1dSJustin T. Gibbs printf("X): "); 35358b8a9b1dSJustin T. Gibbs } 35368b8a9b1dSJustin T. Gibbs } 35378b8a9b1dSJustin T. Gibbs 35388b8a9b1dSJustin T. Gibbs path_id_t 35398b8a9b1dSJustin T. Gibbs xpt_path_path_id(struct cam_path *path) 35408b8a9b1dSJustin T. Gibbs { 35418b8a9b1dSJustin T. Gibbs return(path->bus->path_id); 35428b8a9b1dSJustin T. Gibbs } 35438b8a9b1dSJustin T. Gibbs 35448b8a9b1dSJustin T. Gibbs target_id_t 35458b8a9b1dSJustin T. Gibbs xpt_path_target_id(struct cam_path *path) 35468b8a9b1dSJustin T. Gibbs { 35478b8a9b1dSJustin T. Gibbs if (path->target != NULL) 35488b8a9b1dSJustin T. Gibbs return (path->target->target_id); 35498b8a9b1dSJustin T. Gibbs else 35508b8a9b1dSJustin T. Gibbs return (CAM_TARGET_WILDCARD); 35518b8a9b1dSJustin T. Gibbs } 35528b8a9b1dSJustin T. Gibbs 35538b8a9b1dSJustin T. Gibbs lun_id_t 35548b8a9b1dSJustin T. Gibbs xpt_path_lun_id(struct cam_path *path) 35558b8a9b1dSJustin T. Gibbs { 35568b8a9b1dSJustin T. Gibbs if (path->device != NULL) 35578b8a9b1dSJustin T. Gibbs return (path->device->lun_id); 35588b8a9b1dSJustin T. Gibbs else 35598b8a9b1dSJustin T. Gibbs return (CAM_LUN_WILDCARD); 35608b8a9b1dSJustin T. Gibbs } 35618b8a9b1dSJustin T. Gibbs 35628b8a9b1dSJustin T. Gibbs struct cam_sim * 35638b8a9b1dSJustin T. Gibbs xpt_path_sim(struct cam_path *path) 35648b8a9b1dSJustin T. Gibbs { 35658b8a9b1dSJustin T. Gibbs return (path->bus->sim); 35668b8a9b1dSJustin T. Gibbs } 35678b8a9b1dSJustin T. Gibbs 35688b8a9b1dSJustin T. Gibbs struct cam_periph* 35698b8a9b1dSJustin T. Gibbs xpt_path_periph(struct cam_path *path) 35708b8a9b1dSJustin T. Gibbs { 35718b8a9b1dSJustin T. Gibbs return (path->periph); 35728b8a9b1dSJustin T. Gibbs } 35738b8a9b1dSJustin T. Gibbs 35748b8a9b1dSJustin T. Gibbs /* 35758b8a9b1dSJustin T. Gibbs * Release a CAM control block for the caller. Remit the cost of the structure 35768b8a9b1dSJustin T. Gibbs * to the device referenced by the path. If the this device had no 'credits' 35778b8a9b1dSJustin T. Gibbs * and peripheral drivers have registered async callbacks for this notification 35788b8a9b1dSJustin T. Gibbs * call them now. 35798b8a9b1dSJustin T. Gibbs */ 35808b8a9b1dSJustin T. Gibbs void 35818b8a9b1dSJustin T. Gibbs xpt_release_ccb(union ccb *free_ccb) 35828b8a9b1dSJustin T. Gibbs { 35838b8a9b1dSJustin T. Gibbs int s; 35848b8a9b1dSJustin T. Gibbs struct cam_path *path; 35858b8a9b1dSJustin T. Gibbs struct cam_ed *device; 35868b8a9b1dSJustin T. Gibbs struct cam_eb *bus; 35878b8a9b1dSJustin T. Gibbs 35888b8a9b1dSJustin T. Gibbs CAM_DEBUG_PRINT(CAM_DEBUG_TRACE, ("xpt_release_ccb\n")); 35898b8a9b1dSJustin T. Gibbs path = free_ccb->ccb_h.path; 35908b8a9b1dSJustin T. Gibbs device = path->device; 35918b8a9b1dSJustin T. Gibbs bus = path->bus; 35928b8a9b1dSJustin T. Gibbs s = splsoftcam(); 35938b8a9b1dSJustin T. Gibbs cam_ccbq_release_opening(&device->ccbq); 35948b8a9b1dSJustin T. Gibbs if (xpt_ccb_count > xpt_max_ccbs) { 35958b8a9b1dSJustin T. Gibbs xpt_free_ccb(free_ccb); 35968b8a9b1dSJustin T. Gibbs xpt_ccb_count--; 35978b8a9b1dSJustin T. Gibbs } else { 35988b8a9b1dSJustin T. Gibbs SLIST_INSERT_HEAD(&ccb_freeq, &free_ccb->ccb_h, xpt_links.sle); 35998b8a9b1dSJustin T. Gibbs } 36008b8a9b1dSJustin T. Gibbs bus->sim->devq->alloc_openings++; 36018b8a9b1dSJustin T. Gibbs bus->sim->devq->alloc_active--; 36028b8a9b1dSJustin T. Gibbs /* XXX Turn this into an inline function - xpt_run_device?? */ 36038b8a9b1dSJustin T. Gibbs if ((device_is_alloc_queued(device) == 0) 36048b8a9b1dSJustin T. Gibbs && (device->drvq.entries > 0)) { 36058b8a9b1dSJustin T. Gibbs xpt_schedule_dev_allocq(bus, device); 36068b8a9b1dSJustin T. Gibbs } 36078b8a9b1dSJustin T. Gibbs splx(s); 36088b8a9b1dSJustin T. Gibbs if (dev_allocq_is_runnable(bus->sim->devq)) 36098b8a9b1dSJustin T. Gibbs xpt_run_dev_allocq(bus); 36108b8a9b1dSJustin T. Gibbs } 36118b8a9b1dSJustin T. Gibbs 36128b8a9b1dSJustin T. Gibbs /* Functions accessed by SIM drivers */ 36138b8a9b1dSJustin T. Gibbs 36148b8a9b1dSJustin T. Gibbs /* 36158b8a9b1dSJustin T. Gibbs * A sim structure, listing the SIM entry points and instance 36168b8a9b1dSJustin T. Gibbs * identification info is passed to xpt_bus_register to hook the SIM 36178b8a9b1dSJustin T. Gibbs * into the CAM framework. xpt_bus_register creates a cam_eb entry 36188b8a9b1dSJustin T. Gibbs * for this new bus and places it in the array of busses and assigns 36198b8a9b1dSJustin T. Gibbs * it a path_id. The path_id may be influenced by "hard wiring" 36208b8a9b1dSJustin T. Gibbs * information specified by the user. Once interrupt services are 36218b8a9b1dSJustin T. Gibbs * availible, the bus will be probed. 36228b8a9b1dSJustin T. Gibbs */ 36238b8a9b1dSJustin T. Gibbs int32_t 36248b8a9b1dSJustin T. Gibbs xpt_bus_register(struct cam_sim *sim, u_int32_t bus) 36258b8a9b1dSJustin T. Gibbs { 36268b8a9b1dSJustin T. Gibbs static path_id_t buscount; 36278b8a9b1dSJustin T. Gibbs struct cam_eb *new_bus; 36288b8a9b1dSJustin T. Gibbs struct ccb_pathinq cpi; 36298b8a9b1dSJustin T. Gibbs int s; 36308b8a9b1dSJustin T. Gibbs 36318b8a9b1dSJustin T. Gibbs sim->bus_id = bus; 36328b8a9b1dSJustin T. Gibbs new_bus = (struct cam_eb *)malloc(sizeof(*new_bus), 36338b8a9b1dSJustin T. Gibbs M_DEVBUF, M_NOWAIT); 36348b8a9b1dSJustin T. Gibbs if (new_bus == NULL) { 36358b8a9b1dSJustin T. Gibbs /* Couldn't satisfy request */ 36368b8a9b1dSJustin T. Gibbs return (CAM_RESRC_UNAVAIL); 36378b8a9b1dSJustin T. Gibbs } 36388b8a9b1dSJustin T. Gibbs 36398b8a9b1dSJustin T. Gibbs bzero(new_bus, sizeof(*new_bus)); 36408b8a9b1dSJustin T. Gibbs 36418b8a9b1dSJustin T. Gibbs if (strcmp(sim->sim_name, "xpt") != 0) { 36428b8a9b1dSJustin T. Gibbs 36438b8a9b1dSJustin T. Gibbs sim->path_id = xptpathid(sim->sim_name, sim->unit_number, 36448b8a9b1dSJustin T. Gibbs sim->bus_id, &buscount); 36458b8a9b1dSJustin T. Gibbs } 36468b8a9b1dSJustin T. Gibbs 36478b8a9b1dSJustin T. Gibbs new_bus->path_id = sim->path_id; 36488b8a9b1dSJustin T. Gibbs new_bus->sim = sim; 36498b8a9b1dSJustin T. Gibbs SLIST_INIT(&new_bus->asyncs); 36508b8a9b1dSJustin T. Gibbs TAILQ_INIT(&new_bus->et_entries); 36518b8a9b1dSJustin T. Gibbs s = splsoftcam(); 36528b8a9b1dSJustin T. Gibbs TAILQ_INSERT_TAIL(&xpt_busses, new_bus, links); 36538b8a9b1dSJustin T. Gibbs bus_generation++; 36548b8a9b1dSJustin T. Gibbs 36558b8a9b1dSJustin T. Gibbs /* Notify interested parties */ 36568b8a9b1dSJustin T. Gibbs if (sim->path_id != CAM_XPT_PATH_ID) { 36578b8a9b1dSJustin T. Gibbs struct cam_path path; 36588b8a9b1dSJustin T. Gibbs 36598b8a9b1dSJustin T. Gibbs xpt_compile_path(&path, /*periph*/NULL, sim->path_id, 36608b8a9b1dSJustin T. Gibbs CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD); 36618b8a9b1dSJustin T. Gibbs xpt_setup_ccb(&cpi.ccb_h, &path, /*priority*/1); 36628b8a9b1dSJustin T. Gibbs cpi.ccb_h.func_code = XPT_PATH_INQ; 36638b8a9b1dSJustin T. Gibbs xpt_action((union ccb *)&cpi); 36648b8a9b1dSJustin T. Gibbs xpt_async(AC_PATH_REGISTERED, xpt_periph->path, &cpi); 36658b8a9b1dSJustin T. Gibbs xpt_release_path(&path); 36668b8a9b1dSJustin T. Gibbs } 36678b8a9b1dSJustin T. Gibbs splx(s); 36688b8a9b1dSJustin T. Gibbs return (CAM_SUCCESS); 36698b8a9b1dSJustin T. Gibbs } 36708b8a9b1dSJustin T. Gibbs 36718b8a9b1dSJustin T. Gibbs static int 36728b8a9b1dSJustin T. Gibbs xptnextfreebus(path_id_t startbus) 36738b8a9b1dSJustin T. Gibbs { 36748b8a9b1dSJustin T. Gibbs struct cam_sim_config *sim_conf; 36758b8a9b1dSJustin T. Gibbs 36768b8a9b1dSJustin T. Gibbs sim_conf = cam_sinit; 36778b8a9b1dSJustin T. Gibbs while (sim_conf->sim_name != NULL) { 36788b8a9b1dSJustin T. Gibbs 36798b8a9b1dSJustin T. Gibbs if (IS_SPECIFIED(sim_conf->pathid) 36808b8a9b1dSJustin T. Gibbs && (startbus == sim_conf->pathid)) { 36818b8a9b1dSJustin T. Gibbs ++startbus; 36828b8a9b1dSJustin T. Gibbs /* Start the search over */ 36838b8a9b1dSJustin T. Gibbs sim_conf = cam_sinit; 36848b8a9b1dSJustin T. Gibbs } else { 36858b8a9b1dSJustin T. Gibbs sim_conf++; 36868b8a9b1dSJustin T. Gibbs } 36878b8a9b1dSJustin T. Gibbs } 36888b8a9b1dSJustin T. Gibbs return (startbus); 36898b8a9b1dSJustin T. Gibbs } 36908b8a9b1dSJustin T. Gibbs 36918b8a9b1dSJustin T. Gibbs static int 36928b8a9b1dSJustin T. Gibbs xptpathid(const char *sim_name, int sim_unit, 36938b8a9b1dSJustin T. Gibbs int sim_bus, path_id_t *nextpath) 36948b8a9b1dSJustin T. Gibbs { 36958b8a9b1dSJustin T. Gibbs struct cam_sim_config *sim_conf; 36968b8a9b1dSJustin T. Gibbs path_id_t pathid; 36978b8a9b1dSJustin T. Gibbs 36988b8a9b1dSJustin T. Gibbs pathid = CAM_XPT_PATH_ID; 36998b8a9b1dSJustin T. Gibbs for (sim_conf = cam_sinit; sim_conf->sim_name != NULL; sim_conf++) { 37008b8a9b1dSJustin T. Gibbs 37018b8a9b1dSJustin T. Gibbs if (!IS_SPECIFIED(sim_conf->pathid)) 37028b8a9b1dSJustin T. Gibbs continue; 37038b8a9b1dSJustin T. Gibbs 37048b8a9b1dSJustin T. Gibbs if (!strcmp(sim_name, sim_conf->sim_name) 37058b8a9b1dSJustin T. Gibbs && (sim_unit == sim_conf->sim_unit)) { 37068b8a9b1dSJustin T. Gibbs 37078b8a9b1dSJustin T. Gibbs if (IS_SPECIFIED(sim_conf->sim_bus)) { 37088b8a9b1dSJustin T. Gibbs if (sim_bus == sim_conf->sim_bus) { 37098b8a9b1dSJustin T. Gibbs pathid = sim_conf->pathid; 37108b8a9b1dSJustin T. Gibbs break; 37118b8a9b1dSJustin T. Gibbs } 37128b8a9b1dSJustin T. Gibbs } else if (sim_bus == 0) { 37138b8a9b1dSJustin T. Gibbs /* Unspecified matches bus 0 */ 37148b8a9b1dSJustin T. Gibbs pathid = sim_conf->pathid; 37158b8a9b1dSJustin T. Gibbs break; 37168b8a9b1dSJustin T. Gibbs } else { 37178b8a9b1dSJustin T. Gibbs printf("Ambiguous scbus configuration for %s%d " 37188b8a9b1dSJustin T. Gibbs "bus %d, cannot wire down. The kernel " 37198b8a9b1dSJustin T. Gibbs "config entry for scbus%d should " 37208b8a9b1dSJustin T. Gibbs "specify a controller bus.\n" 37218b8a9b1dSJustin T. Gibbs "Scbus will be assigned dynamically.\n", 37228b8a9b1dSJustin T. Gibbs sim_name, sim_unit, sim_bus, 37238b8a9b1dSJustin T. Gibbs sim_conf->pathid); 37248b8a9b1dSJustin T. Gibbs break; 37258b8a9b1dSJustin T. Gibbs } 37268b8a9b1dSJustin T. Gibbs } 37278b8a9b1dSJustin T. Gibbs } 37288b8a9b1dSJustin T. Gibbs 37298b8a9b1dSJustin T. Gibbs if (pathid == CAM_XPT_PATH_ID) { 37308b8a9b1dSJustin T. Gibbs pathid = xptnextfreebus(*nextpath); 37318b8a9b1dSJustin T. Gibbs *nextpath = pathid + 1; 37328b8a9b1dSJustin T. Gibbs } 37338b8a9b1dSJustin T. Gibbs return (pathid); 37348b8a9b1dSJustin T. Gibbs } 37358b8a9b1dSJustin T. Gibbs 37368b8a9b1dSJustin T. Gibbs int32_t 37378b8a9b1dSJustin T. Gibbs xpt_bus_deregister(path_id) 37388b8a9b1dSJustin T. Gibbs u_int8_t path_id; 37398b8a9b1dSJustin T. Gibbs { 37408b8a9b1dSJustin T. Gibbs /* XXX */ 37418b8a9b1dSJustin T. Gibbs return (CAM_SUCCESS); 37428b8a9b1dSJustin T. Gibbs } 37438b8a9b1dSJustin T. Gibbs 37448b8a9b1dSJustin T. Gibbs void 37458b8a9b1dSJustin T. Gibbs xpt_async(u_int32_t async_code, struct cam_path *path, void *async_arg) 37468b8a9b1dSJustin T. Gibbs { 37478b8a9b1dSJustin T. Gibbs struct cam_eb *bus; 37488b8a9b1dSJustin T. Gibbs struct cam_et *target, *next_target; 37498b8a9b1dSJustin T. Gibbs struct cam_ed *device, *next_device; 37508b8a9b1dSJustin T. Gibbs int s; 37518b8a9b1dSJustin T. Gibbs 37528b8a9b1dSJustin T. Gibbs CAM_DEBUG(path, CAM_DEBUG_TRACE, ("xpt_async\n")); 37538b8a9b1dSJustin T. Gibbs 37548b8a9b1dSJustin T. Gibbs s = splsoftcam(); 37558b8a9b1dSJustin T. Gibbs 37568b8a9b1dSJustin T. Gibbs bus = path->bus; 37578b8a9b1dSJustin T. Gibbs 37588b8a9b1dSJustin T. Gibbs /* 37598b8a9b1dSJustin T. Gibbs * Freeze the SIM queue for SCSI_DELAY ms to 37608b8a9b1dSJustin T. Gibbs * allow the bus to settle. 37618b8a9b1dSJustin T. Gibbs */ 37628b8a9b1dSJustin T. Gibbs if (async_code == AC_BUS_RESET) { 37638b8a9b1dSJustin T. Gibbs struct cam_sim *sim; 37648b8a9b1dSJustin T. Gibbs 37658b8a9b1dSJustin T. Gibbs sim = bus->sim; 37668b8a9b1dSJustin T. Gibbs 37678b8a9b1dSJustin T. Gibbs /* 37688b8a9b1dSJustin T. Gibbs * If there isn't already another timeout pending, go ahead 37698b8a9b1dSJustin T. Gibbs * and freeze the simq and set the timeout flag. If there 37708b8a9b1dSJustin T. Gibbs * is another timeout pending, replace it with this 37718b8a9b1dSJustin T. Gibbs * timeout. There could be two bus reset async broadcasts 37728b8a9b1dSJustin T. Gibbs * sent for some dual-channel controllers. 37738b8a9b1dSJustin T. Gibbs */ 37748b8a9b1dSJustin T. Gibbs if ((sim->flags & CAM_SIM_REL_TIMEOUT_PENDING) == 0) { 37758b8a9b1dSJustin T. Gibbs xpt_freeze_simq(sim, 1); 37768b8a9b1dSJustin T. Gibbs sim->flags |= CAM_SIM_REL_TIMEOUT_PENDING; 37778b8a9b1dSJustin T. Gibbs } else 37788b8a9b1dSJustin T. Gibbs untimeout(xpt_release_simq_timeout, sim, sim->c_handle); 37798b8a9b1dSJustin T. Gibbs 37808b8a9b1dSJustin T. Gibbs sim->c_handle = timeout(xpt_release_simq_timeout, 37818b8a9b1dSJustin T. Gibbs sim, (SCSI_DELAY * hz) / 1000); 37828b8a9b1dSJustin T. Gibbs } 37838b8a9b1dSJustin T. Gibbs 37848b8a9b1dSJustin T. Gibbs for (target = TAILQ_FIRST(&bus->et_entries); 37858b8a9b1dSJustin T. Gibbs target != NULL; 37868b8a9b1dSJustin T. Gibbs target = next_target) { 37878b8a9b1dSJustin T. Gibbs 37888b8a9b1dSJustin T. Gibbs next_target = TAILQ_NEXT(target, links); 37898b8a9b1dSJustin T. Gibbs 37908b8a9b1dSJustin T. Gibbs if (path->target != target 37918b8a9b1dSJustin T. Gibbs && path->target != NULL) 37928b8a9b1dSJustin T. Gibbs continue; 37938b8a9b1dSJustin T. Gibbs 37948b8a9b1dSJustin T. Gibbs if (async_code == AC_TRANSFER_NEG) { 37958b8a9b1dSJustin T. Gibbs struct ccb_trans_settings *settings; 37968b8a9b1dSJustin T. Gibbs 37978b8a9b1dSJustin T. Gibbs settings = (struct ccb_trans_settings *)async_arg; 37988b8a9b1dSJustin T. Gibbs xpt_set_transfer_settings(settings, 37998b8a9b1dSJustin T. Gibbs /*async_update*/TRUE); 38008b8a9b1dSJustin T. Gibbs } 38018b8a9b1dSJustin T. Gibbs 38028b8a9b1dSJustin T. Gibbs for (device = TAILQ_FIRST(&target->ed_entries); 38038b8a9b1dSJustin T. Gibbs device != NULL; 38048b8a9b1dSJustin T. Gibbs device = next_device) { 38058b8a9b1dSJustin T. Gibbs cam_status status; 38068b8a9b1dSJustin T. Gibbs struct cam_path newpath; 38078b8a9b1dSJustin T. Gibbs 38088b8a9b1dSJustin T. Gibbs next_device = TAILQ_NEXT(device, links); 38098b8a9b1dSJustin T. Gibbs 38108b8a9b1dSJustin T. Gibbs if (path->device != device 38118b8a9b1dSJustin T. Gibbs && path->device != NULL) 38128b8a9b1dSJustin T. Gibbs continue; 38138b8a9b1dSJustin T. Gibbs 38148b8a9b1dSJustin T. Gibbs /* 38158b8a9b1dSJustin T. Gibbs * We'll need this path for either one of these two 38168b8a9b1dSJustin T. Gibbs * async callback codes. Basically, we need to 38178b8a9b1dSJustin T. Gibbs * compile our own path instead of just using the path 38188b8a9b1dSJustin T. Gibbs * the user passes in since the user may well have 38198b8a9b1dSJustin T. Gibbs * passed in a wildcardded path. I'm not really 38208b8a9b1dSJustin T. Gibbs * sure why anyone would want to wildcard a path for 38218b8a9b1dSJustin T. Gibbs * either one of these async callbacks, but we need 38228b8a9b1dSJustin T. Gibbs * to be able to handle it if they do. 38238b8a9b1dSJustin T. Gibbs */ 38248b8a9b1dSJustin T. Gibbs if ((async_code == AC_SENT_BDR) 38258b8a9b1dSJustin T. Gibbs || (async_code == AC_INQ_CHANGED)) 38268b8a9b1dSJustin T. Gibbs status = xpt_compile_path(&newpath, NULL, 38278b8a9b1dSJustin T. Gibbs bus->path_id, 38288b8a9b1dSJustin T. Gibbs target->target_id, 38298b8a9b1dSJustin T. Gibbs device->lun_id); 38308b8a9b1dSJustin T. Gibbs else 38318b8a9b1dSJustin T. Gibbs status = CAM_REQ_CMP; /* silence the compiler */ 38328b8a9b1dSJustin T. Gibbs 38338b8a9b1dSJustin T. Gibbs /* 38348b8a9b1dSJustin T. Gibbs * If we send a BDR, freeze the device queue for 38358b8a9b1dSJustin T. Gibbs * SCSI_DELAY seconds to allow it to settle down. 38368b8a9b1dSJustin T. Gibbs */ 38378b8a9b1dSJustin T. Gibbs if (async_code == AC_SENT_BDR) { 38388b8a9b1dSJustin T. Gibbs if (status == CAM_REQ_CMP) { 38398b8a9b1dSJustin T. Gibbs xpt_freeze_devq(&newpath, 1); 38408b8a9b1dSJustin T. Gibbs /* 38418b8a9b1dSJustin T. Gibbs * Although this looks bad, it 38428b8a9b1dSJustin T. Gibbs * isn't as bad as it seems. We're 38438b8a9b1dSJustin T. Gibbs * passing in a stack-allocated path 38448b8a9b1dSJustin T. Gibbs * that we then immediately release 38458b8a9b1dSJustin T. Gibbs * after scheduling a timeout to 38468b8a9b1dSJustin T. Gibbs * release the device queue. So 38478b8a9b1dSJustin T. Gibbs * the path won't be around when 38488b8a9b1dSJustin T. Gibbs * the timeout fires, right? Right. 38498b8a9b1dSJustin T. Gibbs * But it doesn't matter, since 38508b8a9b1dSJustin T. Gibbs * xpt_release_devq and its timeout 38518b8a9b1dSJustin T. Gibbs * function both take the device as 38528b8a9b1dSJustin T. Gibbs * an argument. Theoretically, the 38538b8a9b1dSJustin T. Gibbs * device will still be there when 38548b8a9b1dSJustin T. Gibbs * the timeout fires, even though 38558b8a9b1dSJustin T. Gibbs * the path will be gone. 38568b8a9b1dSJustin T. Gibbs */ 38578b8a9b1dSJustin T. Gibbs cam_release_devq( 38588b8a9b1dSJustin T. Gibbs &newpath, 38598b8a9b1dSJustin T. Gibbs /*relsim_flags*/ 38608b8a9b1dSJustin T. Gibbs RELSIM_RELEASE_AFTER_TIMEOUT, 38618b8a9b1dSJustin T. Gibbs /*reduction*/0, 38628b8a9b1dSJustin T. Gibbs /*timeout*/SCSI_DELAY, 38638b8a9b1dSJustin T. Gibbs /*getcount_only*/0); 38648b8a9b1dSJustin T. Gibbs xpt_release_path(&newpath); 38658b8a9b1dSJustin T. Gibbs } 38668b8a9b1dSJustin T. Gibbs } else if (async_code == AC_INQ_CHANGED) { 38678b8a9b1dSJustin T. Gibbs /* 38688b8a9b1dSJustin T. Gibbs * We've sent a start unit command, or 38698b8a9b1dSJustin T. Gibbs * something similar to a device that may 38708b8a9b1dSJustin T. Gibbs * have caused its inquiry data to change. 38718b8a9b1dSJustin T. Gibbs * So we re-scan the device to refresh the 38728b8a9b1dSJustin T. Gibbs * inquiry data for it. 38738b8a9b1dSJustin T. Gibbs */ 38748b8a9b1dSJustin T. Gibbs if (status == CAM_REQ_CMP) { 38758b8a9b1dSJustin T. Gibbs xpt_scan_lun(path->periph, &newpath, 38768b8a9b1dSJustin T. Gibbs CAM_EXPECT_INQ_CHANGE, 38778b8a9b1dSJustin T. Gibbs NULL); 38788b8a9b1dSJustin T. Gibbs xpt_release_path(&newpath); 38798b8a9b1dSJustin T. Gibbs } 38808b8a9b1dSJustin T. Gibbs } else if (async_code == AC_LOST_DEVICE) 38818b8a9b1dSJustin T. Gibbs device->flags |= CAM_DEV_UNCONFIGURED; 38828b8a9b1dSJustin T. Gibbs 38838b8a9b1dSJustin T. Gibbs xpt_async_bcast(&device->asyncs, 38848b8a9b1dSJustin T. Gibbs async_code, 38858b8a9b1dSJustin T. Gibbs path, 38868b8a9b1dSJustin T. Gibbs async_arg); 38878b8a9b1dSJustin T. Gibbs } 38888b8a9b1dSJustin T. Gibbs } 38898b8a9b1dSJustin T. Gibbs xpt_async_bcast(&bus->asyncs, async_code, 38908b8a9b1dSJustin T. Gibbs path, async_arg); 38918b8a9b1dSJustin T. Gibbs splx(s); 38928b8a9b1dSJustin T. Gibbs } 38938b8a9b1dSJustin T. Gibbs 38948b8a9b1dSJustin T. Gibbs static void 38958b8a9b1dSJustin T. Gibbs xpt_async_bcast(struct async_list *async_head, 38968b8a9b1dSJustin T. Gibbs u_int32_t async_code, 38978b8a9b1dSJustin T. Gibbs struct cam_path *path, void *async_arg) 38988b8a9b1dSJustin T. Gibbs { 38998b8a9b1dSJustin T. Gibbs struct async_node *cur_entry; 39008b8a9b1dSJustin T. Gibbs 39018b8a9b1dSJustin T. Gibbs cur_entry = SLIST_FIRST(async_head); 39028b8a9b1dSJustin T. Gibbs while (cur_entry != NULL) { 39038b8a9b1dSJustin T. Gibbs struct async_node *next_entry; 39048b8a9b1dSJustin T. Gibbs /* 39058b8a9b1dSJustin T. Gibbs * Grab the next list entry before we call the current 39068b8a9b1dSJustin T. Gibbs * entry's callback. This is because the callback function 39078b8a9b1dSJustin T. Gibbs * can delete its async callback entry. 39088b8a9b1dSJustin T. Gibbs */ 39098b8a9b1dSJustin T. Gibbs next_entry = SLIST_NEXT(cur_entry, links); 39108b8a9b1dSJustin T. Gibbs if ((cur_entry->event_enable & async_code) != 0) 39118b8a9b1dSJustin T. Gibbs cur_entry->callback(cur_entry->callback_arg, 39128b8a9b1dSJustin T. Gibbs async_code, path, 39138b8a9b1dSJustin T. Gibbs async_arg); 39148b8a9b1dSJustin T. Gibbs cur_entry = next_entry; 39158b8a9b1dSJustin T. Gibbs } 39168b8a9b1dSJustin T. Gibbs } 39178b8a9b1dSJustin T. Gibbs 39188b8a9b1dSJustin T. Gibbs u_int32_t 39198b8a9b1dSJustin T. Gibbs xpt_freeze_devq(struct cam_path *path, u_int count) 39208b8a9b1dSJustin T. Gibbs { 39218b8a9b1dSJustin T. Gibbs int s; 39228b8a9b1dSJustin T. Gibbs struct ccb_hdr *ccbh; 39238b8a9b1dSJustin T. Gibbs 39248b8a9b1dSJustin T. Gibbs s = splcam(); 39258b8a9b1dSJustin T. Gibbs path->device->qfrozen_cnt += count; 39268b8a9b1dSJustin T. Gibbs 39278b8a9b1dSJustin T. Gibbs /* 39288b8a9b1dSJustin T. Gibbs * Mark the last CCB in the queue as needing 39298b8a9b1dSJustin T. Gibbs * to be requeued if the driver hasn't 39308b8a9b1dSJustin T. Gibbs * changed it's state yet. This fixes a race 39318b8a9b1dSJustin T. Gibbs * where a ccb is just about to be queued to 39328b8a9b1dSJustin T. Gibbs * a controller driver when it's interrupt routine 39338b8a9b1dSJustin T. Gibbs * freezes the queue. To completly close the 39348b8a9b1dSJustin T. Gibbs * hole, controller drives must check to see 39358b8a9b1dSJustin T. Gibbs * if a ccb's status is still CAM_REQ_INPROG 39368b8a9b1dSJustin T. Gibbs * under spl protection just before they queue 39378b8a9b1dSJustin T. Gibbs * the CCB. See ahc_action/ahc_freeze_devq for 39388b8a9b1dSJustin T. Gibbs * an example. 39398b8a9b1dSJustin T. Gibbs */ 39408b8a9b1dSJustin T. Gibbs ccbh = TAILQ_LAST(&path->device->ccbq.active_ccbs, ccb_hdr_list); 39418b8a9b1dSJustin T. Gibbs if (ccbh && ccbh->status == CAM_REQ_INPROG) 39428b8a9b1dSJustin T. Gibbs ccbh->status = CAM_REQUEUE_REQ; 39438b8a9b1dSJustin T. Gibbs splx(s); 39448b8a9b1dSJustin T. Gibbs return (path->device->qfrozen_cnt); 39458b8a9b1dSJustin T. Gibbs } 39468b8a9b1dSJustin T. Gibbs 39478b8a9b1dSJustin T. Gibbs u_int32_t 39488b8a9b1dSJustin T. Gibbs xpt_freeze_simq(struct cam_sim *sim, u_int count) 39498b8a9b1dSJustin T. Gibbs { 39508b8a9b1dSJustin T. Gibbs sim->devq->send_queue.qfrozen_cnt += count; 39518b8a9b1dSJustin T. Gibbs if (sim->devq->active_dev != NULL) { 39528b8a9b1dSJustin T. Gibbs struct ccb_hdr *ccbh; 39538b8a9b1dSJustin T. Gibbs 39548b8a9b1dSJustin T. Gibbs ccbh = TAILQ_LAST(&sim->devq->active_dev->ccbq.active_ccbs, 39558b8a9b1dSJustin T. Gibbs ccb_hdr_list); 39568b8a9b1dSJustin T. Gibbs if (ccbh && ccbh->status == CAM_REQ_INPROG) 39578b8a9b1dSJustin T. Gibbs ccbh->status = CAM_REQUEUE_REQ; 39588b8a9b1dSJustin T. Gibbs } 39598b8a9b1dSJustin T. Gibbs return (sim->devq->send_queue.qfrozen_cnt); 39608b8a9b1dSJustin T. Gibbs } 39618b8a9b1dSJustin T. Gibbs 39628b8a9b1dSJustin T. Gibbs static void 39638b8a9b1dSJustin T. Gibbs xpt_release_devq_timeout(void *arg) 39648b8a9b1dSJustin T. Gibbs { 39658b8a9b1dSJustin T. Gibbs struct cam_ed *device; 39668b8a9b1dSJustin T. Gibbs 39678b8a9b1dSJustin T. Gibbs device = (struct cam_ed *)arg; 39688b8a9b1dSJustin T. Gibbs 39698b8a9b1dSJustin T. Gibbs xpt_release_devq(device, /*run_queue*/TRUE); 39708b8a9b1dSJustin T. Gibbs } 39718b8a9b1dSJustin T. Gibbs 39728b8a9b1dSJustin T. Gibbs void 39738b8a9b1dSJustin T. Gibbs xpt_release_devq(struct cam_ed *dev, int run_queue) 39748b8a9b1dSJustin T. Gibbs { 39758b8a9b1dSJustin T. Gibbs int rundevq; 39768b8a9b1dSJustin T. Gibbs int s; 39778b8a9b1dSJustin T. Gibbs 39788b8a9b1dSJustin T. Gibbs rundevq = 0; 39798b8a9b1dSJustin T. Gibbs s = splcam(); 39808b8a9b1dSJustin T. Gibbs if (dev->qfrozen_cnt > 0) { 39818b8a9b1dSJustin T. Gibbs 39828b8a9b1dSJustin T. Gibbs dev->qfrozen_cnt--; 39838b8a9b1dSJustin T. Gibbs if (dev->qfrozen_cnt == 0) { 39848b8a9b1dSJustin T. Gibbs 39858b8a9b1dSJustin T. Gibbs /* 39868b8a9b1dSJustin T. Gibbs * No longer need to wait for a successful 39878b8a9b1dSJustin T. Gibbs * command completion. 39888b8a9b1dSJustin T. Gibbs */ 39898b8a9b1dSJustin T. Gibbs dev->flags &= ~CAM_DEV_REL_ON_COMPLETE; 39908b8a9b1dSJustin T. Gibbs 39918b8a9b1dSJustin T. Gibbs /* 39928b8a9b1dSJustin T. Gibbs * Remove any timeouts that might be scheduled 39938b8a9b1dSJustin T. Gibbs * to release this queue. 39948b8a9b1dSJustin T. Gibbs */ 39958b8a9b1dSJustin T. Gibbs if ((dev->flags & CAM_DEV_REL_TIMEOUT_PENDING) != 0) { 39968b8a9b1dSJustin T. Gibbs untimeout(xpt_release_devq_timeout, dev, 39978b8a9b1dSJustin T. Gibbs dev->c_handle); 39988b8a9b1dSJustin T. Gibbs dev->flags &= ~CAM_DEV_REL_TIMEOUT_PENDING; 39998b8a9b1dSJustin T. Gibbs } 40008b8a9b1dSJustin T. Gibbs 40018b8a9b1dSJustin T. Gibbs /* 40028b8a9b1dSJustin T. Gibbs * Now that we are unfrozen schedule the 40038b8a9b1dSJustin T. Gibbs * device so any pending transactions are 40048b8a9b1dSJustin T. Gibbs * run. 40058b8a9b1dSJustin T. Gibbs */ 40068b8a9b1dSJustin T. Gibbs if ((dev->ccbq.queue.entries > 0) 40078b8a9b1dSJustin T. Gibbs && (xpt_schedule_dev_sendq(dev->target->bus, dev)) 40088b8a9b1dSJustin T. Gibbs && (run_queue != 0)) { 40098b8a9b1dSJustin T. Gibbs rundevq = 1; 40108b8a9b1dSJustin T. Gibbs } 40118b8a9b1dSJustin T. Gibbs } 40128b8a9b1dSJustin T. Gibbs } 40138b8a9b1dSJustin T. Gibbs splx(s); 40148b8a9b1dSJustin T. Gibbs if (rundevq != 0) 40158b8a9b1dSJustin T. Gibbs xpt_run_dev_sendq(dev->target->bus); 40168b8a9b1dSJustin T. Gibbs } 40178b8a9b1dSJustin T. Gibbs 40188b8a9b1dSJustin T. Gibbs void 40198b8a9b1dSJustin T. Gibbs xpt_release_simq(struct cam_sim *sim, int run_queue) 40208b8a9b1dSJustin T. Gibbs { 40218b8a9b1dSJustin T. Gibbs int s; 40228b8a9b1dSJustin T. Gibbs struct camq *sendq; 40238b8a9b1dSJustin T. Gibbs 40248b8a9b1dSJustin T. Gibbs sendq = &(sim->devq->send_queue); 40258b8a9b1dSJustin T. Gibbs s = splcam(); 40268b8a9b1dSJustin T. Gibbs if (sendq->qfrozen_cnt > 0) { 40278b8a9b1dSJustin T. Gibbs 40288b8a9b1dSJustin T. Gibbs sendq->qfrozen_cnt--; 40298b8a9b1dSJustin T. Gibbs if (sendq->qfrozen_cnt == 0) { 40308b8a9b1dSJustin T. Gibbs 40318b8a9b1dSJustin T. Gibbs /* 40328b8a9b1dSJustin T. Gibbs * If there is a timeout scheduled to release this 40338b8a9b1dSJustin T. Gibbs * sim queue, remove it. The queue frozen count is 40348b8a9b1dSJustin T. Gibbs * already at 0. 40358b8a9b1dSJustin T. Gibbs */ 40368b8a9b1dSJustin T. Gibbs if ((sim->flags & CAM_SIM_REL_TIMEOUT_PENDING) != 0){ 40378b8a9b1dSJustin T. Gibbs untimeout(xpt_release_simq_timeout, sim, 40388b8a9b1dSJustin T. Gibbs sim->c_handle); 40398b8a9b1dSJustin T. Gibbs sim->flags &= ~CAM_SIM_REL_TIMEOUT_PENDING; 40408b8a9b1dSJustin T. Gibbs } 40418b8a9b1dSJustin T. Gibbs 40428b8a9b1dSJustin T. Gibbs splx(s); 40438b8a9b1dSJustin T. Gibbs 40448b8a9b1dSJustin T. Gibbs if (run_queue) { 40458b8a9b1dSJustin T. Gibbs /* 40468b8a9b1dSJustin T. Gibbs * Now that we are unfrozen run the send queue. 40478b8a9b1dSJustin T. Gibbs */ 40488b8a9b1dSJustin T. Gibbs xpt_run_dev_sendq(xpt_find_bus(sim->path_id)); 40498b8a9b1dSJustin T. Gibbs } 40508b8a9b1dSJustin T. Gibbs } else 40518b8a9b1dSJustin T. Gibbs splx(s); 40528b8a9b1dSJustin T. Gibbs } else 40538b8a9b1dSJustin T. Gibbs splx(s); 40548b8a9b1dSJustin T. Gibbs } 40558b8a9b1dSJustin T. Gibbs 40568b8a9b1dSJustin T. Gibbs static void 40578b8a9b1dSJustin T. Gibbs xpt_release_simq_timeout(void *arg) 40588b8a9b1dSJustin T. Gibbs { 40598b8a9b1dSJustin T. Gibbs struct cam_sim *sim; 40608b8a9b1dSJustin T. Gibbs 40618b8a9b1dSJustin T. Gibbs sim = (struct cam_sim *)arg; 40628b8a9b1dSJustin T. Gibbs xpt_release_simq(sim, /* run_queue */ TRUE); 40638b8a9b1dSJustin T. Gibbs } 40648b8a9b1dSJustin T. Gibbs 40658b8a9b1dSJustin T. Gibbs void 40668b8a9b1dSJustin T. Gibbs xpt_done(union ccb *done_ccb) 40678b8a9b1dSJustin T. Gibbs { 40688b8a9b1dSJustin T. Gibbs int s; 40698b8a9b1dSJustin T. Gibbs 40708b8a9b1dSJustin T. Gibbs s = splcam(); 40718b8a9b1dSJustin T. Gibbs 40728b8a9b1dSJustin T. Gibbs CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_TRACE, ("xpt_done\n")); 40738b8a9b1dSJustin T. Gibbs switch (done_ccb->ccb_h.func_code) { 40748b8a9b1dSJustin T. Gibbs case XPT_SCSI_IO: 40758b8a9b1dSJustin T. Gibbs case XPT_ENG_EXEC: 40768b8a9b1dSJustin T. Gibbs case XPT_TARGET_IO: 40778b8a9b1dSJustin T. Gibbs case XPT_ACCEPT_TARGET_IO: 40788b8a9b1dSJustin T. Gibbs case XPT_CONT_TARGET_IO: 40798b8a9b1dSJustin T. Gibbs case XPT_SCAN_BUS: 40808b8a9b1dSJustin T. Gibbs case XPT_SCAN_LUN: 40818b8a9b1dSJustin T. Gibbs { 40828b8a9b1dSJustin T. Gibbs /* 40838b8a9b1dSJustin T. Gibbs * Queue up the request for handling by our SWI handler 40848b8a9b1dSJustin T. Gibbs * any of the "non-immediate" type of ccbs. 40858b8a9b1dSJustin T. Gibbs */ 40868b8a9b1dSJustin T. Gibbs switch (done_ccb->ccb_h.path->periph->type) { 40878b8a9b1dSJustin T. Gibbs case CAM_PERIPH_BIO: 40888b8a9b1dSJustin T. Gibbs TAILQ_INSERT_TAIL(&cam_bioq, &done_ccb->ccb_h, 40898b8a9b1dSJustin T. Gibbs sim_links.tqe); 40908b8a9b1dSJustin T. Gibbs done_ccb->ccb_h.pinfo.index = CAM_DONEQ_INDEX; 40918b8a9b1dSJustin T. Gibbs setsoftcambio(); 40928b8a9b1dSJustin T. Gibbs break; 40938b8a9b1dSJustin T. Gibbs case CAM_PERIPH_NET: 40948b8a9b1dSJustin T. Gibbs TAILQ_INSERT_TAIL(&cam_netq, &done_ccb->ccb_h, 40958b8a9b1dSJustin T. Gibbs sim_links.tqe); 40968b8a9b1dSJustin T. Gibbs done_ccb->ccb_h.pinfo.index = CAM_DONEQ_INDEX; 40978b8a9b1dSJustin T. Gibbs setsoftcamnet(); 40988b8a9b1dSJustin T. Gibbs break; 40998b8a9b1dSJustin T. Gibbs } 41008b8a9b1dSJustin T. Gibbs break; 41018b8a9b1dSJustin T. Gibbs } 41028b8a9b1dSJustin T. Gibbs default: 41038b8a9b1dSJustin T. Gibbs break; 41048b8a9b1dSJustin T. Gibbs } 41058b8a9b1dSJustin T. Gibbs splx(s); 41068b8a9b1dSJustin T. Gibbs } 41078b8a9b1dSJustin T. Gibbs 41088b8a9b1dSJustin T. Gibbs union ccb * 41098b8a9b1dSJustin T. Gibbs xpt_alloc_ccb() 41108b8a9b1dSJustin T. Gibbs { 41118b8a9b1dSJustin T. Gibbs union ccb *new_ccb; 41128b8a9b1dSJustin T. Gibbs 41138b8a9b1dSJustin T. Gibbs new_ccb = malloc(sizeof(*new_ccb), M_DEVBUF, M_WAITOK); 41148b8a9b1dSJustin T. Gibbs return (new_ccb); 41158b8a9b1dSJustin T. Gibbs } 41168b8a9b1dSJustin T. Gibbs 41178b8a9b1dSJustin T. Gibbs void 41188b8a9b1dSJustin T. Gibbs xpt_free_ccb(union ccb *free_ccb) 41198b8a9b1dSJustin T. Gibbs { 41208b8a9b1dSJustin T. Gibbs free(free_ccb, M_DEVBUF); 41218b8a9b1dSJustin T. Gibbs } 41228b8a9b1dSJustin T. Gibbs 41238b8a9b1dSJustin T. Gibbs 41248b8a9b1dSJustin T. Gibbs 41258b8a9b1dSJustin T. Gibbs /* Private XPT functions */ 41268b8a9b1dSJustin T. Gibbs 41278b8a9b1dSJustin T. Gibbs /* 41288b8a9b1dSJustin T. Gibbs * Get a CAM control block for the caller. Charge the structure to the device 41298b8a9b1dSJustin T. Gibbs * referenced by the path. If the this device has no 'credits' then the 41308b8a9b1dSJustin T. Gibbs * device already has the maximum number of outstanding operations under way 41318b8a9b1dSJustin T. Gibbs * and we return NULL. If we don't have sufficient resources to allocate more 41328b8a9b1dSJustin T. Gibbs * ccbs, we also return NULL. 41338b8a9b1dSJustin T. Gibbs */ 41348b8a9b1dSJustin T. Gibbs static union ccb * 41358b8a9b1dSJustin T. Gibbs xpt_get_ccb(struct cam_ed *device) 41368b8a9b1dSJustin T. Gibbs { 41378b8a9b1dSJustin T. Gibbs union ccb *new_ccb; 41388b8a9b1dSJustin T. Gibbs int s; 41398b8a9b1dSJustin T. Gibbs 41408b8a9b1dSJustin T. Gibbs s = splsoftcam(); 41418b8a9b1dSJustin T. Gibbs if ((new_ccb = (union ccb *)ccb_freeq.slh_first) == NULL) { 41428b8a9b1dSJustin T. Gibbs new_ccb = malloc(sizeof(*new_ccb), M_DEVBUF, M_NOWAIT); 41438b8a9b1dSJustin T. Gibbs if (new_ccb == NULL) { 41448b8a9b1dSJustin T. Gibbs splx(s); 41458b8a9b1dSJustin T. Gibbs return (NULL); 41468b8a9b1dSJustin T. Gibbs } 41478b8a9b1dSJustin T. Gibbs callout_handle_init(&new_ccb->ccb_h.timeout_ch); 41488b8a9b1dSJustin T. Gibbs SLIST_INSERT_HEAD(&ccb_freeq, &new_ccb->ccb_h, 41498b8a9b1dSJustin T. Gibbs xpt_links.sle); 41508b8a9b1dSJustin T. Gibbs xpt_ccb_count++; 41518b8a9b1dSJustin T. Gibbs } 41528b8a9b1dSJustin T. Gibbs cam_ccbq_take_opening(&device->ccbq); 41538b8a9b1dSJustin T. Gibbs SLIST_REMOVE_HEAD(&ccb_freeq, xpt_links.sle); 41548b8a9b1dSJustin T. Gibbs splx(s); 41558b8a9b1dSJustin T. Gibbs return (new_ccb); 41568b8a9b1dSJustin T. Gibbs } 41578b8a9b1dSJustin T. Gibbs 41588b8a9b1dSJustin T. Gibbs 41598b8a9b1dSJustin T. Gibbs static struct cam_et * 41608b8a9b1dSJustin T. Gibbs xpt_alloc_target(struct cam_eb *bus, target_id_t target_id) 41618b8a9b1dSJustin T. Gibbs { 41628b8a9b1dSJustin T. Gibbs struct cam_et *target; 41638b8a9b1dSJustin T. Gibbs 41648b8a9b1dSJustin T. Gibbs target = (struct cam_et *)malloc(sizeof(*target), M_DEVBUF, M_NOWAIT); 41658b8a9b1dSJustin T. Gibbs if (target != NULL) { 41668b8a9b1dSJustin T. Gibbs struct cam_et *cur_target; 41678b8a9b1dSJustin T. Gibbs 41688b8a9b1dSJustin T. Gibbs target->bus = bus; 41698b8a9b1dSJustin T. Gibbs target->target_id = target_id; 41708b8a9b1dSJustin T. Gibbs target->refcount = 1; 41718b8a9b1dSJustin T. Gibbs TAILQ_INIT(&target->ed_entries); 41728b8a9b1dSJustin T. Gibbs 41738b8a9b1dSJustin T. Gibbs /* Insertion sort into our bus's target list */ 41748b8a9b1dSJustin T. Gibbs cur_target = TAILQ_FIRST(&bus->et_entries); 41758b8a9b1dSJustin T. Gibbs while (cur_target != NULL && cur_target->target_id < target_id) 41768b8a9b1dSJustin T. Gibbs cur_target = TAILQ_NEXT(cur_target, links); 41778b8a9b1dSJustin T. Gibbs 41788b8a9b1dSJustin T. Gibbs if (cur_target != NULL) { 41798b8a9b1dSJustin T. Gibbs TAILQ_INSERT_BEFORE(cur_target, target, links); 41808b8a9b1dSJustin T. Gibbs } else { 41818b8a9b1dSJustin T. Gibbs TAILQ_INSERT_TAIL(&bus->et_entries, target, links); 41828b8a9b1dSJustin T. Gibbs bus->generation++; 41838b8a9b1dSJustin T. Gibbs } 41848b8a9b1dSJustin T. Gibbs } 41858b8a9b1dSJustin T. Gibbs return (target); 41868b8a9b1dSJustin T. Gibbs } 41878b8a9b1dSJustin T. Gibbs 41888b8a9b1dSJustin T. Gibbs void 41898b8a9b1dSJustin T. Gibbs xpt_release_target(struct cam_eb *bus, struct cam_et *target) 41908b8a9b1dSJustin T. Gibbs { 41918b8a9b1dSJustin T. Gibbs if ((--target->refcount == 0) 41928b8a9b1dSJustin T. Gibbs && (TAILQ_FIRST(&target->ed_entries) == NULL)) { 41938b8a9b1dSJustin T. Gibbs TAILQ_REMOVE(&bus->et_entries, target, links); 41948b8a9b1dSJustin T. Gibbs bus->generation++; 41958b8a9b1dSJustin T. Gibbs free(target, M_DEVBUF); 41968b8a9b1dSJustin T. Gibbs } 41978b8a9b1dSJustin T. Gibbs } 41988b8a9b1dSJustin T. Gibbs 41998b8a9b1dSJustin T. Gibbs static struct cam_ed * 42008b8a9b1dSJustin T. Gibbs xpt_alloc_device(struct cam_eb *bus, struct cam_et *target, lun_id_t lun_id) 42018b8a9b1dSJustin T. Gibbs { 42028b8a9b1dSJustin T. Gibbs struct cam_ed *device; 42038b8a9b1dSJustin T. Gibbs struct cam_devq *devq; 42048b8a9b1dSJustin T. Gibbs int32_t status; 42058b8a9b1dSJustin T. Gibbs int s; 42068b8a9b1dSJustin T. Gibbs 42078b8a9b1dSJustin T. Gibbs s = splsoftcam(); 42088b8a9b1dSJustin T. Gibbs /* Make space for us in the device queue on our bus */ 42098b8a9b1dSJustin T. Gibbs devq = bus->sim->devq; 42108b8a9b1dSJustin T. Gibbs status = cam_devq_resize(devq, devq->alloc_queue.array_size + 1); 42118b8a9b1dSJustin T. Gibbs splx(s); 42128b8a9b1dSJustin T. Gibbs 42138b8a9b1dSJustin T. Gibbs if (status != CAM_REQ_CMP) { 42148b8a9b1dSJustin T. Gibbs device = NULL; 42158b8a9b1dSJustin T. Gibbs } else { 42168b8a9b1dSJustin T. Gibbs device = (struct cam_ed *)malloc(sizeof(*device), 42178b8a9b1dSJustin T. Gibbs M_DEVBUF, M_NOWAIT); 42188b8a9b1dSJustin T. Gibbs } 42198b8a9b1dSJustin T. Gibbs 42208b8a9b1dSJustin T. Gibbs if (device != NULL) { 42218b8a9b1dSJustin T. Gibbs struct cam_ed *cur_device; 42228b8a9b1dSJustin T. Gibbs 42238b8a9b1dSJustin T. Gibbs bzero(device, sizeof(*device)); 42248b8a9b1dSJustin T. Gibbs 42258b8a9b1dSJustin T. Gibbs SLIST_INIT(&device->asyncs); 42268b8a9b1dSJustin T. Gibbs SLIST_INIT(&device->periphs); 42278b8a9b1dSJustin T. Gibbs callout_handle_init(&device->c_handle); 42288b8a9b1dSJustin T. Gibbs device->refcount = 1; 42298b8a9b1dSJustin T. Gibbs device->flags |= CAM_DEV_UNCONFIGURED; 42308b8a9b1dSJustin T. Gibbs 42318b8a9b1dSJustin T. Gibbs cam_init_pinfo(&device->alloc_ccb_entry.pinfo); 42328b8a9b1dSJustin T. Gibbs device->alloc_ccb_entry.device = device; 42338b8a9b1dSJustin T. Gibbs cam_init_pinfo(&device->send_ccb_entry.pinfo); 42348b8a9b1dSJustin T. Gibbs device->send_ccb_entry.device = device; 42358b8a9b1dSJustin T. Gibbs 42368b8a9b1dSJustin T. Gibbs device->target = target; 42378b8a9b1dSJustin T. Gibbs 42388b8a9b1dSJustin T. Gibbs device->lun_id = lun_id; 42398b8a9b1dSJustin T. Gibbs 42408b8a9b1dSJustin T. Gibbs /* Initialize our queues */ 42418b8a9b1dSJustin T. Gibbs if (camq_init(&device->drvq, 0) != 0) { 42428b8a9b1dSJustin T. Gibbs free(device, M_DEVBUF); 42438b8a9b1dSJustin T. Gibbs return (NULL); 42448b8a9b1dSJustin T. Gibbs } 42458b8a9b1dSJustin T. Gibbs 42468b8a9b1dSJustin T. Gibbs if (cam_ccbq_init(&device->ccbq, 42478b8a9b1dSJustin T. Gibbs bus->sim->max_dev_openings) != 0) { 42488b8a9b1dSJustin T. Gibbs camq_fini(&device->drvq); 42498b8a9b1dSJustin T. Gibbs free(device, M_DEVBUF); 42508b8a9b1dSJustin T. Gibbs return (NULL); 42518b8a9b1dSJustin T. Gibbs } 42528b8a9b1dSJustin T. Gibbs s = splsoftcam(); 42538b8a9b1dSJustin T. Gibbs /* 42548b8a9b1dSJustin T. Gibbs * XXX should be limited by number of CCBs this bus can 42558b8a9b1dSJustin T. Gibbs * do. 42568b8a9b1dSJustin T. Gibbs */ 42578b8a9b1dSJustin T. Gibbs xpt_max_ccbs += device->ccbq.devq_openings; 42588b8a9b1dSJustin T. Gibbs /* Insertion sort into our target's device list */ 42598b8a9b1dSJustin T. Gibbs cur_device = TAILQ_FIRST(&target->ed_entries); 42608b8a9b1dSJustin T. Gibbs while (cur_device != NULL && cur_device->lun_id < lun_id) 42618b8a9b1dSJustin T. Gibbs cur_device = TAILQ_NEXT(cur_device, links); 42628b8a9b1dSJustin T. Gibbs if (cur_device != NULL) { 42638b8a9b1dSJustin T. Gibbs TAILQ_INSERT_BEFORE(cur_device, device, links); 42648b8a9b1dSJustin T. Gibbs } else { 42658b8a9b1dSJustin T. Gibbs TAILQ_INSERT_TAIL(&target->ed_entries, device, links); 42668b8a9b1dSJustin T. Gibbs target->generation++; 42678b8a9b1dSJustin T. Gibbs } 42688b8a9b1dSJustin T. Gibbs splx(s); 42698b8a9b1dSJustin T. Gibbs } 42708b8a9b1dSJustin T. Gibbs return (device); 42718b8a9b1dSJustin T. Gibbs } 42728b8a9b1dSJustin T. Gibbs 42738b8a9b1dSJustin T. Gibbs static void 42748b8a9b1dSJustin T. Gibbs xpt_release_device(struct cam_eb *bus, struct cam_et *target, 42758b8a9b1dSJustin T. Gibbs struct cam_ed *device) 42768b8a9b1dSJustin T. Gibbs { 42778b8a9b1dSJustin T. Gibbs int s; 42788b8a9b1dSJustin T. Gibbs 42798b8a9b1dSJustin T. Gibbs if ((--device->refcount == 0) 42808b8a9b1dSJustin T. Gibbs && ((device->flags & CAM_DEV_UNCONFIGURED) != 0)) { 42818b8a9b1dSJustin T. Gibbs struct cam_devq *devq; 42828b8a9b1dSJustin T. Gibbs 42838b8a9b1dSJustin T. Gibbs s = splsoftcam(); 42848b8a9b1dSJustin T. Gibbs TAILQ_REMOVE(&target->ed_entries, device,links); 42858b8a9b1dSJustin T. Gibbs target->generation++; 42868b8a9b1dSJustin T. Gibbs xpt_max_ccbs -= device->ccbq.devq_openings; 42878b8a9b1dSJustin T. Gibbs free(device, M_DEVBUF); 42888b8a9b1dSJustin T. Gibbs /* Release our slot in the devq */ 42898b8a9b1dSJustin T. Gibbs devq = bus->sim->devq; 42908b8a9b1dSJustin T. Gibbs cam_devq_resize(devq, devq->alloc_queue.array_size - 1); 42918b8a9b1dSJustin T. Gibbs splx(s); 42928b8a9b1dSJustin T. Gibbs } 42938b8a9b1dSJustin T. Gibbs } 42948b8a9b1dSJustin T. Gibbs 42958b8a9b1dSJustin T. Gibbs static u_int32_t 42968b8a9b1dSJustin T. Gibbs xpt_dev_ccbq_resize(struct cam_path *path, int newopenings) 42978b8a9b1dSJustin T. Gibbs { 42988b8a9b1dSJustin T. Gibbs int s; 42998b8a9b1dSJustin T. Gibbs int diff; 43008b8a9b1dSJustin T. Gibbs int result; 43018b8a9b1dSJustin T. Gibbs struct cam_ed *dev; 43028b8a9b1dSJustin T. Gibbs 43038b8a9b1dSJustin T. Gibbs dev = path->device; 43048b8a9b1dSJustin T. Gibbs s = splsoftcam(); 43058b8a9b1dSJustin T. Gibbs 43068b8a9b1dSJustin T. Gibbs diff = newopenings - (dev->ccbq.dev_active + dev->ccbq.dev_openings); 43078b8a9b1dSJustin T. Gibbs result = cam_ccbq_resize(&dev->ccbq, newopenings); 43088b8a9b1dSJustin T. Gibbs if (result == CAM_REQ_CMP && (diff < 0)) { 43098b8a9b1dSJustin T. Gibbs dev->flags |= CAM_DEV_RESIZE_QUEUE_NEEDED; 43108b8a9b1dSJustin T. Gibbs } 43118b8a9b1dSJustin T. Gibbs /* Adjust the global limit */ 43128b8a9b1dSJustin T. Gibbs xpt_max_ccbs += diff; 43138b8a9b1dSJustin T. Gibbs splx(s); 43148b8a9b1dSJustin T. Gibbs return (result); 43158b8a9b1dSJustin T. Gibbs } 43168b8a9b1dSJustin T. Gibbs 43178b8a9b1dSJustin T. Gibbs static struct cam_eb * 43188b8a9b1dSJustin T. Gibbs xpt_find_bus(path_id_t path_id) 43198b8a9b1dSJustin T. Gibbs { 43208b8a9b1dSJustin T. Gibbs struct cam_eb *bus; 43218b8a9b1dSJustin T. Gibbs 43228b8a9b1dSJustin T. Gibbs for (bus = TAILQ_FIRST(&xpt_busses); 43238b8a9b1dSJustin T. Gibbs bus != NULL; 43248b8a9b1dSJustin T. Gibbs bus = TAILQ_NEXT(bus, links)) { 43258b8a9b1dSJustin T. Gibbs if (bus->path_id == path_id) 43268b8a9b1dSJustin T. Gibbs break; 43278b8a9b1dSJustin T. Gibbs } 43288b8a9b1dSJustin T. Gibbs return (bus); 43298b8a9b1dSJustin T. Gibbs } 43308b8a9b1dSJustin T. Gibbs 43318b8a9b1dSJustin T. Gibbs static struct cam_et * 43328b8a9b1dSJustin T. Gibbs xpt_find_target(struct cam_eb *bus, target_id_t target_id) 43338b8a9b1dSJustin T. Gibbs { 43348b8a9b1dSJustin T. Gibbs struct cam_et *target; 43358b8a9b1dSJustin T. Gibbs 43368b8a9b1dSJustin T. Gibbs for (target = TAILQ_FIRST(&bus->et_entries); 43378b8a9b1dSJustin T. Gibbs target != NULL; 43388b8a9b1dSJustin T. Gibbs target = TAILQ_NEXT(target, links)) { 43398b8a9b1dSJustin T. Gibbs if (target->target_id == target_id) { 43408b8a9b1dSJustin T. Gibbs target->refcount++; 43418b8a9b1dSJustin T. Gibbs break; 43428b8a9b1dSJustin T. Gibbs } 43438b8a9b1dSJustin T. Gibbs } 43448b8a9b1dSJustin T. Gibbs return (target); 43458b8a9b1dSJustin T. Gibbs } 43468b8a9b1dSJustin T. Gibbs 43478b8a9b1dSJustin T. Gibbs static struct cam_ed * 43488b8a9b1dSJustin T. Gibbs xpt_find_device(struct cam_et *target, lun_id_t lun_id) 43498b8a9b1dSJustin T. Gibbs { 43508b8a9b1dSJustin T. Gibbs struct cam_ed *device; 43518b8a9b1dSJustin T. Gibbs 43528b8a9b1dSJustin T. Gibbs for (device = TAILQ_FIRST(&target->ed_entries); 43538b8a9b1dSJustin T. Gibbs device != NULL; 43548b8a9b1dSJustin T. Gibbs device = TAILQ_NEXT(device, links)) { 43558b8a9b1dSJustin T. Gibbs if (device->lun_id == lun_id) { 43568b8a9b1dSJustin T. Gibbs device->refcount++; 43578b8a9b1dSJustin T. Gibbs break; 43588b8a9b1dSJustin T. Gibbs } 43598b8a9b1dSJustin T. Gibbs } 43608b8a9b1dSJustin T. Gibbs return (device); 43618b8a9b1dSJustin T. Gibbs } 43628b8a9b1dSJustin T. Gibbs 43638b8a9b1dSJustin T. Gibbs typedef struct { 43648b8a9b1dSJustin T. Gibbs union ccb *request_ccb; 43658b8a9b1dSJustin T. Gibbs struct ccb_pathinq *cpi; 43668b8a9b1dSJustin T. Gibbs int pending_count; 43678b8a9b1dSJustin T. Gibbs } xpt_scan_bus_info; 43688b8a9b1dSJustin T. Gibbs 43698b8a9b1dSJustin T. Gibbs /* 43708b8a9b1dSJustin T. Gibbs * To start a scan, request_ccb is an XPT_SCAN_BUS ccb. 43718b8a9b1dSJustin T. Gibbs * As the scan progresses, xpt_scan_bus is used as the 43728b8a9b1dSJustin T. Gibbs * callback on completion function. 43738b8a9b1dSJustin T. Gibbs */ 43748b8a9b1dSJustin T. Gibbs static void 43758b8a9b1dSJustin T. Gibbs xpt_scan_bus(struct cam_periph *periph, union ccb *request_ccb) 43768b8a9b1dSJustin T. Gibbs { 43778b8a9b1dSJustin T. Gibbs CAM_DEBUG(request_ccb->ccb_h.path, CAM_DEBUG_TRACE, 43788b8a9b1dSJustin T. Gibbs ("xpt_scan_bus\n")); 43798b8a9b1dSJustin T. Gibbs switch (request_ccb->ccb_h.func_code) { 43808b8a9b1dSJustin T. Gibbs case XPT_SCAN_BUS: 43818b8a9b1dSJustin T. Gibbs { 43828b8a9b1dSJustin T. Gibbs xpt_scan_bus_info *scan_info; 43838b8a9b1dSJustin T. Gibbs union ccb *work_ccb; 43848b8a9b1dSJustin T. Gibbs struct cam_path *path; 43858b8a9b1dSJustin T. Gibbs u_int i; 43868b8a9b1dSJustin T. Gibbs u_int max_target; 43878b8a9b1dSJustin T. Gibbs u_int initiator_id; 43888b8a9b1dSJustin T. Gibbs 43898b8a9b1dSJustin T. Gibbs /* Find out the characteristics of the bus */ 43908b8a9b1dSJustin T. Gibbs work_ccb = xpt_alloc_ccb(); 43918b8a9b1dSJustin T. Gibbs xpt_setup_ccb(&work_ccb->ccb_h, request_ccb->ccb_h.path, 43928b8a9b1dSJustin T. Gibbs request_ccb->ccb_h.pinfo.priority); 43938b8a9b1dSJustin T. Gibbs work_ccb->ccb_h.func_code = XPT_PATH_INQ; 43948b8a9b1dSJustin T. Gibbs xpt_action(work_ccb); 43958b8a9b1dSJustin T. Gibbs if (work_ccb->ccb_h.status != CAM_REQ_CMP) { 43968b8a9b1dSJustin T. Gibbs request_ccb->ccb_h.status = work_ccb->ccb_h.status; 43978b8a9b1dSJustin T. Gibbs xpt_free_ccb(work_ccb); 43988b8a9b1dSJustin T. Gibbs xpt_done(request_ccb); 43998b8a9b1dSJustin T. Gibbs return; 44008b8a9b1dSJustin T. Gibbs } 44018b8a9b1dSJustin T. Gibbs 44028b8a9b1dSJustin T. Gibbs /* Save some state for use while we probe for devices */ 44038b8a9b1dSJustin T. Gibbs scan_info = (xpt_scan_bus_info *) 44048b8a9b1dSJustin T. Gibbs malloc(sizeof(xpt_scan_bus_info), M_TEMP, M_WAITOK); 44058b8a9b1dSJustin T. Gibbs scan_info->request_ccb = request_ccb; 44068b8a9b1dSJustin T. Gibbs scan_info->cpi = &work_ccb->cpi; 44078b8a9b1dSJustin T. Gibbs 44088b8a9b1dSJustin T. Gibbs /* Cache on our stack so we can work asynchronously */ 44098b8a9b1dSJustin T. Gibbs max_target = scan_info->cpi->max_target; 44108b8a9b1dSJustin T. Gibbs initiator_id = scan_info->cpi->initiator_id; 44118b8a9b1dSJustin T. Gibbs 44128b8a9b1dSJustin T. Gibbs /* 44138b8a9b1dSJustin T. Gibbs * Don't count the initiator if the 44148b8a9b1dSJustin T. Gibbs * initiator is addressable. 44158b8a9b1dSJustin T. Gibbs */ 44168b8a9b1dSJustin T. Gibbs scan_info->pending_count = max_target + 1; 44178b8a9b1dSJustin T. Gibbs if (initiator_id <= max_target) 44188b8a9b1dSJustin T. Gibbs scan_info->pending_count--; 44198b8a9b1dSJustin T. Gibbs 44208b8a9b1dSJustin T. Gibbs for (i = 0; i <= max_target; i++) { 44218b8a9b1dSJustin T. Gibbs cam_status status; 44228b8a9b1dSJustin T. Gibbs if (i == initiator_id) 44238b8a9b1dSJustin T. Gibbs continue; 44248b8a9b1dSJustin T. Gibbs 44258b8a9b1dSJustin T. Gibbs status = xpt_create_path(&path, xpt_periph, 44268b8a9b1dSJustin T. Gibbs request_ccb->ccb_h.path_id, 44278b8a9b1dSJustin T. Gibbs i, 0); 44288b8a9b1dSJustin T. Gibbs if (status != CAM_REQ_CMP) { 44298b8a9b1dSJustin T. Gibbs printf("xpt_scan_bus: xpt_create_path failed" 44308b8a9b1dSJustin T. Gibbs " with status %#x, bus scan halted\n", 44318b8a9b1dSJustin T. Gibbs status); 44328b8a9b1dSJustin T. Gibbs break; 44338b8a9b1dSJustin T. Gibbs } 44348b8a9b1dSJustin T. Gibbs work_ccb = xpt_alloc_ccb(); 44358b8a9b1dSJustin T. Gibbs xpt_setup_ccb(&work_ccb->ccb_h, path, 44368b8a9b1dSJustin T. Gibbs request_ccb->ccb_h.pinfo.priority); 44378b8a9b1dSJustin T. Gibbs work_ccb->ccb_h.func_code = XPT_SCAN_LUN; 44388b8a9b1dSJustin T. Gibbs work_ccb->ccb_h.cbfcnp = xpt_scan_bus; 44398b8a9b1dSJustin T. Gibbs work_ccb->ccb_h.ppriv_ptr0 = scan_info; 44408b8a9b1dSJustin T. Gibbs work_ccb->crcn.flags = request_ccb->crcn.flags; 44418b8a9b1dSJustin T. Gibbs #if 0 44428b8a9b1dSJustin T. Gibbs printf("xpt_scan_bus: probing %d:%d:%d\n", 44438b8a9b1dSJustin T. Gibbs request_ccb->ccb_h.path_id, i, 0); 44448b8a9b1dSJustin T. Gibbs #endif 44458b8a9b1dSJustin T. Gibbs xpt_action(work_ccb); 44468b8a9b1dSJustin T. Gibbs } 44478b8a9b1dSJustin T. Gibbs break; 44488b8a9b1dSJustin T. Gibbs } 44498b8a9b1dSJustin T. Gibbs case XPT_SCAN_LUN: 44508b8a9b1dSJustin T. Gibbs { 44518b8a9b1dSJustin T. Gibbs xpt_scan_bus_info *scan_info; 44528b8a9b1dSJustin T. Gibbs path_id_t path_id; 44538b8a9b1dSJustin T. Gibbs target_id_t target_id; 44548b8a9b1dSJustin T. Gibbs lun_id_t lun_id; 44558b8a9b1dSJustin T. Gibbs 44568b8a9b1dSJustin T. Gibbs /* Reuse the same CCB to query if a device was really found */ 44578b8a9b1dSJustin T. Gibbs scan_info = (xpt_scan_bus_info *)request_ccb->ccb_h.ppriv_ptr0; 44588b8a9b1dSJustin T. Gibbs xpt_setup_ccb(&request_ccb->ccb_h, request_ccb->ccb_h.path, 44598b8a9b1dSJustin T. Gibbs request_ccb->ccb_h.pinfo.priority); 44608b8a9b1dSJustin T. Gibbs request_ccb->ccb_h.func_code = XPT_GDEV_TYPE; 44618b8a9b1dSJustin T. Gibbs 44628b8a9b1dSJustin T. Gibbs path_id = request_ccb->ccb_h.path_id; 44638b8a9b1dSJustin T. Gibbs target_id = request_ccb->ccb_h.target_id; 44648b8a9b1dSJustin T. Gibbs lun_id = request_ccb->ccb_h.target_lun; 44658b8a9b1dSJustin T. Gibbs xpt_action(request_ccb); 44668b8a9b1dSJustin T. Gibbs 44678b8a9b1dSJustin T. Gibbs #if 0 44688b8a9b1dSJustin T. Gibbs printf("xpt_scan_bus: got back probe from %d:%d:%d\n", 44698b8a9b1dSJustin T. Gibbs path_id, target_id, lun_id); 44708b8a9b1dSJustin T. Gibbs #endif 44718b8a9b1dSJustin T. Gibbs 44728b8a9b1dSJustin T. Gibbs if (request_ccb->ccb_h.status != CAM_REQ_CMP) { 44738b8a9b1dSJustin T. Gibbs struct cam_ed *device; 44748b8a9b1dSJustin T. Gibbs struct cam_et *target; 44758b8a9b1dSJustin T. Gibbs 44768b8a9b1dSJustin T. Gibbs /* 44778b8a9b1dSJustin T. Gibbs * If we already probed lun 0 successfully, or 44788b8a9b1dSJustin T. Gibbs * we have additional configured luns on this 44798b8a9b1dSJustin T. Gibbs * target that might have "gone away", go onto 44808b8a9b1dSJustin T. Gibbs * the next lun. 44818b8a9b1dSJustin T. Gibbs */ 44828b8a9b1dSJustin T. Gibbs target = request_ccb->ccb_h.path->target; 44838b8a9b1dSJustin T. Gibbs device = TAILQ_FIRST(&target->ed_entries); 44848b8a9b1dSJustin T. Gibbs if (device != NULL) 44858b8a9b1dSJustin T. Gibbs device = TAILQ_NEXT(device, links); 44868b8a9b1dSJustin T. Gibbs 44878b8a9b1dSJustin T. Gibbs if ((lun_id != 0) || (device != NULL)) { 44888b8a9b1dSJustin T. Gibbs /* Try the next lun */ 44898b8a9b1dSJustin T. Gibbs lun_id++; 44908b8a9b1dSJustin T. Gibbs } 44918b8a9b1dSJustin T. Gibbs } else { 44928b8a9b1dSJustin T. Gibbs struct cam_ed *device; 44938b8a9b1dSJustin T. Gibbs 44948b8a9b1dSJustin T. Gibbs device = request_ccb->ccb_h.path->device; 44958b8a9b1dSJustin T. Gibbs 44968b8a9b1dSJustin T. Gibbs if ((device->quirk->quirks & CAM_QUIRK_NOLUNS) == 0) { 44978b8a9b1dSJustin T. Gibbs /* Try the next lun */ 44988b8a9b1dSJustin T. Gibbs lun_id++; 44998b8a9b1dSJustin T. Gibbs } 45008b8a9b1dSJustin T. Gibbs } 45018b8a9b1dSJustin T. Gibbs 45028b8a9b1dSJustin T. Gibbs xpt_free_path(request_ccb->ccb_h.path); 45038b8a9b1dSJustin T. Gibbs 45048b8a9b1dSJustin T. Gibbs /* Check Bounds */ 45058b8a9b1dSJustin T. Gibbs if ((lun_id == request_ccb->ccb_h.target_lun) 45068b8a9b1dSJustin T. Gibbs || lun_id > scan_info->cpi->max_lun) { 45078b8a9b1dSJustin T. Gibbs /* We're done */ 45088b8a9b1dSJustin T. Gibbs 45098b8a9b1dSJustin T. Gibbs xpt_free_ccb(request_ccb); 45108b8a9b1dSJustin T. Gibbs scan_info->pending_count--; 45118b8a9b1dSJustin T. Gibbs if (scan_info->pending_count == 0) { 45128b8a9b1dSJustin T. Gibbs xpt_free_ccb((union ccb *)scan_info->cpi); 45138b8a9b1dSJustin T. Gibbs request_ccb = scan_info->request_ccb; 45148b8a9b1dSJustin T. Gibbs free(scan_info, M_TEMP); 45158b8a9b1dSJustin T. Gibbs request_ccb->ccb_h.status = CAM_REQ_CMP; 45168b8a9b1dSJustin T. Gibbs xpt_done(request_ccb); 45178b8a9b1dSJustin T. Gibbs } 45188b8a9b1dSJustin T. Gibbs } else { 45198b8a9b1dSJustin T. Gibbs /* Try the next device */ 45208b8a9b1dSJustin T. Gibbs struct cam_path *path; 45218b8a9b1dSJustin T. Gibbs cam_status status; 45228b8a9b1dSJustin T. Gibbs 45238b8a9b1dSJustin T. Gibbs path = request_ccb->ccb_h.path; 45248b8a9b1dSJustin T. Gibbs status = xpt_create_path(&path, xpt_periph, 45258b8a9b1dSJustin T. Gibbs path_id, target_id, lun_id); 45268b8a9b1dSJustin T. Gibbs if (status != CAM_REQ_CMP) { 45278b8a9b1dSJustin T. Gibbs printf("xpt_scan_bus: xpt_create_path failed " 45288b8a9b1dSJustin T. Gibbs "with status %#x, halting LUN scan\n", 45298b8a9b1dSJustin T. Gibbs status); 45308b8a9b1dSJustin T. Gibbs xpt_free_ccb(request_ccb); 45318b8a9b1dSJustin T. Gibbs scan_info->pending_count--; 45328b8a9b1dSJustin T. Gibbs if (scan_info->pending_count == 0) { 45338b8a9b1dSJustin T. Gibbs xpt_free_ccb( 45348b8a9b1dSJustin T. Gibbs (union ccb *)scan_info->cpi); 45358b8a9b1dSJustin T. Gibbs request_ccb = scan_info->request_ccb; 45368b8a9b1dSJustin T. Gibbs free(scan_info, M_TEMP); 45378b8a9b1dSJustin T. Gibbs request_ccb->ccb_h.status = CAM_REQ_CMP; 45388b8a9b1dSJustin T. Gibbs xpt_done(request_ccb); 45398b8a9b1dSJustin T. Gibbs break; 45408b8a9b1dSJustin T. Gibbs } 45418b8a9b1dSJustin T. Gibbs } 45428b8a9b1dSJustin T. Gibbs xpt_setup_ccb(&request_ccb->ccb_h, path, 45438b8a9b1dSJustin T. Gibbs request_ccb->ccb_h.pinfo.priority); 45448b8a9b1dSJustin T. Gibbs request_ccb->ccb_h.func_code = XPT_SCAN_LUN; 45458b8a9b1dSJustin T. Gibbs request_ccb->ccb_h.cbfcnp = xpt_scan_bus; 45468b8a9b1dSJustin T. Gibbs request_ccb->ccb_h.ppriv_ptr0 = scan_info; 45478b8a9b1dSJustin T. Gibbs request_ccb->crcn.flags = 45488b8a9b1dSJustin T. Gibbs scan_info->request_ccb->crcn.flags; 45498b8a9b1dSJustin T. Gibbs #if 0 45508b8a9b1dSJustin T. Gibbs xpt_print_path(path); 45518b8a9b1dSJustin T. Gibbs printf("xpt_scan bus probing\n"); 45528b8a9b1dSJustin T. Gibbs #endif 45538b8a9b1dSJustin T. Gibbs xpt_action(request_ccb); 45548b8a9b1dSJustin T. Gibbs } 45558b8a9b1dSJustin T. Gibbs break; 45568b8a9b1dSJustin T. Gibbs } 45578b8a9b1dSJustin T. Gibbs default: 45588b8a9b1dSJustin T. Gibbs break; 45598b8a9b1dSJustin T. Gibbs } 45608b8a9b1dSJustin T. Gibbs } 45618b8a9b1dSJustin T. Gibbs 45628b8a9b1dSJustin T. Gibbs typedef enum { 45638b8a9b1dSJustin T. Gibbs PROBE_TUR, 45648b8a9b1dSJustin T. Gibbs PROBE_INQUIRY, 45658b8a9b1dSJustin T. Gibbs PROBE_MODE_SENSE, 45668b8a9b1dSJustin T. Gibbs PROBE_SERIAL_NUM, 45678b8a9b1dSJustin T. Gibbs PROBE_TUR_FOR_NEGOTIATION 45688b8a9b1dSJustin T. Gibbs } probe_action; 45698b8a9b1dSJustin T. Gibbs 45708b8a9b1dSJustin T. Gibbs typedef enum { 45718b8a9b1dSJustin T. Gibbs PROBE_INQUIRY_CKSUM = 0x01, 45728b8a9b1dSJustin T. Gibbs PROBE_SERIAL_CKSUM = 0x02, 45738b8a9b1dSJustin T. Gibbs PROBE_NO_ANNOUNCE = 0x04 45748b8a9b1dSJustin T. Gibbs } probe_flags; 45758b8a9b1dSJustin T. Gibbs 45768b8a9b1dSJustin T. Gibbs typedef struct { 45778b8a9b1dSJustin T. Gibbs TAILQ_HEAD(, ccb_hdr) request_ccbs; 45788b8a9b1dSJustin T. Gibbs probe_action action; 45798b8a9b1dSJustin T. Gibbs union ccb saved_ccb; 45808b8a9b1dSJustin T. Gibbs probe_flags flags; 45818b8a9b1dSJustin T. Gibbs MD5_CTX context; 45828b8a9b1dSJustin T. Gibbs u_int8_t digest[16]; 45838b8a9b1dSJustin T. Gibbs } probe_softc; 45848b8a9b1dSJustin T. Gibbs 45858b8a9b1dSJustin T. Gibbs static void 45868b8a9b1dSJustin T. Gibbs xpt_scan_lun(struct cam_periph *periph, struct cam_path *path, 45878b8a9b1dSJustin T. Gibbs cam_flags flags, union ccb *request_ccb) 45888b8a9b1dSJustin T. Gibbs { 45898b8a9b1dSJustin T. Gibbs u_int32_t unit; 45908b8a9b1dSJustin T. Gibbs cam_status status; 45918b8a9b1dSJustin T. Gibbs struct cam_path *new_path; 45928b8a9b1dSJustin T. Gibbs struct cam_periph *old_periph; 45938b8a9b1dSJustin T. Gibbs int s; 45948b8a9b1dSJustin T. Gibbs 45958b8a9b1dSJustin T. Gibbs CAM_DEBUG(request_ccb->ccb_h.path, CAM_DEBUG_TRACE, 45968b8a9b1dSJustin T. Gibbs ("xpt_scan_lun\n")); 45978b8a9b1dSJustin T. Gibbs 45988b8a9b1dSJustin T. Gibbs if (request_ccb == NULL) { 45998b8a9b1dSJustin T. Gibbs request_ccb = malloc(sizeof(union ccb), M_TEMP, M_NOWAIT); 46008b8a9b1dSJustin T. Gibbs if (request_ccb == NULL) { 46018b8a9b1dSJustin T. Gibbs xpt_print_path(path); 46028b8a9b1dSJustin T. Gibbs printf("xpt_scan_lun: can't allocate CCB, can't " 46038b8a9b1dSJustin T. Gibbs "continue\n"); 46048b8a9b1dSJustin T. Gibbs return; 46058b8a9b1dSJustin T. Gibbs } 46068b8a9b1dSJustin T. Gibbs new_path = malloc(sizeof(*new_path), M_TEMP, M_NOWAIT); 46078b8a9b1dSJustin T. Gibbs if (new_path == NULL) { 46088b8a9b1dSJustin T. Gibbs xpt_print_path(path); 46098b8a9b1dSJustin T. Gibbs printf("xpt_scan_lun: can't allocate path, can't " 46108b8a9b1dSJustin T. Gibbs "continue\n"); 46118b8a9b1dSJustin T. Gibbs free(request_ccb, M_TEMP); 46128b8a9b1dSJustin T. Gibbs return; 46138b8a9b1dSJustin T. Gibbs } 46148b8a9b1dSJustin T. Gibbs status = xpt_compile_path(new_path, periph, path->bus->path_id, 46158b8a9b1dSJustin T. Gibbs path->target->target_id, 46168b8a9b1dSJustin T. Gibbs path->device->lun_id); 46178b8a9b1dSJustin T. Gibbs 46188b8a9b1dSJustin T. Gibbs if (status != CAM_REQ_CMP) { 46198b8a9b1dSJustin T. Gibbs xpt_print_path(path); 46208b8a9b1dSJustin T. Gibbs printf("xpt_scan_lun: can't compile path, can't " 46218b8a9b1dSJustin T. Gibbs "continue\n"); 46228b8a9b1dSJustin T. Gibbs free(request_ccb, M_TEMP); 46238b8a9b1dSJustin T. Gibbs free(new_path, M_TEMP); 46248b8a9b1dSJustin T. Gibbs return; 46258b8a9b1dSJustin T. Gibbs } 46268b8a9b1dSJustin T. Gibbs xpt_setup_ccb(&request_ccb->ccb_h, new_path, /*priority*/ 1); 46278b8a9b1dSJustin T. Gibbs request_ccb->ccb_h.cbfcnp = xptscandone; 46288b8a9b1dSJustin T. Gibbs request_ccb->ccb_h.func_code = XPT_SCAN_LUN; 46298b8a9b1dSJustin T. Gibbs request_ccb->crcn.flags = flags; 46308b8a9b1dSJustin T. Gibbs } 46318b8a9b1dSJustin T. Gibbs 46328b8a9b1dSJustin T. Gibbs s = splsoftcam(); 46338b8a9b1dSJustin T. Gibbs if ((old_periph = cam_periph_find(path, "probe")) != NULL) { 46348b8a9b1dSJustin T. Gibbs probe_softc *softc; 46358b8a9b1dSJustin T. Gibbs 46368b8a9b1dSJustin T. Gibbs softc = (probe_softc *)old_periph->softc; 46378b8a9b1dSJustin T. Gibbs TAILQ_INSERT_TAIL(&softc->request_ccbs, &request_ccb->ccb_h, 46388b8a9b1dSJustin T. Gibbs periph_links.tqe); 46398b8a9b1dSJustin T. Gibbs } else { 46408b8a9b1dSJustin T. Gibbs status = cam_periph_alloc(proberegister, probecleanup, 46418b8a9b1dSJustin T. Gibbs probestart, "probe", 46428b8a9b1dSJustin T. Gibbs CAM_PERIPH_BIO, 46438b8a9b1dSJustin T. Gibbs request_ccb->ccb_h.path, NULL, 0, 46448b8a9b1dSJustin T. Gibbs request_ccb); 46458b8a9b1dSJustin T. Gibbs 46468b8a9b1dSJustin T. Gibbs if (status != CAM_REQ_CMP) { 46478b8a9b1dSJustin T. Gibbs xpt_print_path(path); 46488b8a9b1dSJustin T. Gibbs printf("xpt_scan_lun: cam_alloc_periph returned an " 46498b8a9b1dSJustin T. Gibbs "error, can't continue probe\n"); 46508b8a9b1dSJustin T. Gibbs request_ccb->ccb_h.status = status; 46518b8a9b1dSJustin T. Gibbs xpt_done(request_ccb); 46528b8a9b1dSJustin T. Gibbs } 46538b8a9b1dSJustin T. Gibbs } 46548b8a9b1dSJustin T. Gibbs splx(s); 46558b8a9b1dSJustin T. Gibbs } 46568b8a9b1dSJustin T. Gibbs 46578b8a9b1dSJustin T. Gibbs static void 46588b8a9b1dSJustin T. Gibbs xptscandone(struct cam_periph *periph, union ccb *done_ccb) 46598b8a9b1dSJustin T. Gibbs { 46608b8a9b1dSJustin T. Gibbs xpt_release_path(done_ccb->ccb_h.path); 46618b8a9b1dSJustin T. Gibbs free(done_ccb->ccb_h.path, M_TEMP); 46628b8a9b1dSJustin T. Gibbs free(done_ccb, M_TEMP); 46638b8a9b1dSJustin T. Gibbs } 46648b8a9b1dSJustin T. Gibbs 46658b8a9b1dSJustin T. Gibbs static cam_status 46668b8a9b1dSJustin T. Gibbs proberegister(struct cam_periph *periph, void *arg) 46678b8a9b1dSJustin T. Gibbs { 46688b8a9b1dSJustin T. Gibbs struct ccb_getdev *cgd; 46698b8a9b1dSJustin T. Gibbs probe_softc *softc; 46708b8a9b1dSJustin T. Gibbs union ccb *ccb; 46718b8a9b1dSJustin T. Gibbs 46728b8a9b1dSJustin T. Gibbs cgd = (struct ccb_getdev *)arg; 46738b8a9b1dSJustin T. Gibbs if (periph == NULL) { 46748b8a9b1dSJustin T. Gibbs printf("proberegister: periph was NULL!!\n"); 46758b8a9b1dSJustin T. Gibbs return(CAM_REQ_CMP_ERR); 46768b8a9b1dSJustin T. Gibbs } 46778b8a9b1dSJustin T. Gibbs 46788b8a9b1dSJustin T. Gibbs if (cgd == NULL) { 46798b8a9b1dSJustin T. Gibbs printf("proberegister: no getdev CCB, can't register device\n"); 46808b8a9b1dSJustin T. Gibbs return(CAM_REQ_CMP_ERR); 46818b8a9b1dSJustin T. Gibbs } 46828b8a9b1dSJustin T. Gibbs 46839bc66b83SJustin T. Gibbs softc = (probe_softc *)malloc(sizeof(*softc), M_TEMP, M_NOWAIT); 46848b8a9b1dSJustin T. Gibbs 46858b8a9b1dSJustin T. Gibbs if (softc == NULL) { 46868b8a9b1dSJustin T. Gibbs printf("proberegister: Unable to probe new device. " 46878b8a9b1dSJustin T. Gibbs "Unable to allocate softc\n"); 46888b8a9b1dSJustin T. Gibbs return(CAM_REQ_CMP_ERR); 46898b8a9b1dSJustin T. Gibbs } 46908b8a9b1dSJustin T. Gibbs ccb = (union ccb *)cgd; 46918b8a9b1dSJustin T. Gibbs TAILQ_INIT(&softc->request_ccbs); 46928b8a9b1dSJustin T. Gibbs TAILQ_INSERT_TAIL(&softc->request_ccbs, &ccb->ccb_h, periph_links.tqe); 46938b8a9b1dSJustin T. Gibbs softc->flags = 0; 46948b8a9b1dSJustin T. Gibbs periph->softc = softc; 46958b8a9b1dSJustin T. Gibbs cam_periph_acquire(periph); 46968b8a9b1dSJustin T. Gibbs probeschedule(periph); 46978b8a9b1dSJustin T. Gibbs return(CAM_REQ_CMP); 46988b8a9b1dSJustin T. Gibbs } 46998b8a9b1dSJustin T. Gibbs 47008b8a9b1dSJustin T. Gibbs static void 47018b8a9b1dSJustin T. Gibbs probeschedule(struct cam_periph *periph) 47028b8a9b1dSJustin T. Gibbs { 47038b8a9b1dSJustin T. Gibbs union ccb *ccb; 47048b8a9b1dSJustin T. Gibbs probe_softc *softc; 47058b8a9b1dSJustin T. Gibbs 47068b8a9b1dSJustin T. Gibbs softc = (probe_softc *)periph->softc; 47078b8a9b1dSJustin T. Gibbs ccb = (union ccb *)TAILQ_FIRST(&softc->request_ccbs); 47088b8a9b1dSJustin T. Gibbs 47098b8a9b1dSJustin T. Gibbs /* 47108b8a9b1dSJustin T. Gibbs * If a device has gone away and another device, or the same one, 47118b8a9b1dSJustin T. Gibbs * is back in the same place, it should have a unit attention 47128b8a9b1dSJustin T. Gibbs * condition pending. It will not report the unit attention in 47138b8a9b1dSJustin T. Gibbs * response to an inquiry, which may leave invalid transfer 47148b8a9b1dSJustin T. Gibbs * negotiations in effect. The TUR will reveal the unit attention 47158b8a9b1dSJustin T. Gibbs * condition. Only send the TUR for lun 0, since some devices 47168b8a9b1dSJustin T. Gibbs * will get confused by commands other than inquiry to non-existent 47178b8a9b1dSJustin T. Gibbs * luns. If you think a device has gone away start your scan from 47188b8a9b1dSJustin T. Gibbs * lun 0. This will insure that any bogus transfer settings are 47198b8a9b1dSJustin T. Gibbs * invalidated. 47208b8a9b1dSJustin T. Gibbs */ 47218b8a9b1dSJustin T. Gibbs if (((ccb->ccb_h.path->device->flags & CAM_DEV_UNCONFIGURED)==0) 47228b8a9b1dSJustin T. Gibbs && (ccb->ccb_h.target_lun == 0)) 47238b8a9b1dSJustin T. Gibbs softc->action = PROBE_TUR; 47248b8a9b1dSJustin T. Gibbs else 47258b8a9b1dSJustin T. Gibbs softc->action = PROBE_INQUIRY; 47268b8a9b1dSJustin T. Gibbs 47278b8a9b1dSJustin T. Gibbs if (ccb->crcn.flags & CAM_EXPECT_INQ_CHANGE) 47288b8a9b1dSJustin T. Gibbs softc->flags |= PROBE_NO_ANNOUNCE; 47298b8a9b1dSJustin T. Gibbs else 47308b8a9b1dSJustin T. Gibbs softc->flags &= ~PROBE_NO_ANNOUNCE; 47318b8a9b1dSJustin T. Gibbs 47328b8a9b1dSJustin T. Gibbs xpt_schedule(periph, ccb->ccb_h.pinfo.priority); 47338b8a9b1dSJustin T. Gibbs } 47348b8a9b1dSJustin T. Gibbs 47358b8a9b1dSJustin T. Gibbs static void 47368b8a9b1dSJustin T. Gibbs probestart(struct cam_periph *periph, union ccb *start_ccb) 47378b8a9b1dSJustin T. Gibbs { 47388b8a9b1dSJustin T. Gibbs /* Probe the device that our peripheral driver points to */ 47398b8a9b1dSJustin T. Gibbs struct ccb_scsiio *csio; 47408b8a9b1dSJustin T. Gibbs probe_softc *softc; 47418b8a9b1dSJustin T. Gibbs 47428b8a9b1dSJustin T. Gibbs CAM_DEBUG(start_ccb->ccb_h.path, CAM_DEBUG_TRACE, ("probestart\n")); 47438b8a9b1dSJustin T. Gibbs 47448b8a9b1dSJustin T. Gibbs softc = (probe_softc *)periph->softc; 47458b8a9b1dSJustin T. Gibbs csio = &start_ccb->csio; 47468b8a9b1dSJustin T. Gibbs 47478b8a9b1dSJustin T. Gibbs switch (softc->action) { 47488b8a9b1dSJustin T. Gibbs case PROBE_TUR: 47498b8a9b1dSJustin T. Gibbs case PROBE_TUR_FOR_NEGOTIATION: 47508b8a9b1dSJustin T. Gibbs { 47518b8a9b1dSJustin T. Gibbs scsi_test_unit_ready(csio, 47528b8a9b1dSJustin T. Gibbs /*retries*/4, 47538b8a9b1dSJustin T. Gibbs probedone, 47548b8a9b1dSJustin T. Gibbs MSG_SIMPLE_Q_TAG, 47558b8a9b1dSJustin T. Gibbs SSD_FULL_SIZE, 47568b8a9b1dSJustin T. Gibbs /*timeout*/10000); 47578b8a9b1dSJustin T. Gibbs break; 47588b8a9b1dSJustin T. Gibbs } 47598b8a9b1dSJustin T. Gibbs case PROBE_INQUIRY: 47608b8a9b1dSJustin T. Gibbs { 47618b8a9b1dSJustin T. Gibbs struct scsi_inquiry_data *inq_buf; 47628b8a9b1dSJustin T. Gibbs 47638b8a9b1dSJustin T. Gibbs inq_buf = &periph->path->device->inq_data; 47648b8a9b1dSJustin T. Gibbs /* 47658b8a9b1dSJustin T. Gibbs * If the device is currently configured, we calculate an 47668b8a9b1dSJustin T. Gibbs * MD5 checksum of the inquiry data, and if the serial number 47678b8a9b1dSJustin T. Gibbs * length is greater than 0, add the serial number data 47688b8a9b1dSJustin T. Gibbs * into the checksum as well. Once the inquiry and the 47698b8a9b1dSJustin T. Gibbs * serial number check finish, we attempt to figure out 47708b8a9b1dSJustin T. Gibbs * whether we still have the same device. 47718b8a9b1dSJustin T. Gibbs */ 47728b8a9b1dSJustin T. Gibbs if ((periph->path->device->flags & CAM_DEV_UNCONFIGURED) == 0) { 47738b8a9b1dSJustin T. Gibbs 47748b8a9b1dSJustin T. Gibbs MD5Init(&softc->context); 47758b8a9b1dSJustin T. Gibbs MD5Update(&softc->context, (unsigned char *)inq_buf, 47768b8a9b1dSJustin T. Gibbs sizeof(struct scsi_inquiry_data)); 47778b8a9b1dSJustin T. Gibbs softc->flags |= PROBE_INQUIRY_CKSUM; 47788b8a9b1dSJustin T. Gibbs if (periph->path->device->serial_num_len > 0) { 47798b8a9b1dSJustin T. Gibbs MD5Update(&softc->context, 47808b8a9b1dSJustin T. Gibbs periph->path->device->serial_num, 47818b8a9b1dSJustin T. Gibbs periph->path->device->serial_num_len); 47828b8a9b1dSJustin T. Gibbs softc->flags |= PROBE_SERIAL_CKSUM; 47838b8a9b1dSJustin T. Gibbs } 47848b8a9b1dSJustin T. Gibbs MD5Final(softc->digest, &softc->context); 47858b8a9b1dSJustin T. Gibbs } 47868b8a9b1dSJustin T. Gibbs 47878b8a9b1dSJustin T. Gibbs scsi_inquiry(csio, 47888b8a9b1dSJustin T. Gibbs /*retries*/4, 47898b8a9b1dSJustin T. Gibbs probedone, 47908b8a9b1dSJustin T. Gibbs MSG_SIMPLE_Q_TAG, 47918b8a9b1dSJustin T. Gibbs (u_int8_t *)inq_buf, 47928b8a9b1dSJustin T. Gibbs sizeof(*inq_buf), 47938b8a9b1dSJustin T. Gibbs /*evpd*/FALSE, 47948b8a9b1dSJustin T. Gibbs /*page_code*/0, 47958b8a9b1dSJustin T. Gibbs SSD_MIN_SIZE, 47968b8a9b1dSJustin T. Gibbs /*timeout*/5 * 1000); 47978b8a9b1dSJustin T. Gibbs break; 47988b8a9b1dSJustin T. Gibbs } 47998b8a9b1dSJustin T. Gibbs case PROBE_MODE_SENSE: 48008b8a9b1dSJustin T. Gibbs { 48018b8a9b1dSJustin T. Gibbs void *mode_buf; 48028b8a9b1dSJustin T. Gibbs int mode_buf_len; 48038b8a9b1dSJustin T. Gibbs 48048b8a9b1dSJustin T. Gibbs mode_buf_len = sizeof(struct scsi_mode_header_6) 48058b8a9b1dSJustin T. Gibbs + sizeof(struct scsi_mode_blk_desc) 48068b8a9b1dSJustin T. Gibbs + sizeof(struct scsi_control_page); 48078b8a9b1dSJustin T. Gibbs mode_buf = malloc(mode_buf_len, M_TEMP, M_NOWAIT); 48088b8a9b1dSJustin T. Gibbs if (mode_buf != NULL) { 48098b8a9b1dSJustin T. Gibbs scsi_mode_sense(csio, 48108b8a9b1dSJustin T. Gibbs /*retries*/4, 48118b8a9b1dSJustin T. Gibbs probedone, 48128b8a9b1dSJustin T. Gibbs MSG_SIMPLE_Q_TAG, 48138b8a9b1dSJustin T. Gibbs /*dbd*/FALSE, 48148b8a9b1dSJustin T. Gibbs SMS_PAGE_CTRL_CURRENT, 48158b8a9b1dSJustin T. Gibbs SMS_CONTROL_MODE_PAGE, 48168b8a9b1dSJustin T. Gibbs mode_buf, 48178b8a9b1dSJustin T. Gibbs mode_buf_len, 48188b8a9b1dSJustin T. Gibbs SSD_FULL_SIZE, 48198b8a9b1dSJustin T. Gibbs /*timeout*/5000); 48208b8a9b1dSJustin T. Gibbs break; 48218b8a9b1dSJustin T. Gibbs } 48228b8a9b1dSJustin T. Gibbs xpt_print_path(periph->path); 48238b8a9b1dSJustin T. Gibbs printf("Unable to mode sense control page - malloc failure\n"); 48248b8a9b1dSJustin T. Gibbs softc->action = PROBE_SERIAL_NUM; 48258b8a9b1dSJustin T. Gibbs /* FALLTHROUGH */ 48268b8a9b1dSJustin T. Gibbs } 48278b8a9b1dSJustin T. Gibbs case PROBE_SERIAL_NUM: 48288b8a9b1dSJustin T. Gibbs { 48298b8a9b1dSJustin T. Gibbs struct scsi_vpd_unit_serial_number *serial_buf; 48308b8a9b1dSJustin T. Gibbs struct cam_ed* device; 48318b8a9b1dSJustin T. Gibbs 48328b8a9b1dSJustin T. Gibbs serial_buf = NULL; 48338b8a9b1dSJustin T. Gibbs device = periph->path->device; 48348b8a9b1dSJustin T. Gibbs device->serial_num = NULL; 48358b8a9b1dSJustin T. Gibbs device->serial_num_len = 0; 48368b8a9b1dSJustin T. Gibbs 48378b8a9b1dSJustin T. Gibbs if ((device->quirk->quirks & CAM_QUIRK_NOSERIAL) == 0) 48388b8a9b1dSJustin T. Gibbs serial_buf = (struct scsi_vpd_unit_serial_number *) 48398b8a9b1dSJustin T. Gibbs malloc(sizeof(*serial_buf), M_TEMP, M_NOWAIT); 48408b8a9b1dSJustin T. Gibbs 48418b8a9b1dSJustin T. Gibbs if (serial_buf != NULL) { 48428b8a9b1dSJustin T. Gibbs bzero(serial_buf, sizeof(*serial_buf)); 48438b8a9b1dSJustin T. Gibbs scsi_inquiry(csio, 48448b8a9b1dSJustin T. Gibbs /*retries*/4, 48458b8a9b1dSJustin T. Gibbs probedone, 48468b8a9b1dSJustin T. Gibbs MSG_SIMPLE_Q_TAG, 48478b8a9b1dSJustin T. Gibbs (u_int8_t *)serial_buf, 48488b8a9b1dSJustin T. Gibbs sizeof(*serial_buf), 48498b8a9b1dSJustin T. Gibbs /*evpd*/TRUE, 48508b8a9b1dSJustin T. Gibbs SVPD_UNIT_SERIAL_NUMBER, 48518b8a9b1dSJustin T. Gibbs SSD_MIN_SIZE, 48528b8a9b1dSJustin T. Gibbs /*timeout*/5 * 1000); 48538b8a9b1dSJustin T. Gibbs break; 48548b8a9b1dSJustin T. Gibbs } 48558b8a9b1dSJustin T. Gibbs /* 48568b8a9b1dSJustin T. Gibbs * We'll have to do without, let our probedone 48578b8a9b1dSJustin T. Gibbs * routine finish up for us. 48588b8a9b1dSJustin T. Gibbs */ 48598b8a9b1dSJustin T. Gibbs start_ccb->csio.data_ptr = NULL; 48608b8a9b1dSJustin T. Gibbs probedone(periph, start_ccb); 48618b8a9b1dSJustin T. Gibbs return; 48628b8a9b1dSJustin T. Gibbs } 48638b8a9b1dSJustin T. Gibbs } 48648b8a9b1dSJustin T. Gibbs xpt_action(start_ccb); 48658b8a9b1dSJustin T. Gibbs } 48668b8a9b1dSJustin T. Gibbs 48678b8a9b1dSJustin T. Gibbs static void 48688b8a9b1dSJustin T. Gibbs probedone(struct cam_periph *periph, union ccb *done_ccb) 48698b8a9b1dSJustin T. Gibbs { 48708b8a9b1dSJustin T. Gibbs probe_softc *softc; 48718b8a9b1dSJustin T. Gibbs struct cam_path *path; 48728b8a9b1dSJustin T. Gibbs u_int32_t priority; 48738b8a9b1dSJustin T. Gibbs 48748b8a9b1dSJustin T. Gibbs CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_TRACE, ("probedone\n")); 48758b8a9b1dSJustin T. Gibbs 48768b8a9b1dSJustin T. Gibbs softc = (probe_softc *)periph->softc; 48778b8a9b1dSJustin T. Gibbs path = done_ccb->ccb_h.path; 48788b8a9b1dSJustin T. Gibbs priority = done_ccb->ccb_h.pinfo.priority; 48798b8a9b1dSJustin T. Gibbs 48808b8a9b1dSJustin T. Gibbs switch (softc->action) { 48818b8a9b1dSJustin T. Gibbs case PROBE_TUR: 48828b8a9b1dSJustin T. Gibbs { 48838b8a9b1dSJustin T. Gibbs if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 48848b8a9b1dSJustin T. Gibbs 48858b8a9b1dSJustin T. Gibbs if (cam_periph_error(done_ccb, 0, 48868b8a9b1dSJustin T. Gibbs SF_NO_PRINT, NULL) == ERESTART) 48878b8a9b1dSJustin T. Gibbs return; 48888b8a9b1dSJustin T. Gibbs else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) 48898b8a9b1dSJustin T. Gibbs /* Don't wedge the queue */ 48908b8a9b1dSJustin T. Gibbs xpt_release_devq(done_ccb->ccb_h.path->device, 48918b8a9b1dSJustin T. Gibbs /*run_queue*/TRUE); 48928b8a9b1dSJustin T. Gibbs } 48938b8a9b1dSJustin T. Gibbs softc->action = PROBE_INQUIRY; 48948b8a9b1dSJustin T. Gibbs xpt_release_ccb(done_ccb); 48958b8a9b1dSJustin T. Gibbs xpt_schedule(periph, priority); 48968b8a9b1dSJustin T. Gibbs return; 48978b8a9b1dSJustin T. Gibbs } 48988b8a9b1dSJustin T. Gibbs case PROBE_INQUIRY: 48998b8a9b1dSJustin T. Gibbs { 49008b8a9b1dSJustin T. Gibbs if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) { 49018b8a9b1dSJustin T. Gibbs struct scsi_inquiry_data *inq_buf; 49028b8a9b1dSJustin T. Gibbs u_int8_t periph_qual; 49038b8a9b1dSJustin T. Gibbs u_int8_t periph_dtype; 49048b8a9b1dSJustin T. Gibbs 49058b8a9b1dSJustin T. Gibbs inq_buf = &path->device->inq_data; 49068b8a9b1dSJustin T. Gibbs 49078b8a9b1dSJustin T. Gibbs periph_qual = SID_QUAL(inq_buf); 49088b8a9b1dSJustin T. Gibbs periph_dtype = SID_TYPE(inq_buf); 49098b8a9b1dSJustin T. Gibbs if (periph_dtype != T_NODEVICE) { 49108b8a9b1dSJustin T. Gibbs switch(periph_qual) { 49118b8a9b1dSJustin T. Gibbs case SID_QUAL_LU_CONNECTED: 49128b8a9b1dSJustin T. Gibbs { 49138b8a9b1dSJustin T. Gibbs xpt_find_quirk(path->device); 49148b8a9b1dSJustin T. Gibbs 49158b8a9b1dSJustin T. Gibbs if ((inq_buf->flags & SID_CmdQue) != 0) 49168b8a9b1dSJustin T. Gibbs softc->action = 49178b8a9b1dSJustin T. Gibbs PROBE_MODE_SENSE; 49188b8a9b1dSJustin T. Gibbs else 49198b8a9b1dSJustin T. Gibbs softc->action = 49208b8a9b1dSJustin T. Gibbs PROBE_SERIAL_NUM; 49218b8a9b1dSJustin T. Gibbs 49228b8a9b1dSJustin T. Gibbs path->device->flags &= 49238b8a9b1dSJustin T. Gibbs ~CAM_DEV_UNCONFIGURED; 49248b8a9b1dSJustin T. Gibbs 49258b8a9b1dSJustin T. Gibbs xpt_release_ccb(done_ccb); 49268b8a9b1dSJustin T. Gibbs xpt_schedule(periph, priority); 49278b8a9b1dSJustin T. Gibbs return; 49288b8a9b1dSJustin T. Gibbs } 49298b8a9b1dSJustin T. Gibbs default: 49308b8a9b1dSJustin T. Gibbs break; 49318b8a9b1dSJustin T. Gibbs } 49328b8a9b1dSJustin T. Gibbs } 49338b8a9b1dSJustin T. Gibbs } else if (cam_periph_error(done_ccb, 0, 49348b8a9b1dSJustin T. Gibbs done_ccb->ccb_h.target_lun > 0 49358b8a9b1dSJustin T. Gibbs ? SF_RETRY_UA|SF_QUIET_IR 49368b8a9b1dSJustin T. Gibbs : SF_RETRY_UA, 49378b8a9b1dSJustin T. Gibbs &softc->saved_ccb) == ERESTART) { 49388b8a9b1dSJustin T. Gibbs return; 49398b8a9b1dSJustin T. Gibbs } else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) { 49408b8a9b1dSJustin T. Gibbs /* Don't wedge the queue */ 49418b8a9b1dSJustin T. Gibbs xpt_release_devq(done_ccb->ccb_h.path->device, 49428b8a9b1dSJustin T. Gibbs /*run_queue*/TRUE); 49438b8a9b1dSJustin T. Gibbs } 49448b8a9b1dSJustin T. Gibbs /* 49458b8a9b1dSJustin T. Gibbs * If we get to this point, we got an error status back 49468b8a9b1dSJustin T. Gibbs * from the inquiry and the error status doesn't require 49478b8a9b1dSJustin T. Gibbs * automatically retrying the command. Therefore, the 49488b8a9b1dSJustin T. Gibbs * inquiry failed. If we had inquiry information before 49498b8a9b1dSJustin T. Gibbs * for this device, but this latest inquiry command failed, 49508b8a9b1dSJustin T. Gibbs * the device has probably gone away. If this device isn't 49518b8a9b1dSJustin T. Gibbs * already marked unconfigured, notify the peripheral 49528b8a9b1dSJustin T. Gibbs * drivers that this device is no more. 49538b8a9b1dSJustin T. Gibbs */ 49548b8a9b1dSJustin T. Gibbs if ((path->device->flags & CAM_DEV_UNCONFIGURED) == 0) 49558b8a9b1dSJustin T. Gibbs /* Send the async notification. */ 49568b8a9b1dSJustin T. Gibbs xpt_async(AC_LOST_DEVICE, path, NULL); 49578b8a9b1dSJustin T. Gibbs 49588b8a9b1dSJustin T. Gibbs xpt_release_ccb(done_ccb); 49598b8a9b1dSJustin T. Gibbs break; 49608b8a9b1dSJustin T. Gibbs } 49618b8a9b1dSJustin T. Gibbs case PROBE_MODE_SENSE: 49628b8a9b1dSJustin T. Gibbs { 49638b8a9b1dSJustin T. Gibbs struct ccb_scsiio *csio; 49648b8a9b1dSJustin T. Gibbs struct scsi_mode_header_6 *mode_hdr; 49658b8a9b1dSJustin T. Gibbs 49668b8a9b1dSJustin T. Gibbs csio = &done_ccb->csio; 49678b8a9b1dSJustin T. Gibbs mode_hdr = (struct scsi_mode_header_6 *)csio->data_ptr; 49688b8a9b1dSJustin T. Gibbs if ((csio->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) { 49698b8a9b1dSJustin T. Gibbs struct scsi_control_page *page; 49708b8a9b1dSJustin T. Gibbs u_int8_t *offset; 49718b8a9b1dSJustin T. Gibbs 49728b8a9b1dSJustin T. Gibbs offset = ((u_int8_t *)&mode_hdr[1]) 49738b8a9b1dSJustin T. Gibbs + mode_hdr->blk_desc_len; 49748b8a9b1dSJustin T. Gibbs page = (struct scsi_control_page *)offset; 49758b8a9b1dSJustin T. Gibbs path->device->queue_flags = page->queue_flags; 49768b8a9b1dSJustin T. Gibbs } else if (cam_periph_error(done_ccb, 0, 49778b8a9b1dSJustin T. Gibbs SF_RETRY_UA|SF_NO_PRINT, 49788b8a9b1dSJustin T. Gibbs &softc->saved_ccb) == ERESTART) { 49798b8a9b1dSJustin T. Gibbs return; 49808b8a9b1dSJustin T. Gibbs } else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) { 49818b8a9b1dSJustin T. Gibbs /* Don't wedge the queue */ 49828b8a9b1dSJustin T. Gibbs xpt_release_devq(done_ccb->ccb_h.path->device, 49838b8a9b1dSJustin T. Gibbs /*run_queue*/TRUE); 49848b8a9b1dSJustin T. Gibbs } 49858b8a9b1dSJustin T. Gibbs xpt_release_ccb(done_ccb); 49868b8a9b1dSJustin T. Gibbs free(mode_hdr, M_TEMP); 49878b8a9b1dSJustin T. Gibbs softc->action = PROBE_SERIAL_NUM; 49888b8a9b1dSJustin T. Gibbs xpt_schedule(periph, priority); 49898b8a9b1dSJustin T. Gibbs return; 49908b8a9b1dSJustin T. Gibbs } 49918b8a9b1dSJustin T. Gibbs case PROBE_SERIAL_NUM: 49928b8a9b1dSJustin T. Gibbs { 49938b8a9b1dSJustin T. Gibbs struct ccb_scsiio *csio; 49948b8a9b1dSJustin T. Gibbs struct scsi_vpd_unit_serial_number *serial_buf; 49958b8a9b1dSJustin T. Gibbs u_int32_t priority; 49968b8a9b1dSJustin T. Gibbs int changed; 49978b8a9b1dSJustin T. Gibbs int have_serialnum; 49988b8a9b1dSJustin T. Gibbs 49998b8a9b1dSJustin T. Gibbs changed = 1; 50008b8a9b1dSJustin T. Gibbs have_serialnum = 0; 50018b8a9b1dSJustin T. Gibbs csio = &done_ccb->csio; 50028b8a9b1dSJustin T. Gibbs priority = done_ccb->ccb_h.pinfo.priority; 50038b8a9b1dSJustin T. Gibbs serial_buf = 50048b8a9b1dSJustin T. Gibbs (struct scsi_vpd_unit_serial_number *)csio->data_ptr; 50058b8a9b1dSJustin T. Gibbs 50068b8a9b1dSJustin T. Gibbs /* Clean up from previous instance of this device */ 50078b8a9b1dSJustin T. Gibbs if (path->device->serial_num != NULL) { 50088b8a9b1dSJustin T. Gibbs free(path->device->serial_num, M_DEVBUF); 50098b8a9b1dSJustin T. Gibbs path->device->serial_num = NULL; 50108b8a9b1dSJustin T. Gibbs path->device->serial_num_len = 0; 50118b8a9b1dSJustin T. Gibbs } 50128b8a9b1dSJustin T. Gibbs 50138b8a9b1dSJustin T. Gibbs if (serial_buf == NULL) { 50148b8a9b1dSJustin T. Gibbs /* 50158b8a9b1dSJustin T. Gibbs * Don't process the command as it was never sent 50168b8a9b1dSJustin T. Gibbs */ 50178b8a9b1dSJustin T. Gibbs } else if ((csio->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP 50188b8a9b1dSJustin T. Gibbs && (serial_buf->length > 0)) { 50198b8a9b1dSJustin T. Gibbs 50208b8a9b1dSJustin T. Gibbs have_serialnum = 1; 50218b8a9b1dSJustin T. Gibbs path->device->serial_num = 50228b8a9b1dSJustin T. Gibbs (u_int8_t *)malloc((serial_buf->length + 1), 50238b8a9b1dSJustin T. Gibbs M_DEVBUF, M_NOWAIT); 50248b8a9b1dSJustin T. Gibbs if (path->device->serial_num != NULL) { 50258b8a9b1dSJustin T. Gibbs bcopy(serial_buf->serial_num, 50268b8a9b1dSJustin T. Gibbs path->device->serial_num, 50278b8a9b1dSJustin T. Gibbs serial_buf->length); 50288b8a9b1dSJustin T. Gibbs path->device->serial_num_len = 50298b8a9b1dSJustin T. Gibbs serial_buf->length; 50308b8a9b1dSJustin T. Gibbs path->device->serial_num[serial_buf->length] 50318b8a9b1dSJustin T. Gibbs = '\0'; 50328b8a9b1dSJustin T. Gibbs } 50338b8a9b1dSJustin T. Gibbs } else if (cam_periph_error(done_ccb, 0, 50348b8a9b1dSJustin T. Gibbs SF_RETRY_UA|SF_NO_PRINT, 50358b8a9b1dSJustin T. Gibbs &softc->saved_ccb) == ERESTART) { 50368b8a9b1dSJustin T. Gibbs return; 50378b8a9b1dSJustin T. Gibbs } else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) { 50388b8a9b1dSJustin T. Gibbs /* Don't wedge the queue */ 50398b8a9b1dSJustin T. Gibbs xpt_release_devq(done_ccb->ccb_h.path->device, 50408b8a9b1dSJustin T. Gibbs /*run_queue*/TRUE); 50418b8a9b1dSJustin T. Gibbs } 50428b8a9b1dSJustin T. Gibbs 50438b8a9b1dSJustin T. Gibbs /* 50448b8a9b1dSJustin T. Gibbs * Let's see if we have seen this device before. 50458b8a9b1dSJustin T. Gibbs */ 50468b8a9b1dSJustin T. Gibbs if ((softc->flags & PROBE_INQUIRY_CKSUM) != 0) { 50478b8a9b1dSJustin T. Gibbs MD5_CTX context; 50488b8a9b1dSJustin T. Gibbs u_int8_t digest[16]; 50498b8a9b1dSJustin T. Gibbs 50508b8a9b1dSJustin T. Gibbs MD5Init(&context); 50518b8a9b1dSJustin T. Gibbs 50528b8a9b1dSJustin T. Gibbs MD5Update(&context, 50538b8a9b1dSJustin T. Gibbs (unsigned char *)&path->device->inq_data, 50548b8a9b1dSJustin T. Gibbs sizeof(struct scsi_inquiry_data)); 50558b8a9b1dSJustin T. Gibbs 50568b8a9b1dSJustin T. Gibbs if (have_serialnum) 50578b8a9b1dSJustin T. Gibbs MD5Update(&context, serial_buf->serial_num, 50588b8a9b1dSJustin T. Gibbs serial_buf->length); 50598b8a9b1dSJustin T. Gibbs 50608b8a9b1dSJustin T. Gibbs MD5Final(digest, &context); 50618b8a9b1dSJustin T. Gibbs if (bcmp(softc->digest, digest, 16) == 0) 50628b8a9b1dSJustin T. Gibbs changed = 0; 50638b8a9b1dSJustin T. Gibbs 50648b8a9b1dSJustin T. Gibbs /* 50658b8a9b1dSJustin T. Gibbs * XXX Do we need to do a TUR in order to ensure 50668b8a9b1dSJustin T. Gibbs * that the device really hasn't changed??? 50678b8a9b1dSJustin T. Gibbs */ 50688b8a9b1dSJustin T. Gibbs if ((changed != 0) 50698b8a9b1dSJustin T. Gibbs && ((softc->flags & PROBE_NO_ANNOUNCE) == 0)) 50708b8a9b1dSJustin T. Gibbs xpt_async(AC_LOST_DEVICE, path, NULL); 50718b8a9b1dSJustin T. Gibbs } 50728b8a9b1dSJustin T. Gibbs if (serial_buf != NULL) 50738b8a9b1dSJustin T. Gibbs free(serial_buf, M_TEMP); 50748b8a9b1dSJustin T. Gibbs 50758b8a9b1dSJustin T. Gibbs if (changed != 0) { 50768b8a9b1dSJustin T. Gibbs /* 50778b8a9b1dSJustin T. Gibbs * Now that we have all the necessary 50788b8a9b1dSJustin T. Gibbs * information to safely perform transfer 50798b8a9b1dSJustin T. Gibbs * negotiations... Controllers don't perform 50808b8a9b1dSJustin T. Gibbs * any negotiation or tagged queuing until 50818b8a9b1dSJustin T. Gibbs * after the first XPT_SET_TRAN_SETTINGS ccb is 50828b8a9b1dSJustin T. Gibbs * received. So, on a new device, just retreive 50838b8a9b1dSJustin T. Gibbs * the user settings, and set them as the current 50848b8a9b1dSJustin T. Gibbs * settings to set the device up. 50858b8a9b1dSJustin T. Gibbs */ 50868b8a9b1dSJustin T. Gibbs done_ccb->ccb_h.func_code = XPT_GET_TRAN_SETTINGS; 50878b8a9b1dSJustin T. Gibbs done_ccb->cts.flags = CCB_TRANS_USER_SETTINGS; 50888b8a9b1dSJustin T. Gibbs xpt_action(done_ccb); 50898b8a9b1dSJustin T. Gibbs done_ccb->ccb_h.func_code = XPT_SET_TRAN_SETTINGS; 50908b8a9b1dSJustin T. Gibbs done_ccb->cts.flags &= ~CCB_TRANS_USER_SETTINGS; 50918b8a9b1dSJustin T. Gibbs done_ccb->cts.flags |= CCB_TRANS_CURRENT_SETTINGS; 50928b8a9b1dSJustin T. Gibbs xpt_action(done_ccb); 50938b8a9b1dSJustin T. Gibbs xpt_release_ccb(done_ccb); 50948b8a9b1dSJustin T. Gibbs 50958b8a9b1dSJustin T. Gibbs /* 50968b8a9b1dSJustin T. Gibbs * Perform a TUR to allow the controller to 50978b8a9b1dSJustin T. Gibbs * perform any necessary transfer negotiation. 50988b8a9b1dSJustin T. Gibbs */ 50998b8a9b1dSJustin T. Gibbs softc->action = PROBE_TUR_FOR_NEGOTIATION; 51008b8a9b1dSJustin T. Gibbs xpt_schedule(periph, priority); 51018b8a9b1dSJustin T. Gibbs return; 51028b8a9b1dSJustin T. Gibbs } 51038b8a9b1dSJustin T. Gibbs xpt_release_ccb(done_ccb); 51048b8a9b1dSJustin T. Gibbs break; 51058b8a9b1dSJustin T. Gibbs } 51068b8a9b1dSJustin T. Gibbs case PROBE_TUR_FOR_NEGOTIATION: 51078b8a9b1dSJustin T. Gibbs if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) { 51088b8a9b1dSJustin T. Gibbs /* Don't wedge the queue */ 51098b8a9b1dSJustin T. Gibbs xpt_release_devq(done_ccb->ccb_h.path->device, 51108b8a9b1dSJustin T. Gibbs /*run_queue*/TRUE); 51118b8a9b1dSJustin T. Gibbs } 51128b8a9b1dSJustin T. Gibbs 51138b8a9b1dSJustin T. Gibbs path->device->flags &= ~CAM_DEV_UNCONFIGURED; 51148b8a9b1dSJustin T. Gibbs 51158b8a9b1dSJustin T. Gibbs if ((softc->flags & PROBE_NO_ANNOUNCE) == 0) { 51168b8a9b1dSJustin T. Gibbs /* Inform the XPT that a new device has been found */ 51178b8a9b1dSJustin T. Gibbs done_ccb->ccb_h.func_code = XPT_GDEV_TYPE; 51188b8a9b1dSJustin T. Gibbs xpt_action(done_ccb); 51198b8a9b1dSJustin T. Gibbs 51208b8a9b1dSJustin T. Gibbs xpt_async(AC_FOUND_DEVICE, xpt_periph->path, done_ccb); 51218b8a9b1dSJustin T. Gibbs } 51228b8a9b1dSJustin T. Gibbs xpt_release_ccb(done_ccb); 51238b8a9b1dSJustin T. Gibbs break; 51248b8a9b1dSJustin T. Gibbs } 51258b8a9b1dSJustin T. Gibbs done_ccb = (union ccb *)TAILQ_FIRST(&softc->request_ccbs); 51268b8a9b1dSJustin T. Gibbs TAILQ_REMOVE(&softc->request_ccbs, &done_ccb->ccb_h, periph_links.tqe); 51278b8a9b1dSJustin T. Gibbs done_ccb->ccb_h.status = CAM_REQ_CMP; 51288b8a9b1dSJustin T. Gibbs xpt_done(done_ccb); 51298b8a9b1dSJustin T. Gibbs if (TAILQ_FIRST(&softc->request_ccbs) == NULL) { 51308b8a9b1dSJustin T. Gibbs cam_periph_invalidate(periph); 51318b8a9b1dSJustin T. Gibbs cam_periph_release(periph); 51328b8a9b1dSJustin T. Gibbs } else { 51338b8a9b1dSJustin T. Gibbs probeschedule(periph); 51348b8a9b1dSJustin T. Gibbs } 51358b8a9b1dSJustin T. Gibbs } 51368b8a9b1dSJustin T. Gibbs 51378b8a9b1dSJustin T. Gibbs static void 51388b8a9b1dSJustin T. Gibbs probecleanup(struct cam_periph *periph) 51398b8a9b1dSJustin T. Gibbs { 51408b8a9b1dSJustin T. Gibbs free(periph->softc, M_TEMP); 51418b8a9b1dSJustin T. Gibbs } 51428b8a9b1dSJustin T. Gibbs 51438b8a9b1dSJustin T. Gibbs static void 51448b8a9b1dSJustin T. Gibbs xpt_find_quirk(struct cam_ed *device) 51458b8a9b1dSJustin T. Gibbs { 51468b8a9b1dSJustin T. Gibbs caddr_t match; 51478b8a9b1dSJustin T. Gibbs 51488b8a9b1dSJustin T. Gibbs match = cam_quirkmatch((caddr_t)&device->inq_data, 51498b8a9b1dSJustin T. Gibbs (caddr_t)xpt_quirk_table, 51508b8a9b1dSJustin T. Gibbs sizeof(xpt_quirk_table)/sizeof(*xpt_quirk_table), 51518b8a9b1dSJustin T. Gibbs sizeof(*xpt_quirk_table), scsi_inquiry_match); 51528b8a9b1dSJustin T. Gibbs 51538b8a9b1dSJustin T. Gibbs if (match == NULL) 51548b8a9b1dSJustin T. Gibbs panic("xpt_find_quirk: device didn't match wildcard entry!!"); 51558b8a9b1dSJustin T. Gibbs 51568b8a9b1dSJustin T. Gibbs device->quirk = (struct xpt_quirk_entry *)match; 51578b8a9b1dSJustin T. Gibbs } 51588b8a9b1dSJustin T. Gibbs 51598b8a9b1dSJustin T. Gibbs static void 51608b8a9b1dSJustin T. Gibbs xpt_set_transfer_settings(struct ccb_trans_settings *cts, int async_update) 51618b8a9b1dSJustin T. Gibbs { 51628b8a9b1dSJustin T. Gibbs struct cam_ed *device; 51638b8a9b1dSJustin T. Gibbs struct cam_sim *sim; 51648b8a9b1dSJustin T. Gibbs int qfrozen; 51658b8a9b1dSJustin T. Gibbs 51668b8a9b1dSJustin T. Gibbs device = cts->ccb_h.path->device; 51678b8a9b1dSJustin T. Gibbs sim = cts->ccb_h.path->bus->sim; 51688b8a9b1dSJustin T. Gibbs if (async_update == FALSE) { 51698b8a9b1dSJustin T. Gibbs struct scsi_inquiry_data *inq_data; 51708b8a9b1dSJustin T. Gibbs struct ccb_pathinq cpi; 51718b8a9b1dSJustin T. Gibbs 51728b8a9b1dSJustin T. Gibbs /* 51738b8a9b1dSJustin T. Gibbs * Perform sanity checking against what the 51748b8a9b1dSJustin T. Gibbs * controller and device can do. 51758b8a9b1dSJustin T. Gibbs */ 51768b8a9b1dSJustin T. Gibbs xpt_setup_ccb(&cpi.ccb_h, cts->ccb_h.path, /*priority*/1); 51778b8a9b1dSJustin T. Gibbs cpi.ccb_h.func_code = XPT_PATH_INQ; 51788b8a9b1dSJustin T. Gibbs xpt_action((union ccb *)&cpi); 51798b8a9b1dSJustin T. Gibbs 51808b8a9b1dSJustin T. Gibbs inq_data = &device->inq_data; 51818b8a9b1dSJustin T. Gibbs if ((inq_data->flags & SID_Sync) == 0 51828b8a9b1dSJustin T. Gibbs || (cpi.hba_inquiry & PI_SDTR_ABLE) == 0) { 51838b8a9b1dSJustin T. Gibbs /* Force async */ 51848b8a9b1dSJustin T. Gibbs cts->sync_period = 0; 51858b8a9b1dSJustin T. Gibbs cts->sync_offset = 0; 51868b8a9b1dSJustin T. Gibbs } 51878b8a9b1dSJustin T. Gibbs 51888b8a9b1dSJustin T. Gibbs switch (cts->bus_width) { 51898b8a9b1dSJustin T. Gibbs case MSG_EXT_WDTR_BUS_32_BIT: 51908b8a9b1dSJustin T. Gibbs if ((inq_data->flags & SID_WBus32) != 0 51918b8a9b1dSJustin T. Gibbs && (cpi.hba_inquiry & PI_WIDE_32) != 0) 51928b8a9b1dSJustin T. Gibbs break; 51938b8a9b1dSJustin T. Gibbs /* Fall Through to 16-bit */ 51948b8a9b1dSJustin T. Gibbs case MSG_EXT_WDTR_BUS_16_BIT: 51958b8a9b1dSJustin T. Gibbs if ((inq_data->flags & SID_WBus16) != 0 51968b8a9b1dSJustin T. Gibbs && (cpi.hba_inquiry & PI_WIDE_16) != 0) { 51978b8a9b1dSJustin T. Gibbs cts->bus_width = MSG_EXT_WDTR_BUS_16_BIT; 51988b8a9b1dSJustin T. Gibbs break; 51998b8a9b1dSJustin T. Gibbs } 52008b8a9b1dSJustin T. Gibbs /* Fall Through to 8-bit */ 52018b8a9b1dSJustin T. Gibbs default: /* New bus width?? */ 52028b8a9b1dSJustin T. Gibbs case MSG_EXT_WDTR_BUS_8_BIT: 52038b8a9b1dSJustin T. Gibbs /* All targets can do this */ 52048b8a9b1dSJustin T. Gibbs cts->bus_width = MSG_EXT_WDTR_BUS_8_BIT; 52058b8a9b1dSJustin T. Gibbs break; 52068b8a9b1dSJustin T. Gibbs } 52078b8a9b1dSJustin T. Gibbs 52088b8a9b1dSJustin T. Gibbs if ((cts->flags & CCB_TRANS_DISC_ENB) == 0) { 52098b8a9b1dSJustin T. Gibbs /* 52108b8a9b1dSJustin T. Gibbs * Can't tag queue without disconnection. 52118b8a9b1dSJustin T. Gibbs */ 52128b8a9b1dSJustin T. Gibbs cts->flags &= ~CCB_TRANS_TAG_ENB; 52138b8a9b1dSJustin T. Gibbs } 52148b8a9b1dSJustin T. Gibbs 52158b8a9b1dSJustin T. Gibbs if ((cpi.hba_inquiry & PI_TAG_ABLE) == 0 52168b8a9b1dSJustin T. Gibbs || (inq_data->flags & SID_CmdQue) == 0 52178b8a9b1dSJustin T. Gibbs || (device->queue_flags & SCP_QUEUE_DQUE) != 0 52188b8a9b1dSJustin T. Gibbs || (device->quirk->mintags == 0)) { 52198b8a9b1dSJustin T. Gibbs /* 52208b8a9b1dSJustin T. Gibbs * Can't tag on hardware that doesn't support, 52218b8a9b1dSJustin T. Gibbs * doesn't have it enabled, or has broken tag support. 52228b8a9b1dSJustin T. Gibbs */ 52238b8a9b1dSJustin T. Gibbs cts->flags &= ~CCB_TRANS_TAG_ENB; 52248b8a9b1dSJustin T. Gibbs } 52258b8a9b1dSJustin T. Gibbs } 52268b8a9b1dSJustin T. Gibbs 52278b8a9b1dSJustin T. Gibbs /* 52288b8a9b1dSJustin T. Gibbs * If we are transitioning from tags to no-tags or 52298b8a9b1dSJustin T. Gibbs * vice-versa, we need to carefully freeze and restart 52308b8a9b1dSJustin T. Gibbs * the queue so that we don't overlap tagged and non-tagged 52318b8a9b1dSJustin T. Gibbs * commands. 52328b8a9b1dSJustin T. Gibbs */ 52338b8a9b1dSJustin T. Gibbs if ((cts->valid & CCB_TRANS_TQ_VALID) != 0 52348b8a9b1dSJustin T. Gibbs && (((cts->flags & CCB_TRANS_TAG_ENB) != 0 52358b8a9b1dSJustin T. Gibbs && (device->inq_flags & SID_CmdQue) == 0) 52368b8a9b1dSJustin T. Gibbs || ((cts->flags & CCB_TRANS_TAG_ENB) == 0 52378b8a9b1dSJustin T. Gibbs && (device->inq_flags & SID_CmdQue) != 0))) { 52388b8a9b1dSJustin T. Gibbs int newopenings; 52398b8a9b1dSJustin T. Gibbs 52408b8a9b1dSJustin T. Gibbs xpt_freeze_devq(cts->ccb_h.path, /*count*/1); 52418b8a9b1dSJustin T. Gibbs qfrozen = TRUE; 52428b8a9b1dSJustin T. Gibbs 52438b8a9b1dSJustin T. Gibbs if ((cts->flags & CCB_TRANS_TAG_ENB) != 0) { 52448b8a9b1dSJustin T. Gibbs newopenings = min(device->quirk->maxtags, 52458b8a9b1dSJustin T. Gibbs sim->max_tagged_dev_openings); 52468b8a9b1dSJustin T. Gibbs device->inq_flags |= SID_CmdQue; 52478b8a9b1dSJustin T. Gibbs } else { 52488b8a9b1dSJustin T. Gibbs newopenings = sim->max_dev_openings; 52498b8a9b1dSJustin T. Gibbs device->inq_flags &= ~SID_CmdQue; 52508b8a9b1dSJustin T. Gibbs } 52518b8a9b1dSJustin T. Gibbs xpt_dev_ccbq_resize(cts->ccb_h.path, newopenings); 52528b8a9b1dSJustin T. Gibbs } else { 52538b8a9b1dSJustin T. Gibbs qfrozen = FALSE; 52548b8a9b1dSJustin T. Gibbs } 52558b8a9b1dSJustin T. Gibbs 52568b8a9b1dSJustin T. Gibbs if (async_update == FALSE) 52578b8a9b1dSJustin T. Gibbs (*(sim->sim_action))(sim, (union ccb *)cts); 52588b8a9b1dSJustin T. Gibbs 52598b8a9b1dSJustin T. Gibbs if (qfrozen) { 52608b8a9b1dSJustin T. Gibbs struct ccb_relsim crs; 52618b8a9b1dSJustin T. Gibbs 52628b8a9b1dSJustin T. Gibbs xpt_setup_ccb(&crs.ccb_h, cts->ccb_h.path, 52638b8a9b1dSJustin T. Gibbs /*priority*/1); 52648b8a9b1dSJustin T. Gibbs crs.ccb_h.func_code = XPT_REL_SIMQ; 52658b8a9b1dSJustin T. Gibbs crs.release_flags = RELSIM_RELEASE_AFTER_QEMPTY; 52668b8a9b1dSJustin T. Gibbs crs.openings 52678b8a9b1dSJustin T. Gibbs = crs.release_timeout 52688b8a9b1dSJustin T. Gibbs = crs.qfrozen_cnt 52698b8a9b1dSJustin T. Gibbs = 0; 52708b8a9b1dSJustin T. Gibbs xpt_action((union ccb *)&crs); 52718b8a9b1dSJustin T. Gibbs } 52728b8a9b1dSJustin T. Gibbs } 52738b8a9b1dSJustin T. Gibbs 52748b8a9b1dSJustin T. Gibbs static int busses_to_config; 52758b8a9b1dSJustin T. Gibbs 52768b8a9b1dSJustin T. Gibbs static int 52778b8a9b1dSJustin T. Gibbs xptconfigbuscountfunc(struct cam_eb *bus, void *arg) 52788b8a9b1dSJustin T. Gibbs { 52798b8a9b1dSJustin T. Gibbs if (bus->path_id != CAM_XPT_PATH_ID) 52808b8a9b1dSJustin T. Gibbs busses_to_config++; 52818b8a9b1dSJustin T. Gibbs 52828b8a9b1dSJustin T. Gibbs return(1); 52838b8a9b1dSJustin T. Gibbs } 52848b8a9b1dSJustin T. Gibbs 52858b8a9b1dSJustin T. Gibbs static int 52868b8a9b1dSJustin T. Gibbs xptconfigfunc(struct cam_eb *bus, void *arg) 52878b8a9b1dSJustin T. Gibbs { 52888b8a9b1dSJustin T. Gibbs struct cam_path *path; 52898b8a9b1dSJustin T. Gibbs union ccb *work_ccb; 52908b8a9b1dSJustin T. Gibbs 52918b8a9b1dSJustin T. Gibbs if (bus->path_id != CAM_XPT_PATH_ID) { 52928b8a9b1dSJustin T. Gibbs cam_status status; 52938b8a9b1dSJustin T. Gibbs 52948b8a9b1dSJustin T. Gibbs work_ccb = xpt_alloc_ccb(); 52958b8a9b1dSJustin T. Gibbs if ((status = xpt_create_path(&path, xpt_periph, bus->path_id, 52968b8a9b1dSJustin T. Gibbs CAM_TARGET_WILDCARD, 52978b8a9b1dSJustin T. Gibbs CAM_LUN_WILDCARD)) !=CAM_REQ_CMP){ 52988b8a9b1dSJustin T. Gibbs printf("xptconfigfunc: xpt_create_path failed with " 52998b8a9b1dSJustin T. Gibbs "status %#x for bus %d\n", status, bus->path_id); 53008b8a9b1dSJustin T. Gibbs printf("xptconfigfunc: halting bus configuration\n"); 53018b8a9b1dSJustin T. Gibbs xpt_free_ccb(work_ccb); 53028b8a9b1dSJustin T. Gibbs return(0); 53038b8a9b1dSJustin T. Gibbs } 53048b8a9b1dSJustin T. Gibbs xpt_setup_ccb(&work_ccb->ccb_h, path, /*priority*/1); 53058b8a9b1dSJustin T. Gibbs work_ccb->ccb_h.func_code = XPT_RESET_BUS; 53068b8a9b1dSJustin T. Gibbs work_ccb->ccb_h.cbfcnp = NULL; 53078b8a9b1dSJustin T. Gibbs CAM_DEBUG(path, CAM_DEBUG_SUBTRACE, 53088b8a9b1dSJustin T. Gibbs ("Resetting Bus\n")); 53098b8a9b1dSJustin T. Gibbs xpt_action(work_ccb); 53108b8a9b1dSJustin T. Gibbs xpt_finishconfig(xpt_periph, work_ccb); 53118b8a9b1dSJustin T. Gibbs } 53128b8a9b1dSJustin T. Gibbs 53138b8a9b1dSJustin T. Gibbs return(1); 53148b8a9b1dSJustin T. Gibbs 53158b8a9b1dSJustin T. Gibbs } 53168b8a9b1dSJustin T. Gibbs 53178b8a9b1dSJustin T. Gibbs static void 53188b8a9b1dSJustin T. Gibbs xpt_config(void *arg) 53198b8a9b1dSJustin T. Gibbs { 53208b8a9b1dSJustin T. Gibbs /* Now that interrupts are enabled, go find our devices */ 53218b8a9b1dSJustin T. Gibbs struct cam_eb *bus; 53228b8a9b1dSJustin T. Gibbs 53238b8a9b1dSJustin T. Gibbs #ifdef CAMDEBUG 53248b8a9b1dSJustin T. Gibbs /* Setup debugging flags and path */ 53258b8a9b1dSJustin T. Gibbs #ifdef CAM_DEBUG_FLAGS 53268b8a9b1dSJustin T. Gibbs cam_dflags = CAM_DEBUG_FLAGS; 53278b8a9b1dSJustin T. Gibbs #else /* !CAM_DEBUG_FLAGS */ 53288b8a9b1dSJustin T. Gibbs cam_dflags = CAM_DEBUG_NONE; 53298b8a9b1dSJustin T. Gibbs #endif /* CAM_DEBUG_FLAGS */ 53308b8a9b1dSJustin T. Gibbs #ifdef CAM_DEBUG_BUS 53318b8a9b1dSJustin T. Gibbs if (cam_dflags != CAM_DEBUG_NONE) { 53328b8a9b1dSJustin T. Gibbs if (xpt_create_path(&cam_dpath, xpt_periph, 53338b8a9b1dSJustin T. Gibbs CAM_DEBUG_BUS, CAM_DEBUG_TARGET, 53348b8a9b1dSJustin T. Gibbs CAM_DEBUG_LUN) != CAM_REQ_CMP) { 53358b8a9b1dSJustin T. Gibbs printf("xpt_config: xpt_create_path() failed for debug" 53368b8a9b1dSJustin T. Gibbs " target %d:%d:%d, debugging disabled\n", 53378b8a9b1dSJustin T. Gibbs CAM_DEBUG_BUS, CAM_DEBUG_TARGET, CAM_DEBUG_LUN); 53388b8a9b1dSJustin T. Gibbs cam_dflags = CAM_DEBUG_NONE; 53398b8a9b1dSJustin T. Gibbs } 53408b8a9b1dSJustin T. Gibbs } else 53418b8a9b1dSJustin T. Gibbs cam_dpath = NULL; 53428b8a9b1dSJustin T. Gibbs #else /* !CAM_DEBUG_BUS */ 53438b8a9b1dSJustin T. Gibbs cam_dpath = NULL; 53448b8a9b1dSJustin T. Gibbs #endif /* CAM_DEBUG_BUS */ 53458b8a9b1dSJustin T. Gibbs #endif /* CAMDEBUG */ 53468b8a9b1dSJustin T. Gibbs 53478b8a9b1dSJustin T. Gibbs /* Scan all installed busses */ 53488b8a9b1dSJustin T. Gibbs xpt_for_all_busses(xptconfigbuscountfunc, NULL); 53498b8a9b1dSJustin T. Gibbs 53508b8a9b1dSJustin T. Gibbs xpt_for_all_busses(xptconfigfunc, NULL); 53518b8a9b1dSJustin T. Gibbs 53528b8a9b1dSJustin T. Gibbs /* Call xpt_finishconfig once in case we dodn't have any busses */ 53538b8a9b1dSJustin T. Gibbs xpt_finishconfig(xpt_periph, NULL); 53548b8a9b1dSJustin T. Gibbs } 53558b8a9b1dSJustin T. Gibbs 53568b8a9b1dSJustin T. Gibbs static int 53578b8a9b1dSJustin T. Gibbs xptfinishconfigfunc(struct cam_ed *device, void *arg) 53588b8a9b1dSJustin T. Gibbs { 53598b8a9b1dSJustin T. Gibbs union ccb *done_ccb; 53608b8a9b1dSJustin T. Gibbs cam_status status; 53618b8a9b1dSJustin T. Gibbs 53628b8a9b1dSJustin T. Gibbs done_ccb = (union ccb *)arg; 53638b8a9b1dSJustin T. Gibbs 53648b8a9b1dSJustin T. Gibbs if ((status = xpt_create_path(&done_ccb->ccb_h.path, 53658b8a9b1dSJustin T. Gibbs xpt_periph, device->target->bus->path_id, 53668b8a9b1dSJustin T. Gibbs device->target->target_id, 53678b8a9b1dSJustin T. Gibbs device->lun_id)) != CAM_REQ_CMP) { 53688b8a9b1dSJustin T. Gibbs printf("xptfinishconfig: xpt_create_path failed with status" 53695ee58402SJustin T. Gibbs " %#x, halting bus configuration\n", status); 53708b8a9b1dSJustin T. Gibbs return(0); 53718b8a9b1dSJustin T. Gibbs } 53728b8a9b1dSJustin T. Gibbs 53738b8a9b1dSJustin T. Gibbs xpt_setup_ccb(&done_ccb->ccb_h, 53748b8a9b1dSJustin T. Gibbs done_ccb->ccb_h.path, 53758b8a9b1dSJustin T. Gibbs /*priority*/1); 53768b8a9b1dSJustin T. Gibbs 53778b8a9b1dSJustin T. Gibbs done_ccb->ccb_h.func_code = XPT_GDEV_TYPE; 53788b8a9b1dSJustin T. Gibbs xpt_action(done_ccb); 53798b8a9b1dSJustin T. Gibbs xpt_async(AC_FOUND_DEVICE, done_ccb->ccb_h.path, done_ccb); 53808b8a9b1dSJustin T. Gibbs 53818b8a9b1dSJustin T. Gibbs return(1); 53828b8a9b1dSJustin T. Gibbs } 53838b8a9b1dSJustin T. Gibbs 53848b8a9b1dSJustin T. Gibbs /* 53858b8a9b1dSJustin T. Gibbs * If the given device only has one peripheral attached to it, and if that 53868b8a9b1dSJustin T. Gibbs * peripheral is the passthrough driver, announce it. This insures that the 53878b8a9b1dSJustin T. Gibbs * user sees some sort of announcement for every peripheral in their system. 53888b8a9b1dSJustin T. Gibbs */ 53898b8a9b1dSJustin T. Gibbs static int 53908b8a9b1dSJustin T. Gibbs xptpassannouncefunc(struct cam_ed *device, void *arg) 53918b8a9b1dSJustin T. Gibbs { 53928b8a9b1dSJustin T. Gibbs struct cam_periph *periph; 53938b8a9b1dSJustin T. Gibbs int i; 53948b8a9b1dSJustin T. Gibbs 53958b8a9b1dSJustin T. Gibbs for (periph = SLIST_FIRST(&device->periphs), i = 0; periph != NULL; 53968b8a9b1dSJustin T. Gibbs periph = SLIST_NEXT(periph, periph_links), i++); 53978b8a9b1dSJustin T. Gibbs 53988b8a9b1dSJustin T. Gibbs periph = SLIST_FIRST(&device->periphs); 53998b8a9b1dSJustin T. Gibbs if ((i == 1) 54008b8a9b1dSJustin T. Gibbs && (strncmp(periph->periph_name, "pass", 4) == 0)) 54018b8a9b1dSJustin T. Gibbs xpt_announce_periph(periph, NULL); 54028b8a9b1dSJustin T. Gibbs 54038b8a9b1dSJustin T. Gibbs return(1); 54048b8a9b1dSJustin T. Gibbs } 54058b8a9b1dSJustin T. Gibbs 54068b8a9b1dSJustin T. Gibbs static void 54078b8a9b1dSJustin T. Gibbs xpt_finishconfig(struct cam_periph *periph, union ccb *done_ccb) 54088b8a9b1dSJustin T. Gibbs { 54098b8a9b1dSJustin T. Gibbs struct periph_driver **p_drv; 54108b8a9b1dSJustin T. Gibbs struct cam_eb *bus; 54118b8a9b1dSJustin T. Gibbs struct cam_et *target; 54128b8a9b1dSJustin T. Gibbs struct cam_ed *dev; 54138b8a9b1dSJustin T. Gibbs struct cam_periph *nperiph; 54148b8a9b1dSJustin T. Gibbs struct periph_list *periph_head; 54158b8a9b1dSJustin T. Gibbs int i; 54168b8a9b1dSJustin T. Gibbs 54178b8a9b1dSJustin T. Gibbs if (done_ccb != NULL) { 54188b8a9b1dSJustin T. Gibbs CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_TRACE, 54198b8a9b1dSJustin T. Gibbs ("xpt_finishconfig\n")); 54208b8a9b1dSJustin T. Gibbs switch(done_ccb->ccb_h.func_code) { 54218b8a9b1dSJustin T. Gibbs case XPT_RESET_BUS: 54228b8a9b1dSJustin T. Gibbs if (done_ccb->ccb_h.status == CAM_REQ_CMP) { 54238b8a9b1dSJustin T. Gibbs done_ccb->ccb_h.func_code = XPT_SCAN_BUS; 54248b8a9b1dSJustin T. Gibbs done_ccb->ccb_h.cbfcnp = xpt_finishconfig; 54258b8a9b1dSJustin T. Gibbs xpt_action(done_ccb); 54268b8a9b1dSJustin T. Gibbs return; 54278b8a9b1dSJustin T. Gibbs } 54288b8a9b1dSJustin T. Gibbs /* FALLTHROUGH */ 54298b8a9b1dSJustin T. Gibbs case XPT_SCAN_BUS: 54308b8a9b1dSJustin T. Gibbs xpt_free_path(done_ccb->ccb_h.path); 54318b8a9b1dSJustin T. Gibbs busses_to_config--; 54328b8a9b1dSJustin T. Gibbs break; 54338b8a9b1dSJustin T. Gibbs default: 54348b8a9b1dSJustin T. Gibbs break; 54358b8a9b1dSJustin T. Gibbs } 54368b8a9b1dSJustin T. Gibbs } 54378b8a9b1dSJustin T. Gibbs 54388b8a9b1dSJustin T. Gibbs if (busses_to_config == 0) { 54398b8a9b1dSJustin T. Gibbs /* Register all the peripheral drivers */ 54408b8a9b1dSJustin T. Gibbs /* XXX This will have to change when we have LKMs */ 54418b8a9b1dSJustin T. Gibbs p_drv = (struct periph_driver **)periphdriver_set.ls_items; 54428b8a9b1dSJustin T. Gibbs for (i = 0; p_drv[i] != NULL; i++) { 54438b8a9b1dSJustin T. Gibbs (*p_drv[i]->init)(); 54448b8a9b1dSJustin T. Gibbs } 54458b8a9b1dSJustin T. Gibbs 54468b8a9b1dSJustin T. Gibbs /* 54478b8a9b1dSJustin T. Gibbs * Itterate through our devices announcing 54488b8a9b1dSJustin T. Gibbs * them in probed bus order. 54498b8a9b1dSJustin T. Gibbs */ 54508b8a9b1dSJustin T. Gibbs xpt_for_all_devices(xptfinishconfigfunc, done_ccb); 54518b8a9b1dSJustin T. Gibbs 54528b8a9b1dSJustin T. Gibbs /* 54538b8a9b1dSJustin T. Gibbs * Check for devices with no "standard" peripheral driver 54548b8a9b1dSJustin T. Gibbs * attached. For any devices like that, announce the 54558b8a9b1dSJustin T. Gibbs * passthrough driver so the user will see something. 54568b8a9b1dSJustin T. Gibbs */ 54578b8a9b1dSJustin T. Gibbs xpt_for_all_devices(xptpassannouncefunc, NULL); 54588b8a9b1dSJustin T. Gibbs 54598b8a9b1dSJustin T. Gibbs /* Release our hook so that the boot can continue. */ 54608b8a9b1dSJustin T. Gibbs config_intrhook_disestablish(xpt_config_hook); 54618b8a9b1dSJustin T. Gibbs } 54628b8a9b1dSJustin T. Gibbs if (done_ccb != NULL) 54638b8a9b1dSJustin T. Gibbs xpt_free_ccb(done_ccb); 54648b8a9b1dSJustin T. Gibbs } 54658b8a9b1dSJustin T. Gibbs 54668b8a9b1dSJustin T. Gibbs static void 54678b8a9b1dSJustin T. Gibbs xptaction(struct cam_sim *sim, union ccb *work_ccb) 54688b8a9b1dSJustin T. Gibbs { 54698b8a9b1dSJustin T. Gibbs CAM_DEBUG(work_ccb->ccb_h.path, CAM_DEBUG_TRACE, ("xptaction\n")); 54708b8a9b1dSJustin T. Gibbs 54718b8a9b1dSJustin T. Gibbs switch (work_ccb->ccb_h.func_code) { 54728b8a9b1dSJustin T. Gibbs /* Common cases first */ 54738b8a9b1dSJustin T. Gibbs case XPT_PATH_INQ: /* Path routing inquiry */ 54748b8a9b1dSJustin T. Gibbs { 54758b8a9b1dSJustin T. Gibbs struct ccb_pathinq *cpi; 54768b8a9b1dSJustin T. Gibbs 54778b8a9b1dSJustin T. Gibbs cpi = &work_ccb->cpi; 54788b8a9b1dSJustin T. Gibbs cpi->version_num = 1; /* XXX??? */ 54798b8a9b1dSJustin T. Gibbs cpi->hba_inquiry = 0; 54808b8a9b1dSJustin T. Gibbs cpi->target_sprt = 0; 54818b8a9b1dSJustin T. Gibbs cpi->hba_misc = 0; 54828b8a9b1dSJustin T. Gibbs cpi->hba_eng_cnt = 0; 54838b8a9b1dSJustin T. Gibbs cpi->max_target = 0; 54848b8a9b1dSJustin T. Gibbs cpi->max_lun = 0; 54858b8a9b1dSJustin T. Gibbs cpi->initiator_id = 0; 54868b8a9b1dSJustin T. Gibbs strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN); 54878b8a9b1dSJustin T. Gibbs strncpy(cpi->hba_vid, "", HBA_IDLEN); 54888b8a9b1dSJustin T. Gibbs strncpy(cpi->dev_name, sim->sim_name, DEV_IDLEN); 54898b8a9b1dSJustin T. Gibbs cpi->unit_number = sim->unit_number; 54908b8a9b1dSJustin T. Gibbs cpi->bus_id = sim->bus_id; 54918b8a9b1dSJustin T. Gibbs cpi->ccb_h.status = CAM_REQ_CMP; 54928b8a9b1dSJustin T. Gibbs xpt_done(work_ccb); 54938b8a9b1dSJustin T. Gibbs break; 54948b8a9b1dSJustin T. Gibbs } 54958b8a9b1dSJustin T. Gibbs default: 54968b8a9b1dSJustin T. Gibbs work_ccb->ccb_h.status = CAM_REQ_INVALID; 54978b8a9b1dSJustin T. Gibbs xpt_done(work_ccb); 54988b8a9b1dSJustin T. Gibbs break; 54998b8a9b1dSJustin T. Gibbs } 55008b8a9b1dSJustin T. Gibbs } 55018b8a9b1dSJustin T. Gibbs 55028b8a9b1dSJustin T. Gibbs /* 55038b8a9b1dSJustin T. Gibbs * Should only be called by the machine interrupt dispatch routines, 55048b8a9b1dSJustin T. Gibbs * so put these prototypes here instead of in the header. 55058b8a9b1dSJustin T. Gibbs * 55068b8a9b1dSJustin T. Gibbs * XXX we should really have a way to dynamically register SWI handlers. 55078b8a9b1dSJustin T. Gibbs */ 55088b8a9b1dSJustin T. Gibbs 55098b8a9b1dSJustin T. Gibbs void 55108b8a9b1dSJustin T. Gibbs swi_camnet() 55118b8a9b1dSJustin T. Gibbs { 55128b8a9b1dSJustin T. Gibbs camisr(&cam_netq); 55138b8a9b1dSJustin T. Gibbs } 55148b8a9b1dSJustin T. Gibbs 55158b8a9b1dSJustin T. Gibbs void 55168b8a9b1dSJustin T. Gibbs swi_cambio() 55178b8a9b1dSJustin T. Gibbs { 55188b8a9b1dSJustin T. Gibbs camisr(&cam_bioq); 55198b8a9b1dSJustin T. Gibbs } 55208b8a9b1dSJustin T. Gibbs 55218b8a9b1dSJustin T. Gibbs static void 55228b8a9b1dSJustin T. Gibbs camisr(cam_isrq_t *queue) 55238b8a9b1dSJustin T. Gibbs { 55248b8a9b1dSJustin T. Gibbs int s; 55258b8a9b1dSJustin T. Gibbs struct ccb_hdr *ccb_h; 55268b8a9b1dSJustin T. Gibbs 55278b8a9b1dSJustin T. Gibbs s = splcam(); 55288b8a9b1dSJustin T. Gibbs while ((ccb_h = TAILQ_FIRST(queue)) != NULL) { 55298b8a9b1dSJustin T. Gibbs int runq; 55308b8a9b1dSJustin T. Gibbs 55318b8a9b1dSJustin T. Gibbs TAILQ_REMOVE(queue, ccb_h, sim_links.tqe); 55328b8a9b1dSJustin T. Gibbs ccb_h->pinfo.index = CAM_UNQUEUED_INDEX; 55338b8a9b1dSJustin T. Gibbs splx(s); 55348b8a9b1dSJustin T. Gibbs 55358b8a9b1dSJustin T. Gibbs CAM_DEBUG(ccb_h->path, CAM_DEBUG_TRACE, 55368b8a9b1dSJustin T. Gibbs ("camisr")); 55378b8a9b1dSJustin T. Gibbs 55388b8a9b1dSJustin T. Gibbs runq = FALSE; 55398b8a9b1dSJustin T. Gibbs 55408b8a9b1dSJustin T. Gibbs if (ccb_h->flags & CAM_HIGH_POWER) { 55418b8a9b1dSJustin T. Gibbs struct highpowerlist *hphead; 55428b8a9b1dSJustin T. Gibbs struct cam_ed *device; 55438b8a9b1dSJustin T. Gibbs union ccb *send_ccb; 55448b8a9b1dSJustin T. Gibbs 55458b8a9b1dSJustin T. Gibbs hphead = &highpowerq; 55468b8a9b1dSJustin T. Gibbs 55478b8a9b1dSJustin T. Gibbs send_ccb = (union ccb *)STAILQ_FIRST(hphead); 55488b8a9b1dSJustin T. Gibbs 55498b8a9b1dSJustin T. Gibbs /* 55508b8a9b1dSJustin T. Gibbs * Increment the count since this command is done. 55518b8a9b1dSJustin T. Gibbs */ 55528b8a9b1dSJustin T. Gibbs num_highpower++; 55538b8a9b1dSJustin T. Gibbs 55548b8a9b1dSJustin T. Gibbs /* 55558b8a9b1dSJustin T. Gibbs * Any high powered commands queued up? 55568b8a9b1dSJustin T. Gibbs */ 55578b8a9b1dSJustin T. Gibbs if (send_ccb != NULL) { 55588b8a9b1dSJustin T. Gibbs device = send_ccb->ccb_h.path->device; 55598b8a9b1dSJustin T. Gibbs 55608b8a9b1dSJustin T. Gibbs STAILQ_REMOVE_HEAD(hphead, xpt_links.stqe); 55618b8a9b1dSJustin T. Gibbs 55628b8a9b1dSJustin T. Gibbs xpt_release_devq(send_ccb->ccb_h.path->device, 55638b8a9b1dSJustin T. Gibbs TRUE); 55648b8a9b1dSJustin T. Gibbs } 55658b8a9b1dSJustin T. Gibbs } 55668b8a9b1dSJustin T. Gibbs if ((ccb_h->func_code != XPT_ACCEPT_TARGET_IO) 55678b8a9b1dSJustin T. Gibbs && (ccb_h->func_code != XPT_SCAN_LUN) 55688b8a9b1dSJustin T. Gibbs && (ccb_h->func_code != XPT_SCAN_BUS)) { 55698b8a9b1dSJustin T. Gibbs struct cam_ed *dev; 55708b8a9b1dSJustin T. Gibbs 55718b8a9b1dSJustin T. Gibbs dev = ccb_h->path->device; 55728b8a9b1dSJustin T. Gibbs 55738b8a9b1dSJustin T. Gibbs s = splcam(); 55748b8a9b1dSJustin T. Gibbs cam_ccbq_ccb_done(&dev->ccbq, (union ccb *)ccb_h); 55758b8a9b1dSJustin T. Gibbs 55768b8a9b1dSJustin T. Gibbs ccb_h->path->bus->sim->devq->send_active--; 55778b8a9b1dSJustin T. Gibbs ccb_h->path->bus->sim->devq->send_openings++; 55788b8a9b1dSJustin T. Gibbs splx(s); 55798b8a9b1dSJustin T. Gibbs 55808b8a9b1dSJustin T. Gibbs if ((dev->flags & CAM_DEV_REL_ON_COMPLETE) != 0 55818b8a9b1dSJustin T. Gibbs || ((dev->flags & CAM_DEV_REL_ON_QUEUE_EMPTY) != 0 55828b8a9b1dSJustin T. Gibbs && (dev->ccbq.dev_active == 0))) { 55838b8a9b1dSJustin T. Gibbs 55848b8a9b1dSJustin T. Gibbs xpt_release_devq(ccb_h->path->device, 55858b8a9b1dSJustin T. Gibbs /*run_queue*/TRUE); 55868b8a9b1dSJustin T. Gibbs } 55878b8a9b1dSJustin T. Gibbs 55888b8a9b1dSJustin T. Gibbs if ((dev->ccbq.queue.entries > 0) 55898b8a9b1dSJustin T. Gibbs && (dev->qfrozen_cnt == 0) 55908b8a9b1dSJustin T. Gibbs && (device_is_send_queued(dev) == 0)) { 55918b8a9b1dSJustin T. Gibbs runq = xpt_schedule_dev_sendq(ccb_h->path->bus, 55928b8a9b1dSJustin T. Gibbs dev); 55938b8a9b1dSJustin T. Gibbs } 55948b8a9b1dSJustin T. Gibbs } 55958b8a9b1dSJustin T. Gibbs 55968b8a9b1dSJustin T. Gibbs if (ccb_h->status & CAM_RELEASE_SIMQ) { 55978b8a9b1dSJustin T. Gibbs xpt_release_simq(ccb_h->path->bus->sim, 55988b8a9b1dSJustin T. Gibbs /*run_queue*/TRUE); 55998b8a9b1dSJustin T. Gibbs } else if ((ccb_h->flags & CAM_DEV_QFRZDIS) 56008b8a9b1dSJustin T. Gibbs && (ccb_h->status & CAM_DEV_QFRZN)) { 56018b8a9b1dSJustin T. Gibbs xpt_release_devq(ccb_h->path->device, 56028b8a9b1dSJustin T. Gibbs /*run_queue*/TRUE); 56038b8a9b1dSJustin T. Gibbs ccb_h->status &= ~CAM_DEV_QFRZN; 56048b8a9b1dSJustin T. Gibbs } else if (runq) { 56058b8a9b1dSJustin T. Gibbs xpt_run_dev_sendq(ccb_h->path->bus); 56068b8a9b1dSJustin T. Gibbs } 56078b8a9b1dSJustin T. Gibbs 56088b8a9b1dSJustin T. Gibbs /* Call the peripheral driver's callback */ 56098b8a9b1dSJustin T. Gibbs (*ccb_h->cbfcnp)(ccb_h->path->periph, 56108b8a9b1dSJustin T. Gibbs (union ccb *)ccb_h); 56118b8a9b1dSJustin T. Gibbs 56128b8a9b1dSJustin T. Gibbs /* Raise IPL for while test */ 56138b8a9b1dSJustin T. Gibbs s = splcam(); 56148b8a9b1dSJustin T. Gibbs } 56158b8a9b1dSJustin T. Gibbs splx(s); 56168b8a9b1dSJustin T. Gibbs } 5617