1898b0535SWarner Losh /*- 28b8a9b1dSJustin T. Gibbs * Implementation of the Common Access Method Transport (XPT) layer. 38b8a9b1dSJustin T. Gibbs * 4c8bead2aSJustin T. Gibbs * Copyright (c) 1997, 1998, 1999 Justin T. Gibbs. 559190eaaSKenneth D. Merry * Copyright (c) 1997, 1998, 1999 Kenneth D. Merry. 68b8a9b1dSJustin T. Gibbs * All rights reserved. 78b8a9b1dSJustin T. Gibbs * 88b8a9b1dSJustin T. Gibbs * Redistribution and use in source and binary forms, with or without 98b8a9b1dSJustin T. Gibbs * modification, are permitted provided that the following conditions 108b8a9b1dSJustin T. Gibbs * are met: 118b8a9b1dSJustin T. Gibbs * 1. Redistributions of source code must retain the above copyright 128b8a9b1dSJustin T. Gibbs * notice, this list of conditions, and the following disclaimer, 138b8a9b1dSJustin T. Gibbs * without modification, immediately at the beginning of the file. 148b8a9b1dSJustin T. Gibbs * 2. The name of the author may not be used to endorse or promote products 158b8a9b1dSJustin T. Gibbs * derived from this software without specific prior written permission. 168b8a9b1dSJustin T. Gibbs * 178b8a9b1dSJustin T. Gibbs * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 188b8a9b1dSJustin T. Gibbs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 198b8a9b1dSJustin T. Gibbs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 208b8a9b1dSJustin T. Gibbs * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 218b8a9b1dSJustin T. Gibbs * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 228b8a9b1dSJustin T. Gibbs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 238b8a9b1dSJustin T. Gibbs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 248b8a9b1dSJustin T. Gibbs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 258b8a9b1dSJustin T. Gibbs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 268b8a9b1dSJustin T. Gibbs * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 278b8a9b1dSJustin T. Gibbs * SUCH DAMAGE. 288b8a9b1dSJustin T. Gibbs */ 299c963d87SDavid E. O'Brien 309c963d87SDavid E. O'Brien #include <sys/cdefs.h> 319c963d87SDavid E. O'Brien __FBSDID("$FreeBSD$"); 329c963d87SDavid E. O'Brien 338b8a9b1dSJustin T. Gibbs #include <sys/param.h> 349a94c9c5SJohn Baldwin #include <sys/bus.h> 358b8a9b1dSJustin T. Gibbs #include <sys/systm.h> 368b8a9b1dSJustin T. Gibbs #include <sys/types.h> 378b8a9b1dSJustin T. Gibbs #include <sys/malloc.h> 388b8a9b1dSJustin T. Gibbs #include <sys/kernel.h> 3987cfaf0eSJustin T. Gibbs #include <sys/time.h> 408b8a9b1dSJustin T. Gibbs #include <sys/conf.h> 418b8a9b1dSJustin T. Gibbs #include <sys/fcntl.h> 428b8a9b1dSJustin T. Gibbs #include <sys/md5.h> 435d754af7SMatt Jacob #include <sys/interrupt.h> 443393f8daSKenneth D. Merry #include <sys/sbuf.h> 452b83592fSScott Long #include <sys/taskqueue.h> 468b8a9b1dSJustin T. Gibbs 47ef3cf714SScott Long #include <sys/lock.h> 48ef3cf714SScott Long #include <sys/mutex.h> 493b87a552SMatt Jacob #include <sys/sysctl.h> 509e6461a2SMatt Jacob #include <sys/kthread.h> 51ef3cf714SScott Long 528b8a9b1dSJustin T. Gibbs #ifdef PC98 538b8a9b1dSJustin T. Gibbs #include <pc98/pc98/pc98_machdep.h> /* geometry translation */ 548b8a9b1dSJustin T. Gibbs #endif 558b8a9b1dSJustin T. Gibbs 568b8a9b1dSJustin T. Gibbs #include <cam/cam.h> 578b8a9b1dSJustin T. Gibbs #include <cam/cam_ccb.h> 588b8a9b1dSJustin T. Gibbs #include <cam/cam_periph.h> 598b8a9b1dSJustin T. Gibbs #include <cam/cam_sim.h> 608b8a9b1dSJustin T. Gibbs #include <cam/cam_xpt.h> 618b8a9b1dSJustin T. Gibbs #include <cam/cam_xpt_sim.h> 628b8a9b1dSJustin T. Gibbs #include <cam/cam_xpt_periph.h> 638b8a9b1dSJustin T. Gibbs #include <cam/cam_debug.h> 648b8a9b1dSJustin T. Gibbs 658b8a9b1dSJustin T. Gibbs #include <cam/scsi/scsi_all.h> 668b8a9b1dSJustin T. Gibbs #include <cam/scsi/scsi_message.h> 678b8a9b1dSJustin T. Gibbs #include <cam/scsi/scsi_pass.h> 68f0d9af51SMatt Jacob #include <machine/stdarg.h> /* for xpt_print below */ 698b8a9b1dSJustin T. Gibbs #include "opt_cam.h" 708b8a9b1dSJustin T. Gibbs 718b8a9b1dSJustin T. Gibbs /* Datastructures internal to the xpt layer */ 72362abc44STai-hwa Liang MALLOC_DEFINE(M_CAMXPT, "CAM XPT", "CAM XPT buffers"); 738b8a9b1dSJustin T. Gibbs 742b83592fSScott Long /* Object for defering XPT actions to a taskqueue */ 752b83592fSScott Long struct xpt_task { 762b83592fSScott Long struct task task; 7784f82481SScott Long void *data1; 7884f82481SScott Long uintptr_t data2; 792b83592fSScott Long }; 802b83592fSScott Long 818b8a9b1dSJustin T. Gibbs /* 828b8a9b1dSJustin T. Gibbs * Definition of an async handler callback block. These are used to add 838b8a9b1dSJustin T. Gibbs * SIMs and peripherals to the async callback lists. 848b8a9b1dSJustin T. Gibbs */ 858b8a9b1dSJustin T. Gibbs struct async_node { 86e3975643SJake Burkholder SLIST_ENTRY(async_node) links; 878b8a9b1dSJustin T. Gibbs u_int32_t event_enable; /* Async Event enables */ 888b8a9b1dSJustin T. Gibbs void (*callback)(void *arg, u_int32_t code, 898b8a9b1dSJustin T. Gibbs struct cam_path *path, void *args); 908b8a9b1dSJustin T. Gibbs void *callback_arg; 918b8a9b1dSJustin T. Gibbs }; 928b8a9b1dSJustin T. Gibbs 93e3975643SJake Burkholder SLIST_HEAD(async_list, async_node); 94e3975643SJake Burkholder SLIST_HEAD(periph_list, cam_periph); 958b8a9b1dSJustin T. Gibbs 968b8a9b1dSJustin T. Gibbs /* 978b8a9b1dSJustin T. Gibbs * This is the maximum number of high powered commands (e.g. start unit) 988b8a9b1dSJustin T. Gibbs * that can be outstanding at a particular time. 998b8a9b1dSJustin T. Gibbs */ 1008b8a9b1dSJustin T. Gibbs #ifndef CAM_MAX_HIGHPOWER 1018b8a9b1dSJustin T. Gibbs #define CAM_MAX_HIGHPOWER 4 1028b8a9b1dSJustin T. Gibbs #endif 1038b8a9b1dSJustin T. Gibbs 1048b8a9b1dSJustin T. Gibbs /* 1058b8a9b1dSJustin T. Gibbs * Structure for queueing a device in a run queue. 1068b8a9b1dSJustin T. Gibbs * There is one run queue for allocating new ccbs, 1078b8a9b1dSJustin T. Gibbs * and another for sending ccbs to the controller. 1088b8a9b1dSJustin T. Gibbs */ 1098b8a9b1dSJustin T. Gibbs struct cam_ed_qinfo { 1108b8a9b1dSJustin T. Gibbs cam_pinfo pinfo; 1118b8a9b1dSJustin T. Gibbs struct cam_ed *device; 1128b8a9b1dSJustin T. Gibbs }; 1138b8a9b1dSJustin T. Gibbs 1148b8a9b1dSJustin T. Gibbs /* 1158b8a9b1dSJustin T. Gibbs * The CAM EDT (Existing Device Table) contains the device information for 1168b8a9b1dSJustin T. Gibbs * all devices for all busses in the system. The table contains a 1178b8a9b1dSJustin T. Gibbs * cam_ed structure for each device on the bus. 1188b8a9b1dSJustin T. Gibbs */ 1198b8a9b1dSJustin T. Gibbs struct cam_ed { 120e3975643SJake Burkholder TAILQ_ENTRY(cam_ed) links; 1218b8a9b1dSJustin T. Gibbs struct cam_ed_qinfo alloc_ccb_entry; 1228b8a9b1dSJustin T. Gibbs struct cam_ed_qinfo send_ccb_entry; 1238b8a9b1dSJustin T. Gibbs struct cam_et *target; 1242b83592fSScott Long struct cam_sim *sim; 1258b8a9b1dSJustin T. Gibbs lun_id_t lun_id; 1268b8a9b1dSJustin T. Gibbs struct camq drvq; /* 1278b8a9b1dSJustin T. Gibbs * Queue of type drivers wanting to do 1288b8a9b1dSJustin T. Gibbs * work on this device. 1298b8a9b1dSJustin T. Gibbs */ 1308b8a9b1dSJustin T. Gibbs struct cam_ccbq ccbq; /* Queue of pending ccbs */ 1318b8a9b1dSJustin T. Gibbs struct async_list asyncs; /* Async callback info for this B/T/L */ 1328b8a9b1dSJustin T. Gibbs struct periph_list periphs; /* All attached devices */ 1338b8a9b1dSJustin T. Gibbs u_int generation; /* Generation number */ 1348b8a9b1dSJustin T. Gibbs struct cam_periph *owner; /* Peripheral driver's ownership tag */ 1358b8a9b1dSJustin T. Gibbs struct xpt_quirk_entry *quirk; /* Oddities about this device */ 1368b8a9b1dSJustin T. Gibbs /* Storage for the inquiry data */ 1373393f8daSKenneth D. Merry cam_proto protocol; 1383393f8daSKenneth D. Merry u_int protocol_version; 1393393f8daSKenneth D. Merry cam_xport transport; 1403393f8daSKenneth D. Merry u_int transport_version; 1418b8a9b1dSJustin T. Gibbs struct scsi_inquiry_data inq_data; 1428b8a9b1dSJustin T. Gibbs u_int8_t inq_flags; /* 1438b8a9b1dSJustin T. Gibbs * Current settings for inquiry flags. 1448b8a9b1dSJustin T. Gibbs * This allows us to override settings 1458b8a9b1dSJustin T. Gibbs * like disconnection and tagged 1468b8a9b1dSJustin T. Gibbs * queuing for a device. 1478b8a9b1dSJustin T. Gibbs */ 1488b8a9b1dSJustin T. Gibbs u_int8_t queue_flags; /* Queue flags from the control page */ 1498b8a9b1dSJustin T. Gibbs u_int8_t serial_num_len; 1509ec5d7cdSMatt Jacob u_int8_t *serial_num; 1518b8a9b1dSJustin T. Gibbs u_int32_t qfrozen_cnt; 1528b8a9b1dSJustin T. Gibbs u_int32_t flags; 1538b8a9b1dSJustin T. Gibbs #define CAM_DEV_UNCONFIGURED 0x01 1548b8a9b1dSJustin T. Gibbs #define CAM_DEV_REL_TIMEOUT_PENDING 0x02 1558b8a9b1dSJustin T. Gibbs #define CAM_DEV_REL_ON_COMPLETE 0x04 1568b8a9b1dSJustin T. Gibbs #define CAM_DEV_REL_ON_QUEUE_EMPTY 0x08 1578b8a9b1dSJustin T. Gibbs #define CAM_DEV_RESIZE_QUEUE_NEEDED 0x10 158fd21cc5eSJustin T. Gibbs #define CAM_DEV_TAG_AFTER_COUNT 0x20 15987cfaf0eSJustin T. Gibbs #define CAM_DEV_INQUIRY_DATA_VALID 0x40 1602afca7acSMatt Jacob #define CAM_DEV_IN_DV 0x80 1612afca7acSMatt Jacob #define CAM_DEV_DV_HIT_BOTTOM 0x100 162fd21cc5eSJustin T. Gibbs u_int32_t tag_delay_count; 163fd21cc5eSJustin T. Gibbs #define CAM_TAG_DELAY_COUNT 5 164df8f9080SJustin T. Gibbs u_int32_t tag_saved_openings; 1658b8a9b1dSJustin T. Gibbs u_int32_t refcount; 1662b83592fSScott Long struct callout callout; 1678b8a9b1dSJustin T. Gibbs }; 1688b8a9b1dSJustin T. Gibbs 1698b8a9b1dSJustin T. Gibbs /* 1708b8a9b1dSJustin T. Gibbs * Each target is represented by an ET (Existing Target). These 1718b8a9b1dSJustin T. Gibbs * entries are created when a target is successfully probed with an 1728b8a9b1dSJustin T. Gibbs * identify, and removed when a device fails to respond after a number 1738b8a9b1dSJustin T. Gibbs * of retries, or a bus rescan finds the device missing. 1748b8a9b1dSJustin T. Gibbs */ 1758b8a9b1dSJustin T. Gibbs struct cam_et { 176e3975643SJake Burkholder TAILQ_HEAD(, cam_ed) ed_entries; 177e3975643SJake Burkholder TAILQ_ENTRY(cam_et) links; 1788b8a9b1dSJustin T. Gibbs struct cam_eb *bus; 1798b8a9b1dSJustin T. Gibbs target_id_t target_id; 1808b8a9b1dSJustin T. Gibbs u_int32_t refcount; 1818b8a9b1dSJustin T. Gibbs u_int generation; 18287cfaf0eSJustin T. Gibbs struct timeval last_reset; 1838b8a9b1dSJustin T. Gibbs }; 1848b8a9b1dSJustin T. Gibbs 1858b8a9b1dSJustin T. Gibbs /* 1868b8a9b1dSJustin T. Gibbs * Each bus is represented by an EB (Existing Bus). These entries 1878b8a9b1dSJustin T. Gibbs * are created by calls to xpt_bus_register and deleted by calls to 1888b8a9b1dSJustin T. Gibbs * xpt_bus_deregister. 1898b8a9b1dSJustin T. Gibbs */ 1908b8a9b1dSJustin T. Gibbs struct cam_eb { 191e3975643SJake Burkholder TAILQ_HEAD(, cam_et) et_entries; 192e3975643SJake Burkholder TAILQ_ENTRY(cam_eb) links; 1938b8a9b1dSJustin T. Gibbs path_id_t path_id; 1948b8a9b1dSJustin T. Gibbs struct cam_sim *sim; 19587cfaf0eSJustin T. Gibbs struct timeval last_reset; 1968b8a9b1dSJustin T. Gibbs u_int32_t flags; 1978b8a9b1dSJustin T. Gibbs #define CAM_EB_RUNQ_SCHEDULED 0x01 198a5479bc5SJustin T. Gibbs u_int32_t refcount; 1998b8a9b1dSJustin T. Gibbs u_int generation; 200b50569b7SScott Long device_t parent_dev; 2018b8a9b1dSJustin T. Gibbs }; 2028b8a9b1dSJustin T. Gibbs 2038b8a9b1dSJustin T. Gibbs struct cam_path { 2048b8a9b1dSJustin T. Gibbs struct cam_periph *periph; 2058b8a9b1dSJustin T. Gibbs struct cam_eb *bus; 2068b8a9b1dSJustin T. Gibbs struct cam_et *target; 2078b8a9b1dSJustin T. Gibbs struct cam_ed *device; 2088b8a9b1dSJustin T. Gibbs }; 2098b8a9b1dSJustin T. Gibbs 2108b8a9b1dSJustin T. Gibbs struct xpt_quirk_entry { 2118b8a9b1dSJustin T. Gibbs struct scsi_inquiry_pattern inq_pat; 2128b8a9b1dSJustin T. Gibbs u_int8_t quirks; 2138b8a9b1dSJustin T. Gibbs #define CAM_QUIRK_NOLUNS 0x01 2148b8a9b1dSJustin T. Gibbs #define CAM_QUIRK_NOSERIAL 0x02 21548f6456dSMatt Jacob #define CAM_QUIRK_HILUNS 0x04 216f4322bc8SMatt Jacob #define CAM_QUIRK_NOHILUNS 0x08 2179deea857SKenneth D. Merry u_int mintags; 2189deea857SKenneth D. Merry u_int maxtags; 2198b8a9b1dSJustin T. Gibbs }; 2203b87a552SMatt Jacob 2213b87a552SMatt Jacob static int cam_srch_hi = 0; 2223b87a552SMatt Jacob TUNABLE_INT("kern.cam.cam_srch_hi", &cam_srch_hi); 2233b87a552SMatt Jacob static int sysctl_cam_search_luns(SYSCTL_HANDLER_ARGS); 2243b87a552SMatt Jacob SYSCTL_PROC(_kern_cam, OID_AUTO, cam_srch_hi, CTLTYPE_INT|CTLFLAG_RW, 0, 0, 2253b87a552SMatt Jacob sysctl_cam_search_luns, "I", 2263b87a552SMatt Jacob "allow search above LUN 7 for SCSI3 and greater devices"); 2273b87a552SMatt Jacob 22848f6456dSMatt Jacob #define CAM_SCSI2_MAXLUN 8 229f4322bc8SMatt Jacob /* 230f4322bc8SMatt Jacob * If we're not quirked to search <= the first 8 luns 231f4322bc8SMatt Jacob * and we are either quirked to search above lun 8, 2323b87a552SMatt Jacob * or we're > SCSI-2 and we've enabled hilun searching, 2333b87a552SMatt Jacob * or we're > SCSI-2 and the last lun was a success, 2343b87a552SMatt Jacob * we can look for luns above lun 8. 235f4322bc8SMatt Jacob */ 2363b87a552SMatt Jacob #define CAN_SRCH_HI_SPARSE(dv) \ 237f4322bc8SMatt Jacob (((dv->quirk->quirks & CAM_QUIRK_NOHILUNS) == 0) \ 238f4322bc8SMatt Jacob && ((dv->quirk->quirks & CAM_QUIRK_HILUNS) \ 2393b87a552SMatt Jacob || (SID_ANSI_REV(&dv->inq_data) > SCSI_REV_2 && cam_srch_hi))) 2403b87a552SMatt Jacob 2413b87a552SMatt Jacob #define CAN_SRCH_HI_DENSE(dv) \ 2423b87a552SMatt Jacob (((dv->quirk->quirks & CAM_QUIRK_NOHILUNS) == 0) \ 2433b87a552SMatt Jacob && ((dv->quirk->quirks & CAM_QUIRK_HILUNS) \ 2443b87a552SMatt Jacob || (SID_ANSI_REV(&dv->inq_data) > SCSI_REV_2))) 2458b8a9b1dSJustin T. Gibbs 2468b8a9b1dSJustin T. Gibbs typedef enum { 2478b8a9b1dSJustin T. Gibbs XPT_FLAG_OPEN = 0x01 2488b8a9b1dSJustin T. Gibbs } xpt_flags; 2498b8a9b1dSJustin T. Gibbs 2508b8a9b1dSJustin T. Gibbs struct xpt_softc { 2518b8a9b1dSJustin T. Gibbs xpt_flags flags; 2522b83592fSScott Long u_int32_t xpt_generation; 2532b83592fSScott Long 2542b83592fSScott Long /* number of high powered commands that can go through right now */ 2552b83592fSScott Long STAILQ_HEAD(highpowerlist, ccb_hdr) highpowerq; 2562b83592fSScott Long int num_highpower; 2572b83592fSScott Long 2582b83592fSScott Long /* queue for handling async rescan requests. */ 2592b83592fSScott Long TAILQ_HEAD(, ccb_hdr) ccb_scanq; 2602b83592fSScott Long 2612b83592fSScott Long /* Registered busses */ 2622b83592fSScott Long TAILQ_HEAD(,cam_eb) xpt_busses; 2632b83592fSScott Long u_int bus_generation; 2642b83592fSScott Long 2652b83592fSScott Long struct intr_config_hook *xpt_config_hook; 2662b83592fSScott Long 2672b83592fSScott Long struct mtx xpt_topo_lock; 2682b83592fSScott Long struct mtx xpt_lock; 2698b8a9b1dSJustin T. Gibbs }; 2708b8a9b1dSJustin T. Gibbs 2718b8a9b1dSJustin T. Gibbs static const char quantum[] = "QUANTUM"; 272f24c39c7SKenneth D. Merry static const char sony[] = "SONY"; 273f24c39c7SKenneth D. Merry static const char west_digital[] = "WDIGTL"; 2741f04f5abSKenneth D. Merry static const char samsung[] = "SAMSUNG"; 275560d629fSKenneth D. Merry static const char seagate[] = "SEAGATE"; 2765acba6ecSJohn-Mark Gurney static const char microp[] = "MICROP"; 2778b8a9b1dSJustin T. Gibbs 2788b8a9b1dSJustin T. Gibbs static struct xpt_quirk_entry xpt_quirk_table[] = 2798b8a9b1dSJustin T. Gibbs { 2808b8a9b1dSJustin T. Gibbs { 2818b8a9b1dSJustin T. Gibbs /* Reports QUEUE FULL for temporary resource shortages */ 2826747168dSKenneth D. Merry { T_DIRECT, SIP_MEDIA_FIXED, quantum, "XP39100*", "*" }, 2838b8a9b1dSJustin T. Gibbs /*quirks*/0, /*mintags*/24, /*maxtags*/32 2848b8a9b1dSJustin T. Gibbs }, 2858b8a9b1dSJustin T. Gibbs { 2868b8a9b1dSJustin T. Gibbs /* Reports QUEUE FULL for temporary resource shortages */ 2876747168dSKenneth D. Merry { T_DIRECT, SIP_MEDIA_FIXED, quantum, "XP34550*", "*" }, 2886747168dSKenneth D. Merry /*quirks*/0, /*mintags*/24, /*maxtags*/32 2896747168dSKenneth D. Merry }, 2906747168dSKenneth D. Merry { 2916747168dSKenneth D. Merry /* Reports QUEUE FULL for temporary resource shortages */ 2926747168dSKenneth D. Merry { T_DIRECT, SIP_MEDIA_FIXED, quantum, "XP32275*", "*" }, 2938b8a9b1dSJustin T. Gibbs /*quirks*/0, /*mintags*/24, /*maxtags*/32 2948b8a9b1dSJustin T. Gibbs }, 2958b8a9b1dSJustin T. Gibbs { 2968b8a9b1dSJustin T. Gibbs /* Broken tagged queuing drive */ 2975acba6ecSJohn-Mark Gurney { T_DIRECT, SIP_MEDIA_FIXED, microp, "4421-07*", "*" }, 2985acba6ecSJohn-Mark Gurney /*quirks*/0, /*mintags*/0, /*maxtags*/0 2995acba6ecSJohn-Mark Gurney }, 3005acba6ecSJohn-Mark Gurney { 3015acba6ecSJohn-Mark Gurney /* Broken tagged queuing drive */ 3028b8a9b1dSJustin T. Gibbs { T_DIRECT, SIP_MEDIA_FIXED, "HP", "C372*", "*" }, 3038b8a9b1dSJustin T. Gibbs /*quirks*/0, /*mintags*/0, /*maxtags*/0 3048b8a9b1dSJustin T. Gibbs }, 3058b8a9b1dSJustin T. Gibbs { 3068b8a9b1dSJustin T. Gibbs /* Broken tagged queuing drive */ 3075acba6ecSJohn-Mark Gurney { T_DIRECT, SIP_MEDIA_FIXED, microp, "3391*", "x43h" }, 3088b8a9b1dSJustin T. Gibbs /*quirks*/0, /*mintags*/0, /*maxtags*/0 3098b8a9b1dSJustin T. Gibbs }, 3108b8a9b1dSJustin T. Gibbs { 3118597eafeSKenneth D. Merry /* 3124cdd0221SKenneth D. Merry * Unfortunately, the Quantum Atlas III has the same 3134cdd0221SKenneth D. Merry * problem as the Atlas II drives above. 3144cdd0221SKenneth D. Merry * Reported by: "Johan Granlund" <johan@granlund.nu> 3154cdd0221SKenneth D. Merry * 3164cdd0221SKenneth D. Merry * For future reference, the drive with the problem was: 3174cdd0221SKenneth D. Merry * QUANTUM QM39100TD-SW N1B0 3184cdd0221SKenneth D. Merry * 3194cdd0221SKenneth D. Merry * It's possible that Quantum will fix the problem in later 3204cdd0221SKenneth D. Merry * firmware revisions. If that happens, the quirk entry 3214cdd0221SKenneth D. Merry * will need to be made specific to the firmware revisions 3224cdd0221SKenneth D. Merry * with the problem. 3234cdd0221SKenneth D. Merry * 3244cdd0221SKenneth D. Merry */ 3254cdd0221SKenneth D. Merry /* Reports QUEUE FULL for temporary resource shortages */ 3264cdd0221SKenneth D. Merry { T_DIRECT, SIP_MEDIA_FIXED, quantum, "QM39100*", "*" }, 3274cdd0221SKenneth D. Merry /*quirks*/0, /*mintags*/24, /*maxtags*/32 3284cdd0221SKenneth D. Merry }, 3294cdd0221SKenneth D. Merry { 3304cdd0221SKenneth D. Merry /* 331588b47e5SKenneth D. Merry * 18 Gig Atlas III, same problem as the 9G version. 332588b47e5SKenneth D. Merry * Reported by: Andre Albsmeier 333588b47e5SKenneth D. Merry * <andre.albsmeier@mchp.siemens.de> 334588b47e5SKenneth D. Merry * 335588b47e5SKenneth D. Merry * For future reference, the drive with the problem was: 336588b47e5SKenneth D. Merry * QUANTUM QM318000TD-S N491 337588b47e5SKenneth D. Merry */ 338588b47e5SKenneth D. Merry /* Reports QUEUE FULL for temporary resource shortages */ 339588b47e5SKenneth D. Merry { T_DIRECT, SIP_MEDIA_FIXED, quantum, "QM318000*", "*" }, 340588b47e5SKenneth D. Merry /*quirks*/0, /*mintags*/24, /*maxtags*/32 341588b47e5SKenneth D. Merry }, 342588b47e5SKenneth D. Merry { 343588b47e5SKenneth D. Merry /* 3448597eafeSKenneth D. Merry * Broken tagged queuing drive 3458597eafeSKenneth D. Merry * Reported by: Bret Ford <bford@uop.cs.uop.edu> 3468597eafeSKenneth D. Merry * and: Martin Renters <martin@tdc.on.ca> 3478597eafeSKenneth D. Merry */ 348560d629fSKenneth D. Merry { T_DIRECT, SIP_MEDIA_FIXED, seagate, "ST410800*", "71*" }, 3498597eafeSKenneth D. Merry /*quirks*/0, /*mintags*/0, /*maxtags*/0 3508597eafeSKenneth D. Merry }, 351560d629fSKenneth D. Merry /* 352c816e025SKenneth D. Merry * The Seagate Medalist Pro drives have very poor write 353c816e025SKenneth D. Merry * performance with anything more than 2 tags. 354560d629fSKenneth D. Merry * 355560d629fSKenneth D. Merry * Reported by: Paul van der Zwan <paulz@trantor.xs4all.nl> 356560d629fSKenneth D. Merry * Drive: <SEAGATE ST36530N 1444> 357c816e025SKenneth D. Merry * 358c816e025SKenneth D. Merry * Reported by: Jeremy Lea <reg@shale.csir.co.za> 359c816e025SKenneth D. Merry * Drive: <SEAGATE ST34520W 1281> 360c816e025SKenneth D. Merry * 361c816e025SKenneth D. Merry * No one has actually reported that the 9G version 362c816e025SKenneth D. Merry * (ST39140*) of the Medalist Pro has the same problem, but 363c816e025SKenneth D. Merry * we're assuming that it does because the 4G and 6.5G 364c816e025SKenneth D. Merry * versions of the drive are broken. 365560d629fSKenneth D. Merry */ 366c816e025SKenneth D. Merry { 367c816e025SKenneth D. Merry { T_DIRECT, SIP_MEDIA_FIXED, seagate, "ST34520*", "*"}, 368c816e025SKenneth D. Merry /*quirks*/0, /*mintags*/2, /*maxtags*/2 369c816e025SKenneth D. Merry }, 370c816e025SKenneth D. Merry { 371560d629fSKenneth D. Merry { T_DIRECT, SIP_MEDIA_FIXED, seagate, "ST36530*", "*"}, 372560d629fSKenneth D. Merry /*quirks*/0, /*mintags*/2, /*maxtags*/2 373560d629fSKenneth D. Merry }, 374560d629fSKenneth D. Merry { 375c816e025SKenneth D. Merry { T_DIRECT, SIP_MEDIA_FIXED, seagate, "ST39140*", "*"}, 376c816e025SKenneth D. Merry /*quirks*/0, /*mintags*/2, /*maxtags*/2 377c816e025SKenneth D. Merry }, 378c816e025SKenneth D. Merry { 379ca3b51e9SKenneth D. Merry /* 380ca3b51e9SKenneth D. Merry * Slow when tagged queueing is enabled. Write performance 381ca3b51e9SKenneth D. Merry * steadily drops off with more and more concurrent 382ca3b51e9SKenneth D. Merry * transactions. Best sequential write performance with 383ca3b51e9SKenneth D. Merry * tagged queueing turned off and write caching turned on. 384ca3b51e9SKenneth D. Merry * 385ca3b51e9SKenneth D. Merry * PR: kern/10398 386ca3b51e9SKenneth D. Merry * Submitted by: Hideaki Okada <hokada@isl.melco.co.jp> 387ca3b51e9SKenneth D. Merry * Drive: DCAS-34330 w/ "S65A" firmware. 388ca3b51e9SKenneth D. Merry * 389ca3b51e9SKenneth D. Merry * The drive with the problem had the "S65A" firmware 390ca3b51e9SKenneth D. Merry * revision, and has also been reported (by Stephen J. 391ca3b51e9SKenneth D. Merry * Roznowski <sjr@home.net>) for a drive with the "S61A" 392ca3b51e9SKenneth D. Merry * firmware revision. 393ca3b51e9SKenneth D. Merry * 394ca3b51e9SKenneth D. Merry * Although no one has reported problems with the 2 gig 395ca3b51e9SKenneth D. Merry * version of the DCAS drive, the assumption is that it 396ca3b51e9SKenneth D. Merry * has the same problems as the 4 gig version. Therefore 397ca3b51e9SKenneth D. Merry * this quirk entries disables tagged queueing for all 398ca3b51e9SKenneth D. Merry * DCAS drives. 399ca3b51e9SKenneth D. Merry */ 400ca3b51e9SKenneth D. Merry { T_DIRECT, SIP_MEDIA_FIXED, "IBM", "DCAS*", "*" }, 401ca3b51e9SKenneth D. Merry /*quirks*/0, /*mintags*/0, /*maxtags*/0 402ca3b51e9SKenneth D. Merry }, 403ca3b51e9SKenneth D. Merry { 4048b8a9b1dSJustin T. Gibbs /* Broken tagged queuing drive */ 4058b8a9b1dSJustin T. Gibbs { T_DIRECT, SIP_MEDIA_REMOVABLE, "iomega", "jaz*", "*" }, 4068b8a9b1dSJustin T. Gibbs /*quirks*/0, /*mintags*/0, /*maxtags*/0 4078b8a9b1dSJustin T. Gibbs }, 4088b8a9b1dSJustin T. Gibbs { 4092ba01e6fSJustin T. Gibbs /* Broken tagged queuing drive */ 4106dd76100SKenneth D. Merry { T_DIRECT, SIP_MEDIA_FIXED, "CONNER", "CFP2107*", "*" }, 4112ba01e6fSJustin T. Gibbs /*quirks*/0, /*mintags*/0, /*maxtags*/0 4122ba01e6fSJustin T. Gibbs }, 4132ba01e6fSJustin T. Gibbs { 4149fdeccedSMatt Jacob /* This does not support other than LUN 0 */ 4155ce1b004SMatt Jacob { T_DIRECT, SIP_MEDIA_FIXED, "VMware*", "*", "*" }, 416df4b14f4SMatt Jacob CAM_QUIRK_NOLUNS, /*mintags*/2, /*maxtags*/255 417015a972cSMatt Jacob }, 418015a972cSMatt Jacob { 419e471e974SJustin T. Gibbs /* 4201f04f5abSKenneth D. Merry * Broken tagged queuing drive. 4211f04f5abSKenneth D. Merry * Submitted by: 4221f04f5abSKenneth D. Merry * NAKAJI Hiroyuki <nakaji@zeisei.dpri.kyoto-u.ac.jp> 4231f04f5abSKenneth D. Merry * in PR kern/9535 4241f04f5abSKenneth D. Merry */ 4251f04f5abSKenneth D. Merry { T_DIRECT, SIP_MEDIA_FIXED, samsung, "WN34324U*", "*" }, 4261f04f5abSKenneth D. Merry /*quirks*/0, /*mintags*/0, /*maxtags*/0 4271f04f5abSKenneth D. Merry }, 4281f04f5abSKenneth D. Merry { 4291f04f5abSKenneth D. Merry /* 430f24c39c7SKenneth D. Merry * Slow when tagged queueing is enabled. (1.5MB/sec versus 431f24c39c7SKenneth D. Merry * 8MB/sec.) 432f24c39c7SKenneth D. Merry * Submitted by: Andrew Gallatin <gallatin@cs.duke.edu> 433ca3b51e9SKenneth D. Merry * Best performance with these drives is achieved with 434ca3b51e9SKenneth D. Merry * tagged queueing turned off, and write caching turned on. 435f24c39c7SKenneth D. Merry */ 436f24c39c7SKenneth D. Merry { T_DIRECT, SIP_MEDIA_FIXED, west_digital, "WDE*", "*" }, 437f24c39c7SKenneth D. Merry /*quirks*/0, /*mintags*/0, /*maxtags*/0 438f24c39c7SKenneth D. Merry }, 439f24c39c7SKenneth D. Merry { 440f24c39c7SKenneth D. Merry /* 441f24c39c7SKenneth D. Merry * Slow when tagged queueing is enabled. (1.5MB/sec versus 442f24c39c7SKenneth D. Merry * 8MB/sec.) 443f24c39c7SKenneth D. Merry * Submitted by: Andrew Gallatin <gallatin@cs.duke.edu> 444ca3b51e9SKenneth D. Merry * Best performance with these drives is achieved with 445ca3b51e9SKenneth D. Merry * tagged queueing turned off, and write caching turned on. 446f24c39c7SKenneth D. Merry */ 447f24c39c7SKenneth D. Merry { T_DIRECT, SIP_MEDIA_FIXED, west_digital, "ENTERPRISE", "*" }, 448f24c39c7SKenneth D. Merry /*quirks*/0, /*mintags*/0, /*maxtags*/0 449f24c39c7SKenneth D. Merry }, 450f24c39c7SKenneth D. Merry { 451f24c39c7SKenneth D. Merry /* 452e471e974SJustin T. Gibbs * Doesn't handle queue full condition correctly, 453e471e974SJustin T. Gibbs * so we need to limit maxtags to what the device 454e471e974SJustin T. Gibbs * can handle instead of determining this automatically. 455e471e974SJustin T. Gibbs */ 4561f04f5abSKenneth D. Merry { T_DIRECT, SIP_MEDIA_FIXED, samsung, "WN321010S*", "*" }, 457fd21cc5eSJustin T. Gibbs /*quirks*/0, /*mintags*/2, /*maxtags*/32 458e471e974SJustin T. Gibbs }, 459e471e974SJustin T. Gibbs { 4608b8a9b1dSJustin T. Gibbs /* Really only one LUN */ 461f2538844SMatt Jacob { T_ENCLOSURE, SIP_MEDIA_FIXED, "SUN", "SENA", "*" }, 4628b8a9b1dSJustin T. Gibbs CAM_QUIRK_NOLUNS, /*mintags*/0, /*maxtags*/0 4638b8a9b1dSJustin T. Gibbs }, 4648b8a9b1dSJustin T. Gibbs { 465fd21cc5eSJustin T. Gibbs /* I can't believe we need a quirk for DPT volumes. */ 4664b4c702bSMatt Jacob { T_ANY, SIP_MEDIA_FIXED|SIP_MEDIA_REMOVABLE, "DPT", "*", "*" }, 467fd21cc5eSJustin T. Gibbs CAM_QUIRK_NOSERIAL|CAM_QUIRK_NOLUNS, 468fd21cc5eSJustin T. Gibbs /*mintags*/0, /*maxtags*/255 469fd21cc5eSJustin T. Gibbs }, 470fd21cc5eSJustin T. Gibbs { 471f24c39c7SKenneth D. Merry /* 47225e5ca27SKenneth D. Merry * Many Sony CDROM drives don't like multi-LUN probing. 473f24c39c7SKenneth D. Merry */ 4744b4c702bSMatt Jacob { T_CDROM, SIP_MEDIA_REMOVABLE, sony, "CD-ROM CDU*", "*" }, 475f24c39c7SKenneth D. Merry CAM_QUIRK_NOLUNS, /*mintags*/0, /*maxtags*/0 476f24c39c7SKenneth D. Merry }, 477f24c39c7SKenneth D. Merry { 478f24c39c7SKenneth D. Merry /* 479f24c39c7SKenneth D. Merry * This drive doesn't like multiple LUN probing. 480f24c39c7SKenneth D. Merry * Submitted by: Parag Patel <parag@cgt.com> 481f24c39c7SKenneth D. Merry */ 4824b4c702bSMatt Jacob { T_WORM, SIP_MEDIA_REMOVABLE, sony, "CD-R CDU9*", "*" }, 483f24c39c7SKenneth D. Merry CAM_QUIRK_NOLUNS, /*mintags*/0, /*maxtags*/0 484f24c39c7SKenneth D. Merry }, 485f24c39c7SKenneth D. Merry { 486ca2b07adSKenneth D. Merry { T_WORM, SIP_MEDIA_REMOVABLE, "YAMAHA", "CDR100*", "*" }, 487ca2b07adSKenneth D. Merry CAM_QUIRK_NOLUNS, /*mintags*/0, /*maxtags*/0 488ca2b07adSKenneth D. Merry }, 489ca2b07adSKenneth D. Merry { 490b1d26455SKenneth D. Merry /* 491b1d26455SKenneth D. Merry * The 8200 doesn't like multi-lun probing, and probably 492b1d26455SKenneth D. Merry * don't like serial number requests either. 493b1d26455SKenneth D. Merry */ 494b1d26455SKenneth D. Merry { 495b1d26455SKenneth D. Merry T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "EXABYTE", 496b1d26455SKenneth D. Merry "EXB-8200*", "*" 497b1d26455SKenneth D. Merry }, 498b1d26455SKenneth D. Merry CAM_QUIRK_NOSERIAL|CAM_QUIRK_NOLUNS, /*mintags*/0, /*maxtags*/0 499b1d26455SKenneth D. Merry }, 500b1d26455SKenneth D. Merry { 50136230d67SJoerg Wunsch /* 502f2538844SMatt Jacob * Let's try the same as above, but for a drive that says 503f2538844SMatt Jacob * it's an IPL-6860 but is actually an EXB 8200. 504f2538844SMatt Jacob */ 505f2538844SMatt Jacob { 506f2538844SMatt Jacob T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "EXABYTE", 507f2538844SMatt Jacob "IPL-6860*", "*" 508f2538844SMatt Jacob }, 509f2538844SMatt Jacob CAM_QUIRK_NOSERIAL|CAM_QUIRK_NOLUNS, /*mintags*/0, /*maxtags*/0 510f2538844SMatt Jacob }, 511f2538844SMatt Jacob { 512f2538844SMatt Jacob /* 513a6cb9949SKenneth D. Merry * These Hitachi drives don't like multi-lun probing. 514a6cb9949SKenneth D. Merry * The PR submitter has a DK319H, but says that the Linux 515a6cb9949SKenneth D. Merry * kernel has a similar work-around for the DK312 and DK314, 516a6cb9949SKenneth D. Merry * so all DK31* drives are quirked here. 517a6cb9949SKenneth D. Merry * PR: misc/18793 518a6cb9949SKenneth D. Merry * Submitted by: Paul Haddad <paul@pth.com> 519a6cb9949SKenneth D. Merry */ 520a6cb9949SKenneth D. Merry { T_DIRECT, SIP_MEDIA_FIXED, "HITACHI", "DK31*", "*" }, 521a6cb9949SKenneth D. Merry CAM_QUIRK_NOLUNS, /*mintags*/2, /*maxtags*/255 522a6cb9949SKenneth D. Merry }, 523a6cb9949SKenneth D. Merry { 524a6cb9949SKenneth D. Merry /* 525136b546aSDavid Greenman * The Hitachi CJ series with J8A8 firmware apparantly has 526136b546aSDavid Greenman * problems with tagged commands. 527136b546aSDavid Greenman * PR: 23536 528136b546aSDavid Greenman * Reported by: amagai@nue.org 529136b546aSDavid Greenman */ 530136b546aSDavid Greenman { T_DIRECT, SIP_MEDIA_FIXED, "HITACHI", "DK32CJ*", "J8A8" }, 531136b546aSDavid Greenman CAM_QUIRK_NOLUNS, /*mintags*/0, /*maxtags*/0 532136b546aSDavid Greenman }, 533136b546aSDavid Greenman { 534136b546aSDavid Greenman /* 53578900a83SMatt Jacob * These are the large storage arrays. 53678900a83SMatt Jacob * Submitted by: William Carrel <william.carrel@infospace.com> 53778900a83SMatt Jacob */ 53878900a83SMatt Jacob { T_DIRECT, SIP_MEDIA_FIXED, "HITACHI", "OPEN*", "*" }, 53978900a83SMatt Jacob CAM_QUIRK_HILUNS, 2, 1024 54078900a83SMatt Jacob }, 54178900a83SMatt Jacob { 54278900a83SMatt Jacob /* 54336230d67SJoerg Wunsch * This old revision of the TDC3600 is also SCSI-1, and 54436230d67SJoerg Wunsch * hangs upon serial number probing. 54536230d67SJoerg Wunsch */ 54636230d67SJoerg Wunsch { 54736230d67SJoerg Wunsch T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "TANDBERG", 54836230d67SJoerg Wunsch " TDC 3600", "U07:" 54936230d67SJoerg Wunsch }, 55036230d67SJoerg Wunsch CAM_QUIRK_NOSERIAL, /*mintags*/0, /*maxtags*/0 55136230d67SJoerg Wunsch }, 55236230d67SJoerg Wunsch { 5532c3cca96SMatt Jacob /* 5547afa4afbSHidetoshi Shimokawa * Maxtor Personal Storage 3000XT (Firewire) 5557afa4afbSHidetoshi Shimokawa * hangs upon serial number probing. 5567afa4afbSHidetoshi Shimokawa */ 5577afa4afbSHidetoshi Shimokawa { 5587afa4afbSHidetoshi Shimokawa T_DIRECT, SIP_MEDIA_FIXED, "Maxtor", 5597afa4afbSHidetoshi Shimokawa "1394 storage", "*" 5607afa4afbSHidetoshi Shimokawa }, 5617afa4afbSHidetoshi Shimokawa CAM_QUIRK_NOSERIAL, /*mintags*/0, /*maxtags*/0 5627afa4afbSHidetoshi Shimokawa }, 5637afa4afbSHidetoshi Shimokawa { 5647afa4afbSHidetoshi Shimokawa /* 5652c3cca96SMatt Jacob * Would repond to all LUNs if asked for. 5662c3cca96SMatt Jacob */ 5672c3cca96SMatt Jacob { 5682c3cca96SMatt Jacob T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "CALIPER", 5692c3cca96SMatt Jacob "CP150", "*" 5702c3cca96SMatt Jacob }, 5712c3cca96SMatt Jacob CAM_QUIRK_NOLUNS, /*mintags*/0, /*maxtags*/0 5722c3cca96SMatt Jacob }, 5732c3cca96SMatt Jacob { 574040816ecSMatt Jacob /* 575040816ecSMatt Jacob * Would repond to all LUNs if asked for. 576040816ecSMatt Jacob */ 577040816ecSMatt Jacob { 578040816ecSMatt Jacob T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "KENNEDY", 579040816ecSMatt Jacob "96X2*", "*" 580040816ecSMatt Jacob }, 581040816ecSMatt Jacob CAM_QUIRK_NOLUNS, /*mintags*/0, /*maxtags*/0 582040816ecSMatt Jacob }, 583040816ecSMatt Jacob { 5844b4c702bSMatt Jacob /* Submitted by: Matthew Dodd <winter@jurai.net> */ 5854b4c702bSMatt Jacob { T_PROCESSOR, SIP_MEDIA_FIXED, "Cabletrn", "EA41*", "*" }, 5864b4c702bSMatt Jacob CAM_QUIRK_NOLUNS, /*mintags*/0, /*maxtags*/0 5874b4c702bSMatt Jacob }, 5884b4c702bSMatt Jacob { 5894b4c702bSMatt Jacob /* Submitted by: Matthew Dodd <winter@jurai.net> */ 5904b4c702bSMatt Jacob { T_PROCESSOR, SIP_MEDIA_FIXED, "CABLETRN", "EA41*", "*" }, 5914b4c702bSMatt Jacob CAM_QUIRK_NOLUNS, /*mintags*/0, /*maxtags*/0 5924b4c702bSMatt Jacob }, 5934b4c702bSMatt Jacob { 594da6efda6SDavid Greenman /* TeraSolutions special settings for TRC-22 RAID */ 595da6efda6SDavid Greenman { T_DIRECT, SIP_MEDIA_FIXED, "TERASOLU", "TRC-22", "*" }, 596da6efda6SDavid Greenman /*quirks*/0, /*mintags*/55, /*maxtags*/255 597da6efda6SDavid Greenman }, 598da6efda6SDavid Greenman { 599c7948a94SMatt Jacob /* Veritas Storage Appliance */ 600c7948a94SMatt Jacob { T_DIRECT, SIP_MEDIA_FIXED, "VERITAS", "*", "*" }, 601c7948a94SMatt Jacob CAM_QUIRK_HILUNS, /*mintags*/2, /*maxtags*/1024 602c7948a94SMatt Jacob }, 603c7948a94SMatt Jacob { 6043b9d81dcSJoerg Wunsch /* 6053b9d81dcSJoerg Wunsch * Would respond to all LUNs. Device type and removable 6063b9d81dcSJoerg Wunsch * flag are jumper-selectable. 6073b9d81dcSJoerg Wunsch */ 6083b9d81dcSJoerg Wunsch { T_ANY, SIP_MEDIA_REMOVABLE|SIP_MEDIA_FIXED, "MaxOptix", 6093b9d81dcSJoerg Wunsch "Tahiti 1", "*" 6103b9d81dcSJoerg Wunsch }, 6113b9d81dcSJoerg Wunsch CAM_QUIRK_NOLUNS, /*mintags*/0, /*maxtags*/0 6123b9d81dcSJoerg Wunsch }, 6133b9d81dcSJoerg Wunsch { 6148924340fSMichael Reifenberger /* EasyRAID E5A aka. areca ARC-6010 */ 6158924340fSMichael Reifenberger { T_DIRECT, SIP_MEDIA_FIXED, "easyRAID", "*", "*" }, 6168924340fSMichael Reifenberger CAM_QUIRK_NOHILUNS, /*mintags*/2, /*maxtags*/255 6178924340fSMichael Reifenberger }, 6188924340fSMichael Reifenberger { 6191190a85bSMatt Jacob { T_ENCLOSURE, SIP_MEDIA_FIXED, "DP", "BACKPLANE", "*" }, 6201190a85bSMatt Jacob CAM_QUIRK_NOLUNS, /*mintags*/0, /*maxtags*/0 6211190a85bSMatt Jacob }, 6221190a85bSMatt Jacob { 6231accd65dSWarner Losh /* 6241accd65dSWarner Losh * Western Digital My Book 250GB (USB) 6251accd65dSWarner Losh * hangs upon serial number probing. 6261accd65dSWarner Losh * PR: 107495 6271accd65dSWarner Losh */ 6281accd65dSWarner Losh { 6291accd65dSWarner Losh T_DIRECT, SIP_MEDIA_FIXED, "WD", 6301accd65dSWarner Losh "2500JB External", "*" 6311accd65dSWarner Losh }, 6321accd65dSWarner Losh CAM_QUIRK_NOSERIAL, /*mintags*/0, /*maxtags*/0 6331accd65dSWarner Losh }, 6341accd65dSWarner Losh { 6358b8a9b1dSJustin T. Gibbs /* Default tagged queuing parameters for all devices */ 6368b8a9b1dSJustin T. Gibbs { 6378b8a9b1dSJustin T. Gibbs T_ANY, SIP_MEDIA_REMOVABLE|SIP_MEDIA_FIXED, 6388b8a9b1dSJustin T. Gibbs /*vendor*/"*", /*product*/"*", /*revision*/"*" 6398b8a9b1dSJustin T. Gibbs }, 640fd21cc5eSJustin T. Gibbs /*quirks*/0, /*mintags*/2, /*maxtags*/255 6418b8a9b1dSJustin T. Gibbs }, 6428b8a9b1dSJustin T. Gibbs }; 643fd21cc5eSJustin T. Gibbs 64487cfaf0eSJustin T. Gibbs static const int xpt_quirk_table_size = 64587cfaf0eSJustin T. Gibbs sizeof(xpt_quirk_table) / sizeof(*xpt_quirk_table); 64687cfaf0eSJustin T. Gibbs 6478b8a9b1dSJustin T. Gibbs typedef enum { 6488b8a9b1dSJustin T. Gibbs DM_RET_COPY = 0x01, 6498b8a9b1dSJustin T. Gibbs DM_RET_FLAG_MASK = 0x0f, 6508b8a9b1dSJustin T. Gibbs DM_RET_NONE = 0x00, 6518b8a9b1dSJustin T. Gibbs DM_RET_STOP = 0x10, 6528b8a9b1dSJustin T. Gibbs DM_RET_DESCEND = 0x20, 6538b8a9b1dSJustin T. Gibbs DM_RET_ERROR = 0x30, 6548b8a9b1dSJustin T. Gibbs DM_RET_ACTION_MASK = 0xf0 6558b8a9b1dSJustin T. Gibbs } dev_match_ret; 6568b8a9b1dSJustin T. Gibbs 6578b8a9b1dSJustin T. Gibbs typedef enum { 6588b8a9b1dSJustin T. Gibbs XPT_DEPTH_BUS, 6598b8a9b1dSJustin T. Gibbs XPT_DEPTH_TARGET, 6608b8a9b1dSJustin T. Gibbs XPT_DEPTH_DEVICE, 6618b8a9b1dSJustin T. Gibbs XPT_DEPTH_PERIPH 6628b8a9b1dSJustin T. Gibbs } xpt_traverse_depth; 6638b8a9b1dSJustin T. Gibbs 6648b8a9b1dSJustin T. Gibbs struct xpt_traverse_config { 6658b8a9b1dSJustin T. Gibbs xpt_traverse_depth depth; 6668b8a9b1dSJustin T. Gibbs void *tr_func; 6678b8a9b1dSJustin T. Gibbs void *tr_arg; 6688b8a9b1dSJustin T. Gibbs }; 6698b8a9b1dSJustin T. Gibbs 6708b8a9b1dSJustin T. Gibbs typedef int xpt_busfunc_t (struct cam_eb *bus, void *arg); 6718b8a9b1dSJustin T. Gibbs typedef int xpt_targetfunc_t (struct cam_et *target, void *arg); 6728b8a9b1dSJustin T. Gibbs typedef int xpt_devicefunc_t (struct cam_ed *device, void *arg); 6738b8a9b1dSJustin T. Gibbs typedef int xpt_periphfunc_t (struct cam_periph *periph, void *arg); 6748b8a9b1dSJustin T. Gibbs typedef int xpt_pdrvfunc_t (struct periph_driver **pdrv, void *arg); 6758b8a9b1dSJustin T. Gibbs 6768b8a9b1dSJustin T. Gibbs /* Transport layer configuration information */ 6778b8a9b1dSJustin T. Gibbs static struct xpt_softc xsoftc; 6788b8a9b1dSJustin T. Gibbs 6798b8a9b1dSJustin T. Gibbs /* Queues for our software interrupt handler */ 680e3975643SJake Burkholder typedef TAILQ_HEAD(cam_isrq, ccb_hdr) cam_isrq_t; 6819758cc83SScott Long typedef TAILQ_HEAD(cam_simq, cam_sim) cam_simq_t; 6829758cc83SScott Long static cam_simq_t cam_simq; 6839758cc83SScott Long static struct mtx cam_simq_lock; 6848b8a9b1dSJustin T. Gibbs 6852b83592fSScott Long /* Pointers to software interrupt handlers */ 6862b83592fSScott Long static void *cambio_ih; 6878b8a9b1dSJustin T. Gibbs 6889a1c8571SNick Hibma struct cam_periph *xpt_periph; 6899a1c8571SNick Hibma 6908b8a9b1dSJustin T. Gibbs static periph_init_t xpt_periph_init; 6918b8a9b1dSJustin T. Gibbs 6928b8a9b1dSJustin T. Gibbs static periph_init_t probe_periph_init; 6938b8a9b1dSJustin T. Gibbs 6948b8a9b1dSJustin T. Gibbs static struct periph_driver xpt_driver = 6958b8a9b1dSJustin T. Gibbs { 6968b8a9b1dSJustin T. Gibbs xpt_periph_init, "xpt", 6978b8a9b1dSJustin T. Gibbs TAILQ_HEAD_INITIALIZER(xpt_driver.units) 6988b8a9b1dSJustin T. Gibbs }; 6998b8a9b1dSJustin T. Gibbs 7008b8a9b1dSJustin T. Gibbs static struct periph_driver probe_driver = 7018b8a9b1dSJustin T. Gibbs { 7028b8a9b1dSJustin T. Gibbs probe_periph_init, "probe", 7038b8a9b1dSJustin T. Gibbs TAILQ_HEAD_INITIALIZER(probe_driver.units) 7048b8a9b1dSJustin T. Gibbs }; 7058b8a9b1dSJustin T. Gibbs 7060b7c27b9SPeter Wemm PERIPHDRIVER_DECLARE(xpt, xpt_driver); 7070b7c27b9SPeter Wemm PERIPHDRIVER_DECLARE(probe, probe_driver); 7088b8a9b1dSJustin T. Gibbs 7098b8a9b1dSJustin T. Gibbs 7108b8a9b1dSJustin T. Gibbs static d_open_t xptopen; 7118b8a9b1dSJustin T. Gibbs static d_close_t xptclose; 7128b8a9b1dSJustin T. Gibbs static d_ioctl_t xptioctl; 7138b8a9b1dSJustin T. Gibbs 7144e2f199eSPoul-Henning Kamp static struct cdevsw xpt_cdevsw = { 715dc08ffecSPoul-Henning Kamp .d_version = D_VERSION, 7162b83592fSScott Long .d_flags = 0, 7177ac40f5fSPoul-Henning Kamp .d_open = xptopen, 7187ac40f5fSPoul-Henning Kamp .d_close = xptclose, 7197ac40f5fSPoul-Henning Kamp .d_ioctl = xptioctl, 7207ac40f5fSPoul-Henning Kamp .d_name = "xpt", 7218b8a9b1dSJustin T. Gibbs }; 7228b8a9b1dSJustin T. Gibbs 7238b8a9b1dSJustin T. Gibbs 724d3ef3454SIan Dowse static void dead_sim_action(struct cam_sim *sim, union ccb *ccb); 725d3ef3454SIan Dowse static void dead_sim_poll(struct cam_sim *sim); 726d3ef3454SIan Dowse 727d3ef3454SIan Dowse /* Dummy SIM that is used when the real one has gone. */ 728d3ef3454SIan Dowse static struct cam_sim cam_dead_sim = { 729d3ef3454SIan Dowse .sim_action = dead_sim_action, 730d3ef3454SIan Dowse .sim_poll = dead_sim_poll, 731d3ef3454SIan Dowse .sim_name = "dead_sim", 732d3ef3454SIan Dowse }; 733d3ef3454SIan Dowse 734d3ef3454SIan Dowse #define SIM_DEAD(sim) ((sim) == &cam_dead_sim) 735d3ef3454SIan Dowse 7368b8a9b1dSJustin T. Gibbs 7378b8a9b1dSJustin T. Gibbs /* Storage for debugging datastructures */ 7388b8a9b1dSJustin T. Gibbs #ifdef CAMDEBUG 7398b8a9b1dSJustin T. Gibbs struct cam_path *cam_dpath; 7408b8a9b1dSJustin T. Gibbs u_int32_t cam_dflags; 7412cefde5fSJustin T. Gibbs u_int32_t cam_debug_delay; 7428b8a9b1dSJustin T. Gibbs #endif 7438b8a9b1dSJustin T. Gibbs 7448b8a9b1dSJustin T. Gibbs #if defined(CAM_DEBUG_FLAGS) && !defined(CAMDEBUG) 7458b8a9b1dSJustin T. Gibbs #error "You must have options CAMDEBUG to use options CAM_DEBUG_FLAGS" 7468b8a9b1dSJustin T. Gibbs #endif 7478b8a9b1dSJustin T. Gibbs 7488b8a9b1dSJustin T. Gibbs /* 7498b8a9b1dSJustin T. Gibbs * In order to enable the CAM_DEBUG_* options, the user must have CAMDEBUG 7508b8a9b1dSJustin T. Gibbs * enabled. Also, the user must have either none, or all of CAM_DEBUG_BUS, 7518b8a9b1dSJustin T. Gibbs * CAM_DEBUG_TARGET, and CAM_DEBUG_LUN specified. 7528b8a9b1dSJustin T. Gibbs */ 7538b8a9b1dSJustin T. Gibbs #if defined(CAM_DEBUG_BUS) || defined(CAM_DEBUG_TARGET) \ 7548b8a9b1dSJustin T. Gibbs || defined(CAM_DEBUG_LUN) 7558b8a9b1dSJustin T. Gibbs #ifdef CAMDEBUG 7568b8a9b1dSJustin T. Gibbs #if !defined(CAM_DEBUG_BUS) || !defined(CAM_DEBUG_TARGET) \ 7578b8a9b1dSJustin T. Gibbs || !defined(CAM_DEBUG_LUN) 7588b8a9b1dSJustin T. Gibbs #error "You must define all or none of CAM_DEBUG_BUS, CAM_DEBUG_TARGET \ 7598b8a9b1dSJustin T. Gibbs and CAM_DEBUG_LUN" 7608b8a9b1dSJustin T. Gibbs #endif /* !CAM_DEBUG_BUS || !CAM_DEBUG_TARGET || !CAM_DEBUG_LUN */ 7618b8a9b1dSJustin T. Gibbs #else /* !CAMDEBUG */ 7628b8a9b1dSJustin T. Gibbs #error "You must use options CAMDEBUG if you use the CAM_DEBUG_* options" 7638b8a9b1dSJustin T. Gibbs #endif /* CAMDEBUG */ 7648b8a9b1dSJustin T. Gibbs #endif /* CAM_DEBUG_BUS || CAM_DEBUG_TARGET || CAM_DEBUG_LUN */ 7658b8a9b1dSJustin T. Gibbs 7666d2a8f1cSPeter Wemm /* Our boot-time initialization hook */ 76774bd1c10SNick Hibma static int cam_module_event_handler(module_t, int /*modeventtype_t*/, void *); 76874bd1c10SNick Hibma 76974bd1c10SNick Hibma static moduledata_t cam_moduledata = { 77074bd1c10SNick Hibma "cam", 77174bd1c10SNick Hibma cam_module_event_handler, 77274bd1c10SNick Hibma NULL 77374bd1c10SNick Hibma }; 77474bd1c10SNick Hibma 7752b83592fSScott Long static int xpt_init(void *); 77674bd1c10SNick Hibma 77774bd1c10SNick Hibma DECLARE_MODULE(cam, cam_moduledata, SI_SUB_CONFIGURE, SI_ORDER_SECOND); 77874bd1c10SNick Hibma MODULE_VERSION(cam, 1); 77974bd1c10SNick Hibma 7808b8a9b1dSJustin T. Gibbs 7818b8a9b1dSJustin T. Gibbs static cam_status xpt_compile_path(struct cam_path *new_path, 7828b8a9b1dSJustin T. Gibbs struct cam_periph *perph, 7838b8a9b1dSJustin T. Gibbs path_id_t path_id, 7848b8a9b1dSJustin T. Gibbs target_id_t target_id, 7858b8a9b1dSJustin T. Gibbs lun_id_t lun_id); 7868b8a9b1dSJustin T. Gibbs 7878b8a9b1dSJustin T. Gibbs static void xpt_release_path(struct cam_path *path); 7888b8a9b1dSJustin T. Gibbs 7898b8a9b1dSJustin T. Gibbs static void xpt_async_bcast(struct async_list *async_head, 7908b8a9b1dSJustin T. Gibbs u_int32_t async_code, 7918b8a9b1dSJustin T. Gibbs struct cam_path *path, 7928b8a9b1dSJustin T. Gibbs void *async_arg); 7932f22d08dSJustin T. Gibbs static void xpt_dev_async(u_int32_t async_code, 7942f22d08dSJustin T. Gibbs struct cam_eb *bus, 7952f22d08dSJustin T. Gibbs struct cam_et *target, 7962f22d08dSJustin T. Gibbs struct cam_ed *device, 7972f22d08dSJustin T. Gibbs void *async_arg); 798434bbf6eSJustin T. Gibbs static path_id_t xptnextfreepathid(void); 799434bbf6eSJustin T. Gibbs static path_id_t xptpathid(const char *sim_name, int sim_unit, int sim_bus); 8008b8a9b1dSJustin T. Gibbs static union ccb *xpt_get_ccb(struct cam_ed *device); 8018b8a9b1dSJustin T. Gibbs static int xpt_schedule_dev(struct camq *queue, cam_pinfo *dev_pinfo, 8028b8a9b1dSJustin T. Gibbs u_int32_t new_priority); 8038b8a9b1dSJustin T. Gibbs static void xpt_run_dev_allocq(struct cam_eb *bus); 8048b8a9b1dSJustin T. Gibbs static void xpt_run_dev_sendq(struct cam_eb *bus); 8058b8a9b1dSJustin T. Gibbs static timeout_t xpt_release_devq_timeout; 8062b83592fSScott Long static void xpt_release_simq_timeout(void *arg) __unused; 807a5479bc5SJustin T. Gibbs static void xpt_release_bus(struct cam_eb *bus); 8082cefde5fSJustin T. Gibbs static void xpt_release_devq_device(struct cam_ed *dev, u_int count, 8092cefde5fSJustin T. Gibbs int run_queue); 8108b8a9b1dSJustin T. Gibbs static struct cam_et* 8118b8a9b1dSJustin T. Gibbs xpt_alloc_target(struct cam_eb *bus, target_id_t target_id); 8128b8a9b1dSJustin T. Gibbs static void xpt_release_target(struct cam_eb *bus, struct cam_et *target); 8138b8a9b1dSJustin T. Gibbs static struct cam_ed* 8148b8a9b1dSJustin T. Gibbs xpt_alloc_device(struct cam_eb *bus, struct cam_et *target, 8158b8a9b1dSJustin T. Gibbs lun_id_t lun_id); 8168b8a9b1dSJustin T. Gibbs static void xpt_release_device(struct cam_eb *bus, struct cam_et *target, 8178b8a9b1dSJustin T. Gibbs struct cam_ed *device); 8188b8a9b1dSJustin T. Gibbs static u_int32_t xpt_dev_ccbq_resize(struct cam_path *path, int newopenings); 8198b8a9b1dSJustin T. Gibbs static struct cam_eb* 8208b8a9b1dSJustin T. Gibbs xpt_find_bus(path_id_t path_id); 8218b8a9b1dSJustin T. Gibbs static struct cam_et* 8228b8a9b1dSJustin T. Gibbs xpt_find_target(struct cam_eb *bus, target_id_t target_id); 8238b8a9b1dSJustin T. Gibbs static struct cam_ed* 8248b8a9b1dSJustin T. Gibbs xpt_find_device(struct cam_et *target, lun_id_t lun_id); 8258b8a9b1dSJustin T. Gibbs static void xpt_scan_bus(struct cam_periph *periph, union ccb *ccb); 8268b8a9b1dSJustin T. Gibbs static void xpt_scan_lun(struct cam_periph *periph, 8278b8a9b1dSJustin T. Gibbs struct cam_path *path, cam_flags flags, 8288b8a9b1dSJustin T. Gibbs union ccb *ccb); 8298b8a9b1dSJustin T. Gibbs static void xptscandone(struct cam_periph *periph, union ccb *done_ccb); 8308b8a9b1dSJustin T. Gibbs static xpt_busfunc_t xptconfigbuscountfunc; 8318b8a9b1dSJustin T. Gibbs static xpt_busfunc_t xptconfigfunc; 8328b8a9b1dSJustin T. Gibbs static void xpt_config(void *arg); 8338b8a9b1dSJustin T. Gibbs static xpt_devicefunc_t xptpassannouncefunc; 8348b8a9b1dSJustin T. Gibbs static void xpt_finishconfig(struct cam_periph *periph, union ccb *ccb); 8358b8a9b1dSJustin T. Gibbs static void xptaction(struct cam_sim *sim, union ccb *work_ccb); 836434bbf6eSJustin T. Gibbs static void xptpoll(struct cam_sim *sim); 8378088699fSJohn Baldwin static void camisr(void *); 8389758cc83SScott Long static void camisr_runqueue(void *); 8398b8a9b1dSJustin T. Gibbs static dev_match_ret xptbusmatch(struct dev_match_pattern *patterns, 8403393f8daSKenneth D. Merry u_int num_patterns, struct cam_eb *bus); 8418b8a9b1dSJustin T. Gibbs static dev_match_ret xptdevicematch(struct dev_match_pattern *patterns, 8423393f8daSKenneth D. Merry u_int num_patterns, 8433393f8daSKenneth D. Merry struct cam_ed *device); 8448b8a9b1dSJustin T. Gibbs static dev_match_ret xptperiphmatch(struct dev_match_pattern *patterns, 8453393f8daSKenneth D. Merry u_int num_patterns, 8468b8a9b1dSJustin T. Gibbs struct cam_periph *periph); 8478b8a9b1dSJustin T. Gibbs static xpt_busfunc_t xptedtbusfunc; 8488b8a9b1dSJustin T. Gibbs static xpt_targetfunc_t xptedttargetfunc; 8498b8a9b1dSJustin T. Gibbs static xpt_devicefunc_t xptedtdevicefunc; 8508b8a9b1dSJustin T. Gibbs static xpt_periphfunc_t xptedtperiphfunc; 8518b8a9b1dSJustin T. Gibbs static xpt_pdrvfunc_t xptplistpdrvfunc; 8528b8a9b1dSJustin T. Gibbs static xpt_periphfunc_t xptplistperiphfunc; 8538b8a9b1dSJustin T. Gibbs static int xptedtmatch(struct ccb_dev_match *cdm); 8548b8a9b1dSJustin T. Gibbs static int xptperiphlistmatch(struct ccb_dev_match *cdm); 8558b8a9b1dSJustin T. Gibbs static int xptbustraverse(struct cam_eb *start_bus, 8568b8a9b1dSJustin T. Gibbs xpt_busfunc_t *tr_func, void *arg); 8578b8a9b1dSJustin T. Gibbs static int xpttargettraverse(struct cam_eb *bus, 8588b8a9b1dSJustin T. Gibbs struct cam_et *start_target, 8598b8a9b1dSJustin T. Gibbs xpt_targetfunc_t *tr_func, void *arg); 8608b8a9b1dSJustin T. Gibbs static int xptdevicetraverse(struct cam_et *target, 8618b8a9b1dSJustin T. Gibbs struct cam_ed *start_device, 8628b8a9b1dSJustin T. Gibbs xpt_devicefunc_t *tr_func, void *arg); 8638b8a9b1dSJustin T. Gibbs static int xptperiphtraverse(struct cam_ed *device, 8648b8a9b1dSJustin T. Gibbs struct cam_periph *start_periph, 8658b8a9b1dSJustin T. Gibbs xpt_periphfunc_t *tr_func, void *arg); 8668b8a9b1dSJustin T. Gibbs static int xptpdrvtraverse(struct periph_driver **start_pdrv, 8678b8a9b1dSJustin T. Gibbs xpt_pdrvfunc_t *tr_func, void *arg); 8688b8a9b1dSJustin T. Gibbs static int xptpdperiphtraverse(struct periph_driver **pdrv, 8698b8a9b1dSJustin T. Gibbs struct cam_periph *start_periph, 8708b8a9b1dSJustin T. Gibbs xpt_periphfunc_t *tr_func, 8718b8a9b1dSJustin T. Gibbs void *arg); 8728b8a9b1dSJustin T. Gibbs static xpt_busfunc_t xptdefbusfunc; 8738b8a9b1dSJustin T. Gibbs static xpt_targetfunc_t xptdeftargetfunc; 8748b8a9b1dSJustin T. Gibbs static xpt_devicefunc_t xptdefdevicefunc; 8758b8a9b1dSJustin T. Gibbs static xpt_periphfunc_t xptdefperiphfunc; 8768b8a9b1dSJustin T. Gibbs static int xpt_for_all_busses(xpt_busfunc_t *tr_func, void *arg); 8778b8a9b1dSJustin T. Gibbs static int xpt_for_all_devices(xpt_devicefunc_t *tr_func, 8788b8a9b1dSJustin T. Gibbs void *arg); 8798b8a9b1dSJustin T. Gibbs static xpt_devicefunc_t xptsetasyncfunc; 8808b8a9b1dSJustin T. Gibbs static xpt_busfunc_t xptsetasyncbusfunc; 8818b8a9b1dSJustin T. Gibbs static cam_status xptregister(struct cam_periph *periph, 8828b8a9b1dSJustin T. Gibbs void *arg); 8838b8a9b1dSJustin T. Gibbs static cam_status proberegister(struct cam_periph *periph, 8848b8a9b1dSJustin T. Gibbs void *arg); 8858b8a9b1dSJustin T. Gibbs static void probeschedule(struct cam_periph *probe_periph); 8868b8a9b1dSJustin T. Gibbs static void probestart(struct cam_periph *periph, union ccb *start_ccb); 88787cfaf0eSJustin T. Gibbs static void proberequestdefaultnegotiation(struct cam_periph *periph); 8882afca7acSMatt Jacob static int proberequestbackoff(struct cam_periph *periph, 8892afca7acSMatt Jacob struct cam_ed *device); 8908b8a9b1dSJustin T. Gibbs static void probedone(struct cam_periph *periph, union ccb *done_ccb); 8918b8a9b1dSJustin T. Gibbs static void probecleanup(struct cam_periph *periph); 8928b8a9b1dSJustin T. Gibbs static void xpt_find_quirk(struct cam_ed *device); 8933393f8daSKenneth D. Merry static void xpt_devise_transport(struct cam_path *path); 8948b8a9b1dSJustin T. Gibbs static void xpt_set_transfer_settings(struct ccb_trans_settings *cts, 89503e3511bSJustin T. Gibbs struct cam_ed *device, 8968b8a9b1dSJustin T. Gibbs int async_update); 897f0adc790SJustin T. Gibbs static void xpt_toggle_tags(struct cam_path *path); 898fd21cc5eSJustin T. Gibbs static void xpt_start_tags(struct cam_path *path); 8998b8a9b1dSJustin T. Gibbs static __inline int xpt_schedule_dev_allocq(struct cam_eb *bus, 9008b8a9b1dSJustin T. Gibbs struct cam_ed *dev); 9018b8a9b1dSJustin T. Gibbs static __inline int xpt_schedule_dev_sendq(struct cam_eb *bus, 9028b8a9b1dSJustin T. Gibbs struct cam_ed *dev); 9038b8a9b1dSJustin T. Gibbs static __inline int periph_is_queued(struct cam_periph *periph); 9048b8a9b1dSJustin T. Gibbs static __inline int device_is_alloc_queued(struct cam_ed *device); 9058b8a9b1dSJustin T. Gibbs static __inline int device_is_send_queued(struct cam_ed *device); 9068b8a9b1dSJustin T. Gibbs static __inline int dev_allocq_is_runnable(struct cam_devq *devq); 9078b8a9b1dSJustin T. Gibbs 9088b8a9b1dSJustin T. Gibbs static __inline int 9098b8a9b1dSJustin T. Gibbs xpt_schedule_dev_allocq(struct cam_eb *bus, struct cam_ed *dev) 9108b8a9b1dSJustin T. Gibbs { 9118b8a9b1dSJustin T. Gibbs int retval; 9128b8a9b1dSJustin T. Gibbs 9138b8a9b1dSJustin T. Gibbs if (dev->ccbq.devq_openings > 0) { 9148b8a9b1dSJustin T. Gibbs if ((dev->flags & CAM_DEV_RESIZE_QUEUE_NEEDED) != 0) { 9158b8a9b1dSJustin T. Gibbs cam_ccbq_resize(&dev->ccbq, 9168b8a9b1dSJustin T. Gibbs dev->ccbq.dev_openings 9178b8a9b1dSJustin T. Gibbs + dev->ccbq.dev_active); 9188b8a9b1dSJustin T. Gibbs dev->flags &= ~CAM_DEV_RESIZE_QUEUE_NEEDED; 9198b8a9b1dSJustin T. Gibbs } 9205a526431SJustin T. Gibbs /* 9215a526431SJustin T. Gibbs * The priority of a device waiting for CCB resources 9225a526431SJustin T. Gibbs * is that of the the highest priority peripheral driver 9235a526431SJustin T. Gibbs * enqueued. 9245a526431SJustin T. Gibbs */ 9258b8a9b1dSJustin T. Gibbs retval = xpt_schedule_dev(&bus->sim->devq->alloc_queue, 9268b8a9b1dSJustin T. Gibbs &dev->alloc_ccb_entry.pinfo, 9275a526431SJustin T. Gibbs CAMQ_GET_HEAD(&dev->drvq)->priority); 9288b8a9b1dSJustin T. Gibbs } else { 9298b8a9b1dSJustin T. Gibbs retval = 0; 9308b8a9b1dSJustin T. Gibbs } 9318b8a9b1dSJustin T. Gibbs 9328b8a9b1dSJustin T. Gibbs return (retval); 9338b8a9b1dSJustin T. Gibbs } 9348b8a9b1dSJustin T. Gibbs 9358b8a9b1dSJustin T. Gibbs static __inline int 9368b8a9b1dSJustin T. Gibbs xpt_schedule_dev_sendq(struct cam_eb *bus, struct cam_ed *dev) 9378b8a9b1dSJustin T. Gibbs { 9388b8a9b1dSJustin T. Gibbs int retval; 9398b8a9b1dSJustin T. Gibbs 9408b8a9b1dSJustin T. Gibbs if (dev->ccbq.dev_openings > 0) { 9415a526431SJustin T. Gibbs /* 9425a526431SJustin T. Gibbs * The priority of a device waiting for controller 9435a526431SJustin T. Gibbs * resources is that of the the highest priority CCB 9445a526431SJustin T. Gibbs * enqueued. 9455a526431SJustin T. Gibbs */ 9465a526431SJustin T. Gibbs retval = 9475a526431SJustin T. Gibbs xpt_schedule_dev(&bus->sim->devq->send_queue, 9488b8a9b1dSJustin T. Gibbs &dev->send_ccb_entry.pinfo, 9495a526431SJustin T. Gibbs CAMQ_GET_HEAD(&dev->ccbq.queue)->priority); 9508b8a9b1dSJustin T. Gibbs } else { 9518b8a9b1dSJustin T. Gibbs retval = 0; 9528b8a9b1dSJustin T. Gibbs } 9538b8a9b1dSJustin T. Gibbs return (retval); 9548b8a9b1dSJustin T. Gibbs } 9558b8a9b1dSJustin T. Gibbs 9568b8a9b1dSJustin T. Gibbs static __inline int 9578b8a9b1dSJustin T. Gibbs periph_is_queued(struct cam_periph *periph) 9588b8a9b1dSJustin T. Gibbs { 9598b8a9b1dSJustin T. Gibbs return (periph->pinfo.index != CAM_UNQUEUED_INDEX); 9608b8a9b1dSJustin T. Gibbs } 9618b8a9b1dSJustin T. Gibbs 9628b8a9b1dSJustin T. Gibbs static __inline int 9638b8a9b1dSJustin T. Gibbs device_is_alloc_queued(struct cam_ed *device) 9648b8a9b1dSJustin T. Gibbs { 9658b8a9b1dSJustin T. Gibbs return (device->alloc_ccb_entry.pinfo.index != CAM_UNQUEUED_INDEX); 9668b8a9b1dSJustin T. Gibbs } 9678b8a9b1dSJustin T. Gibbs 9688b8a9b1dSJustin T. Gibbs static __inline int 9698b8a9b1dSJustin T. Gibbs device_is_send_queued(struct cam_ed *device) 9708b8a9b1dSJustin T. Gibbs { 9718b8a9b1dSJustin T. Gibbs return (device->send_ccb_entry.pinfo.index != CAM_UNQUEUED_INDEX); 9728b8a9b1dSJustin T. Gibbs } 9738b8a9b1dSJustin T. Gibbs 9748b8a9b1dSJustin T. Gibbs static __inline int 9758b8a9b1dSJustin T. Gibbs dev_allocq_is_runnable(struct cam_devq *devq) 9768b8a9b1dSJustin T. Gibbs { 9778b8a9b1dSJustin T. Gibbs /* 9788b8a9b1dSJustin T. Gibbs * Have work to do. 9798b8a9b1dSJustin T. Gibbs * Have space to do more work. 9808b8a9b1dSJustin T. Gibbs * Allowed to do work. 9818b8a9b1dSJustin T. Gibbs */ 9828b8a9b1dSJustin T. Gibbs return ((devq->alloc_queue.qfrozen_cnt == 0) 9838b8a9b1dSJustin T. Gibbs && (devq->alloc_queue.entries > 0) 9848b8a9b1dSJustin T. Gibbs && (devq->alloc_openings > 0)); 9858b8a9b1dSJustin T. Gibbs } 9868b8a9b1dSJustin T. Gibbs 9878b8a9b1dSJustin T. Gibbs static void 9888b8a9b1dSJustin T. Gibbs xpt_periph_init() 9898b8a9b1dSJustin T. Gibbs { 99073d26919SKenneth D. Merry make_dev(&xpt_cdevsw, 0, UID_ROOT, GID_OPERATOR, 0600, "xpt0"); 9918b8a9b1dSJustin T. Gibbs } 9928b8a9b1dSJustin T. Gibbs 9938b8a9b1dSJustin T. Gibbs static void 9948b8a9b1dSJustin T. Gibbs probe_periph_init() 9958b8a9b1dSJustin T. Gibbs { 9968b8a9b1dSJustin T. Gibbs } 9978b8a9b1dSJustin T. Gibbs 9988b8a9b1dSJustin T. Gibbs 9998b8a9b1dSJustin T. Gibbs static void 10008b8a9b1dSJustin T. Gibbs xptdone(struct cam_periph *periph, union ccb *done_ccb) 10018b8a9b1dSJustin T. Gibbs { 10028b8a9b1dSJustin T. Gibbs /* Caller will release the CCB */ 10038b8a9b1dSJustin T. Gibbs wakeup(&done_ccb->ccb_h.cbfcnp); 10048b8a9b1dSJustin T. Gibbs } 10058b8a9b1dSJustin T. Gibbs 10068b8a9b1dSJustin T. Gibbs static int 100789c9c53dSPoul-Henning Kamp xptopen(struct cdev *dev, int flags, int fmt, struct thread *td) 10088b8a9b1dSJustin T. Gibbs { 10098b8a9b1dSJustin T. Gibbs 10108b8a9b1dSJustin T. Gibbs /* 101166a0780eSKenneth D. Merry * Only allow read-write access. 101266a0780eSKenneth D. Merry */ 101366a0780eSKenneth D. Merry if (((flags & FWRITE) == 0) || ((flags & FREAD) == 0)) 101466a0780eSKenneth D. Merry return(EPERM); 101566a0780eSKenneth D. Merry 101666a0780eSKenneth D. Merry /* 10178b8a9b1dSJustin T. Gibbs * We don't allow nonblocking access. 10188b8a9b1dSJustin T. Gibbs */ 10198b8a9b1dSJustin T. Gibbs if ((flags & O_NONBLOCK) != 0) { 10202b83592fSScott Long printf("%s: can't do nonblocking access\n", devtoname(dev)); 10218b8a9b1dSJustin T. Gibbs return(ENODEV); 10228b8a9b1dSJustin T. Gibbs } 10238b8a9b1dSJustin T. Gibbs 10248b8a9b1dSJustin T. Gibbs /* Mark ourselves open */ 10252b83592fSScott Long mtx_lock(&xsoftc.xpt_lock); 10268b8a9b1dSJustin T. Gibbs xsoftc.flags |= XPT_FLAG_OPEN; 10272b83592fSScott Long mtx_unlock(&xsoftc.xpt_lock); 10288b8a9b1dSJustin T. Gibbs 10298b8a9b1dSJustin T. Gibbs return(0); 10308b8a9b1dSJustin T. Gibbs } 10318b8a9b1dSJustin T. Gibbs 10328b8a9b1dSJustin T. Gibbs static int 103389c9c53dSPoul-Henning Kamp xptclose(struct cdev *dev, int flag, int fmt, struct thread *td) 10348b8a9b1dSJustin T. Gibbs { 10358b8a9b1dSJustin T. Gibbs 10368b8a9b1dSJustin T. Gibbs /* Mark ourselves closed */ 10372b83592fSScott Long mtx_lock(&xsoftc.xpt_lock); 10388b8a9b1dSJustin T. Gibbs xsoftc.flags &= ~XPT_FLAG_OPEN; 10392b83592fSScott Long mtx_unlock(&xsoftc.xpt_lock); 10408b8a9b1dSJustin T. Gibbs 10418b8a9b1dSJustin T. Gibbs return(0); 10428b8a9b1dSJustin T. Gibbs } 10438b8a9b1dSJustin T. Gibbs 10442b83592fSScott Long /* 10452b83592fSScott Long * Don't automatically grab the xpt softc lock here even though this is going 10462b83592fSScott Long * through the xpt device. The xpt device is really just a back door for 10472b83592fSScott Long * accessing other devices and SIMs, so the right thing to do is to grab 10482b83592fSScott Long * the appropriate SIM lock once the bus/SIM is located. 10492b83592fSScott Long */ 10508b8a9b1dSJustin T. Gibbs static int 105189c9c53dSPoul-Henning Kamp xptioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, struct thread *td) 10528b8a9b1dSJustin T. Gibbs { 10532b83592fSScott Long int error; 10548b8a9b1dSJustin T. Gibbs 10558b8a9b1dSJustin T. Gibbs error = 0; 10568b8a9b1dSJustin T. Gibbs 10578b8a9b1dSJustin T. Gibbs switch(cmd) { 10588b8a9b1dSJustin T. Gibbs /* 10598b8a9b1dSJustin T. Gibbs * For the transport layer CAMIOCOMMAND ioctl, we really only want 10608b8a9b1dSJustin T. Gibbs * to accept CCB types that don't quite make sense to send through a 10618c7a96c5SScott Long * passthrough driver. XPT_PATH_INQ is an exception to this, as stated 10628c7a96c5SScott Long * in the CAM spec. 10638b8a9b1dSJustin T. Gibbs */ 10648b8a9b1dSJustin T. Gibbs case CAMIOCOMMAND: { 10658b8a9b1dSJustin T. Gibbs union ccb *ccb; 10668b8a9b1dSJustin T. Gibbs union ccb *inccb; 10672b83592fSScott Long struct cam_eb *bus; 10688b8a9b1dSJustin T. Gibbs 10698b8a9b1dSJustin T. Gibbs inccb = (union ccb *)addr; 10708b8a9b1dSJustin T. Gibbs 10712b83592fSScott Long bus = xpt_find_bus(inccb->ccb_h.path_id); 10722b83592fSScott Long if (bus == NULL) { 10732b83592fSScott Long error = EINVAL; 10742b83592fSScott Long break; 10752b83592fSScott Long } 10762b83592fSScott Long 10778b8a9b1dSJustin T. Gibbs switch(inccb->ccb_h.func_code) { 10788b8a9b1dSJustin T. Gibbs case XPT_SCAN_BUS: 10798b8a9b1dSJustin T. Gibbs case XPT_RESET_BUS: 10808b8a9b1dSJustin T. Gibbs if ((inccb->ccb_h.target_id != CAM_TARGET_WILDCARD) 10818b8a9b1dSJustin T. Gibbs || (inccb->ccb_h.target_lun != CAM_LUN_WILDCARD)) { 10828b8a9b1dSJustin T. Gibbs error = EINVAL; 10838b8a9b1dSJustin T. Gibbs break; 10848b8a9b1dSJustin T. Gibbs } 10858b8a9b1dSJustin T. Gibbs /* FALLTHROUGH */ 10868c7a96c5SScott Long case XPT_PATH_INQ: 10878fcf57f5SJustin T. Gibbs case XPT_ENG_INQ: 10888b8a9b1dSJustin T. Gibbs case XPT_SCAN_LUN: 10898b8a9b1dSJustin T. Gibbs 10908008a935SScott Long ccb = xpt_alloc_ccb(); 10912b83592fSScott Long 10922b83592fSScott Long CAM_SIM_LOCK(bus->sim); 10938b8a9b1dSJustin T. Gibbs 10948b8a9b1dSJustin T. Gibbs /* 10958b8a9b1dSJustin T. Gibbs * Create a path using the bus, target, and lun the 10968b8a9b1dSJustin T. Gibbs * user passed in. 10978b8a9b1dSJustin T. Gibbs */ 10988b8a9b1dSJustin T. Gibbs if (xpt_create_path(&ccb->ccb_h.path, xpt_periph, 10998b8a9b1dSJustin T. Gibbs inccb->ccb_h.path_id, 11008b8a9b1dSJustin T. Gibbs inccb->ccb_h.target_id, 11018b8a9b1dSJustin T. Gibbs inccb->ccb_h.target_lun) != 11028b8a9b1dSJustin T. Gibbs CAM_REQ_CMP){ 11038b8a9b1dSJustin T. Gibbs error = EINVAL; 11042b83592fSScott Long CAM_SIM_UNLOCK(bus->sim); 11058b8a9b1dSJustin T. Gibbs xpt_free_ccb(ccb); 11068b8a9b1dSJustin T. Gibbs break; 11078b8a9b1dSJustin T. Gibbs } 11088b8a9b1dSJustin T. Gibbs /* Ensure all of our fields are correct */ 11098b8a9b1dSJustin T. Gibbs xpt_setup_ccb(&ccb->ccb_h, ccb->ccb_h.path, 11108b8a9b1dSJustin T. Gibbs inccb->ccb_h.pinfo.priority); 11118b8a9b1dSJustin T. Gibbs xpt_merge_ccb(ccb, inccb); 11128b8a9b1dSJustin T. Gibbs ccb->ccb_h.cbfcnp = xptdone; 11138b8a9b1dSJustin T. Gibbs cam_periph_runccb(ccb, NULL, 0, 0, NULL); 11148b8a9b1dSJustin T. Gibbs bcopy(ccb, inccb, sizeof(union ccb)); 11158b8a9b1dSJustin T. Gibbs xpt_free_path(ccb->ccb_h.path); 11168b8a9b1dSJustin T. Gibbs xpt_free_ccb(ccb); 11172b83592fSScott Long CAM_SIM_UNLOCK(bus->sim); 11188b8a9b1dSJustin T. Gibbs break; 11198b8a9b1dSJustin T. Gibbs 11208b8a9b1dSJustin T. Gibbs case XPT_DEBUG: { 11218b8a9b1dSJustin T. Gibbs union ccb ccb; 11228b8a9b1dSJustin T. Gibbs 11238b8a9b1dSJustin T. Gibbs /* 1124aa872be6SMatt Jacob * This is an immediate CCB, so it's okay to 11258b8a9b1dSJustin T. Gibbs * allocate it on the stack. 11268b8a9b1dSJustin T. Gibbs */ 11278b8a9b1dSJustin T. Gibbs 11282b83592fSScott Long CAM_SIM_LOCK(bus->sim); 11292b83592fSScott Long 11308b8a9b1dSJustin T. Gibbs /* 11318b8a9b1dSJustin T. Gibbs * Create a path using the bus, target, and lun the 11328b8a9b1dSJustin T. Gibbs * user passed in. 11338b8a9b1dSJustin T. Gibbs */ 11348b8a9b1dSJustin T. Gibbs if (xpt_create_path(&ccb.ccb_h.path, xpt_periph, 11358b8a9b1dSJustin T. Gibbs inccb->ccb_h.path_id, 11368b8a9b1dSJustin T. Gibbs inccb->ccb_h.target_id, 11378b8a9b1dSJustin T. Gibbs inccb->ccb_h.target_lun) != 11388b8a9b1dSJustin T. Gibbs CAM_REQ_CMP){ 11398b8a9b1dSJustin T. Gibbs error = EINVAL; 11408b8a9b1dSJustin T. Gibbs break; 11418b8a9b1dSJustin T. Gibbs } 11428b8a9b1dSJustin T. Gibbs /* Ensure all of our fields are correct */ 11438b8a9b1dSJustin T. Gibbs xpt_setup_ccb(&ccb.ccb_h, ccb.ccb_h.path, 11448b8a9b1dSJustin T. Gibbs inccb->ccb_h.pinfo.priority); 11458b8a9b1dSJustin T. Gibbs xpt_merge_ccb(&ccb, inccb); 11468b8a9b1dSJustin T. Gibbs ccb.ccb_h.cbfcnp = xptdone; 11478b8a9b1dSJustin T. Gibbs xpt_action(&ccb); 11482b83592fSScott Long CAM_SIM_UNLOCK(bus->sim); 11498b8a9b1dSJustin T. Gibbs bcopy(&ccb, inccb, sizeof(union ccb)); 11508b8a9b1dSJustin T. Gibbs xpt_free_path(ccb.ccb_h.path); 11518b8a9b1dSJustin T. Gibbs break; 11528b8a9b1dSJustin T. Gibbs 11538b8a9b1dSJustin T. Gibbs } 11548b8a9b1dSJustin T. Gibbs case XPT_DEV_MATCH: { 11558b8a9b1dSJustin T. Gibbs struct cam_periph_map_info mapinfo; 115659190eaaSKenneth D. Merry struct cam_path *old_path; 11578b8a9b1dSJustin T. Gibbs 11588b8a9b1dSJustin T. Gibbs /* 11598b8a9b1dSJustin T. Gibbs * We can't deal with physical addresses for this 11608b8a9b1dSJustin T. Gibbs * type of transaction. 11618b8a9b1dSJustin T. Gibbs */ 11628b8a9b1dSJustin T. Gibbs if (inccb->ccb_h.flags & CAM_DATA_PHYS) { 11638b8a9b1dSJustin T. Gibbs error = EINVAL; 11648b8a9b1dSJustin T. Gibbs break; 11658b8a9b1dSJustin T. Gibbs } 116659190eaaSKenneth D. Merry 116759190eaaSKenneth D. Merry /* 116859190eaaSKenneth D. Merry * Save this in case the caller had it set to 116959190eaaSKenneth D. Merry * something in particular. 117059190eaaSKenneth D. Merry */ 117159190eaaSKenneth D. Merry old_path = inccb->ccb_h.path; 117259190eaaSKenneth D. Merry 117359190eaaSKenneth D. Merry /* 117459190eaaSKenneth D. Merry * We really don't need a path for the matching 117559190eaaSKenneth D. Merry * code. The path is needed because of the 117659190eaaSKenneth D. Merry * debugging statements in xpt_action(). They 117759190eaaSKenneth D. Merry * assume that the CCB has a valid path. 117859190eaaSKenneth D. Merry */ 117959190eaaSKenneth D. Merry inccb->ccb_h.path = xpt_periph->path; 118059190eaaSKenneth D. Merry 11818b8a9b1dSJustin T. Gibbs bzero(&mapinfo, sizeof(mapinfo)); 11828b8a9b1dSJustin T. Gibbs 11838b8a9b1dSJustin T. Gibbs /* 11848b8a9b1dSJustin T. Gibbs * Map the pattern and match buffers into kernel 11858b8a9b1dSJustin T. Gibbs * virtual address space. 11868b8a9b1dSJustin T. Gibbs */ 11878b8a9b1dSJustin T. Gibbs error = cam_periph_mapmem(inccb, &mapinfo); 11888b8a9b1dSJustin T. Gibbs 118959190eaaSKenneth D. Merry if (error) { 119059190eaaSKenneth D. Merry inccb->ccb_h.path = old_path; 11918b8a9b1dSJustin T. Gibbs break; 119259190eaaSKenneth D. Merry } 11938b8a9b1dSJustin T. Gibbs 11948b8a9b1dSJustin T. Gibbs /* 11958b8a9b1dSJustin T. Gibbs * This is an immediate CCB, we can send it on directly. 11968b8a9b1dSJustin T. Gibbs */ 11978b8a9b1dSJustin T. Gibbs xpt_action(inccb); 11988b8a9b1dSJustin T. Gibbs 11998b8a9b1dSJustin T. Gibbs /* 12008b8a9b1dSJustin T. Gibbs * Map the buffers back into user space. 12018b8a9b1dSJustin T. Gibbs */ 12028b8a9b1dSJustin T. Gibbs cam_periph_unmapmem(inccb, &mapinfo); 12038b8a9b1dSJustin T. Gibbs 120459190eaaSKenneth D. Merry inccb->ccb_h.path = old_path; 120559190eaaSKenneth D. Merry 12068b8a9b1dSJustin T. Gibbs error = 0; 12078b8a9b1dSJustin T. Gibbs break; 12088b8a9b1dSJustin T. Gibbs } 12098b8a9b1dSJustin T. Gibbs default: 12108fcf57f5SJustin T. Gibbs error = ENOTSUP; 12118b8a9b1dSJustin T. Gibbs break; 12128b8a9b1dSJustin T. Gibbs } 1213daddc001SScott Long xpt_release_bus(bus); 12148b8a9b1dSJustin T. Gibbs break; 12158b8a9b1dSJustin T. Gibbs } 12168b8a9b1dSJustin T. Gibbs /* 12178b8a9b1dSJustin T. Gibbs * This is the getpassthru ioctl. It takes a XPT_GDEVLIST ccb as input, 12188b8a9b1dSJustin T. Gibbs * with the periphal driver name and unit name filled in. The other 12198b8a9b1dSJustin T. Gibbs * fields don't really matter as input. The passthrough driver name 12208b8a9b1dSJustin T. Gibbs * ("pass"), and unit number are passed back in the ccb. The current 12218b8a9b1dSJustin T. Gibbs * device generation number, and the index into the device peripheral 12228b8a9b1dSJustin T. Gibbs * driver list, and the status are also passed back. Note that 12238b8a9b1dSJustin T. Gibbs * since we do everything in one pass, unlike the XPT_GDEVLIST ccb, 12248b8a9b1dSJustin T. Gibbs * we never return a status of CAM_GDEVLIST_LIST_CHANGED. It is 12258b8a9b1dSJustin T. Gibbs * (or rather should be) impossible for the device peripheral driver 12268b8a9b1dSJustin T. Gibbs * list to change since we look at the whole thing in one pass, and 122777dc25ccSScott Long * we do it with lock protection. 12288b8a9b1dSJustin T. Gibbs * 12298b8a9b1dSJustin T. Gibbs */ 12308b8a9b1dSJustin T. Gibbs case CAMGETPASSTHRU: { 12318b8a9b1dSJustin T. Gibbs union ccb *ccb; 12328b8a9b1dSJustin T. Gibbs struct cam_periph *periph; 12338b8a9b1dSJustin T. Gibbs struct periph_driver **p_drv; 12348b8a9b1dSJustin T. Gibbs char *name; 12353393f8daSKenneth D. Merry u_int unit; 12363393f8daSKenneth D. Merry u_int cur_generation; 1237621a60d4SKenneth D. Merry int base_periph_found; 12388b8a9b1dSJustin T. Gibbs int splbreaknum; 12398b8a9b1dSJustin T. Gibbs 12408b8a9b1dSJustin T. Gibbs ccb = (union ccb *)addr; 12418b8a9b1dSJustin T. Gibbs unit = ccb->cgdl.unit_number; 12428b8a9b1dSJustin T. Gibbs name = ccb->cgdl.periph_name; 12438b8a9b1dSJustin T. Gibbs /* 124477dc25ccSScott Long * Every 100 devices, we want to drop our lock protection to 12458b8a9b1dSJustin T. Gibbs * give the software interrupt handler a chance to run. 12468b8a9b1dSJustin T. Gibbs * Most systems won't run into this check, but this should 12478b8a9b1dSJustin T. Gibbs * avoid starvation in the software interrupt handler in 12488b8a9b1dSJustin T. Gibbs * large systems. 12498b8a9b1dSJustin T. Gibbs */ 12508b8a9b1dSJustin T. Gibbs splbreaknum = 100; 12518b8a9b1dSJustin T. Gibbs 12528b8a9b1dSJustin T. Gibbs ccb = (union ccb *)addr; 12538b8a9b1dSJustin T. Gibbs 1254621a60d4SKenneth D. Merry base_periph_found = 0; 1255621a60d4SKenneth D. Merry 12568b8a9b1dSJustin T. Gibbs /* 12578b8a9b1dSJustin T. Gibbs * Sanity check -- make sure we don't get a null peripheral 12588b8a9b1dSJustin T. Gibbs * driver name. 12598b8a9b1dSJustin T. Gibbs */ 12608b8a9b1dSJustin T. Gibbs if (*ccb->cgdl.periph_name == '\0') { 12618b8a9b1dSJustin T. Gibbs error = EINVAL; 12628b8a9b1dSJustin T. Gibbs break; 12638b8a9b1dSJustin T. Gibbs } 12648b8a9b1dSJustin T. Gibbs 12658b8a9b1dSJustin T. Gibbs /* Keep the list from changing while we traverse it */ 126677dc25ccSScott Long mtx_lock(&xsoftc.xpt_topo_lock); 12678b8a9b1dSJustin T. Gibbs ptstartover: 12682b83592fSScott Long cur_generation = xsoftc.xpt_generation; 12698b8a9b1dSJustin T. Gibbs 12708b8a9b1dSJustin T. Gibbs /* first find our driver in the list of drivers */ 12710b7c27b9SPeter Wemm for (p_drv = periph_drivers; *p_drv != NULL; p_drv++) 12728b8a9b1dSJustin T. Gibbs if (strcmp((*p_drv)->driver_name, name) == 0) 12738b8a9b1dSJustin T. Gibbs break; 12748b8a9b1dSJustin T. Gibbs 12758b8a9b1dSJustin T. Gibbs if (*p_drv == NULL) { 127677dc25ccSScott Long mtx_unlock(&xsoftc.xpt_topo_lock); 12778b8a9b1dSJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_CMP_ERR; 12788b8a9b1dSJustin T. Gibbs ccb->cgdl.status = CAM_GDEVLIST_ERROR; 12798b8a9b1dSJustin T. Gibbs *ccb->cgdl.periph_name = '\0'; 12808b8a9b1dSJustin T. Gibbs ccb->cgdl.unit_number = 0; 12818b8a9b1dSJustin T. Gibbs error = ENOENT; 12828b8a9b1dSJustin T. Gibbs break; 12838b8a9b1dSJustin T. Gibbs } 12848b8a9b1dSJustin T. Gibbs 12858b8a9b1dSJustin T. Gibbs /* 12868b8a9b1dSJustin T. Gibbs * Run through every peripheral instance of this driver 12878b8a9b1dSJustin T. Gibbs * and check to see whether it matches the unit passed 12888b8a9b1dSJustin T. Gibbs * in by the user. If it does, get out of the loops and 12898b8a9b1dSJustin T. Gibbs * find the passthrough driver associated with that 12908b8a9b1dSJustin T. Gibbs * peripheral driver. 12918b8a9b1dSJustin T. Gibbs */ 12928b8a9b1dSJustin T. Gibbs for (periph = TAILQ_FIRST(&(*p_drv)->units); periph != NULL; 12938b8a9b1dSJustin T. Gibbs periph = TAILQ_NEXT(periph, unit_links)) { 12948b8a9b1dSJustin T. Gibbs 12958b8a9b1dSJustin T. Gibbs if (periph->unit_number == unit) { 12968b8a9b1dSJustin T. Gibbs break; 12978b8a9b1dSJustin T. Gibbs } else if (--splbreaknum == 0) { 129877dc25ccSScott Long mtx_unlock(&xsoftc.xpt_topo_lock); 129977dc25ccSScott Long mtx_lock(&xsoftc.xpt_topo_lock); 13008b8a9b1dSJustin T. Gibbs splbreaknum = 100; 13012b83592fSScott Long if (cur_generation != xsoftc.xpt_generation) 13028b8a9b1dSJustin T. Gibbs goto ptstartover; 13038b8a9b1dSJustin T. Gibbs } 13048b8a9b1dSJustin T. Gibbs } 13058b8a9b1dSJustin T. Gibbs /* 13068b8a9b1dSJustin T. Gibbs * If we found the peripheral driver that the user passed 13078b8a9b1dSJustin T. Gibbs * in, go through all of the peripheral drivers for that 13088b8a9b1dSJustin T. Gibbs * particular device and look for a passthrough driver. 13098b8a9b1dSJustin T. Gibbs */ 13108b8a9b1dSJustin T. Gibbs if (periph != NULL) { 13118b8a9b1dSJustin T. Gibbs struct cam_ed *device; 13128b8a9b1dSJustin T. Gibbs int i; 13138b8a9b1dSJustin T. Gibbs 1314621a60d4SKenneth D. Merry base_periph_found = 1; 13158b8a9b1dSJustin T. Gibbs device = periph->path->device; 1316fc2ffbe6SPoul-Henning Kamp for (i = 0, periph = SLIST_FIRST(&device->periphs); 13178b8a9b1dSJustin T. Gibbs periph != NULL; 1318fc2ffbe6SPoul-Henning Kamp periph = SLIST_NEXT(periph, periph_links), i++) { 13198b8a9b1dSJustin T. Gibbs /* 13208b8a9b1dSJustin T. Gibbs * Check to see whether we have a 13218b8a9b1dSJustin T. Gibbs * passthrough device or not. 13228b8a9b1dSJustin T. Gibbs */ 13238b8a9b1dSJustin T. Gibbs if (strcmp(periph->periph_name, "pass") == 0) { 13248b8a9b1dSJustin T. Gibbs /* 13258b8a9b1dSJustin T. Gibbs * Fill in the getdevlist fields. 13268b8a9b1dSJustin T. Gibbs */ 13278b8a9b1dSJustin T. Gibbs strcpy(ccb->cgdl.periph_name, 13288b8a9b1dSJustin T. Gibbs periph->periph_name); 13298b8a9b1dSJustin T. Gibbs ccb->cgdl.unit_number = 13308b8a9b1dSJustin T. Gibbs periph->unit_number; 1331fc2ffbe6SPoul-Henning Kamp if (SLIST_NEXT(periph, periph_links)) 13328b8a9b1dSJustin T. Gibbs ccb->cgdl.status = 13338b8a9b1dSJustin T. Gibbs CAM_GDEVLIST_MORE_DEVS; 13348b8a9b1dSJustin T. Gibbs else 13358b8a9b1dSJustin T. Gibbs ccb->cgdl.status = 13368b8a9b1dSJustin T. Gibbs CAM_GDEVLIST_LAST_DEVICE; 13378b8a9b1dSJustin T. Gibbs ccb->cgdl.generation = 13388b8a9b1dSJustin T. Gibbs device->generation; 13398b8a9b1dSJustin T. Gibbs ccb->cgdl.index = i; 13408b8a9b1dSJustin T. Gibbs /* 13418b8a9b1dSJustin T. Gibbs * Fill in some CCB header fields 13428b8a9b1dSJustin T. Gibbs * that the user may want. 13438b8a9b1dSJustin T. Gibbs */ 13448b8a9b1dSJustin T. Gibbs ccb->ccb_h.path_id = 13458b8a9b1dSJustin T. Gibbs periph->path->bus->path_id; 13468b8a9b1dSJustin T. Gibbs ccb->ccb_h.target_id = 13478b8a9b1dSJustin T. Gibbs periph->path->target->target_id; 13488b8a9b1dSJustin T. Gibbs ccb->ccb_h.target_lun = 13498b8a9b1dSJustin T. Gibbs periph->path->device->lun_id; 13508b8a9b1dSJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_CMP; 13518b8a9b1dSJustin T. Gibbs break; 13528b8a9b1dSJustin T. Gibbs } 13538b8a9b1dSJustin T. Gibbs } 13548b8a9b1dSJustin T. Gibbs } 13558b8a9b1dSJustin T. Gibbs 13568b8a9b1dSJustin T. Gibbs /* 13578b8a9b1dSJustin T. Gibbs * If the periph is null here, one of two things has 13588b8a9b1dSJustin T. Gibbs * happened. The first possibility is that we couldn't 13598b8a9b1dSJustin T. Gibbs * find the unit number of the particular peripheral driver 13608b8a9b1dSJustin T. Gibbs * that the user is asking about. e.g. the user asks for 13618b8a9b1dSJustin T. Gibbs * the passthrough driver for "da11". We find the list of 13628b8a9b1dSJustin T. Gibbs * "da" peripherals all right, but there is no unit 11. 13638b8a9b1dSJustin T. Gibbs * The other possibility is that we went through the list 13648b8a9b1dSJustin T. Gibbs * of peripheral drivers attached to the device structure, 13658b8a9b1dSJustin T. Gibbs * but didn't find one with the name "pass". Either way, 13668b8a9b1dSJustin T. Gibbs * we return ENOENT, since we couldn't find something. 13678b8a9b1dSJustin T. Gibbs */ 13688b8a9b1dSJustin T. Gibbs if (periph == NULL) { 13698b8a9b1dSJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_CMP_ERR; 13708b8a9b1dSJustin T. Gibbs ccb->cgdl.status = CAM_GDEVLIST_ERROR; 13718b8a9b1dSJustin T. Gibbs *ccb->cgdl.periph_name = '\0'; 13728b8a9b1dSJustin T. Gibbs ccb->cgdl.unit_number = 0; 13738b8a9b1dSJustin T. Gibbs error = ENOENT; 1374621a60d4SKenneth D. Merry /* 1375621a60d4SKenneth D. Merry * It is unfortunate that this is even necessary, 1376621a60d4SKenneth D. Merry * but there are many, many clueless users out there. 1377621a60d4SKenneth D. Merry * If this is true, the user is looking for the 1378621a60d4SKenneth D. Merry * passthrough driver, but doesn't have one in his 1379621a60d4SKenneth D. Merry * kernel. 1380621a60d4SKenneth D. Merry */ 1381621a60d4SKenneth D. Merry if (base_periph_found == 1) { 1382621a60d4SKenneth D. Merry printf("xptioctl: pass driver is not in the " 1383621a60d4SKenneth D. Merry "kernel\n"); 1384621a60d4SKenneth D. Merry printf("xptioctl: put \"device pass0\" in " 1385621a60d4SKenneth D. Merry "your kernel config file\n"); 1386621a60d4SKenneth D. Merry } 13878b8a9b1dSJustin T. Gibbs } 138877dc25ccSScott Long mtx_unlock(&xsoftc.xpt_topo_lock); 13898b8a9b1dSJustin T. Gibbs break; 13908b8a9b1dSJustin T. Gibbs } 13918b8a9b1dSJustin T. Gibbs default: 13928b8a9b1dSJustin T. Gibbs error = ENOTTY; 13938b8a9b1dSJustin T. Gibbs break; 13948b8a9b1dSJustin T. Gibbs } 13958b8a9b1dSJustin T. Gibbs 13968b8a9b1dSJustin T. Gibbs return(error); 13978b8a9b1dSJustin T. Gibbs } 13988b8a9b1dSJustin T. Gibbs 139974bd1c10SNick Hibma static int 140074bd1c10SNick Hibma cam_module_event_handler(module_t mod, int what, void *arg) 140174bd1c10SNick Hibma { 14022b83592fSScott Long int error; 14032b83592fSScott Long 14042b83592fSScott Long switch (what) { 14052b83592fSScott Long case MOD_LOAD: 14062b83592fSScott Long if ((error = xpt_init(NULL)) != 0) 14072b83592fSScott Long return (error); 14082b83592fSScott Long break; 14092b83592fSScott Long case MOD_UNLOAD: 141074bd1c10SNick Hibma return EBUSY; 14112b83592fSScott Long default: 14123e019deaSPoul-Henning Kamp return EOPNOTSUPP; 141374bd1c10SNick Hibma } 141474bd1c10SNick Hibma 141574bd1c10SNick Hibma return 0; 141674bd1c10SNick Hibma } 141774bd1c10SNick Hibma 14189e6461a2SMatt Jacob /* thread to handle bus rescans */ 14199e6461a2SMatt Jacob static void 14209e6461a2SMatt Jacob xpt_scanner_thread(void *dummy) 14219e6461a2SMatt Jacob { 14222b83592fSScott Long cam_isrq_t queue; 14239e6461a2SMatt Jacob union ccb *ccb; 14242b83592fSScott Long struct cam_sim *sim; 14252b83592fSScott Long 14262b83592fSScott Long for (;;) { 14272b83592fSScott Long /* 14282b83592fSScott Long * Wait for a rescan request to come in. When it does, splice 14292b83592fSScott Long * it onto a queue from local storage so that the xpt lock 14302b83592fSScott Long * doesn't need to be held while the requests are being 14312b83592fSScott Long * processed. 14322b83592fSScott Long */ 14332b83592fSScott Long xpt_lock_buses(); 14342b83592fSScott Long msleep(&xsoftc.ccb_scanq, &xsoftc.xpt_topo_lock, PRIBIO, 14352b83592fSScott Long "ccb_scanq", 0); 14362b83592fSScott Long TAILQ_INIT(&queue); 14372b83592fSScott Long TAILQ_CONCAT(&queue, &xsoftc.ccb_scanq, sim_links.tqe); 14382b83592fSScott Long xpt_unlock_buses(); 14392b83592fSScott Long 14402b83592fSScott Long while ((ccb = (union ccb *)TAILQ_FIRST(&queue)) != NULL) { 14412b83592fSScott Long TAILQ_REMOVE(&queue, &ccb->ccb_h, sim_links.tqe); 14422b83592fSScott Long 14432b83592fSScott Long sim = ccb->ccb_h.path->bus->sim; 144411e4faceSScott Long CAM_SIM_LOCK(sim); 14452b83592fSScott Long 14469e6461a2SMatt Jacob ccb->ccb_h.func_code = XPT_SCAN_BUS; 14479e6461a2SMatt Jacob ccb->ccb_h.cbfcnp = xptdone; 14489e6461a2SMatt Jacob xpt_setup_ccb(&ccb->ccb_h, ccb->ccb_h.path, 5); 14499e6461a2SMatt Jacob cam_periph_runccb(ccb, NULL, 0, 0, NULL); 14509e6461a2SMatt Jacob xpt_free_path(ccb->ccb_h.path); 14519e6461a2SMatt Jacob xpt_free_ccb(ccb); 145211e4faceSScott Long CAM_SIM_UNLOCK(sim); 14539e6461a2SMatt Jacob } 14549e6461a2SMatt Jacob } 14559e6461a2SMatt Jacob } 14569e6461a2SMatt Jacob 14579e6461a2SMatt Jacob void 14589e6461a2SMatt Jacob xpt_rescan(union ccb *ccb) 14599e6461a2SMatt Jacob { 14609e6461a2SMatt Jacob struct ccb_hdr *hdr; 14612b83592fSScott Long 14629e6461a2SMatt Jacob /* 14639e6461a2SMatt Jacob * Don't make duplicate entries for the same paths. 14649e6461a2SMatt Jacob */ 14652b83592fSScott Long xpt_lock_buses(); 14662b83592fSScott Long TAILQ_FOREACH(hdr, &xsoftc.ccb_scanq, sim_links.tqe) { 14679e6461a2SMatt Jacob if (xpt_path_comp(hdr->path, ccb->ccb_h.path) == 0) { 14682b83592fSScott Long xpt_unlock_buses(); 14699e6461a2SMatt Jacob xpt_print(ccb->ccb_h.path, "rescan already queued\n"); 14709e6461a2SMatt Jacob xpt_free_path(ccb->ccb_h.path); 14719e6461a2SMatt Jacob xpt_free_ccb(ccb); 14729e6461a2SMatt Jacob return; 14739e6461a2SMatt Jacob } 14749e6461a2SMatt Jacob } 14752b83592fSScott Long TAILQ_INSERT_TAIL(&xsoftc.ccb_scanq, &ccb->ccb_h, sim_links.tqe); 14762b83592fSScott Long wakeup(&xsoftc.ccb_scanq); 14772b83592fSScott Long xpt_unlock_buses(); 14789e6461a2SMatt Jacob } 14799e6461a2SMatt Jacob 14808b8a9b1dSJustin T. Gibbs /* Functions accessed by the peripheral drivers */ 14812b83592fSScott Long static int 14829e6461a2SMatt Jacob xpt_init(void *dummy) 14838b8a9b1dSJustin T. Gibbs { 14848b8a9b1dSJustin T. Gibbs struct cam_sim *xpt_sim; 14858b8a9b1dSJustin T. Gibbs struct cam_path *path; 1486434bbf6eSJustin T. Gibbs struct cam_devq *devq; 14878b8a9b1dSJustin T. Gibbs cam_status status; 14888b8a9b1dSJustin T. Gibbs 14892b83592fSScott Long TAILQ_INIT(&xsoftc.xpt_busses); 14909758cc83SScott Long TAILQ_INIT(&cam_simq); 14912b83592fSScott Long TAILQ_INIT(&xsoftc.ccb_scanq); 14922b83592fSScott Long STAILQ_INIT(&xsoftc.highpowerq); 14932b83592fSScott Long xsoftc.num_highpower = CAM_MAX_HIGHPOWER; 14948b8a9b1dSJustin T. Gibbs 14959758cc83SScott Long mtx_init(&cam_simq_lock, "CAM SIMQ lock", NULL, MTX_DEF); 14962b83592fSScott Long mtx_init(&xsoftc.xpt_lock, "XPT lock", NULL, MTX_DEF); 14972b83592fSScott Long mtx_init(&xsoftc.xpt_topo_lock, "XPT topology lock", NULL, MTX_DEF); 1498ef3cf714SScott Long 14998b8a9b1dSJustin T. Gibbs /* 15008b8a9b1dSJustin T. Gibbs * The xpt layer is, itself, the equivelent of a SIM. 15018b8a9b1dSJustin T. Gibbs * Allow 16 ccbs in the ccb pool for it. This should 15028b8a9b1dSJustin T. Gibbs * give decent parallelism when we probe busses and 15038b8a9b1dSJustin T. Gibbs * perform other XPT functions. 15048b8a9b1dSJustin T. Gibbs */ 1505434bbf6eSJustin T. Gibbs devq = cam_simq_alloc(16); 1506434bbf6eSJustin T. Gibbs xpt_sim = cam_sim_alloc(xptaction, 1507434bbf6eSJustin T. Gibbs xptpoll, 1508434bbf6eSJustin T. Gibbs "xpt", 1509434bbf6eSJustin T. Gibbs /*softc*/NULL, 1510434bbf6eSJustin T. Gibbs /*unit*/0, 15112b83592fSScott Long /*mtx*/&xsoftc.xpt_lock, 1512434bbf6eSJustin T. Gibbs /*max_dev_transactions*/0, 1513434bbf6eSJustin T. Gibbs /*max_tagged_dev_transactions*/0, 1514434bbf6eSJustin T. Gibbs devq); 15152b83592fSScott Long if (xpt_sim == NULL) 15162b83592fSScott Long return (ENOMEM); 15178b8a9b1dSJustin T. Gibbs 15182b83592fSScott Long xpt_sim->max_ccbs = 16; 15192b83592fSScott Long 15202b83592fSScott Long mtx_lock(&xsoftc.xpt_lock); 1521b50569b7SScott Long if ((status = xpt_bus_register(xpt_sim, NULL, 0)) != CAM_SUCCESS) { 1522a2821e04SMatt Jacob printf("xpt_init: xpt_bus_register failed with status %#x," 1523df826980SMatt Jacob " failing attach\n", status); 15242b83592fSScott Long return (EINVAL); 1525df826980SMatt Jacob } 15268b8a9b1dSJustin T. Gibbs 15278b8a9b1dSJustin T. Gibbs /* 15288b8a9b1dSJustin T. Gibbs * Looking at the XPT from the SIM layer, the XPT is 15298b8a9b1dSJustin T. Gibbs * the equivelent of a peripheral driver. Allocate 15308b8a9b1dSJustin T. Gibbs * a peripheral driver entry for us. 15318b8a9b1dSJustin T. Gibbs */ 15328b8a9b1dSJustin T. Gibbs if ((status = xpt_create_path(&path, NULL, CAM_XPT_PATH_ID, 15338b8a9b1dSJustin T. Gibbs CAM_TARGET_WILDCARD, 15348b8a9b1dSJustin T. Gibbs CAM_LUN_WILDCARD)) != CAM_REQ_CMP) { 15358b8a9b1dSJustin T. Gibbs printf("xpt_init: xpt_create_path failed with status %#x," 15368b8a9b1dSJustin T. Gibbs " failing attach\n", status); 15372b83592fSScott Long return (EINVAL); 15388b8a9b1dSJustin T. Gibbs } 15398b8a9b1dSJustin T. Gibbs 1540ee9c90c7SKenneth D. Merry cam_periph_alloc(xptregister, NULL, NULL, NULL, "xpt", CAM_PERIPH_BIO, 15412b83592fSScott Long path, NULL, 0, xpt_sim); 15428b8a9b1dSJustin T. Gibbs xpt_free_path(path); 15432b83592fSScott Long mtx_unlock(&xsoftc.xpt_lock); 15448b8a9b1dSJustin T. Gibbs 15458b8a9b1dSJustin T. Gibbs /* 15468b8a9b1dSJustin T. Gibbs * Register a callback for when interrupts are enabled. 15478b8a9b1dSJustin T. Gibbs */ 15482b83592fSScott Long xsoftc.xpt_config_hook = 15498b8a9b1dSJustin T. Gibbs (struct intr_config_hook *)malloc(sizeof(struct intr_config_hook), 15500dd50e9bSScott Long M_CAMXPT, M_NOWAIT | M_ZERO); 15512b83592fSScott Long if (xsoftc.xpt_config_hook == NULL) { 15528b8a9b1dSJustin T. Gibbs printf("xpt_init: Cannot malloc config hook " 15538b8a9b1dSJustin T. Gibbs "- failing attach\n"); 15542b83592fSScott Long return (ENOMEM); 15558b8a9b1dSJustin T. Gibbs } 15568b8a9b1dSJustin T. Gibbs 15572b83592fSScott Long xsoftc.xpt_config_hook->ich_func = xpt_config; 15582b83592fSScott Long if (config_intrhook_establish(xsoftc.xpt_config_hook) != 0) { 15590dd50e9bSScott Long free (xsoftc.xpt_config_hook, M_CAMXPT); 15608b8a9b1dSJustin T. Gibbs printf("xpt_init: config_intrhook_establish failed " 15618b8a9b1dSJustin T. Gibbs "- failing attach\n"); 15628b8a9b1dSJustin T. Gibbs } 15638b8a9b1dSJustin T. Gibbs 15649e6461a2SMatt Jacob /* fire up rescan thread */ 15653745c395SJulian Elischer if (kproc_create(xpt_scanner_thread, NULL, NULL, 0, 0, "xpt_thrd")) { 15669e6461a2SMatt Jacob printf("xpt_init: failed to create rescan thread\n"); 15679e6461a2SMatt Jacob } 15688b8a9b1dSJustin T. Gibbs /* Install our software interrupt handlers */ 15699758cc83SScott Long swi_add(NULL, "cambio", camisr, NULL, SWI_CAMBIO, INTR_MPSAFE, &cambio_ih); 15702b83592fSScott Long 15712b83592fSScott Long return (0); 15728b8a9b1dSJustin T. Gibbs } 15738b8a9b1dSJustin T. Gibbs 15748b8a9b1dSJustin T. Gibbs static cam_status 15758b8a9b1dSJustin T. Gibbs xptregister(struct cam_periph *periph, void *arg) 15768b8a9b1dSJustin T. Gibbs { 15772b83592fSScott Long struct cam_sim *xpt_sim; 15782b83592fSScott Long 15798b8a9b1dSJustin T. Gibbs if (periph == NULL) { 15808b8a9b1dSJustin T. Gibbs printf("xptregister: periph was NULL!!\n"); 15818b8a9b1dSJustin T. Gibbs return(CAM_REQ_CMP_ERR); 15828b8a9b1dSJustin T. Gibbs } 15838b8a9b1dSJustin T. Gibbs 15842b83592fSScott Long xpt_sim = (struct cam_sim *)arg; 15852b83592fSScott Long xpt_sim->softc = periph; 15868b8a9b1dSJustin T. Gibbs xpt_periph = periph; 15872b83592fSScott Long periph->softc = NULL; 15888b8a9b1dSJustin T. Gibbs 15898b8a9b1dSJustin T. Gibbs return(CAM_REQ_CMP); 15908b8a9b1dSJustin T. Gibbs } 15918b8a9b1dSJustin T. Gibbs 15928b8a9b1dSJustin T. Gibbs int32_t 15938b8a9b1dSJustin T. Gibbs xpt_add_periph(struct cam_periph *periph) 15948b8a9b1dSJustin T. Gibbs { 15958b8a9b1dSJustin T. Gibbs struct cam_ed *device; 15968b8a9b1dSJustin T. Gibbs int32_t status; 15978b8a9b1dSJustin T. Gibbs struct periph_list *periph_head; 15988b8a9b1dSJustin T. Gibbs 15992b83592fSScott Long mtx_assert(periph->sim->mtx, MA_OWNED); 160068153f43SScott Long 16018b8a9b1dSJustin T. Gibbs device = periph->path->device; 16028b8a9b1dSJustin T. Gibbs 16038b8a9b1dSJustin T. Gibbs periph_head = &device->periphs; 16048b8a9b1dSJustin T. Gibbs 16058b8a9b1dSJustin T. Gibbs status = CAM_REQ_CMP; 16068b8a9b1dSJustin T. Gibbs 16078b8a9b1dSJustin T. Gibbs if (device != NULL) { 16088b8a9b1dSJustin T. Gibbs /* 16098b8a9b1dSJustin T. Gibbs * Make room for this peripheral 16108b8a9b1dSJustin T. Gibbs * so it will fit in the queue 16118b8a9b1dSJustin T. Gibbs * when it's scheduled to run 16128b8a9b1dSJustin T. Gibbs */ 16138b8a9b1dSJustin T. Gibbs status = camq_resize(&device->drvq, 16148b8a9b1dSJustin T. Gibbs device->drvq.array_size + 1); 16158b8a9b1dSJustin T. Gibbs 16168b8a9b1dSJustin T. Gibbs device->generation++; 16178b8a9b1dSJustin T. Gibbs 16188b8a9b1dSJustin T. Gibbs SLIST_INSERT_HEAD(periph_head, periph, periph_links); 16198b8a9b1dSJustin T. Gibbs } 16208b8a9b1dSJustin T. Gibbs 162177dc25ccSScott Long mtx_lock(&xsoftc.xpt_topo_lock); 162277dc25ccSScott Long xsoftc.xpt_generation++; 162377dc25ccSScott Long mtx_unlock(&xsoftc.xpt_topo_lock); 16248b8a9b1dSJustin T. Gibbs 16258b8a9b1dSJustin T. Gibbs return (status); 16268b8a9b1dSJustin T. Gibbs } 16278b8a9b1dSJustin T. Gibbs 16288b8a9b1dSJustin T. Gibbs void 16298b8a9b1dSJustin T. Gibbs xpt_remove_periph(struct cam_periph *periph) 16308b8a9b1dSJustin T. Gibbs { 16318b8a9b1dSJustin T. Gibbs struct cam_ed *device; 16328b8a9b1dSJustin T. Gibbs 16332b83592fSScott Long mtx_assert(periph->sim->mtx, MA_OWNED); 163468153f43SScott Long 16358b8a9b1dSJustin T. Gibbs device = periph->path->device; 16368b8a9b1dSJustin T. Gibbs 16378b8a9b1dSJustin T. Gibbs if (device != NULL) { 16388b8a9b1dSJustin T. Gibbs struct periph_list *periph_head; 16398b8a9b1dSJustin T. Gibbs 16408b8a9b1dSJustin T. Gibbs periph_head = &device->periphs; 16418b8a9b1dSJustin T. Gibbs 16428b8a9b1dSJustin T. Gibbs /* Release the slot for this peripheral */ 16438b8a9b1dSJustin T. Gibbs camq_resize(&device->drvq, device->drvq.array_size - 1); 16448b8a9b1dSJustin T. Gibbs 16458b8a9b1dSJustin T. Gibbs device->generation++; 16468b8a9b1dSJustin T. Gibbs 1647e3975643SJake Burkholder SLIST_REMOVE(periph_head, periph, cam_periph, periph_links); 16488b8a9b1dSJustin T. Gibbs } 16498b8a9b1dSJustin T. Gibbs 165077dc25ccSScott Long mtx_lock(&xsoftc.xpt_topo_lock); 165177dc25ccSScott Long xsoftc.xpt_generation++; 165277dc25ccSScott Long mtx_unlock(&xsoftc.xpt_topo_lock); 16538b8a9b1dSJustin T. Gibbs } 16548b8a9b1dSJustin T. Gibbs 16553393f8daSKenneth D. Merry 16563393f8daSKenneth D. Merry void 16573393f8daSKenneth D. Merry xpt_announce_periph(struct cam_periph *periph, char *announce_string) 16583393f8daSKenneth D. Merry { 16593393f8daSKenneth D. Merry struct ccb_pathinq cpi; 16603393f8daSKenneth D. Merry struct ccb_trans_settings cts; 16613393f8daSKenneth D. Merry struct cam_path *path; 16623393f8daSKenneth D. Merry u_int speed; 16633393f8daSKenneth D. Merry u_int freq; 16643393f8daSKenneth D. Merry u_int mb; 16653393f8daSKenneth D. Merry 16662b83592fSScott Long mtx_assert(periph->sim->mtx, MA_OWNED); 166768153f43SScott Long 16683393f8daSKenneth D. Merry path = periph->path; 16693393f8daSKenneth D. Merry /* 16703393f8daSKenneth D. Merry * To ensure that this is printed in one piece, 16713393f8daSKenneth D. Merry * mask out CAM interrupts. 16723393f8daSKenneth D. Merry */ 16733393f8daSKenneth D. Merry printf("%s%d at %s%d bus %d target %d lun %d\n", 16743393f8daSKenneth D. Merry periph->periph_name, periph->unit_number, 16753393f8daSKenneth D. Merry path->bus->sim->sim_name, 16763393f8daSKenneth D. Merry path->bus->sim->unit_number, 16773393f8daSKenneth D. Merry path->bus->sim->bus_id, 16783393f8daSKenneth D. Merry path->target->target_id, 16793393f8daSKenneth D. Merry path->device->lun_id); 16803393f8daSKenneth D. Merry printf("%s%d: ", periph->periph_name, periph->unit_number); 16813393f8daSKenneth D. Merry scsi_print_inquiry(&path->device->inq_data); 1682f053d777SMatt Jacob if (bootverbose && path->device->serial_num_len > 0) { 16833393f8daSKenneth D. Merry /* Don't wrap the screen - print only the first 60 chars */ 16843393f8daSKenneth D. Merry printf("%s%d: Serial Number %.60s\n", periph->periph_name, 16853393f8daSKenneth D. Merry periph->unit_number, path->device->serial_num); 16863393f8daSKenneth D. Merry } 16873393f8daSKenneth D. Merry xpt_setup_ccb(&cts.ccb_h, path, /*priority*/1); 16883393f8daSKenneth D. Merry cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS; 16893393f8daSKenneth D. Merry cts.type = CTS_TYPE_CURRENT_SETTINGS; 16903393f8daSKenneth D. Merry xpt_action((union ccb*)&cts); 16910a480cf0SMatt Jacob if ((cts.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 16920a480cf0SMatt Jacob return; 16930a480cf0SMatt Jacob } 16943393f8daSKenneth D. Merry 16953393f8daSKenneth D. Merry /* Ask the SIM for its base transfer speed */ 16963393f8daSKenneth D. Merry xpt_setup_ccb(&cpi.ccb_h, path, /*priority*/1); 16973393f8daSKenneth D. Merry cpi.ccb_h.func_code = XPT_PATH_INQ; 16983393f8daSKenneth D. Merry xpt_action((union ccb *)&cpi); 16993393f8daSKenneth D. Merry 17003393f8daSKenneth D. Merry speed = cpi.base_transfer_speed; 17013393f8daSKenneth D. Merry freq = 0; 1702f053d777SMatt Jacob if (cts.ccb_h.status == CAM_REQ_CMP && cts.transport == XPORT_SPI) { 17033393f8daSKenneth D. Merry struct ccb_trans_settings_spi *spi; 17043393f8daSKenneth D. Merry 17053393f8daSKenneth D. Merry spi = &cts.xport_specific.spi; 17063393f8daSKenneth D. Merry if ((spi->valid & CTS_SPI_VALID_SYNC_OFFSET) != 0 17073393f8daSKenneth D. Merry && spi->sync_offset != 0) { 17083393f8daSKenneth D. Merry freq = scsi_calc_syncsrate(spi->sync_period); 17093393f8daSKenneth D. Merry speed = freq; 17103393f8daSKenneth D. Merry } 17113393f8daSKenneth D. Merry 17123393f8daSKenneth D. Merry if ((spi->valid & CTS_SPI_VALID_BUS_WIDTH) != 0) 17133393f8daSKenneth D. Merry speed *= (0x01 << spi->bus_width); 17143393f8daSKenneth D. Merry } 17152c7d0b8dSMatt Jacob 1716f053d777SMatt Jacob if (cts.ccb_h.status == CAM_REQ_CMP && cts.transport == XPORT_FC) { 1717f053d777SMatt Jacob struct ccb_trans_settings_fc *fc = &cts.xport_specific.fc; 1718f053d777SMatt Jacob if (fc->valid & CTS_FC_VALID_SPEED) { 17192c7d0b8dSMatt Jacob speed = fc->bitrate; 17202c7d0b8dSMatt Jacob } 1721f053d777SMatt Jacob } 17223393f8daSKenneth D. Merry 1723c4270cb6SMatt Jacob if (cts.ccb_h.status == CAM_REQ_CMP && cts.transport == XPORT_SAS) { 1724c4270cb6SMatt Jacob struct ccb_trans_settings_sas *sas = &cts.xport_specific.sas; 1725c4270cb6SMatt Jacob if (sas->valid & CTS_SAS_VALID_SPEED) { 1726c4270cb6SMatt Jacob speed = sas->bitrate; 1727c4270cb6SMatt Jacob } 1728c4270cb6SMatt Jacob } 1729c4270cb6SMatt Jacob 17303393f8daSKenneth D. Merry mb = speed / 1000; 17313393f8daSKenneth D. Merry if (mb > 0) 17323393f8daSKenneth D. Merry printf("%s%d: %d.%03dMB/s transfers", 17333393f8daSKenneth D. Merry periph->periph_name, periph->unit_number, 17343393f8daSKenneth D. Merry mb, speed % 1000); 17353393f8daSKenneth D. Merry else 17363393f8daSKenneth D. Merry printf("%s%d: %dKB/s transfers", periph->periph_name, 17373393f8daSKenneth D. Merry periph->unit_number, speed); 17383393f8daSKenneth D. Merry /* Report additional information about SPI connections */ 1739f053d777SMatt Jacob if (cts.ccb_h.status == CAM_REQ_CMP && cts.transport == XPORT_SPI) { 17403393f8daSKenneth D. Merry struct ccb_trans_settings_spi *spi; 17413393f8daSKenneth D. Merry 17423393f8daSKenneth D. Merry spi = &cts.xport_specific.spi; 17433393f8daSKenneth D. Merry if (freq != 0) { 17443393f8daSKenneth D. Merry printf(" (%d.%03dMHz%s, offset %d", freq / 1000, 17453393f8daSKenneth D. Merry freq % 1000, 17463393f8daSKenneth D. Merry (spi->ppr_options & MSG_EXT_PPR_DT_REQ) != 0 17473393f8daSKenneth D. Merry ? " DT" : "", 17483393f8daSKenneth D. Merry spi->sync_offset); 17493393f8daSKenneth D. Merry } 17503393f8daSKenneth D. Merry if ((spi->valid & CTS_SPI_VALID_BUS_WIDTH) != 0 17513393f8daSKenneth D. Merry && spi->bus_width > 0) { 17523393f8daSKenneth D. Merry if (freq != 0) { 17533393f8daSKenneth D. Merry printf(", "); 17543393f8daSKenneth D. Merry } else { 17553393f8daSKenneth D. Merry printf(" ("); 17563393f8daSKenneth D. Merry } 17573393f8daSKenneth D. Merry printf("%dbit)", 8 * (0x01 << spi->bus_width)); 17583393f8daSKenneth D. Merry } else if (freq != 0) { 17593393f8daSKenneth D. Merry printf(")"); 17603393f8daSKenneth D. Merry } 17613393f8daSKenneth D. Merry } 1762f053d777SMatt Jacob if (cts.ccb_h.status == CAM_REQ_CMP && cts.transport == XPORT_FC) { 17632c7d0b8dSMatt Jacob struct ccb_trans_settings_fc *fc; 17642c7d0b8dSMatt Jacob 17652c7d0b8dSMatt Jacob fc = &cts.xport_specific.fc; 1766f053d777SMatt Jacob if (fc->valid & CTS_FC_VALID_WWNN) 1767f053d777SMatt Jacob printf(" WWNN 0x%llx", (long long) fc->wwnn); 1768f053d777SMatt Jacob if (fc->valid & CTS_FC_VALID_WWPN) 1769f053d777SMatt Jacob printf(" WWPN 0x%llx", (long long) fc->wwpn); 1770f053d777SMatt Jacob if (fc->valid & CTS_FC_VALID_PORT) 1771f053d777SMatt Jacob printf(" PortID 0x%x", fc->port); 17722c7d0b8dSMatt Jacob } 17733393f8daSKenneth D. Merry 17743393f8daSKenneth D. Merry if (path->device->inq_flags & SID_CmdQue 17753393f8daSKenneth D. Merry || path->device->flags & CAM_DEV_TAG_AFTER_COUNT) { 17767ffbfcd7SMatt Jacob printf("\n%s%d: Command Queueing Enabled", 17773393f8daSKenneth D. Merry periph->periph_name, periph->unit_number); 17783393f8daSKenneth D. Merry } 17793393f8daSKenneth D. Merry printf("\n"); 17803393f8daSKenneth D. Merry 17813393f8daSKenneth D. Merry /* 17823393f8daSKenneth D. Merry * We only want to print the caller's announce string if they've 17833393f8daSKenneth D. Merry * passed one in.. 17843393f8daSKenneth D. Merry */ 17853393f8daSKenneth D. Merry if (announce_string != NULL) 17863393f8daSKenneth D. Merry printf("%s%d: %s\n", periph->periph_name, 17873393f8daSKenneth D. Merry periph->unit_number, announce_string); 17883393f8daSKenneth D. Merry } 17898b8a9b1dSJustin T. Gibbs 17908b8a9b1dSJustin T. Gibbs static dev_match_ret 17913393f8daSKenneth D. Merry xptbusmatch(struct dev_match_pattern *patterns, u_int num_patterns, 17928b8a9b1dSJustin T. Gibbs struct cam_eb *bus) 17938b8a9b1dSJustin T. Gibbs { 17948b8a9b1dSJustin T. Gibbs dev_match_ret retval; 17958b8a9b1dSJustin T. Gibbs int i; 17968b8a9b1dSJustin T. Gibbs 17978b8a9b1dSJustin T. Gibbs retval = DM_RET_NONE; 17988b8a9b1dSJustin T. Gibbs 17998b8a9b1dSJustin T. Gibbs /* 18008b8a9b1dSJustin T. Gibbs * If we aren't given something to match against, that's an error. 18018b8a9b1dSJustin T. Gibbs */ 18028b8a9b1dSJustin T. Gibbs if (bus == NULL) 18038b8a9b1dSJustin T. Gibbs return(DM_RET_ERROR); 18048b8a9b1dSJustin T. Gibbs 18058b8a9b1dSJustin T. Gibbs /* 18068b8a9b1dSJustin T. Gibbs * If there are no match entries, then this bus matches no 18078b8a9b1dSJustin T. Gibbs * matter what. 18088b8a9b1dSJustin T. Gibbs */ 18098b8a9b1dSJustin T. Gibbs if ((patterns == NULL) || (num_patterns == 0)) 18108b8a9b1dSJustin T. Gibbs return(DM_RET_DESCEND | DM_RET_COPY); 18118b8a9b1dSJustin T. Gibbs 18128b8a9b1dSJustin T. Gibbs for (i = 0; i < num_patterns; i++) { 18138b8a9b1dSJustin T. Gibbs struct bus_match_pattern *cur_pattern; 18148b8a9b1dSJustin T. Gibbs 18158b8a9b1dSJustin T. Gibbs /* 18168b8a9b1dSJustin T. Gibbs * If the pattern in question isn't for a bus node, we 18178b8a9b1dSJustin T. Gibbs * aren't interested. However, we do indicate to the 18188b8a9b1dSJustin T. Gibbs * calling routine that we should continue descending the 18198b8a9b1dSJustin T. Gibbs * tree, since the user wants to match against lower-level 18208b8a9b1dSJustin T. Gibbs * EDT elements. 18218b8a9b1dSJustin T. Gibbs */ 18228b8a9b1dSJustin T. Gibbs if (patterns[i].type != DEV_MATCH_BUS) { 18238b8a9b1dSJustin T. Gibbs if ((retval & DM_RET_ACTION_MASK) == DM_RET_NONE) 18248b8a9b1dSJustin T. Gibbs retval |= DM_RET_DESCEND; 18258b8a9b1dSJustin T. Gibbs continue; 18268b8a9b1dSJustin T. Gibbs } 18278b8a9b1dSJustin T. Gibbs 18288b8a9b1dSJustin T. Gibbs cur_pattern = &patterns[i].pattern.bus_pattern; 18298b8a9b1dSJustin T. Gibbs 18308b8a9b1dSJustin T. Gibbs /* 18318b8a9b1dSJustin T. Gibbs * If they want to match any bus node, we give them any 18328b8a9b1dSJustin T. Gibbs * device node. 18338b8a9b1dSJustin T. Gibbs */ 18348b8a9b1dSJustin T. Gibbs if (cur_pattern->flags == BUS_MATCH_ANY) { 18358b8a9b1dSJustin T. Gibbs /* set the copy flag */ 18368b8a9b1dSJustin T. Gibbs retval |= DM_RET_COPY; 18378b8a9b1dSJustin T. Gibbs 18388b8a9b1dSJustin T. Gibbs /* 18398b8a9b1dSJustin T. Gibbs * If we've already decided on an action, go ahead 18408b8a9b1dSJustin T. Gibbs * and return. 18418b8a9b1dSJustin T. Gibbs */ 18428b8a9b1dSJustin T. Gibbs if ((retval & DM_RET_ACTION_MASK) != DM_RET_NONE) 18438b8a9b1dSJustin T. Gibbs return(retval); 18448b8a9b1dSJustin T. Gibbs } 18458b8a9b1dSJustin T. Gibbs 18468b8a9b1dSJustin T. Gibbs /* 18478b8a9b1dSJustin T. Gibbs * Not sure why someone would do this... 18488b8a9b1dSJustin T. Gibbs */ 18498b8a9b1dSJustin T. Gibbs if (cur_pattern->flags == BUS_MATCH_NONE) 18508b8a9b1dSJustin T. Gibbs continue; 18518b8a9b1dSJustin T. Gibbs 18528b8a9b1dSJustin T. Gibbs if (((cur_pattern->flags & BUS_MATCH_PATH) != 0) 18538b8a9b1dSJustin T. Gibbs && (cur_pattern->path_id != bus->path_id)) 18548b8a9b1dSJustin T. Gibbs continue; 18558b8a9b1dSJustin T. Gibbs 18568b8a9b1dSJustin T. Gibbs if (((cur_pattern->flags & BUS_MATCH_BUS_ID) != 0) 18578b8a9b1dSJustin T. Gibbs && (cur_pattern->bus_id != bus->sim->bus_id)) 18588b8a9b1dSJustin T. Gibbs continue; 18598b8a9b1dSJustin T. Gibbs 18608b8a9b1dSJustin T. Gibbs if (((cur_pattern->flags & BUS_MATCH_UNIT) != 0) 18618b8a9b1dSJustin T. Gibbs && (cur_pattern->unit_number != bus->sim->unit_number)) 18628b8a9b1dSJustin T. Gibbs continue; 18638b8a9b1dSJustin T. Gibbs 18648b8a9b1dSJustin T. Gibbs if (((cur_pattern->flags & BUS_MATCH_NAME) != 0) 18658b8a9b1dSJustin T. Gibbs && (strncmp(cur_pattern->dev_name, bus->sim->sim_name, 18668b8a9b1dSJustin T. Gibbs DEV_IDLEN) != 0)) 18678b8a9b1dSJustin T. Gibbs continue; 18688b8a9b1dSJustin T. Gibbs 18698b8a9b1dSJustin T. Gibbs /* 18708b8a9b1dSJustin T. Gibbs * If we get to this point, the user definitely wants 18718b8a9b1dSJustin T. Gibbs * information on this bus. So tell the caller to copy the 18728b8a9b1dSJustin T. Gibbs * data out. 18738b8a9b1dSJustin T. Gibbs */ 18748b8a9b1dSJustin T. Gibbs retval |= DM_RET_COPY; 18758b8a9b1dSJustin T. Gibbs 18768b8a9b1dSJustin T. Gibbs /* 18778b8a9b1dSJustin T. Gibbs * If the return action has been set to descend, then we 18788b8a9b1dSJustin T. Gibbs * know that we've already seen a non-bus matching 18798b8a9b1dSJustin T. Gibbs * expression, therefore we need to further descend the tree. 18808b8a9b1dSJustin T. Gibbs * This won't change by continuing around the loop, so we 18818b8a9b1dSJustin T. Gibbs * go ahead and return. If we haven't seen a non-bus 18828b8a9b1dSJustin T. Gibbs * matching expression, we keep going around the loop until 18838b8a9b1dSJustin T. Gibbs * we exhaust the matching expressions. We'll set the stop 18848b8a9b1dSJustin T. Gibbs * flag once we fall out of the loop. 18858b8a9b1dSJustin T. Gibbs */ 18868b8a9b1dSJustin T. Gibbs if ((retval & DM_RET_ACTION_MASK) == DM_RET_DESCEND) 18878b8a9b1dSJustin T. Gibbs return(retval); 18888b8a9b1dSJustin T. Gibbs } 18898b8a9b1dSJustin T. Gibbs 18908b8a9b1dSJustin T. Gibbs /* 18918b8a9b1dSJustin T. Gibbs * If the return action hasn't been set to descend yet, that means 18928b8a9b1dSJustin T. Gibbs * we haven't seen anything other than bus matching patterns. So 18938b8a9b1dSJustin T. Gibbs * tell the caller to stop descending the tree -- the user doesn't 18948b8a9b1dSJustin T. Gibbs * want to match against lower level tree elements. 18958b8a9b1dSJustin T. Gibbs */ 18968b8a9b1dSJustin T. Gibbs if ((retval & DM_RET_ACTION_MASK) == DM_RET_NONE) 18978b8a9b1dSJustin T. Gibbs retval |= DM_RET_STOP; 18988b8a9b1dSJustin T. Gibbs 18998b8a9b1dSJustin T. Gibbs return(retval); 19008b8a9b1dSJustin T. Gibbs } 19018b8a9b1dSJustin T. Gibbs 19028b8a9b1dSJustin T. Gibbs static dev_match_ret 19033393f8daSKenneth D. Merry xptdevicematch(struct dev_match_pattern *patterns, u_int num_patterns, 19048b8a9b1dSJustin T. Gibbs struct cam_ed *device) 19058b8a9b1dSJustin T. Gibbs { 19068b8a9b1dSJustin T. Gibbs dev_match_ret retval; 19078b8a9b1dSJustin T. Gibbs int i; 19088b8a9b1dSJustin T. Gibbs 19098b8a9b1dSJustin T. Gibbs retval = DM_RET_NONE; 19108b8a9b1dSJustin T. Gibbs 19118b8a9b1dSJustin T. Gibbs /* 19128b8a9b1dSJustin T. Gibbs * If we aren't given something to match against, that's an error. 19138b8a9b1dSJustin T. Gibbs */ 19148b8a9b1dSJustin T. Gibbs if (device == NULL) 19158b8a9b1dSJustin T. Gibbs return(DM_RET_ERROR); 19168b8a9b1dSJustin T. Gibbs 19178b8a9b1dSJustin T. Gibbs /* 19188b8a9b1dSJustin T. Gibbs * If there are no match entries, then this device matches no 19198b8a9b1dSJustin T. Gibbs * matter what. 19208b8a9b1dSJustin T. Gibbs */ 192159e75884SColin Percival if ((patterns == NULL) || (num_patterns == 0)) 19228b8a9b1dSJustin T. Gibbs return(DM_RET_DESCEND | DM_RET_COPY); 19238b8a9b1dSJustin T. Gibbs 19248b8a9b1dSJustin T. Gibbs for (i = 0; i < num_patterns; i++) { 19258b8a9b1dSJustin T. Gibbs struct device_match_pattern *cur_pattern; 19268b8a9b1dSJustin T. Gibbs 19278b8a9b1dSJustin T. Gibbs /* 19288b8a9b1dSJustin T. Gibbs * If the pattern in question isn't for a device node, we 19298b8a9b1dSJustin T. Gibbs * aren't interested. 19308b8a9b1dSJustin T. Gibbs */ 19318b8a9b1dSJustin T. Gibbs if (patterns[i].type != DEV_MATCH_DEVICE) { 19328b8a9b1dSJustin T. Gibbs if ((patterns[i].type == DEV_MATCH_PERIPH) 19338b8a9b1dSJustin T. Gibbs && ((retval & DM_RET_ACTION_MASK) == DM_RET_NONE)) 19348b8a9b1dSJustin T. Gibbs retval |= DM_RET_DESCEND; 19358b8a9b1dSJustin T. Gibbs continue; 19368b8a9b1dSJustin T. Gibbs } 19378b8a9b1dSJustin T. Gibbs 19388b8a9b1dSJustin T. Gibbs cur_pattern = &patterns[i].pattern.device_pattern; 19398b8a9b1dSJustin T. Gibbs 19408b8a9b1dSJustin T. Gibbs /* 19418b8a9b1dSJustin T. Gibbs * If they want to match any device node, we give them any 19428b8a9b1dSJustin T. Gibbs * device node. 19438b8a9b1dSJustin T. Gibbs */ 19448b8a9b1dSJustin T. Gibbs if (cur_pattern->flags == DEV_MATCH_ANY) { 19458b8a9b1dSJustin T. Gibbs /* set the copy flag */ 19468b8a9b1dSJustin T. Gibbs retval |= DM_RET_COPY; 19478b8a9b1dSJustin T. Gibbs 19488b8a9b1dSJustin T. Gibbs 19498b8a9b1dSJustin T. Gibbs /* 19508b8a9b1dSJustin T. Gibbs * If we've already decided on an action, go ahead 19518b8a9b1dSJustin T. Gibbs * and return. 19528b8a9b1dSJustin T. Gibbs */ 19538b8a9b1dSJustin T. Gibbs if ((retval & DM_RET_ACTION_MASK) != DM_RET_NONE) 19548b8a9b1dSJustin T. Gibbs return(retval); 19558b8a9b1dSJustin T. Gibbs } 19568b8a9b1dSJustin T. Gibbs 19578b8a9b1dSJustin T. Gibbs /* 19588b8a9b1dSJustin T. Gibbs * Not sure why someone would do this... 19598b8a9b1dSJustin T. Gibbs */ 19608b8a9b1dSJustin T. Gibbs if (cur_pattern->flags == DEV_MATCH_NONE) 19618b8a9b1dSJustin T. Gibbs continue; 19628b8a9b1dSJustin T. Gibbs 19638b8a9b1dSJustin T. Gibbs if (((cur_pattern->flags & DEV_MATCH_PATH) != 0) 19648b8a9b1dSJustin T. Gibbs && (cur_pattern->path_id != device->target->bus->path_id)) 19658b8a9b1dSJustin T. Gibbs continue; 19668b8a9b1dSJustin T. Gibbs 19678b8a9b1dSJustin T. Gibbs if (((cur_pattern->flags & DEV_MATCH_TARGET) != 0) 19688b8a9b1dSJustin T. Gibbs && (cur_pattern->target_id != device->target->target_id)) 19698b8a9b1dSJustin T. Gibbs continue; 19708b8a9b1dSJustin T. Gibbs 19718b8a9b1dSJustin T. Gibbs if (((cur_pattern->flags & DEV_MATCH_LUN) != 0) 19728b8a9b1dSJustin T. Gibbs && (cur_pattern->target_lun != device->lun_id)) 19738b8a9b1dSJustin T. Gibbs continue; 19748b8a9b1dSJustin T. Gibbs 19758b8a9b1dSJustin T. Gibbs if (((cur_pattern->flags & DEV_MATCH_INQUIRY) != 0) 19768b8a9b1dSJustin T. Gibbs && (cam_quirkmatch((caddr_t)&device->inq_data, 19778b8a9b1dSJustin T. Gibbs (caddr_t)&cur_pattern->inq_pat, 19788b8a9b1dSJustin T. Gibbs 1, sizeof(cur_pattern->inq_pat), 19798b8a9b1dSJustin T. Gibbs scsi_static_inquiry_match) == NULL)) 19808b8a9b1dSJustin T. Gibbs continue; 19818b8a9b1dSJustin T. Gibbs 19828b8a9b1dSJustin T. Gibbs /* 19838b8a9b1dSJustin T. Gibbs * If we get to this point, the user definitely wants 19848b8a9b1dSJustin T. Gibbs * information on this device. So tell the caller to copy 19858b8a9b1dSJustin T. Gibbs * the data out. 19868b8a9b1dSJustin T. Gibbs */ 19878b8a9b1dSJustin T. Gibbs retval |= DM_RET_COPY; 19888b8a9b1dSJustin T. Gibbs 19898b8a9b1dSJustin T. Gibbs /* 19908b8a9b1dSJustin T. Gibbs * If the return action has been set to descend, then we 19918b8a9b1dSJustin T. Gibbs * know that we've already seen a peripheral matching 19928b8a9b1dSJustin T. Gibbs * expression, therefore we need to further descend the tree. 19938b8a9b1dSJustin T. Gibbs * This won't change by continuing around the loop, so we 19948b8a9b1dSJustin T. Gibbs * go ahead and return. If we haven't seen a peripheral 19958b8a9b1dSJustin T. Gibbs * matching expression, we keep going around the loop until 19968b8a9b1dSJustin T. Gibbs * we exhaust the matching expressions. We'll set the stop 19978b8a9b1dSJustin T. Gibbs * flag once we fall out of the loop. 19988b8a9b1dSJustin T. Gibbs */ 19998b8a9b1dSJustin T. Gibbs if ((retval & DM_RET_ACTION_MASK) == DM_RET_DESCEND) 20008b8a9b1dSJustin T. Gibbs return(retval); 20018b8a9b1dSJustin T. Gibbs } 20028b8a9b1dSJustin T. Gibbs 20038b8a9b1dSJustin T. Gibbs /* 20048b8a9b1dSJustin T. Gibbs * If the return action hasn't been set to descend yet, that means 20058b8a9b1dSJustin T. Gibbs * we haven't seen any peripheral matching patterns. So tell the 20068b8a9b1dSJustin T. Gibbs * caller to stop descending the tree -- the user doesn't want to 20078b8a9b1dSJustin T. Gibbs * match against lower level tree elements. 20088b8a9b1dSJustin T. Gibbs */ 20098b8a9b1dSJustin T. Gibbs if ((retval & DM_RET_ACTION_MASK) == DM_RET_NONE) 20108b8a9b1dSJustin T. Gibbs retval |= DM_RET_STOP; 20118b8a9b1dSJustin T. Gibbs 20128b8a9b1dSJustin T. Gibbs return(retval); 20138b8a9b1dSJustin T. Gibbs } 20148b8a9b1dSJustin T. Gibbs 20158b8a9b1dSJustin T. Gibbs /* 20168b8a9b1dSJustin T. Gibbs * Match a single peripheral against any number of match patterns. 20178b8a9b1dSJustin T. Gibbs */ 20188b8a9b1dSJustin T. Gibbs static dev_match_ret 20193393f8daSKenneth D. Merry xptperiphmatch(struct dev_match_pattern *patterns, u_int num_patterns, 20208b8a9b1dSJustin T. Gibbs struct cam_periph *periph) 20218b8a9b1dSJustin T. Gibbs { 20228b8a9b1dSJustin T. Gibbs dev_match_ret retval; 20238b8a9b1dSJustin T. Gibbs int i; 20248b8a9b1dSJustin T. Gibbs 20258b8a9b1dSJustin T. Gibbs /* 20268b8a9b1dSJustin T. Gibbs * If we aren't given something to match against, that's an error. 20278b8a9b1dSJustin T. Gibbs */ 20288b8a9b1dSJustin T. Gibbs if (periph == NULL) 20298b8a9b1dSJustin T. Gibbs return(DM_RET_ERROR); 20308b8a9b1dSJustin T. Gibbs 20318b8a9b1dSJustin T. Gibbs /* 20328b8a9b1dSJustin T. Gibbs * If there are no match entries, then this peripheral matches no 20338b8a9b1dSJustin T. Gibbs * matter what. 20348b8a9b1dSJustin T. Gibbs */ 20358b8a9b1dSJustin T. Gibbs if ((patterns == NULL) || (num_patterns == 0)) 20368b8a9b1dSJustin T. Gibbs return(DM_RET_STOP | DM_RET_COPY); 20378b8a9b1dSJustin T. Gibbs 20388b8a9b1dSJustin T. Gibbs /* 20398b8a9b1dSJustin T. Gibbs * There aren't any nodes below a peripheral node, so there's no 20408b8a9b1dSJustin T. Gibbs * reason to descend the tree any further. 20418b8a9b1dSJustin T. Gibbs */ 20428b8a9b1dSJustin T. Gibbs retval = DM_RET_STOP; 20438b8a9b1dSJustin T. Gibbs 20448b8a9b1dSJustin T. Gibbs for (i = 0; i < num_patterns; i++) { 20458b8a9b1dSJustin T. Gibbs struct periph_match_pattern *cur_pattern; 20468b8a9b1dSJustin T. Gibbs 20478b8a9b1dSJustin T. Gibbs /* 20488b8a9b1dSJustin T. Gibbs * If the pattern in question isn't for a peripheral, we 20498b8a9b1dSJustin T. Gibbs * aren't interested. 20508b8a9b1dSJustin T. Gibbs */ 20518b8a9b1dSJustin T. Gibbs if (patterns[i].type != DEV_MATCH_PERIPH) 20528b8a9b1dSJustin T. Gibbs continue; 20538b8a9b1dSJustin T. Gibbs 20548b8a9b1dSJustin T. Gibbs cur_pattern = &patterns[i].pattern.periph_pattern; 20558b8a9b1dSJustin T. Gibbs 20568b8a9b1dSJustin T. Gibbs /* 20578b8a9b1dSJustin T. Gibbs * If they want to match on anything, then we will do so. 20588b8a9b1dSJustin T. Gibbs */ 20598b8a9b1dSJustin T. Gibbs if (cur_pattern->flags == PERIPH_MATCH_ANY) { 20608b8a9b1dSJustin T. Gibbs /* set the copy flag */ 20618b8a9b1dSJustin T. Gibbs retval |= DM_RET_COPY; 20628b8a9b1dSJustin T. Gibbs 20638b8a9b1dSJustin T. Gibbs /* 20648b8a9b1dSJustin T. Gibbs * We've already set the return action to stop, 20658b8a9b1dSJustin T. Gibbs * since there are no nodes below peripherals in 20668b8a9b1dSJustin T. Gibbs * the tree. 20678b8a9b1dSJustin T. Gibbs */ 20688b8a9b1dSJustin T. Gibbs return(retval); 20698b8a9b1dSJustin T. Gibbs } 20708b8a9b1dSJustin T. Gibbs 20718b8a9b1dSJustin T. Gibbs /* 20728b8a9b1dSJustin T. Gibbs * Not sure why someone would do this... 20738b8a9b1dSJustin T. Gibbs */ 20748b8a9b1dSJustin T. Gibbs if (cur_pattern->flags == PERIPH_MATCH_NONE) 20758b8a9b1dSJustin T. Gibbs continue; 20768b8a9b1dSJustin T. Gibbs 20778b8a9b1dSJustin T. Gibbs if (((cur_pattern->flags & PERIPH_MATCH_PATH) != 0) 20788b8a9b1dSJustin T. Gibbs && (cur_pattern->path_id != periph->path->bus->path_id)) 20798b8a9b1dSJustin T. Gibbs continue; 20808b8a9b1dSJustin T. Gibbs 20818b8a9b1dSJustin T. Gibbs /* 20828b8a9b1dSJustin T. Gibbs * For the target and lun id's, we have to make sure the 20838b8a9b1dSJustin T. Gibbs * target and lun pointers aren't NULL. The xpt peripheral 20848b8a9b1dSJustin T. Gibbs * has a wildcard target and device. 20858b8a9b1dSJustin T. Gibbs */ 20868b8a9b1dSJustin T. Gibbs if (((cur_pattern->flags & PERIPH_MATCH_TARGET) != 0) 20878b8a9b1dSJustin T. Gibbs && ((periph->path->target == NULL) 20888b8a9b1dSJustin T. Gibbs ||(cur_pattern->target_id != periph->path->target->target_id))) 20898b8a9b1dSJustin T. Gibbs continue; 20908b8a9b1dSJustin T. Gibbs 20918b8a9b1dSJustin T. Gibbs if (((cur_pattern->flags & PERIPH_MATCH_LUN) != 0) 20928b8a9b1dSJustin T. Gibbs && ((periph->path->device == NULL) 20938b8a9b1dSJustin T. Gibbs || (cur_pattern->target_lun != periph->path->device->lun_id))) 20948b8a9b1dSJustin T. Gibbs continue; 20958b8a9b1dSJustin T. Gibbs 20968b8a9b1dSJustin T. Gibbs if (((cur_pattern->flags & PERIPH_MATCH_UNIT) != 0) 20978b8a9b1dSJustin T. Gibbs && (cur_pattern->unit_number != periph->unit_number)) 20988b8a9b1dSJustin T. Gibbs continue; 20998b8a9b1dSJustin T. Gibbs 21008b8a9b1dSJustin T. Gibbs if (((cur_pattern->flags & PERIPH_MATCH_NAME) != 0) 21018b8a9b1dSJustin T. Gibbs && (strncmp(cur_pattern->periph_name, periph->periph_name, 21028b8a9b1dSJustin T. Gibbs DEV_IDLEN) != 0)) 21038b8a9b1dSJustin T. Gibbs continue; 21048b8a9b1dSJustin T. Gibbs 21058b8a9b1dSJustin T. Gibbs /* 21068b8a9b1dSJustin T. Gibbs * If we get to this point, the user definitely wants 21078b8a9b1dSJustin T. Gibbs * information on this peripheral. So tell the caller to 21088b8a9b1dSJustin T. Gibbs * copy the data out. 21098b8a9b1dSJustin T. Gibbs */ 21108b8a9b1dSJustin T. Gibbs retval |= DM_RET_COPY; 21118b8a9b1dSJustin T. Gibbs 21128b8a9b1dSJustin T. Gibbs /* 21138b8a9b1dSJustin T. Gibbs * The return action has already been set to stop, since 21148b8a9b1dSJustin T. Gibbs * peripherals don't have any nodes below them in the EDT. 21158b8a9b1dSJustin T. Gibbs */ 21168b8a9b1dSJustin T. Gibbs return(retval); 21178b8a9b1dSJustin T. Gibbs } 21188b8a9b1dSJustin T. Gibbs 21198b8a9b1dSJustin T. Gibbs /* 21208b8a9b1dSJustin T. Gibbs * If we get to this point, the peripheral that was passed in 21218b8a9b1dSJustin T. Gibbs * doesn't match any of the patterns. 21228b8a9b1dSJustin T. Gibbs */ 21238b8a9b1dSJustin T. Gibbs return(retval); 21248b8a9b1dSJustin T. Gibbs } 21258b8a9b1dSJustin T. Gibbs 21268b8a9b1dSJustin T. Gibbs static int 21278b8a9b1dSJustin T. Gibbs xptedtbusfunc(struct cam_eb *bus, void *arg) 21288b8a9b1dSJustin T. Gibbs { 21298b8a9b1dSJustin T. Gibbs struct ccb_dev_match *cdm; 21308b8a9b1dSJustin T. Gibbs dev_match_ret retval; 21318b8a9b1dSJustin T. Gibbs 21328b8a9b1dSJustin T. Gibbs cdm = (struct ccb_dev_match *)arg; 21338b8a9b1dSJustin T. Gibbs 21348b8a9b1dSJustin T. Gibbs /* 21358b8a9b1dSJustin T. Gibbs * If our position is for something deeper in the tree, that means 21368b8a9b1dSJustin T. Gibbs * that we've already seen this node. So, we keep going down. 21378b8a9b1dSJustin T. Gibbs */ 21388b8a9b1dSJustin T. Gibbs if ((cdm->pos.position_type & CAM_DEV_POS_BUS) 21398b8a9b1dSJustin T. Gibbs && (cdm->pos.cookie.bus == bus) 21408b8a9b1dSJustin T. Gibbs && (cdm->pos.position_type & CAM_DEV_POS_TARGET) 21418b8a9b1dSJustin T. Gibbs && (cdm->pos.cookie.target != NULL)) 21428b8a9b1dSJustin T. Gibbs retval = DM_RET_DESCEND; 21438b8a9b1dSJustin T. Gibbs else 21448b8a9b1dSJustin T. Gibbs retval = xptbusmatch(cdm->patterns, cdm->num_patterns, bus); 21458b8a9b1dSJustin T. Gibbs 21468b8a9b1dSJustin T. Gibbs /* 21478b8a9b1dSJustin T. Gibbs * If we got an error, bail out of the search. 21488b8a9b1dSJustin T. Gibbs */ 21498b8a9b1dSJustin T. Gibbs if ((retval & DM_RET_ACTION_MASK) == DM_RET_ERROR) { 21508b8a9b1dSJustin T. Gibbs cdm->status = CAM_DEV_MATCH_ERROR; 21518b8a9b1dSJustin T. Gibbs return(0); 21528b8a9b1dSJustin T. Gibbs } 21538b8a9b1dSJustin T. Gibbs 21548b8a9b1dSJustin T. Gibbs /* 21558b8a9b1dSJustin T. Gibbs * If the copy flag is set, copy this bus out. 21568b8a9b1dSJustin T. Gibbs */ 21578b8a9b1dSJustin T. Gibbs if (retval & DM_RET_COPY) { 21588b8a9b1dSJustin T. Gibbs int spaceleft, j; 21598b8a9b1dSJustin T. Gibbs 21608b8a9b1dSJustin T. Gibbs spaceleft = cdm->match_buf_len - (cdm->num_matches * 21618b8a9b1dSJustin T. Gibbs sizeof(struct dev_match_result)); 21628b8a9b1dSJustin T. Gibbs 21638b8a9b1dSJustin T. Gibbs /* 21648b8a9b1dSJustin T. Gibbs * If we don't have enough space to put in another 21658b8a9b1dSJustin T. Gibbs * match result, save our position and tell the 21668b8a9b1dSJustin T. Gibbs * user there are more devices to check. 21678b8a9b1dSJustin T. Gibbs */ 21688b8a9b1dSJustin T. Gibbs if (spaceleft < sizeof(struct dev_match_result)) { 21698b8a9b1dSJustin T. Gibbs bzero(&cdm->pos, sizeof(cdm->pos)); 21708b8a9b1dSJustin T. Gibbs cdm->pos.position_type = 21718b8a9b1dSJustin T. Gibbs CAM_DEV_POS_EDT | CAM_DEV_POS_BUS; 21728b8a9b1dSJustin T. Gibbs 21738b8a9b1dSJustin T. Gibbs cdm->pos.cookie.bus = bus; 21748b8a9b1dSJustin T. Gibbs cdm->pos.generations[CAM_BUS_GENERATION]= 21752b83592fSScott Long xsoftc.bus_generation; 21768b8a9b1dSJustin T. Gibbs cdm->status = CAM_DEV_MATCH_MORE; 21778b8a9b1dSJustin T. Gibbs return(0); 21788b8a9b1dSJustin T. Gibbs } 21798b8a9b1dSJustin T. Gibbs j = cdm->num_matches; 21808b8a9b1dSJustin T. Gibbs cdm->num_matches++; 21818b8a9b1dSJustin T. Gibbs cdm->matches[j].type = DEV_MATCH_BUS; 21828b8a9b1dSJustin T. Gibbs cdm->matches[j].result.bus_result.path_id = bus->path_id; 21838b8a9b1dSJustin T. Gibbs cdm->matches[j].result.bus_result.bus_id = bus->sim->bus_id; 21848b8a9b1dSJustin T. Gibbs cdm->matches[j].result.bus_result.unit_number = 21858b8a9b1dSJustin T. Gibbs bus->sim->unit_number; 21868b8a9b1dSJustin T. Gibbs strncpy(cdm->matches[j].result.bus_result.dev_name, 21878b8a9b1dSJustin T. Gibbs bus->sim->sim_name, DEV_IDLEN); 21888b8a9b1dSJustin T. Gibbs } 21898b8a9b1dSJustin T. Gibbs 21908b8a9b1dSJustin T. Gibbs /* 21918b8a9b1dSJustin T. Gibbs * If the user is only interested in busses, there's no 21928b8a9b1dSJustin T. Gibbs * reason to descend to the next level in the tree. 21938b8a9b1dSJustin T. Gibbs */ 21948b8a9b1dSJustin T. Gibbs if ((retval & DM_RET_ACTION_MASK) == DM_RET_STOP) 21958b8a9b1dSJustin T. Gibbs return(1); 21968b8a9b1dSJustin T. Gibbs 21978b8a9b1dSJustin T. Gibbs /* 21988b8a9b1dSJustin T. Gibbs * If there is a target generation recorded, check it to 21998b8a9b1dSJustin T. Gibbs * make sure the target list hasn't changed. 22008b8a9b1dSJustin T. Gibbs */ 22018b8a9b1dSJustin T. Gibbs if ((cdm->pos.position_type & CAM_DEV_POS_BUS) 22028b8a9b1dSJustin T. Gibbs && (bus == cdm->pos.cookie.bus) 22038b8a9b1dSJustin T. Gibbs && (cdm->pos.position_type & CAM_DEV_POS_TARGET) 22048b8a9b1dSJustin T. Gibbs && (cdm->pos.generations[CAM_TARGET_GENERATION] != 0) 22058b8a9b1dSJustin T. Gibbs && (cdm->pos.generations[CAM_TARGET_GENERATION] != 22068b8a9b1dSJustin T. Gibbs bus->generation)) { 22078b8a9b1dSJustin T. Gibbs cdm->status = CAM_DEV_MATCH_LIST_CHANGED; 22088b8a9b1dSJustin T. Gibbs return(0); 22098b8a9b1dSJustin T. Gibbs } 22108b8a9b1dSJustin T. Gibbs 22118b8a9b1dSJustin T. Gibbs if ((cdm->pos.position_type & CAM_DEV_POS_BUS) 22128b8a9b1dSJustin T. Gibbs && (cdm->pos.cookie.bus == bus) 22138b8a9b1dSJustin T. Gibbs && (cdm->pos.position_type & CAM_DEV_POS_TARGET) 22148b8a9b1dSJustin T. Gibbs && (cdm->pos.cookie.target != NULL)) 22158b8a9b1dSJustin T. Gibbs return(xpttargettraverse(bus, 22168b8a9b1dSJustin T. Gibbs (struct cam_et *)cdm->pos.cookie.target, 22178b8a9b1dSJustin T. Gibbs xptedttargetfunc, arg)); 22188b8a9b1dSJustin T. Gibbs else 22198b8a9b1dSJustin T. Gibbs return(xpttargettraverse(bus, NULL, xptedttargetfunc, arg)); 22208b8a9b1dSJustin T. Gibbs } 22218b8a9b1dSJustin T. Gibbs 22228b8a9b1dSJustin T. Gibbs static int 22238b8a9b1dSJustin T. Gibbs xptedttargetfunc(struct cam_et *target, void *arg) 22248b8a9b1dSJustin T. Gibbs { 22258b8a9b1dSJustin T. Gibbs struct ccb_dev_match *cdm; 22268b8a9b1dSJustin T. Gibbs 22278b8a9b1dSJustin T. Gibbs cdm = (struct ccb_dev_match *)arg; 22288b8a9b1dSJustin T. Gibbs 22298b8a9b1dSJustin T. Gibbs /* 22308b8a9b1dSJustin T. Gibbs * If there is a device list generation recorded, check it to 22318b8a9b1dSJustin T. Gibbs * make sure the device list hasn't changed. 22328b8a9b1dSJustin T. Gibbs */ 22338b8a9b1dSJustin T. Gibbs if ((cdm->pos.position_type & CAM_DEV_POS_BUS) 22348b8a9b1dSJustin T. Gibbs && (cdm->pos.cookie.bus == target->bus) 22358b8a9b1dSJustin T. Gibbs && (cdm->pos.position_type & CAM_DEV_POS_TARGET) 22368b8a9b1dSJustin T. Gibbs && (cdm->pos.cookie.target == target) 22378b8a9b1dSJustin T. Gibbs && (cdm->pos.position_type & CAM_DEV_POS_DEVICE) 22388b8a9b1dSJustin T. Gibbs && (cdm->pos.generations[CAM_DEV_GENERATION] != 0) 22398b8a9b1dSJustin T. Gibbs && (cdm->pos.generations[CAM_DEV_GENERATION] != 22408b8a9b1dSJustin T. Gibbs target->generation)) { 22418b8a9b1dSJustin T. Gibbs cdm->status = CAM_DEV_MATCH_LIST_CHANGED; 22428b8a9b1dSJustin T. Gibbs return(0); 22438b8a9b1dSJustin T. Gibbs } 22448b8a9b1dSJustin T. Gibbs 22458b8a9b1dSJustin T. Gibbs if ((cdm->pos.position_type & CAM_DEV_POS_BUS) 22468b8a9b1dSJustin T. Gibbs && (cdm->pos.cookie.bus == target->bus) 22478b8a9b1dSJustin T. Gibbs && (cdm->pos.position_type & CAM_DEV_POS_TARGET) 22488b8a9b1dSJustin T. Gibbs && (cdm->pos.cookie.target == target) 22498b8a9b1dSJustin T. Gibbs && (cdm->pos.position_type & CAM_DEV_POS_DEVICE) 22508b8a9b1dSJustin T. Gibbs && (cdm->pos.cookie.device != NULL)) 22518b8a9b1dSJustin T. Gibbs return(xptdevicetraverse(target, 22528b8a9b1dSJustin T. Gibbs (struct cam_ed *)cdm->pos.cookie.device, 22538b8a9b1dSJustin T. Gibbs xptedtdevicefunc, arg)); 22548b8a9b1dSJustin T. Gibbs else 22558b8a9b1dSJustin T. Gibbs return(xptdevicetraverse(target, NULL, xptedtdevicefunc, arg)); 22568b8a9b1dSJustin T. Gibbs } 22578b8a9b1dSJustin T. Gibbs 22588b8a9b1dSJustin T. Gibbs static int 22598b8a9b1dSJustin T. Gibbs xptedtdevicefunc(struct cam_ed *device, void *arg) 22608b8a9b1dSJustin T. Gibbs { 22618b8a9b1dSJustin T. Gibbs 22628b8a9b1dSJustin T. Gibbs struct ccb_dev_match *cdm; 22638b8a9b1dSJustin T. Gibbs dev_match_ret retval; 22648b8a9b1dSJustin T. Gibbs 22658b8a9b1dSJustin T. Gibbs cdm = (struct ccb_dev_match *)arg; 22668b8a9b1dSJustin T. Gibbs 22678b8a9b1dSJustin T. Gibbs /* 22688b8a9b1dSJustin T. Gibbs * If our position is for something deeper in the tree, that means 22698b8a9b1dSJustin T. Gibbs * that we've already seen this node. So, we keep going down. 22708b8a9b1dSJustin T. Gibbs */ 22718b8a9b1dSJustin T. Gibbs if ((cdm->pos.position_type & CAM_DEV_POS_DEVICE) 22728b8a9b1dSJustin T. Gibbs && (cdm->pos.cookie.device == device) 22738b8a9b1dSJustin T. Gibbs && (cdm->pos.position_type & CAM_DEV_POS_PERIPH) 22748b8a9b1dSJustin T. Gibbs && (cdm->pos.cookie.periph != NULL)) 22758b8a9b1dSJustin T. Gibbs retval = DM_RET_DESCEND; 22768b8a9b1dSJustin T. Gibbs else 22778b8a9b1dSJustin T. Gibbs retval = xptdevicematch(cdm->patterns, cdm->num_patterns, 22788b8a9b1dSJustin T. Gibbs device); 22798b8a9b1dSJustin T. Gibbs 22808b8a9b1dSJustin T. Gibbs if ((retval & DM_RET_ACTION_MASK) == DM_RET_ERROR) { 22818b8a9b1dSJustin T. Gibbs cdm->status = CAM_DEV_MATCH_ERROR; 22828b8a9b1dSJustin T. Gibbs return(0); 22838b8a9b1dSJustin T. Gibbs } 22848b8a9b1dSJustin T. Gibbs 22858b8a9b1dSJustin T. Gibbs /* 22868b8a9b1dSJustin T. Gibbs * If the copy flag is set, copy this device out. 22878b8a9b1dSJustin T. Gibbs */ 22888b8a9b1dSJustin T. Gibbs if (retval & DM_RET_COPY) { 22898b8a9b1dSJustin T. Gibbs int spaceleft, j; 22908b8a9b1dSJustin T. Gibbs 22918b8a9b1dSJustin T. Gibbs spaceleft = cdm->match_buf_len - (cdm->num_matches * 22928b8a9b1dSJustin T. Gibbs sizeof(struct dev_match_result)); 22938b8a9b1dSJustin T. Gibbs 22948b8a9b1dSJustin T. Gibbs /* 22958b8a9b1dSJustin T. Gibbs * If we don't have enough space to put in another 22968b8a9b1dSJustin T. Gibbs * match result, save our position and tell the 22978b8a9b1dSJustin T. Gibbs * user there are more devices to check. 22988b8a9b1dSJustin T. Gibbs */ 22998b8a9b1dSJustin T. Gibbs if (spaceleft < sizeof(struct dev_match_result)) { 23008b8a9b1dSJustin T. Gibbs bzero(&cdm->pos, sizeof(cdm->pos)); 23018b8a9b1dSJustin T. Gibbs cdm->pos.position_type = 23028b8a9b1dSJustin T. Gibbs CAM_DEV_POS_EDT | CAM_DEV_POS_BUS | 23038b8a9b1dSJustin T. Gibbs CAM_DEV_POS_TARGET | CAM_DEV_POS_DEVICE; 23048b8a9b1dSJustin T. Gibbs 23058b8a9b1dSJustin T. Gibbs cdm->pos.cookie.bus = device->target->bus; 23068b8a9b1dSJustin T. Gibbs cdm->pos.generations[CAM_BUS_GENERATION]= 23072b83592fSScott Long xsoftc.bus_generation; 23088b8a9b1dSJustin T. Gibbs cdm->pos.cookie.target = device->target; 23098b8a9b1dSJustin T. Gibbs cdm->pos.generations[CAM_TARGET_GENERATION] = 23108b8a9b1dSJustin T. Gibbs device->target->bus->generation; 23118b8a9b1dSJustin T. Gibbs cdm->pos.cookie.device = device; 23128b8a9b1dSJustin T. Gibbs cdm->pos.generations[CAM_DEV_GENERATION] = 23138b8a9b1dSJustin T. Gibbs device->target->generation; 23148b8a9b1dSJustin T. Gibbs cdm->status = CAM_DEV_MATCH_MORE; 23158b8a9b1dSJustin T. Gibbs return(0); 23168b8a9b1dSJustin T. Gibbs } 23178b8a9b1dSJustin T. Gibbs j = cdm->num_matches; 23188b8a9b1dSJustin T. Gibbs cdm->num_matches++; 23198b8a9b1dSJustin T. Gibbs cdm->matches[j].type = DEV_MATCH_DEVICE; 23208b8a9b1dSJustin T. Gibbs cdm->matches[j].result.device_result.path_id = 23218b8a9b1dSJustin T. Gibbs device->target->bus->path_id; 23228b8a9b1dSJustin T. Gibbs cdm->matches[j].result.device_result.target_id = 23238b8a9b1dSJustin T. Gibbs device->target->target_id; 23248b8a9b1dSJustin T. Gibbs cdm->matches[j].result.device_result.target_lun = 23258b8a9b1dSJustin T. Gibbs device->lun_id; 23268b8a9b1dSJustin T. Gibbs bcopy(&device->inq_data, 23278b8a9b1dSJustin T. Gibbs &cdm->matches[j].result.device_result.inq_data, 23288b8a9b1dSJustin T. Gibbs sizeof(struct scsi_inquiry_data)); 23299deea857SKenneth D. Merry 23309deea857SKenneth D. Merry /* Let the user know whether this device is unconfigured */ 23319deea857SKenneth D. Merry if (device->flags & CAM_DEV_UNCONFIGURED) 23329deea857SKenneth D. Merry cdm->matches[j].result.device_result.flags = 23339deea857SKenneth D. Merry DEV_RESULT_UNCONFIGURED; 23349deea857SKenneth D. Merry else 23359deea857SKenneth D. Merry cdm->matches[j].result.device_result.flags = 23369deea857SKenneth D. Merry DEV_RESULT_NOFLAG; 23378b8a9b1dSJustin T. Gibbs } 23388b8a9b1dSJustin T. Gibbs 23398b8a9b1dSJustin T. Gibbs /* 23408b8a9b1dSJustin T. Gibbs * If the user isn't interested in peripherals, don't descend 23418b8a9b1dSJustin T. Gibbs * the tree any further. 23428b8a9b1dSJustin T. Gibbs */ 23438b8a9b1dSJustin T. Gibbs if ((retval & DM_RET_ACTION_MASK) == DM_RET_STOP) 23448b8a9b1dSJustin T. Gibbs return(1); 23458b8a9b1dSJustin T. Gibbs 23468b8a9b1dSJustin T. Gibbs /* 23478b8a9b1dSJustin T. Gibbs * If there is a peripheral list generation recorded, make sure 23488b8a9b1dSJustin T. Gibbs * it hasn't changed. 23498b8a9b1dSJustin T. Gibbs */ 23508b8a9b1dSJustin T. Gibbs if ((cdm->pos.position_type & CAM_DEV_POS_BUS) 23518b8a9b1dSJustin T. Gibbs && (device->target->bus == cdm->pos.cookie.bus) 23528b8a9b1dSJustin T. Gibbs && (cdm->pos.position_type & CAM_DEV_POS_TARGET) 23538b8a9b1dSJustin T. Gibbs && (device->target == cdm->pos.cookie.target) 23548b8a9b1dSJustin T. Gibbs && (cdm->pos.position_type & CAM_DEV_POS_DEVICE) 23558b8a9b1dSJustin T. Gibbs && (device == cdm->pos.cookie.device) 23568b8a9b1dSJustin T. Gibbs && (cdm->pos.position_type & CAM_DEV_POS_PERIPH) 23578b8a9b1dSJustin T. Gibbs && (cdm->pos.generations[CAM_PERIPH_GENERATION] != 0) 23588b8a9b1dSJustin T. Gibbs && (cdm->pos.generations[CAM_PERIPH_GENERATION] != 23598b8a9b1dSJustin T. Gibbs device->generation)){ 23608b8a9b1dSJustin T. Gibbs cdm->status = CAM_DEV_MATCH_LIST_CHANGED; 23618b8a9b1dSJustin T. Gibbs return(0); 23628b8a9b1dSJustin T. Gibbs } 23638b8a9b1dSJustin T. Gibbs 23648b8a9b1dSJustin T. Gibbs if ((cdm->pos.position_type & CAM_DEV_POS_BUS) 23658b8a9b1dSJustin T. Gibbs && (cdm->pos.cookie.bus == device->target->bus) 23668b8a9b1dSJustin T. Gibbs && (cdm->pos.position_type & CAM_DEV_POS_TARGET) 23678b8a9b1dSJustin T. Gibbs && (cdm->pos.cookie.target == device->target) 23688b8a9b1dSJustin T. Gibbs && (cdm->pos.position_type & CAM_DEV_POS_DEVICE) 23698b8a9b1dSJustin T. Gibbs && (cdm->pos.cookie.device == device) 23708b8a9b1dSJustin T. Gibbs && (cdm->pos.position_type & CAM_DEV_POS_PERIPH) 23718b8a9b1dSJustin T. Gibbs && (cdm->pos.cookie.periph != NULL)) 23728b8a9b1dSJustin T. Gibbs return(xptperiphtraverse(device, 23738b8a9b1dSJustin T. Gibbs (struct cam_periph *)cdm->pos.cookie.periph, 23748b8a9b1dSJustin T. Gibbs xptedtperiphfunc, arg)); 23758b8a9b1dSJustin T. Gibbs else 23768b8a9b1dSJustin T. Gibbs return(xptperiphtraverse(device, NULL, xptedtperiphfunc, arg)); 23778b8a9b1dSJustin T. Gibbs } 23788b8a9b1dSJustin T. Gibbs 23798b8a9b1dSJustin T. Gibbs static int 23808b8a9b1dSJustin T. Gibbs xptedtperiphfunc(struct cam_periph *periph, void *arg) 23818b8a9b1dSJustin T. Gibbs { 23828b8a9b1dSJustin T. Gibbs struct ccb_dev_match *cdm; 23838b8a9b1dSJustin T. Gibbs dev_match_ret retval; 23848b8a9b1dSJustin T. Gibbs 23858b8a9b1dSJustin T. Gibbs cdm = (struct ccb_dev_match *)arg; 23868b8a9b1dSJustin T. Gibbs 23878b8a9b1dSJustin T. Gibbs retval = xptperiphmatch(cdm->patterns, cdm->num_patterns, periph); 23888b8a9b1dSJustin T. Gibbs 23898b8a9b1dSJustin T. Gibbs if ((retval & DM_RET_ACTION_MASK) == DM_RET_ERROR) { 23908b8a9b1dSJustin T. Gibbs cdm->status = CAM_DEV_MATCH_ERROR; 23918b8a9b1dSJustin T. Gibbs return(0); 23928b8a9b1dSJustin T. Gibbs } 23938b8a9b1dSJustin T. Gibbs 23948b8a9b1dSJustin T. Gibbs /* 23958b8a9b1dSJustin T. Gibbs * If the copy flag is set, copy this peripheral out. 23968b8a9b1dSJustin T. Gibbs */ 23978b8a9b1dSJustin T. Gibbs if (retval & DM_RET_COPY) { 23988b8a9b1dSJustin T. Gibbs int spaceleft, j; 23998b8a9b1dSJustin T. Gibbs 24008b8a9b1dSJustin T. Gibbs spaceleft = cdm->match_buf_len - (cdm->num_matches * 24018b8a9b1dSJustin T. Gibbs sizeof(struct dev_match_result)); 24028b8a9b1dSJustin T. Gibbs 24038b8a9b1dSJustin T. Gibbs /* 24048b8a9b1dSJustin T. Gibbs * If we don't have enough space to put in another 24058b8a9b1dSJustin T. Gibbs * match result, save our position and tell the 24068b8a9b1dSJustin T. Gibbs * user there are more devices to check. 24078b8a9b1dSJustin T. Gibbs */ 24088b8a9b1dSJustin T. Gibbs if (spaceleft < sizeof(struct dev_match_result)) { 24098b8a9b1dSJustin T. Gibbs bzero(&cdm->pos, sizeof(cdm->pos)); 24108b8a9b1dSJustin T. Gibbs cdm->pos.position_type = 24118b8a9b1dSJustin T. Gibbs CAM_DEV_POS_EDT | CAM_DEV_POS_BUS | 24128b8a9b1dSJustin T. Gibbs CAM_DEV_POS_TARGET | CAM_DEV_POS_DEVICE | 24138b8a9b1dSJustin T. Gibbs CAM_DEV_POS_PERIPH; 24148b8a9b1dSJustin T. Gibbs 24158b8a9b1dSJustin T. Gibbs cdm->pos.cookie.bus = periph->path->bus; 24168b8a9b1dSJustin T. Gibbs cdm->pos.generations[CAM_BUS_GENERATION]= 24172b83592fSScott Long xsoftc.bus_generation; 24188b8a9b1dSJustin T. Gibbs cdm->pos.cookie.target = periph->path->target; 24198b8a9b1dSJustin T. Gibbs cdm->pos.generations[CAM_TARGET_GENERATION] = 24208b8a9b1dSJustin T. Gibbs periph->path->bus->generation; 24218b8a9b1dSJustin T. Gibbs cdm->pos.cookie.device = periph->path->device; 24228b8a9b1dSJustin T. Gibbs cdm->pos.generations[CAM_DEV_GENERATION] = 24238b8a9b1dSJustin T. Gibbs periph->path->target->generation; 24248b8a9b1dSJustin T. Gibbs cdm->pos.cookie.periph = periph; 24258b8a9b1dSJustin T. Gibbs cdm->pos.generations[CAM_PERIPH_GENERATION] = 24268b8a9b1dSJustin T. Gibbs periph->path->device->generation; 24278b8a9b1dSJustin T. Gibbs cdm->status = CAM_DEV_MATCH_MORE; 24288b8a9b1dSJustin T. Gibbs return(0); 24298b8a9b1dSJustin T. Gibbs } 24308b8a9b1dSJustin T. Gibbs 24318b8a9b1dSJustin T. Gibbs j = cdm->num_matches; 24328b8a9b1dSJustin T. Gibbs cdm->num_matches++; 24338b8a9b1dSJustin T. Gibbs cdm->matches[j].type = DEV_MATCH_PERIPH; 24348b8a9b1dSJustin T. Gibbs cdm->matches[j].result.periph_result.path_id = 24358b8a9b1dSJustin T. Gibbs periph->path->bus->path_id; 24368b8a9b1dSJustin T. Gibbs cdm->matches[j].result.periph_result.target_id = 24378b8a9b1dSJustin T. Gibbs periph->path->target->target_id; 24388b8a9b1dSJustin T. Gibbs cdm->matches[j].result.periph_result.target_lun = 24398b8a9b1dSJustin T. Gibbs periph->path->device->lun_id; 24408b8a9b1dSJustin T. Gibbs cdm->matches[j].result.periph_result.unit_number = 24418b8a9b1dSJustin T. Gibbs periph->unit_number; 24428b8a9b1dSJustin T. Gibbs strncpy(cdm->matches[j].result.periph_result.periph_name, 24438b8a9b1dSJustin T. Gibbs periph->periph_name, DEV_IDLEN); 24448b8a9b1dSJustin T. Gibbs } 24458b8a9b1dSJustin T. Gibbs 24468b8a9b1dSJustin T. Gibbs return(1); 24478b8a9b1dSJustin T. Gibbs } 24488b8a9b1dSJustin T. Gibbs 24498b8a9b1dSJustin T. Gibbs static int 24508b8a9b1dSJustin T. Gibbs xptedtmatch(struct ccb_dev_match *cdm) 24518b8a9b1dSJustin T. Gibbs { 24528b8a9b1dSJustin T. Gibbs int ret; 24538b8a9b1dSJustin T. Gibbs 24548b8a9b1dSJustin T. Gibbs cdm->num_matches = 0; 24558b8a9b1dSJustin T. Gibbs 24568b8a9b1dSJustin T. Gibbs /* 24578b8a9b1dSJustin T. Gibbs * Check the bus list generation. If it has changed, the user 24588b8a9b1dSJustin T. Gibbs * needs to reset everything and start over. 24598b8a9b1dSJustin T. Gibbs */ 24608b8a9b1dSJustin T. Gibbs if ((cdm->pos.position_type & CAM_DEV_POS_BUS) 24618b8a9b1dSJustin T. Gibbs && (cdm->pos.generations[CAM_BUS_GENERATION] != 0) 24622b83592fSScott Long && (cdm->pos.generations[CAM_BUS_GENERATION] != xsoftc.bus_generation)) { 24638b8a9b1dSJustin T. Gibbs cdm->status = CAM_DEV_MATCH_LIST_CHANGED; 24648b8a9b1dSJustin T. Gibbs return(0); 24658b8a9b1dSJustin T. Gibbs } 24668b8a9b1dSJustin T. Gibbs 24678b8a9b1dSJustin T. Gibbs if ((cdm->pos.position_type & CAM_DEV_POS_BUS) 24688b8a9b1dSJustin T. Gibbs && (cdm->pos.cookie.bus != NULL)) 24698b8a9b1dSJustin T. Gibbs ret = xptbustraverse((struct cam_eb *)cdm->pos.cookie.bus, 24708b8a9b1dSJustin T. Gibbs xptedtbusfunc, cdm); 24718b8a9b1dSJustin T. Gibbs else 24728b8a9b1dSJustin T. Gibbs ret = xptbustraverse(NULL, xptedtbusfunc, cdm); 24738b8a9b1dSJustin T. Gibbs 24748b8a9b1dSJustin T. Gibbs /* 24758b8a9b1dSJustin T. Gibbs * If we get back 0, that means that we had to stop before fully 24768b8a9b1dSJustin T. Gibbs * traversing the EDT. It also means that one of the subroutines 24778b8a9b1dSJustin T. Gibbs * has set the status field to the proper value. If we get back 1, 24788b8a9b1dSJustin T. Gibbs * we've fully traversed the EDT and copied out any matching entries. 24798b8a9b1dSJustin T. Gibbs */ 24808b8a9b1dSJustin T. Gibbs if (ret == 1) 24818b8a9b1dSJustin T. Gibbs cdm->status = CAM_DEV_MATCH_LAST; 24828b8a9b1dSJustin T. Gibbs 24838b8a9b1dSJustin T. Gibbs return(ret); 24848b8a9b1dSJustin T. Gibbs } 24858b8a9b1dSJustin T. Gibbs 24868b8a9b1dSJustin T. Gibbs static int 24878b8a9b1dSJustin T. Gibbs xptplistpdrvfunc(struct periph_driver **pdrv, void *arg) 24888b8a9b1dSJustin T. Gibbs { 24898b8a9b1dSJustin T. Gibbs struct ccb_dev_match *cdm; 24908b8a9b1dSJustin T. Gibbs 24918b8a9b1dSJustin T. Gibbs cdm = (struct ccb_dev_match *)arg; 24928b8a9b1dSJustin T. Gibbs 24938b8a9b1dSJustin T. Gibbs if ((cdm->pos.position_type & CAM_DEV_POS_PDPTR) 24948b8a9b1dSJustin T. Gibbs && (cdm->pos.cookie.pdrv == pdrv) 24958b8a9b1dSJustin T. Gibbs && (cdm->pos.position_type & CAM_DEV_POS_PERIPH) 24968b8a9b1dSJustin T. Gibbs && (cdm->pos.generations[CAM_PERIPH_GENERATION] != 0) 24978b8a9b1dSJustin T. Gibbs && (cdm->pos.generations[CAM_PERIPH_GENERATION] != 24988b8a9b1dSJustin T. Gibbs (*pdrv)->generation)) { 24998b8a9b1dSJustin T. Gibbs cdm->status = CAM_DEV_MATCH_LIST_CHANGED; 25008b8a9b1dSJustin T. Gibbs return(0); 25018b8a9b1dSJustin T. Gibbs } 25028b8a9b1dSJustin T. Gibbs 25038b8a9b1dSJustin T. Gibbs if ((cdm->pos.position_type & CAM_DEV_POS_PDPTR) 25048b8a9b1dSJustin T. Gibbs && (cdm->pos.cookie.pdrv == pdrv) 25058b8a9b1dSJustin T. Gibbs && (cdm->pos.position_type & CAM_DEV_POS_PERIPH) 25068b8a9b1dSJustin T. Gibbs && (cdm->pos.cookie.periph != NULL)) 25078b8a9b1dSJustin T. Gibbs return(xptpdperiphtraverse(pdrv, 25088b8a9b1dSJustin T. Gibbs (struct cam_periph *)cdm->pos.cookie.periph, 25098b8a9b1dSJustin T. Gibbs xptplistperiphfunc, arg)); 25108b8a9b1dSJustin T. Gibbs else 25118b8a9b1dSJustin T. Gibbs return(xptpdperiphtraverse(pdrv, NULL,xptplistperiphfunc, arg)); 25128b8a9b1dSJustin T. Gibbs } 25138b8a9b1dSJustin T. Gibbs 25148b8a9b1dSJustin T. Gibbs static int 25158b8a9b1dSJustin T. Gibbs xptplistperiphfunc(struct cam_periph *periph, void *arg) 25168b8a9b1dSJustin T. Gibbs { 25178b8a9b1dSJustin T. Gibbs struct ccb_dev_match *cdm; 25188b8a9b1dSJustin T. Gibbs dev_match_ret retval; 25198b8a9b1dSJustin T. Gibbs 25208b8a9b1dSJustin T. Gibbs cdm = (struct ccb_dev_match *)arg; 25218b8a9b1dSJustin T. Gibbs 25228b8a9b1dSJustin T. Gibbs retval = xptperiphmatch(cdm->patterns, cdm->num_patterns, periph); 25238b8a9b1dSJustin T. Gibbs 25248b8a9b1dSJustin T. Gibbs if ((retval & DM_RET_ACTION_MASK) == DM_RET_ERROR) { 25258b8a9b1dSJustin T. Gibbs cdm->status = CAM_DEV_MATCH_ERROR; 25268b8a9b1dSJustin T. Gibbs return(0); 25278b8a9b1dSJustin T. Gibbs } 25288b8a9b1dSJustin T. Gibbs 25298b8a9b1dSJustin T. Gibbs /* 25308b8a9b1dSJustin T. Gibbs * If the copy flag is set, copy this peripheral out. 25318b8a9b1dSJustin T. Gibbs */ 25328b8a9b1dSJustin T. Gibbs if (retval & DM_RET_COPY) { 25338b8a9b1dSJustin T. Gibbs int spaceleft, j; 25348b8a9b1dSJustin T. Gibbs 25358b8a9b1dSJustin T. Gibbs spaceleft = cdm->match_buf_len - (cdm->num_matches * 25368b8a9b1dSJustin T. Gibbs sizeof(struct dev_match_result)); 25378b8a9b1dSJustin T. Gibbs 25388b8a9b1dSJustin T. Gibbs /* 25398b8a9b1dSJustin T. Gibbs * If we don't have enough space to put in another 25408b8a9b1dSJustin T. Gibbs * match result, save our position and tell the 25418b8a9b1dSJustin T. Gibbs * user there are more devices to check. 25428b8a9b1dSJustin T. Gibbs */ 25438b8a9b1dSJustin T. Gibbs if (spaceleft < sizeof(struct dev_match_result)) { 25448b8a9b1dSJustin T. Gibbs struct periph_driver **pdrv; 25458b8a9b1dSJustin T. Gibbs 25468b8a9b1dSJustin T. Gibbs pdrv = NULL; 25478b8a9b1dSJustin T. Gibbs bzero(&cdm->pos, sizeof(cdm->pos)); 25488b8a9b1dSJustin T. Gibbs cdm->pos.position_type = 25498b8a9b1dSJustin T. Gibbs CAM_DEV_POS_PDRV | CAM_DEV_POS_PDPTR | 25508b8a9b1dSJustin T. Gibbs CAM_DEV_POS_PERIPH; 25518b8a9b1dSJustin T. Gibbs 25528b8a9b1dSJustin T. Gibbs /* 25538b8a9b1dSJustin T. Gibbs * This may look a bit non-sensical, but it is 25548b8a9b1dSJustin T. Gibbs * actually quite logical. There are very few 25558b8a9b1dSJustin T. Gibbs * peripheral drivers, and bloating every peripheral 25568b8a9b1dSJustin T. Gibbs * structure with a pointer back to its parent 25578b8a9b1dSJustin T. Gibbs * peripheral driver linker set entry would cost 25588b8a9b1dSJustin T. Gibbs * more in the long run than doing this quick lookup. 25598b8a9b1dSJustin T. Gibbs */ 25600b7c27b9SPeter Wemm for (pdrv = periph_drivers; *pdrv != NULL; pdrv++) { 25618b8a9b1dSJustin T. Gibbs if (strcmp((*pdrv)->driver_name, 25628b8a9b1dSJustin T. Gibbs periph->periph_name) == 0) 25638b8a9b1dSJustin T. Gibbs break; 25648b8a9b1dSJustin T. Gibbs } 25658b8a9b1dSJustin T. Gibbs 256601910babSScott Long if (*pdrv == NULL) { 25678b8a9b1dSJustin T. Gibbs cdm->status = CAM_DEV_MATCH_ERROR; 25688b8a9b1dSJustin T. Gibbs return(0); 25698b8a9b1dSJustin T. Gibbs } 25708b8a9b1dSJustin T. Gibbs 25718b8a9b1dSJustin T. Gibbs cdm->pos.cookie.pdrv = pdrv; 25728b8a9b1dSJustin T. Gibbs /* 25738b8a9b1dSJustin T. Gibbs * The periph generation slot does double duty, as 25748b8a9b1dSJustin T. Gibbs * does the periph pointer slot. They are used for 25758b8a9b1dSJustin T. Gibbs * both edt and pdrv lookups and positioning. 25768b8a9b1dSJustin T. Gibbs */ 25778b8a9b1dSJustin T. Gibbs cdm->pos.cookie.periph = periph; 25788b8a9b1dSJustin T. Gibbs cdm->pos.generations[CAM_PERIPH_GENERATION] = 25798b8a9b1dSJustin T. Gibbs (*pdrv)->generation; 25808b8a9b1dSJustin T. Gibbs cdm->status = CAM_DEV_MATCH_MORE; 25818b8a9b1dSJustin T. Gibbs return(0); 25828b8a9b1dSJustin T. Gibbs } 25838b8a9b1dSJustin T. Gibbs 25848b8a9b1dSJustin T. Gibbs j = cdm->num_matches; 25858b8a9b1dSJustin T. Gibbs cdm->num_matches++; 25868b8a9b1dSJustin T. Gibbs cdm->matches[j].type = DEV_MATCH_PERIPH; 25878b8a9b1dSJustin T. Gibbs cdm->matches[j].result.periph_result.path_id = 25888b8a9b1dSJustin T. Gibbs periph->path->bus->path_id; 25898b8a9b1dSJustin T. Gibbs 25908b8a9b1dSJustin T. Gibbs /* 25918b8a9b1dSJustin T. Gibbs * The transport layer peripheral doesn't have a target or 25928b8a9b1dSJustin T. Gibbs * lun. 25938b8a9b1dSJustin T. Gibbs */ 25948b8a9b1dSJustin T. Gibbs if (periph->path->target) 25958b8a9b1dSJustin T. Gibbs cdm->matches[j].result.periph_result.target_id = 25968b8a9b1dSJustin T. Gibbs periph->path->target->target_id; 25978b8a9b1dSJustin T. Gibbs else 25988b8a9b1dSJustin T. Gibbs cdm->matches[j].result.periph_result.target_id = -1; 25998b8a9b1dSJustin T. Gibbs 26008b8a9b1dSJustin T. Gibbs if (periph->path->device) 26018b8a9b1dSJustin T. Gibbs cdm->matches[j].result.periph_result.target_lun = 26028b8a9b1dSJustin T. Gibbs periph->path->device->lun_id; 26038b8a9b1dSJustin T. Gibbs else 26048b8a9b1dSJustin T. Gibbs cdm->matches[j].result.periph_result.target_lun = -1; 26058b8a9b1dSJustin T. Gibbs 26068b8a9b1dSJustin T. Gibbs cdm->matches[j].result.periph_result.unit_number = 26078b8a9b1dSJustin T. Gibbs periph->unit_number; 26088b8a9b1dSJustin T. Gibbs strncpy(cdm->matches[j].result.periph_result.periph_name, 26098b8a9b1dSJustin T. Gibbs periph->periph_name, DEV_IDLEN); 26108b8a9b1dSJustin T. Gibbs } 26118b8a9b1dSJustin T. Gibbs 26128b8a9b1dSJustin T. Gibbs return(1); 26138b8a9b1dSJustin T. Gibbs } 26148b8a9b1dSJustin T. Gibbs 26158b8a9b1dSJustin T. Gibbs static int 26168b8a9b1dSJustin T. Gibbs xptperiphlistmatch(struct ccb_dev_match *cdm) 26178b8a9b1dSJustin T. Gibbs { 26188b8a9b1dSJustin T. Gibbs int ret; 26198b8a9b1dSJustin T. Gibbs 26208b8a9b1dSJustin T. Gibbs cdm->num_matches = 0; 26218b8a9b1dSJustin T. Gibbs 26228b8a9b1dSJustin T. Gibbs /* 26238b8a9b1dSJustin T. Gibbs * At this point in the edt traversal function, we check the bus 26248b8a9b1dSJustin T. Gibbs * list generation to make sure that no busses have been added or 26258b8a9b1dSJustin T. Gibbs * removed since the user last sent a XPT_DEV_MATCH ccb through. 26268b8a9b1dSJustin T. Gibbs * For the peripheral driver list traversal function, however, we 26278b8a9b1dSJustin T. Gibbs * don't have to worry about new peripheral driver types coming or 26288b8a9b1dSJustin T. Gibbs * going; they're in a linker set, and therefore can't change 26298b8a9b1dSJustin T. Gibbs * without a recompile. 26308b8a9b1dSJustin T. Gibbs */ 26318b8a9b1dSJustin T. Gibbs 26328b8a9b1dSJustin T. Gibbs if ((cdm->pos.position_type & CAM_DEV_POS_PDPTR) 26338b8a9b1dSJustin T. Gibbs && (cdm->pos.cookie.pdrv != NULL)) 26348b8a9b1dSJustin T. Gibbs ret = xptpdrvtraverse( 26358b8a9b1dSJustin T. Gibbs (struct periph_driver **)cdm->pos.cookie.pdrv, 26368b8a9b1dSJustin T. Gibbs xptplistpdrvfunc, cdm); 26378b8a9b1dSJustin T. Gibbs else 26388b8a9b1dSJustin T. Gibbs ret = xptpdrvtraverse(NULL, xptplistpdrvfunc, cdm); 26398b8a9b1dSJustin T. Gibbs 26408b8a9b1dSJustin T. Gibbs /* 26418b8a9b1dSJustin T. Gibbs * If we get back 0, that means that we had to stop before fully 26428b8a9b1dSJustin T. Gibbs * traversing the peripheral driver tree. It also means that one of 26438b8a9b1dSJustin T. Gibbs * the subroutines has set the status field to the proper value. If 26448b8a9b1dSJustin T. Gibbs * we get back 1, we've fully traversed the EDT and copied out any 26458b8a9b1dSJustin T. Gibbs * matching entries. 26468b8a9b1dSJustin T. Gibbs */ 26478b8a9b1dSJustin T. Gibbs if (ret == 1) 26488b8a9b1dSJustin T. Gibbs cdm->status = CAM_DEV_MATCH_LAST; 26498b8a9b1dSJustin T. Gibbs 26508b8a9b1dSJustin T. Gibbs return(ret); 26518b8a9b1dSJustin T. Gibbs } 26528b8a9b1dSJustin T. Gibbs 26538b8a9b1dSJustin T. Gibbs static int 26548b8a9b1dSJustin T. Gibbs xptbustraverse(struct cam_eb *start_bus, xpt_busfunc_t *tr_func, void *arg) 26558b8a9b1dSJustin T. Gibbs { 26568b8a9b1dSJustin T. Gibbs struct cam_eb *bus, *next_bus; 26578b8a9b1dSJustin T. Gibbs int retval; 26588b8a9b1dSJustin T. Gibbs 26598b8a9b1dSJustin T. Gibbs retval = 1; 26608b8a9b1dSJustin T. Gibbs 26612b83592fSScott Long mtx_lock(&xsoftc.xpt_topo_lock); 26622b83592fSScott Long for (bus = (start_bus ? start_bus : TAILQ_FIRST(&xsoftc.xpt_busses)); 26638b8a9b1dSJustin T. Gibbs bus != NULL; 26648b8a9b1dSJustin T. Gibbs bus = next_bus) { 26658b8a9b1dSJustin T. Gibbs next_bus = TAILQ_NEXT(bus, links); 26668b8a9b1dSJustin T. Gibbs 26672b83592fSScott Long mtx_unlock(&xsoftc.xpt_topo_lock); 266811e4faceSScott Long CAM_SIM_LOCK(bus->sim); 26698b8a9b1dSJustin T. Gibbs retval = tr_func(bus, arg); 267011e4faceSScott Long CAM_SIM_UNLOCK(bus->sim); 26718b8a9b1dSJustin T. Gibbs if (retval == 0) 26728b8a9b1dSJustin T. Gibbs return(retval); 26732b83592fSScott Long mtx_lock(&xsoftc.xpt_topo_lock); 26748b8a9b1dSJustin T. Gibbs } 26752b83592fSScott Long mtx_unlock(&xsoftc.xpt_topo_lock); 26768b8a9b1dSJustin T. Gibbs 26778b8a9b1dSJustin T. Gibbs return(retval); 26788b8a9b1dSJustin T. Gibbs } 26798b8a9b1dSJustin T. Gibbs 26808b8a9b1dSJustin T. Gibbs static int 26818b8a9b1dSJustin T. Gibbs xpttargettraverse(struct cam_eb *bus, struct cam_et *start_target, 26828b8a9b1dSJustin T. Gibbs xpt_targetfunc_t *tr_func, void *arg) 26838b8a9b1dSJustin T. Gibbs { 26848b8a9b1dSJustin T. Gibbs struct cam_et *target, *next_target; 26858b8a9b1dSJustin T. Gibbs int retval; 26868b8a9b1dSJustin T. Gibbs 26878b8a9b1dSJustin T. Gibbs retval = 1; 26888b8a9b1dSJustin T. Gibbs for (target = (start_target ? start_target : 26898b8a9b1dSJustin T. Gibbs TAILQ_FIRST(&bus->et_entries)); 26908b8a9b1dSJustin T. Gibbs target != NULL; target = next_target) { 26918b8a9b1dSJustin T. Gibbs 26928b8a9b1dSJustin T. Gibbs next_target = TAILQ_NEXT(target, links); 26938b8a9b1dSJustin T. Gibbs 26948b8a9b1dSJustin T. Gibbs retval = tr_func(target, arg); 26958b8a9b1dSJustin T. Gibbs 26968b8a9b1dSJustin T. Gibbs if (retval == 0) 26978b8a9b1dSJustin T. Gibbs return(retval); 26988b8a9b1dSJustin T. Gibbs } 26998b8a9b1dSJustin T. Gibbs 27008b8a9b1dSJustin T. Gibbs return(retval); 27018b8a9b1dSJustin T. Gibbs } 27028b8a9b1dSJustin T. Gibbs 27038b8a9b1dSJustin T. Gibbs static int 27048b8a9b1dSJustin T. Gibbs xptdevicetraverse(struct cam_et *target, struct cam_ed *start_device, 27058b8a9b1dSJustin T. Gibbs xpt_devicefunc_t *tr_func, void *arg) 27068b8a9b1dSJustin T. Gibbs { 27078b8a9b1dSJustin T. Gibbs struct cam_ed *device, *next_device; 27088b8a9b1dSJustin T. Gibbs int retval; 27098b8a9b1dSJustin T. Gibbs 27108b8a9b1dSJustin T. Gibbs retval = 1; 27118b8a9b1dSJustin T. Gibbs for (device = (start_device ? start_device : 27128b8a9b1dSJustin T. Gibbs TAILQ_FIRST(&target->ed_entries)); 27138b8a9b1dSJustin T. Gibbs device != NULL; 27148b8a9b1dSJustin T. Gibbs device = next_device) { 27158b8a9b1dSJustin T. Gibbs 27168b8a9b1dSJustin T. Gibbs next_device = TAILQ_NEXT(device, links); 27178b8a9b1dSJustin T. Gibbs 27188b8a9b1dSJustin T. Gibbs retval = tr_func(device, arg); 27198b8a9b1dSJustin T. Gibbs 27208b8a9b1dSJustin T. Gibbs if (retval == 0) 27218b8a9b1dSJustin T. Gibbs return(retval); 27228b8a9b1dSJustin T. Gibbs } 27238b8a9b1dSJustin T. Gibbs 27248b8a9b1dSJustin T. Gibbs return(retval); 27258b8a9b1dSJustin T. Gibbs } 27268b8a9b1dSJustin T. Gibbs 27278b8a9b1dSJustin T. Gibbs static int 27288b8a9b1dSJustin T. Gibbs xptperiphtraverse(struct cam_ed *device, struct cam_periph *start_periph, 27298b8a9b1dSJustin T. Gibbs xpt_periphfunc_t *tr_func, void *arg) 27308b8a9b1dSJustin T. Gibbs { 27318b8a9b1dSJustin T. Gibbs struct cam_periph *periph, *next_periph; 27328b8a9b1dSJustin T. Gibbs int retval; 27338b8a9b1dSJustin T. Gibbs 27348b8a9b1dSJustin T. Gibbs retval = 1; 27358b8a9b1dSJustin T. Gibbs 27368b8a9b1dSJustin T. Gibbs for (periph = (start_periph ? start_periph : 27378b8a9b1dSJustin T. Gibbs SLIST_FIRST(&device->periphs)); 27388b8a9b1dSJustin T. Gibbs periph != NULL; 27398b8a9b1dSJustin T. Gibbs periph = next_periph) { 27408b8a9b1dSJustin T. Gibbs 27418b8a9b1dSJustin T. Gibbs next_periph = SLIST_NEXT(periph, periph_links); 27428b8a9b1dSJustin T. Gibbs 27438b8a9b1dSJustin T. Gibbs retval = tr_func(periph, arg); 27448b8a9b1dSJustin T. Gibbs if (retval == 0) 27458b8a9b1dSJustin T. Gibbs return(retval); 27468b8a9b1dSJustin T. Gibbs } 27478b8a9b1dSJustin T. Gibbs 27488b8a9b1dSJustin T. Gibbs return(retval); 27498b8a9b1dSJustin T. Gibbs } 27508b8a9b1dSJustin T. Gibbs 27518b8a9b1dSJustin T. Gibbs static int 27528b8a9b1dSJustin T. Gibbs xptpdrvtraverse(struct periph_driver **start_pdrv, 27538b8a9b1dSJustin T. Gibbs xpt_pdrvfunc_t *tr_func, void *arg) 27548b8a9b1dSJustin T. Gibbs { 27558b8a9b1dSJustin T. Gibbs struct periph_driver **pdrv; 27568b8a9b1dSJustin T. Gibbs int retval; 27578b8a9b1dSJustin T. Gibbs 27588b8a9b1dSJustin T. Gibbs retval = 1; 27598b8a9b1dSJustin T. Gibbs 27608b8a9b1dSJustin T. Gibbs /* 27618b8a9b1dSJustin T. Gibbs * We don't traverse the peripheral driver list like we do the 27628b8a9b1dSJustin T. Gibbs * other lists, because it is a linker set, and therefore cannot be 27638b8a9b1dSJustin T. Gibbs * changed during runtime. If the peripheral driver list is ever 27648b8a9b1dSJustin T. Gibbs * re-done to be something other than a linker set (i.e. it can 27658b8a9b1dSJustin T. Gibbs * change while the system is running), the list traversal should 27668b8a9b1dSJustin T. Gibbs * be modified to work like the other traversal functions. 27678b8a9b1dSJustin T. Gibbs */ 27680b7c27b9SPeter Wemm for (pdrv = (start_pdrv ? start_pdrv : periph_drivers); 27698b8a9b1dSJustin T. Gibbs *pdrv != NULL; pdrv++) { 27708b8a9b1dSJustin T. Gibbs retval = tr_func(pdrv, arg); 27718b8a9b1dSJustin T. Gibbs 27728b8a9b1dSJustin T. Gibbs if (retval == 0) 27738b8a9b1dSJustin T. Gibbs return(retval); 27748b8a9b1dSJustin T. Gibbs } 27758b8a9b1dSJustin T. Gibbs 27768b8a9b1dSJustin T. Gibbs return(retval); 27778b8a9b1dSJustin T. Gibbs } 27788b8a9b1dSJustin T. Gibbs 27798b8a9b1dSJustin T. Gibbs static int 27808b8a9b1dSJustin T. Gibbs xptpdperiphtraverse(struct periph_driver **pdrv, 27818b8a9b1dSJustin T. Gibbs struct cam_periph *start_periph, 27828b8a9b1dSJustin T. Gibbs xpt_periphfunc_t *tr_func, void *arg) 27838b8a9b1dSJustin T. Gibbs { 27848b8a9b1dSJustin T. Gibbs struct cam_periph *periph, *next_periph; 27858b8a9b1dSJustin T. Gibbs int retval; 27868b8a9b1dSJustin T. Gibbs 27878b8a9b1dSJustin T. Gibbs retval = 1; 27888b8a9b1dSJustin T. Gibbs 27898b8a9b1dSJustin T. Gibbs for (periph = (start_periph ? start_periph : 27908b8a9b1dSJustin T. Gibbs TAILQ_FIRST(&(*pdrv)->units)); periph != NULL; 27918b8a9b1dSJustin T. Gibbs periph = next_periph) { 27928b8a9b1dSJustin T. Gibbs 27938b8a9b1dSJustin T. Gibbs next_periph = TAILQ_NEXT(periph, unit_links); 27948b8a9b1dSJustin T. Gibbs 27958b8a9b1dSJustin T. Gibbs retval = tr_func(periph, arg); 27968b8a9b1dSJustin T. Gibbs if (retval == 0) 27978b8a9b1dSJustin T. Gibbs return(retval); 27988b8a9b1dSJustin T. Gibbs } 27998b8a9b1dSJustin T. Gibbs return(retval); 28008b8a9b1dSJustin T. Gibbs } 28018b8a9b1dSJustin T. Gibbs 28028b8a9b1dSJustin T. Gibbs static int 28038b8a9b1dSJustin T. Gibbs xptdefbusfunc(struct cam_eb *bus, void *arg) 28048b8a9b1dSJustin T. Gibbs { 28058b8a9b1dSJustin T. Gibbs struct xpt_traverse_config *tr_config; 28068b8a9b1dSJustin T. Gibbs 28078b8a9b1dSJustin T. Gibbs tr_config = (struct xpt_traverse_config *)arg; 28088b8a9b1dSJustin T. Gibbs 28098b8a9b1dSJustin T. Gibbs if (tr_config->depth == XPT_DEPTH_BUS) { 28108b8a9b1dSJustin T. Gibbs xpt_busfunc_t *tr_func; 28118b8a9b1dSJustin T. Gibbs 28128b8a9b1dSJustin T. Gibbs tr_func = (xpt_busfunc_t *)tr_config->tr_func; 28138b8a9b1dSJustin T. Gibbs 28148b8a9b1dSJustin T. Gibbs return(tr_func(bus, tr_config->tr_arg)); 28158b8a9b1dSJustin T. Gibbs } else 28168b8a9b1dSJustin T. Gibbs return(xpttargettraverse(bus, NULL, xptdeftargetfunc, arg)); 28178b8a9b1dSJustin T. Gibbs } 28188b8a9b1dSJustin T. Gibbs 28198b8a9b1dSJustin T. Gibbs static int 28208b8a9b1dSJustin T. Gibbs xptdeftargetfunc(struct cam_et *target, void *arg) 28218b8a9b1dSJustin T. Gibbs { 28228b8a9b1dSJustin T. Gibbs struct xpt_traverse_config *tr_config; 28238b8a9b1dSJustin T. Gibbs 28248b8a9b1dSJustin T. Gibbs tr_config = (struct xpt_traverse_config *)arg; 28258b8a9b1dSJustin T. Gibbs 28268b8a9b1dSJustin T. Gibbs if (tr_config->depth == XPT_DEPTH_TARGET) { 28278b8a9b1dSJustin T. Gibbs xpt_targetfunc_t *tr_func; 28288b8a9b1dSJustin T. Gibbs 28298b8a9b1dSJustin T. Gibbs tr_func = (xpt_targetfunc_t *)tr_config->tr_func; 28308b8a9b1dSJustin T. Gibbs 28318b8a9b1dSJustin T. Gibbs return(tr_func(target, tr_config->tr_arg)); 28328b8a9b1dSJustin T. Gibbs } else 28338b8a9b1dSJustin T. Gibbs return(xptdevicetraverse(target, NULL, xptdefdevicefunc, arg)); 28348b8a9b1dSJustin T. Gibbs } 28358b8a9b1dSJustin T. Gibbs 28368b8a9b1dSJustin T. Gibbs static int 28378b8a9b1dSJustin T. Gibbs xptdefdevicefunc(struct cam_ed *device, void *arg) 28388b8a9b1dSJustin T. Gibbs { 28398b8a9b1dSJustin T. Gibbs struct xpt_traverse_config *tr_config; 28408b8a9b1dSJustin T. Gibbs 28418b8a9b1dSJustin T. Gibbs tr_config = (struct xpt_traverse_config *)arg; 28428b8a9b1dSJustin T. Gibbs 28438b8a9b1dSJustin T. Gibbs if (tr_config->depth == XPT_DEPTH_DEVICE) { 28448b8a9b1dSJustin T. Gibbs xpt_devicefunc_t *tr_func; 28458b8a9b1dSJustin T. Gibbs 28468b8a9b1dSJustin T. Gibbs tr_func = (xpt_devicefunc_t *)tr_config->tr_func; 28478b8a9b1dSJustin T. Gibbs 28488b8a9b1dSJustin T. Gibbs return(tr_func(device, tr_config->tr_arg)); 28498b8a9b1dSJustin T. Gibbs } else 28508b8a9b1dSJustin T. Gibbs return(xptperiphtraverse(device, NULL, xptdefperiphfunc, arg)); 28518b8a9b1dSJustin T. Gibbs } 28528b8a9b1dSJustin T. Gibbs 28538b8a9b1dSJustin T. Gibbs static int 28548b8a9b1dSJustin T. Gibbs xptdefperiphfunc(struct cam_periph *periph, void *arg) 28558b8a9b1dSJustin T. Gibbs { 28568b8a9b1dSJustin T. Gibbs struct xpt_traverse_config *tr_config; 28578b8a9b1dSJustin T. Gibbs xpt_periphfunc_t *tr_func; 28588b8a9b1dSJustin T. Gibbs 28598b8a9b1dSJustin T. Gibbs tr_config = (struct xpt_traverse_config *)arg; 28608b8a9b1dSJustin T. Gibbs 28618b8a9b1dSJustin T. Gibbs tr_func = (xpt_periphfunc_t *)tr_config->tr_func; 28628b8a9b1dSJustin T. Gibbs 28638b8a9b1dSJustin T. Gibbs /* 28648b8a9b1dSJustin T. Gibbs * Unlike the other default functions, we don't check for depth 28658b8a9b1dSJustin T. Gibbs * here. The peripheral driver level is the last level in the EDT, 28668b8a9b1dSJustin T. Gibbs * so if we're here, we should execute the function in question. 28678b8a9b1dSJustin T. Gibbs */ 28688b8a9b1dSJustin T. Gibbs return(tr_func(periph, tr_config->tr_arg)); 28698b8a9b1dSJustin T. Gibbs } 28708b8a9b1dSJustin T. Gibbs 28718b8a9b1dSJustin T. Gibbs /* 28728b8a9b1dSJustin T. Gibbs * Execute the given function for every bus in the EDT. 28738b8a9b1dSJustin T. Gibbs */ 28748b8a9b1dSJustin T. Gibbs static int 28758b8a9b1dSJustin T. Gibbs xpt_for_all_busses(xpt_busfunc_t *tr_func, void *arg) 28768b8a9b1dSJustin T. Gibbs { 28778b8a9b1dSJustin T. Gibbs struct xpt_traverse_config tr_config; 28788b8a9b1dSJustin T. Gibbs 28798b8a9b1dSJustin T. Gibbs tr_config.depth = XPT_DEPTH_BUS; 28808b8a9b1dSJustin T. Gibbs tr_config.tr_func = tr_func; 28818b8a9b1dSJustin T. Gibbs tr_config.tr_arg = arg; 28828b8a9b1dSJustin T. Gibbs 28838b8a9b1dSJustin T. Gibbs return(xptbustraverse(NULL, xptdefbusfunc, &tr_config)); 28848b8a9b1dSJustin T. Gibbs } 28858b8a9b1dSJustin T. Gibbs 28868b8a9b1dSJustin T. Gibbs /* 28878b8a9b1dSJustin T. Gibbs * Execute the given function for every device in the EDT. 28888b8a9b1dSJustin T. Gibbs */ 28898b8a9b1dSJustin T. Gibbs static int 28908b8a9b1dSJustin T. Gibbs xpt_for_all_devices(xpt_devicefunc_t *tr_func, void *arg) 28918b8a9b1dSJustin T. Gibbs { 28928b8a9b1dSJustin T. Gibbs struct xpt_traverse_config tr_config; 28938b8a9b1dSJustin T. Gibbs 28948b8a9b1dSJustin T. Gibbs tr_config.depth = XPT_DEPTH_DEVICE; 28958b8a9b1dSJustin T. Gibbs tr_config.tr_func = tr_func; 28968b8a9b1dSJustin T. Gibbs tr_config.tr_arg = arg; 28978b8a9b1dSJustin T. Gibbs 28988b8a9b1dSJustin T. Gibbs return(xptbustraverse(NULL, xptdefbusfunc, &tr_config)); 28998b8a9b1dSJustin T. Gibbs } 29008b8a9b1dSJustin T. Gibbs 29018b8a9b1dSJustin T. Gibbs static int 29028b8a9b1dSJustin T. Gibbs xptsetasyncfunc(struct cam_ed *device, void *arg) 29038b8a9b1dSJustin T. Gibbs { 29048b8a9b1dSJustin T. Gibbs struct cam_path path; 29058b8a9b1dSJustin T. Gibbs struct ccb_getdev cgd; 29068b8a9b1dSJustin T. Gibbs struct async_node *cur_entry; 29078b8a9b1dSJustin T. Gibbs 29088b8a9b1dSJustin T. Gibbs cur_entry = (struct async_node *)arg; 29098b8a9b1dSJustin T. Gibbs 2910c8bead2aSJustin T. Gibbs /* 2911c8bead2aSJustin T. Gibbs * Don't report unconfigured devices (Wildcard devs, 2912c8bead2aSJustin T. Gibbs * devices only for target mode, device instances 2913c8bead2aSJustin T. Gibbs * that have been invalidated but are waiting for 2914c8bead2aSJustin T. Gibbs * their last reference count to be released). 2915c8bead2aSJustin T. Gibbs */ 2916c8bead2aSJustin T. Gibbs if ((device->flags & CAM_DEV_UNCONFIGURED) != 0) 2917c8bead2aSJustin T. Gibbs return (1); 2918c8bead2aSJustin T. Gibbs 29198b8a9b1dSJustin T. Gibbs xpt_compile_path(&path, 29208b8a9b1dSJustin T. Gibbs NULL, 29218b8a9b1dSJustin T. Gibbs device->target->bus->path_id, 29228b8a9b1dSJustin T. Gibbs device->target->target_id, 29238b8a9b1dSJustin T. Gibbs device->lun_id); 29248b8a9b1dSJustin T. Gibbs xpt_setup_ccb(&cgd.ccb_h, &path, /*priority*/1); 29258b8a9b1dSJustin T. Gibbs cgd.ccb_h.func_code = XPT_GDEV_TYPE; 29268b8a9b1dSJustin T. Gibbs xpt_action((union ccb *)&cgd); 29278b8a9b1dSJustin T. Gibbs cur_entry->callback(cur_entry->callback_arg, 29288b8a9b1dSJustin T. Gibbs AC_FOUND_DEVICE, 29298b8a9b1dSJustin T. Gibbs &path, &cgd); 29308b8a9b1dSJustin T. Gibbs xpt_release_path(&path); 29318b8a9b1dSJustin T. Gibbs 29328b8a9b1dSJustin T. Gibbs return(1); 29338b8a9b1dSJustin T. Gibbs } 2934c8bead2aSJustin T. Gibbs 29358b8a9b1dSJustin T. Gibbs static int 29368b8a9b1dSJustin T. Gibbs xptsetasyncbusfunc(struct cam_eb *bus, void *arg) 29378b8a9b1dSJustin T. Gibbs { 29388b8a9b1dSJustin T. Gibbs struct cam_path path; 29398b8a9b1dSJustin T. Gibbs struct ccb_pathinq cpi; 29408b8a9b1dSJustin T. Gibbs struct async_node *cur_entry; 29418b8a9b1dSJustin T. Gibbs 29428b8a9b1dSJustin T. Gibbs cur_entry = (struct async_node *)arg; 29438b8a9b1dSJustin T. Gibbs 29448b8a9b1dSJustin T. Gibbs xpt_compile_path(&path, /*periph*/NULL, 29458b8a9b1dSJustin T. Gibbs bus->sim->path_id, 29468b8a9b1dSJustin T. Gibbs CAM_TARGET_WILDCARD, 29478b8a9b1dSJustin T. Gibbs CAM_LUN_WILDCARD); 29488b8a9b1dSJustin T. Gibbs xpt_setup_ccb(&cpi.ccb_h, &path, /*priority*/1); 29498b8a9b1dSJustin T. Gibbs cpi.ccb_h.func_code = XPT_PATH_INQ; 29508b8a9b1dSJustin T. Gibbs xpt_action((union ccb *)&cpi); 29518b8a9b1dSJustin T. Gibbs cur_entry->callback(cur_entry->callback_arg, 29528b8a9b1dSJustin T. Gibbs AC_PATH_REGISTERED, 29538b8a9b1dSJustin T. Gibbs &path, &cpi); 29548b8a9b1dSJustin T. Gibbs xpt_release_path(&path); 29558b8a9b1dSJustin T. Gibbs 29568b8a9b1dSJustin T. Gibbs return(1); 29578b8a9b1dSJustin T. Gibbs } 29588b8a9b1dSJustin T. Gibbs 29592b83592fSScott Long static void 29602b83592fSScott Long xpt_action_sasync_cb(void *context, int pending) 29612b83592fSScott Long { 29622b83592fSScott Long struct async_node *cur_entry; 296384f82481SScott Long struct xpt_task *task; 296484f82481SScott Long uint32_t added; 29652b83592fSScott Long 29662b83592fSScott Long task = (struct xpt_task *)context; 296784f82481SScott Long cur_entry = (struct async_node *)task->data1; 296884f82481SScott Long added = task->data2; 29692b83592fSScott Long 29702b83592fSScott Long if ((added & AC_FOUND_DEVICE) != 0) { 29712b83592fSScott Long /* 29722b83592fSScott Long * Get this peripheral up to date with all 29732b83592fSScott Long * the currently existing devices. 29742b83592fSScott Long */ 29752b83592fSScott Long xpt_for_all_devices(xptsetasyncfunc, cur_entry); 29762b83592fSScott Long } 29772b83592fSScott Long if ((added & AC_PATH_REGISTERED) != 0) { 29782b83592fSScott Long /* 29792b83592fSScott Long * Get this peripheral up to date with all 29802b83592fSScott Long * the currently existing busses. 29812b83592fSScott Long */ 29822b83592fSScott Long xpt_for_all_busses(xptsetasyncbusfunc, cur_entry); 29832b83592fSScott Long } 29842b83592fSScott Long 29852b83592fSScott Long free(task, M_CAMXPT); 29862b83592fSScott Long } 29872b83592fSScott Long 29888b8a9b1dSJustin T. Gibbs void 29898b8a9b1dSJustin T. Gibbs xpt_action(union ccb *start_ccb) 29908b8a9b1dSJustin T. Gibbs { 29919911ecf9SJustin T. Gibbs 29928b8a9b1dSJustin T. Gibbs CAM_DEBUG(start_ccb->ccb_h.path, CAM_DEBUG_TRACE, ("xpt_action\n")); 29938b8a9b1dSJustin T. Gibbs 29948b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.status = CAM_REQ_INPROG; 29958b8a9b1dSJustin T. Gibbs 29968b8a9b1dSJustin T. Gibbs switch (start_ccb->ccb_h.func_code) { 29978b8a9b1dSJustin T. Gibbs case XPT_SCSI_IO: 2998d05caa00SKenneth D. Merry { 29993393f8daSKenneth D. Merry struct cam_ed *device; 3000d05caa00SKenneth D. Merry #ifdef CAMDEBUG 3001d05caa00SKenneth D. Merry char cdb_str[(SCSI_MAX_CDBLEN * 3) + 1]; 3002d05caa00SKenneth D. Merry struct cam_path *path; 3003d05caa00SKenneth D. Merry 3004d05caa00SKenneth D. Merry path = start_ccb->ccb_h.path; 3005d05caa00SKenneth D. Merry #endif 3006d05caa00SKenneth D. Merry 30078b8a9b1dSJustin T. Gibbs /* 30088b8a9b1dSJustin T. Gibbs * For the sake of compatibility with SCSI-1 30098b8a9b1dSJustin T. Gibbs * devices that may not understand the identify 30108b8a9b1dSJustin T. Gibbs * message, we include lun information in the 30118b8a9b1dSJustin T. Gibbs * second byte of all commands. SCSI-1 specifies 30128b8a9b1dSJustin T. Gibbs * that luns are a 3 bit value and reserves only 3 30138b8a9b1dSJustin T. Gibbs * bits for lun information in the CDB. Later 30148b8a9b1dSJustin T. Gibbs * revisions of the SCSI spec allow for more than 8 30158b8a9b1dSJustin T. Gibbs * luns, but have deprecated lun information in the 30168b8a9b1dSJustin T. Gibbs * CDB. So, if the lun won't fit, we must omit. 30178b8a9b1dSJustin T. Gibbs * 30188b8a9b1dSJustin T. Gibbs * Also be aware that during initial probing for devices, 30198b8a9b1dSJustin T. Gibbs * the inquiry information is unknown but initialized to 0. 30208b8a9b1dSJustin T. Gibbs * This means that this code will be exercised while probing 30218b8a9b1dSJustin T. Gibbs * devices with an ANSI revision greater than 2. 30228b8a9b1dSJustin T. Gibbs */ 30233393f8daSKenneth D. Merry device = start_ccb->ccb_h.path->device; 30243393f8daSKenneth D. Merry if (device->protocol_version <= SCSI_REV_2 30258b8a9b1dSJustin T. Gibbs && start_ccb->ccb_h.target_lun < 8 30268b8a9b1dSJustin T. Gibbs && (start_ccb->ccb_h.flags & CAM_CDB_POINTER) == 0) { 30278b8a9b1dSJustin T. Gibbs 30288b8a9b1dSJustin T. Gibbs start_ccb->csio.cdb_io.cdb_bytes[1] |= 30298b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.target_lun << 5; 30308b8a9b1dSJustin T. Gibbs } 30318b8a9b1dSJustin T. Gibbs start_ccb->csio.scsi_status = SCSI_STATUS_OK; 3032d05caa00SKenneth D. Merry CAM_DEBUG(path, CAM_DEBUG_CDB,("%s. CDB: %s\n", 3033d05caa00SKenneth D. Merry scsi_op_desc(start_ccb->csio.cdb_io.cdb_bytes[0], 3034d05caa00SKenneth D. Merry &path->device->inq_data), 3035d05caa00SKenneth D. Merry scsi_cdb_string(start_ccb->csio.cdb_io.cdb_bytes, 303650642f18SKenneth D. Merry cdb_str, sizeof(cdb_str)))); 3037d05caa00SKenneth D. Merry } 303807c6eac9SPoul-Henning Kamp /* FALLTHROUGH */ 30398b8a9b1dSJustin T. Gibbs case XPT_TARGET_IO: 30408b8a9b1dSJustin T. Gibbs case XPT_CONT_TARGET_IO: 30412cefde5fSJustin T. Gibbs start_ccb->csio.sense_resid = 0; 30422cefde5fSJustin T. Gibbs start_ccb->csio.resid = 0; 30432cefde5fSJustin T. Gibbs /* FALLTHROUGH */ 304410e1cf63SKenneth D. Merry case XPT_RESET_DEV: 30458b8a9b1dSJustin T. Gibbs case XPT_ENG_EXEC: 30468b8a9b1dSJustin T. Gibbs { 30478b8a9b1dSJustin T. Gibbs struct cam_path *path; 3048d3ef3454SIan Dowse struct cam_sim *sim; 30498b8a9b1dSJustin T. Gibbs int runq; 30508b8a9b1dSJustin T. Gibbs 30518b8a9b1dSJustin T. Gibbs path = start_ccb->ccb_h.path; 30528b8a9b1dSJustin T. Gibbs 3053d3ef3454SIan Dowse sim = path->bus->sim; 3054d3ef3454SIan Dowse if (SIM_DEAD(sim)) { 3055d3ef3454SIan Dowse /* The SIM has gone; just execute the CCB directly. */ 3056d3ef3454SIan Dowse cam_ccbq_send_ccb(&path->device->ccbq, start_ccb); 3057d3ef3454SIan Dowse (*(sim->sim_action))(sim, start_ccb); 3058d3ef3454SIan Dowse break; 3059d3ef3454SIan Dowse } 3060d3ef3454SIan Dowse 30618b8a9b1dSJustin T. Gibbs cam_ccbq_insert_ccb(&path->device->ccbq, start_ccb); 30628b8a9b1dSJustin T. Gibbs if (path->device->qfrozen_cnt == 0) 30638b8a9b1dSJustin T. Gibbs runq = xpt_schedule_dev_sendq(path->bus, path->device); 30648b8a9b1dSJustin T. Gibbs else 30658b8a9b1dSJustin T. Gibbs runq = 0; 30668b8a9b1dSJustin T. Gibbs if (runq != 0) 30678b8a9b1dSJustin T. Gibbs xpt_run_dev_sendq(path->bus); 30688b8a9b1dSJustin T. Gibbs break; 30698b8a9b1dSJustin T. Gibbs } 30708b8a9b1dSJustin T. Gibbs case XPT_SET_TRAN_SETTINGS: 30718b8a9b1dSJustin T. Gibbs { 30728b8a9b1dSJustin T. Gibbs xpt_set_transfer_settings(&start_ccb->cts, 307303e3511bSJustin T. Gibbs start_ccb->ccb_h.path->device, 30748b8a9b1dSJustin T. Gibbs /*async_update*/FALSE); 30758b8a9b1dSJustin T. Gibbs break; 30768b8a9b1dSJustin T. Gibbs } 30778b8a9b1dSJustin T. Gibbs case XPT_CALC_GEOMETRY: 30782cefde5fSJustin T. Gibbs { 30792cefde5fSJustin T. Gibbs struct cam_sim *sim; 30802cefde5fSJustin T. Gibbs 30818b8a9b1dSJustin T. Gibbs /* Filter out garbage */ 30828b8a9b1dSJustin T. Gibbs if (start_ccb->ccg.block_size == 0 30838b8a9b1dSJustin T. Gibbs || start_ccb->ccg.volume_size == 0) { 30848b8a9b1dSJustin T. Gibbs start_ccb->ccg.cylinders = 0; 30858b8a9b1dSJustin T. Gibbs start_ccb->ccg.heads = 0; 30868b8a9b1dSJustin T. Gibbs start_ccb->ccg.secs_per_track = 0; 30878b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.status = CAM_REQ_CMP; 30888b8a9b1dSJustin T. Gibbs break; 30898b8a9b1dSJustin T. Gibbs } 30908b8a9b1dSJustin T. Gibbs #ifdef PC98 30918b8a9b1dSJustin T. Gibbs /* 30928b8a9b1dSJustin T. Gibbs * In a PC-98 system, geometry translation depens on 30938b8a9b1dSJustin T. Gibbs * the "real" device geometry obtained from mode page 4. 30948b8a9b1dSJustin T. Gibbs * SCSI geometry translation is performed in the 30958b8a9b1dSJustin T. Gibbs * initialization routine of the SCSI BIOS and the result 30968b8a9b1dSJustin T. Gibbs * stored in host memory. If the translation is available 30978b8a9b1dSJustin T. Gibbs * in host memory, use it. If not, rely on the default 30988b8a9b1dSJustin T. Gibbs * translation the device driver performs. 30998b8a9b1dSJustin T. Gibbs */ 31008b8a9b1dSJustin T. Gibbs if (scsi_da_bios_params(&start_ccb->ccg) != 0) { 31018b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.status = CAM_REQ_CMP; 31028b8a9b1dSJustin T. Gibbs break; 31038b8a9b1dSJustin T. Gibbs } 31048b8a9b1dSJustin T. Gibbs #endif 31052cefde5fSJustin T. Gibbs sim = start_ccb->ccb_h.path->bus->sim; 31062cefde5fSJustin T. Gibbs (*(sim->sim_action))(sim, start_ccb); 31072cefde5fSJustin T. Gibbs break; 31082cefde5fSJustin T. Gibbs } 3109bb6087e5SJustin T. Gibbs case XPT_ABORT: 31102cefde5fSJustin T. Gibbs { 31112cefde5fSJustin T. Gibbs union ccb* abort_ccb; 31122cefde5fSJustin T. Gibbs 31132cefde5fSJustin T. Gibbs abort_ccb = start_ccb->cab.abort_ccb; 31142cefde5fSJustin T. Gibbs if (XPT_FC_IS_DEV_QUEUED(abort_ccb)) { 31152cefde5fSJustin T. Gibbs 31162cefde5fSJustin T. Gibbs if (abort_ccb->ccb_h.pinfo.index >= 0) { 31172cefde5fSJustin T. Gibbs struct cam_ccbq *ccbq; 31182cefde5fSJustin T. Gibbs 31192cefde5fSJustin T. Gibbs ccbq = &abort_ccb->ccb_h.path->device->ccbq; 31202cefde5fSJustin T. Gibbs cam_ccbq_remove_ccb(ccbq, abort_ccb); 31212cefde5fSJustin T. Gibbs abort_ccb->ccb_h.status = 31222cefde5fSJustin T. Gibbs CAM_REQ_ABORTED|CAM_DEV_QFRZN; 31232cefde5fSJustin T. Gibbs xpt_freeze_devq(abort_ccb->ccb_h.path, 1); 31242cefde5fSJustin T. Gibbs xpt_done(abort_ccb); 31252cefde5fSJustin T. Gibbs start_ccb->ccb_h.status = CAM_REQ_CMP; 31262cefde5fSJustin T. Gibbs break; 31272cefde5fSJustin T. Gibbs } 31282cefde5fSJustin T. Gibbs if (abort_ccb->ccb_h.pinfo.index == CAM_UNQUEUED_INDEX 31292cefde5fSJustin T. Gibbs && (abort_ccb->ccb_h.status & CAM_SIM_QUEUED) == 0) { 31302cefde5fSJustin T. Gibbs /* 31312cefde5fSJustin T. Gibbs * We've caught this ccb en route to 31322cefde5fSJustin T. Gibbs * the SIM. Flag it for abort and the 31332cefde5fSJustin T. Gibbs * SIM will do so just before starting 31342cefde5fSJustin T. Gibbs * real work on the CCB. 31352cefde5fSJustin T. Gibbs */ 31362cefde5fSJustin T. Gibbs abort_ccb->ccb_h.status = 31372cefde5fSJustin T. Gibbs CAM_REQ_ABORTED|CAM_DEV_QFRZN; 31382cefde5fSJustin T. Gibbs xpt_freeze_devq(abort_ccb->ccb_h.path, 1); 31392cefde5fSJustin T. Gibbs start_ccb->ccb_h.status = CAM_REQ_CMP; 31402cefde5fSJustin T. Gibbs break; 31412cefde5fSJustin T. Gibbs } 31422cefde5fSJustin T. Gibbs } 31432cefde5fSJustin T. Gibbs if (XPT_FC_IS_QUEUED(abort_ccb) 31442cefde5fSJustin T. Gibbs && (abort_ccb->ccb_h.pinfo.index == CAM_DONEQ_INDEX)) { 31452cefde5fSJustin T. Gibbs /* 31462cefde5fSJustin T. Gibbs * It's already completed but waiting 31472cefde5fSJustin T. Gibbs * for our SWI to get to it. 31482cefde5fSJustin T. Gibbs */ 31492cefde5fSJustin T. Gibbs start_ccb->ccb_h.status = CAM_UA_ABORT; 31502cefde5fSJustin T. Gibbs break; 31512cefde5fSJustin T. Gibbs } 31522cefde5fSJustin T. Gibbs /* 31532cefde5fSJustin T. Gibbs * If we weren't able to take care of the abort request 31542cefde5fSJustin T. Gibbs * in the XPT, pass the request down to the SIM for processing. 31552cefde5fSJustin T. Gibbs */ 31562cefde5fSJustin T. Gibbs } 315707c6eac9SPoul-Henning Kamp /* FALLTHROUGH */ 31588b8a9b1dSJustin T. Gibbs case XPT_ACCEPT_TARGET_IO: 31598b8a9b1dSJustin T. Gibbs case XPT_EN_LUN: 31608b8a9b1dSJustin T. Gibbs case XPT_IMMED_NOTIFY: 31618b8a9b1dSJustin T. Gibbs case XPT_NOTIFY_ACK: 31628b8a9b1dSJustin T. Gibbs case XPT_GET_TRAN_SETTINGS: 31638b8a9b1dSJustin T. Gibbs case XPT_RESET_BUS: 31648b8a9b1dSJustin T. Gibbs { 31658b8a9b1dSJustin T. Gibbs struct cam_sim *sim; 31668b8a9b1dSJustin T. Gibbs 31678b8a9b1dSJustin T. Gibbs sim = start_ccb->ccb_h.path->bus->sim; 31688b8a9b1dSJustin T. Gibbs (*(sim->sim_action))(sim, start_ccb); 31698b8a9b1dSJustin T. Gibbs break; 31708b8a9b1dSJustin T. Gibbs } 317187cfaf0eSJustin T. Gibbs case XPT_PATH_INQ: 317287cfaf0eSJustin T. Gibbs { 317387cfaf0eSJustin T. Gibbs struct cam_sim *sim; 317487cfaf0eSJustin T. Gibbs 317587cfaf0eSJustin T. Gibbs sim = start_ccb->ccb_h.path->bus->sim; 317687cfaf0eSJustin T. Gibbs (*(sim->sim_action))(sim, start_ccb); 317787cfaf0eSJustin T. Gibbs break; 317887cfaf0eSJustin T. Gibbs } 317987cfaf0eSJustin T. Gibbs case XPT_PATH_STATS: 318087cfaf0eSJustin T. Gibbs start_ccb->cpis.last_reset = 318187cfaf0eSJustin T. Gibbs start_ccb->ccb_h.path->bus->last_reset; 318287cfaf0eSJustin T. Gibbs start_ccb->ccb_h.status = CAM_REQ_CMP; 318387cfaf0eSJustin T. Gibbs break; 31848b8a9b1dSJustin T. Gibbs case XPT_GDEV_TYPE: 3185a5479bc5SJustin T. Gibbs { 318687cfaf0eSJustin T. Gibbs struct cam_ed *dev; 3187a5479bc5SJustin T. Gibbs 318887cfaf0eSJustin T. Gibbs dev = start_ccb->ccb_h.path->device; 318987cfaf0eSJustin T. Gibbs if ((dev->flags & CAM_DEV_UNCONFIGURED) != 0) { 31908b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.status = CAM_DEV_NOT_THERE; 31918b8a9b1dSJustin T. Gibbs } else { 31928b8a9b1dSJustin T. Gibbs struct ccb_getdev *cgd; 319387cfaf0eSJustin T. Gibbs struct cam_eb *bus; 31948b8a9b1dSJustin T. Gibbs struct cam_et *tar; 31958b8a9b1dSJustin T. Gibbs 31968b8a9b1dSJustin T. Gibbs cgd = &start_ccb->cgd; 319787cfaf0eSJustin T. Gibbs bus = cgd->ccb_h.path->bus; 31988b8a9b1dSJustin T. Gibbs tar = cgd->ccb_h.path->target; 31998b8a9b1dSJustin T. Gibbs cgd->inq_data = dev->inq_data; 32008b8a9b1dSJustin T. Gibbs cgd->ccb_h.status = CAM_REQ_CMP; 32018b8a9b1dSJustin T. Gibbs cgd->serial_num_len = dev->serial_num_len; 32028b8a9b1dSJustin T. Gibbs if ((dev->serial_num_len > 0) 32038b8a9b1dSJustin T. Gibbs && (dev->serial_num != NULL)) 32048b8a9b1dSJustin T. Gibbs bcopy(dev->serial_num, cgd->serial_num, 32058b8a9b1dSJustin T. Gibbs dev->serial_num_len); 32068b8a9b1dSJustin T. Gibbs } 32078b8a9b1dSJustin T. Gibbs break; 3208a5479bc5SJustin T. Gibbs } 320987cfaf0eSJustin T. Gibbs case XPT_GDEV_STATS: 321087cfaf0eSJustin T. Gibbs { 321187cfaf0eSJustin T. Gibbs struct cam_ed *dev; 321287cfaf0eSJustin T. Gibbs 321387cfaf0eSJustin T. Gibbs dev = start_ccb->ccb_h.path->device; 321487cfaf0eSJustin T. Gibbs if ((dev->flags & CAM_DEV_UNCONFIGURED) != 0) { 321587cfaf0eSJustin T. Gibbs start_ccb->ccb_h.status = CAM_DEV_NOT_THERE; 321687cfaf0eSJustin T. Gibbs } else { 321787cfaf0eSJustin T. Gibbs struct ccb_getdevstats *cgds; 321887cfaf0eSJustin T. Gibbs struct cam_eb *bus; 321987cfaf0eSJustin T. Gibbs struct cam_et *tar; 322087cfaf0eSJustin T. Gibbs 322187cfaf0eSJustin T. Gibbs cgds = &start_ccb->cgds; 322287cfaf0eSJustin T. Gibbs bus = cgds->ccb_h.path->bus; 322387cfaf0eSJustin T. Gibbs tar = cgds->ccb_h.path->target; 322487cfaf0eSJustin T. Gibbs cgds->dev_openings = dev->ccbq.dev_openings; 322587cfaf0eSJustin T. Gibbs cgds->dev_active = dev->ccbq.dev_active; 322687cfaf0eSJustin T. Gibbs cgds->devq_openings = dev->ccbq.devq_openings; 322787cfaf0eSJustin T. Gibbs cgds->devq_queued = dev->ccbq.queue.entries; 322887cfaf0eSJustin T. Gibbs cgds->held = dev->ccbq.held; 322987cfaf0eSJustin T. Gibbs cgds->last_reset = tar->last_reset; 323082815562SJustin T. Gibbs cgds->maxtags = dev->quirk->maxtags; 323182815562SJustin T. Gibbs cgds->mintags = dev->quirk->mintags; 323287cfaf0eSJustin T. Gibbs if (timevalcmp(&tar->last_reset, &bus->last_reset, <)) 323387cfaf0eSJustin T. Gibbs cgds->last_reset = bus->last_reset; 323487cfaf0eSJustin T. Gibbs cgds->ccb_h.status = CAM_REQ_CMP; 323587cfaf0eSJustin T. Gibbs } 323687cfaf0eSJustin T. Gibbs break; 323787cfaf0eSJustin T. Gibbs } 32388b8a9b1dSJustin T. Gibbs case XPT_GDEVLIST: 32398b8a9b1dSJustin T. Gibbs { 32408b8a9b1dSJustin T. Gibbs struct cam_periph *nperiph; 32418b8a9b1dSJustin T. Gibbs struct periph_list *periph_head; 32428b8a9b1dSJustin T. Gibbs struct ccb_getdevlist *cgdl; 32433393f8daSKenneth D. Merry u_int i; 32448b8a9b1dSJustin T. Gibbs struct cam_ed *device; 32458b8a9b1dSJustin T. Gibbs int found; 32468b8a9b1dSJustin T. Gibbs 32478b8a9b1dSJustin T. Gibbs 32488b8a9b1dSJustin T. Gibbs found = 0; 32498b8a9b1dSJustin T. Gibbs 32508b8a9b1dSJustin T. Gibbs /* 32518b8a9b1dSJustin T. Gibbs * Don't want anyone mucking with our data. 32528b8a9b1dSJustin T. Gibbs */ 32538b8a9b1dSJustin T. Gibbs device = start_ccb->ccb_h.path->device; 32548b8a9b1dSJustin T. Gibbs periph_head = &device->periphs; 32558b8a9b1dSJustin T. Gibbs cgdl = &start_ccb->cgdl; 32568b8a9b1dSJustin T. Gibbs 32578b8a9b1dSJustin T. Gibbs /* 32588b8a9b1dSJustin T. Gibbs * Check and see if the list has changed since the user 32598b8a9b1dSJustin T. Gibbs * last requested a list member. If so, tell them that the 32608b8a9b1dSJustin T. Gibbs * list has changed, and therefore they need to start over 32618b8a9b1dSJustin T. Gibbs * from the beginning. 32628b8a9b1dSJustin T. Gibbs */ 32638b8a9b1dSJustin T. Gibbs if ((cgdl->index != 0) && 32648b8a9b1dSJustin T. Gibbs (cgdl->generation != device->generation)) { 32658b8a9b1dSJustin T. Gibbs cgdl->status = CAM_GDEVLIST_LIST_CHANGED; 32668b8a9b1dSJustin T. Gibbs break; 32678b8a9b1dSJustin T. Gibbs } 32688b8a9b1dSJustin T. Gibbs 32698b8a9b1dSJustin T. Gibbs /* 32708b8a9b1dSJustin T. Gibbs * Traverse the list of peripherals and attempt to find 32718b8a9b1dSJustin T. Gibbs * the requested peripheral. 32728b8a9b1dSJustin T. Gibbs */ 3273fc2ffbe6SPoul-Henning Kamp for (nperiph = SLIST_FIRST(periph_head), i = 0; 32748b8a9b1dSJustin T. Gibbs (nperiph != NULL) && (i <= cgdl->index); 3275fc2ffbe6SPoul-Henning Kamp nperiph = SLIST_NEXT(nperiph, periph_links), i++) { 32768b8a9b1dSJustin T. Gibbs if (i == cgdl->index) { 32778b8a9b1dSJustin T. Gibbs strncpy(cgdl->periph_name, 32788b8a9b1dSJustin T. Gibbs nperiph->periph_name, 32798b8a9b1dSJustin T. Gibbs DEV_IDLEN); 32808b8a9b1dSJustin T. Gibbs cgdl->unit_number = nperiph->unit_number; 32818b8a9b1dSJustin T. Gibbs found = 1; 32828b8a9b1dSJustin T. Gibbs } 32838b8a9b1dSJustin T. Gibbs } 32848b8a9b1dSJustin T. Gibbs if (found == 0) { 32858b8a9b1dSJustin T. Gibbs cgdl->status = CAM_GDEVLIST_ERROR; 32868b8a9b1dSJustin T. Gibbs break; 32878b8a9b1dSJustin T. Gibbs } 32888b8a9b1dSJustin T. Gibbs 32898b8a9b1dSJustin T. Gibbs if (nperiph == NULL) 32908b8a9b1dSJustin T. Gibbs cgdl->status = CAM_GDEVLIST_LAST_DEVICE; 32918b8a9b1dSJustin T. Gibbs else 32928b8a9b1dSJustin T. Gibbs cgdl->status = CAM_GDEVLIST_MORE_DEVS; 32938b8a9b1dSJustin T. Gibbs 32948b8a9b1dSJustin T. Gibbs cgdl->index++; 32958b8a9b1dSJustin T. Gibbs cgdl->generation = device->generation; 32968b8a9b1dSJustin T. Gibbs 32978b8a9b1dSJustin T. Gibbs cgdl->ccb_h.status = CAM_REQ_CMP; 32988b8a9b1dSJustin T. Gibbs break; 32998b8a9b1dSJustin T. Gibbs } 33008b8a9b1dSJustin T. Gibbs case XPT_DEV_MATCH: 33018b8a9b1dSJustin T. Gibbs { 33028b8a9b1dSJustin T. Gibbs dev_pos_type position_type; 33038b8a9b1dSJustin T. Gibbs struct ccb_dev_match *cdm; 33048b8a9b1dSJustin T. Gibbs 33058b8a9b1dSJustin T. Gibbs cdm = &start_ccb->cdm; 33068b8a9b1dSJustin T. Gibbs 33078b8a9b1dSJustin T. Gibbs /* 33088b8a9b1dSJustin T. Gibbs * There are two ways of getting at information in the EDT. 33098b8a9b1dSJustin T. Gibbs * The first way is via the primary EDT tree. It starts 33108b8a9b1dSJustin T. Gibbs * with a list of busses, then a list of targets on a bus, 33118b8a9b1dSJustin T. Gibbs * then devices/luns on a target, and then peripherals on a 33128b8a9b1dSJustin T. Gibbs * device/lun. The "other" way is by the peripheral driver 33138b8a9b1dSJustin T. Gibbs * lists. The peripheral driver lists are organized by 33148b8a9b1dSJustin T. Gibbs * peripheral driver. (obviously) So it makes sense to 33158b8a9b1dSJustin T. Gibbs * use the peripheral driver list if the user is looking 33168b8a9b1dSJustin T. Gibbs * for something like "da1", or all "da" devices. If the 33178b8a9b1dSJustin T. Gibbs * user is looking for something on a particular bus/target 33188b8a9b1dSJustin T. Gibbs * or lun, it's generally better to go through the EDT tree. 33198b8a9b1dSJustin T. Gibbs */ 33208b8a9b1dSJustin T. Gibbs 33218b8a9b1dSJustin T. Gibbs if (cdm->pos.position_type != CAM_DEV_POS_NONE) 33228b8a9b1dSJustin T. Gibbs position_type = cdm->pos.position_type; 33238b8a9b1dSJustin T. Gibbs else { 33243393f8daSKenneth D. Merry u_int i; 33258b8a9b1dSJustin T. Gibbs 33268b8a9b1dSJustin T. Gibbs position_type = CAM_DEV_POS_NONE; 33278b8a9b1dSJustin T. Gibbs 33288b8a9b1dSJustin T. Gibbs for (i = 0; i < cdm->num_patterns; i++) { 33298b8a9b1dSJustin T. Gibbs if ((cdm->patterns[i].type == DEV_MATCH_BUS) 33308b8a9b1dSJustin T. Gibbs ||(cdm->patterns[i].type == DEV_MATCH_DEVICE)){ 33318b8a9b1dSJustin T. Gibbs position_type = CAM_DEV_POS_EDT; 33328b8a9b1dSJustin T. Gibbs break; 33338b8a9b1dSJustin T. Gibbs } 33348b8a9b1dSJustin T. Gibbs } 33358b8a9b1dSJustin T. Gibbs 33368b8a9b1dSJustin T. Gibbs if (cdm->num_patterns == 0) 33378b8a9b1dSJustin T. Gibbs position_type = CAM_DEV_POS_EDT; 33388b8a9b1dSJustin T. Gibbs else if (position_type == CAM_DEV_POS_NONE) 33398b8a9b1dSJustin T. Gibbs position_type = CAM_DEV_POS_PDRV; 33408b8a9b1dSJustin T. Gibbs } 33418b8a9b1dSJustin T. Gibbs 33428b8a9b1dSJustin T. Gibbs switch(position_type & CAM_DEV_POS_TYPEMASK) { 33438b8a9b1dSJustin T. Gibbs case CAM_DEV_POS_EDT: 334407c6eac9SPoul-Henning Kamp xptedtmatch(cdm); 33458b8a9b1dSJustin T. Gibbs break; 33468b8a9b1dSJustin T. Gibbs case CAM_DEV_POS_PDRV: 334707c6eac9SPoul-Henning Kamp xptperiphlistmatch(cdm); 33488b8a9b1dSJustin T. Gibbs break; 33498b8a9b1dSJustin T. Gibbs default: 33508b8a9b1dSJustin T. Gibbs cdm->status = CAM_DEV_MATCH_ERROR; 33518b8a9b1dSJustin T. Gibbs break; 33528b8a9b1dSJustin T. Gibbs } 33538b8a9b1dSJustin T. Gibbs 33548b8a9b1dSJustin T. Gibbs if (cdm->status == CAM_DEV_MATCH_ERROR) 33558b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.status = CAM_REQ_CMP_ERR; 33568b8a9b1dSJustin T. Gibbs else 33578b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.status = CAM_REQ_CMP; 33588b8a9b1dSJustin T. Gibbs 33598b8a9b1dSJustin T. Gibbs break; 33608b8a9b1dSJustin T. Gibbs } 33618b8a9b1dSJustin T. Gibbs case XPT_SASYNC_CB: 33628b8a9b1dSJustin T. Gibbs { 336384f82481SScott Long struct ccb_setasync *csa; 336484f82481SScott Long struct async_node *cur_entry; 336584f82481SScott Long struct async_list *async_head; 336684f82481SScott Long u_int32_t added; 336784f82481SScott Long 336884f82481SScott Long csa = &start_ccb->csa; 336984f82481SScott Long added = csa->event_enable; 337084f82481SScott Long async_head = &csa->ccb_h.path->device->asyncs; 337184f82481SScott Long 337284f82481SScott Long /* 337384f82481SScott Long * If there is already an entry for us, simply 337484f82481SScott Long * update it. 337584f82481SScott Long */ 337684f82481SScott Long cur_entry = SLIST_FIRST(async_head); 337784f82481SScott Long while (cur_entry != NULL) { 337884f82481SScott Long if ((cur_entry->callback_arg == csa->callback_arg) 337984f82481SScott Long && (cur_entry->callback == csa->callback)) 338084f82481SScott Long break; 338184f82481SScott Long cur_entry = SLIST_NEXT(cur_entry, links); 338284f82481SScott Long } 338384f82481SScott Long 338484f82481SScott Long if (cur_entry != NULL) { 338584f82481SScott Long /* 338684f82481SScott Long * If the request has no flags set, 338784f82481SScott Long * remove the entry. 338884f82481SScott Long */ 338984f82481SScott Long added &= ~cur_entry->event_enable; 339084f82481SScott Long if (csa->event_enable == 0) { 339184f82481SScott Long SLIST_REMOVE(async_head, cur_entry, 339284f82481SScott Long async_node, links); 339384f82481SScott Long csa->ccb_h.path->device->refcount--; 339484f82481SScott Long free(cur_entry, M_CAMXPT); 339584f82481SScott Long } else { 339684f82481SScott Long cur_entry->event_enable = csa->event_enable; 339784f82481SScott Long } 339884f82481SScott Long } else { 339984f82481SScott Long cur_entry = malloc(sizeof(*cur_entry), M_CAMXPT, 340084f82481SScott Long M_NOWAIT); 340184f82481SScott Long if (cur_entry == NULL) { 340284f82481SScott Long csa->ccb_h.status = CAM_RESRC_UNAVAIL; 340384f82481SScott Long break; 340484f82481SScott Long } 340584f82481SScott Long cur_entry->event_enable = csa->event_enable; 340684f82481SScott Long cur_entry->callback_arg = csa->callback_arg; 340784f82481SScott Long cur_entry->callback = csa->callback; 340884f82481SScott Long SLIST_INSERT_HEAD(async_head, cur_entry, links); 340984f82481SScott Long csa->ccb_h.path->device->refcount++; 341084f82481SScott Long } 34118b8a9b1dSJustin T. Gibbs 34128b8a9b1dSJustin T. Gibbs /* 34132b83592fSScott Long * Need to decouple this operation via a taqskqueue so that 341484f82481SScott Long * the locking doesn't become a mess. 34158b8a9b1dSJustin T. Gibbs */ 341684f82481SScott Long if ((added & (AC_FOUND_DEVICE | AC_PATH_REGISTERED)) != 0) { 341784f82481SScott Long struct xpt_task *task; 34188b8a9b1dSJustin T. Gibbs 341984f82481SScott Long task = malloc(sizeof(struct xpt_task), M_CAMXPT, 342084f82481SScott Long M_NOWAIT); 34212b83592fSScott Long if (task == NULL) { 342284f82481SScott Long csa->ccb_h.status = CAM_RESRC_UNAVAIL; 34232b83592fSScott Long break; 34248b8a9b1dSJustin T. Gibbs } 34252b83592fSScott Long 34262b83592fSScott Long TASK_INIT(&task->task, 0, xpt_action_sasync_cb, task); 342784f82481SScott Long task->data1 = cur_entry; 342884f82481SScott Long task->data2 = added; 34292b83592fSScott Long taskqueue_enqueue(taskqueue_thread, &task->task); 343084f82481SScott Long } 34312b83592fSScott Long 34328b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.status = CAM_REQ_CMP; 34338b8a9b1dSJustin T. Gibbs break; 34348b8a9b1dSJustin T. Gibbs } 34358b8a9b1dSJustin T. Gibbs case XPT_REL_SIMQ: 34368b8a9b1dSJustin T. Gibbs { 34378b8a9b1dSJustin T. Gibbs struct ccb_relsim *crs; 34388b8a9b1dSJustin T. Gibbs struct cam_ed *dev; 34398b8a9b1dSJustin T. Gibbs 34408b8a9b1dSJustin T. Gibbs crs = &start_ccb->crs; 34418b8a9b1dSJustin T. Gibbs dev = crs->ccb_h.path->device; 34428b8a9b1dSJustin T. Gibbs if (dev == NULL) { 34438b8a9b1dSJustin T. Gibbs 34448b8a9b1dSJustin T. Gibbs crs->ccb_h.status = CAM_DEV_NOT_THERE; 34458b8a9b1dSJustin T. Gibbs break; 34468b8a9b1dSJustin T. Gibbs } 34478b8a9b1dSJustin T. Gibbs 34488b8a9b1dSJustin T. Gibbs if ((crs->release_flags & RELSIM_ADJUST_OPENINGS) != 0) { 34498b8a9b1dSJustin T. Gibbs 34504e359f5aSMatt Jacob if (INQ_DATA_TQ_ENABLED(&dev->inq_data)) { 34518b8a9b1dSJustin T. Gibbs /* Don't ever go below one opening */ 34528b8a9b1dSJustin T. Gibbs if (crs->openings > 0) { 34538b8a9b1dSJustin T. Gibbs xpt_dev_ccbq_resize(crs->ccb_h.path, 34548b8a9b1dSJustin T. Gibbs crs->openings); 34558b8a9b1dSJustin T. Gibbs 345679ccc199SJordan K. Hubbard if (bootverbose) { 3457f0d9af51SMatt Jacob xpt_print(crs->ccb_h.path, 3458f0d9af51SMatt Jacob "tagged openings now %d\n", 34598b8a9b1dSJustin T. Gibbs crs->openings); 34608b8a9b1dSJustin T. Gibbs } 34618b8a9b1dSJustin T. Gibbs } 34628b8a9b1dSJustin T. Gibbs } 34638b8a9b1dSJustin T. Gibbs } 34648b8a9b1dSJustin T. Gibbs 34658b8a9b1dSJustin T. Gibbs if ((crs->release_flags & RELSIM_RELEASE_AFTER_TIMEOUT) != 0) { 34668b8a9b1dSJustin T. Gibbs 34678b8a9b1dSJustin T. Gibbs if ((dev->flags & CAM_DEV_REL_TIMEOUT_PENDING) != 0) { 34688b8a9b1dSJustin T. Gibbs 34698b8a9b1dSJustin T. Gibbs /* 34708b8a9b1dSJustin T. Gibbs * Just extend the old timeout and decrement 34718b8a9b1dSJustin T. Gibbs * the freeze count so that a single timeout 34728b8a9b1dSJustin T. Gibbs * is sufficient for releasing the queue. 34738b8a9b1dSJustin T. Gibbs */ 34748b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.flags &= ~CAM_DEV_QFREEZE; 34752b83592fSScott Long callout_stop(&dev->callout); 34768b8a9b1dSJustin T. Gibbs } else { 34778b8a9b1dSJustin T. Gibbs 34788b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.flags |= CAM_DEV_QFREEZE; 34798b8a9b1dSJustin T. Gibbs } 34808b8a9b1dSJustin T. Gibbs 34812b83592fSScott Long callout_reset(&dev->callout, 34822b83592fSScott Long (crs->release_timeout * hz) / 1000, 34832b83592fSScott Long xpt_release_devq_timeout, dev); 34848b8a9b1dSJustin T. Gibbs 34858b8a9b1dSJustin T. Gibbs dev->flags |= CAM_DEV_REL_TIMEOUT_PENDING; 34868b8a9b1dSJustin T. Gibbs 34878b8a9b1dSJustin T. Gibbs } 34888b8a9b1dSJustin T. Gibbs 34898b8a9b1dSJustin T. Gibbs if ((crs->release_flags & RELSIM_RELEASE_AFTER_CMDCMPLT) != 0) { 34908b8a9b1dSJustin T. Gibbs 34918b8a9b1dSJustin T. Gibbs if ((dev->flags & CAM_DEV_REL_ON_COMPLETE) != 0) { 34928b8a9b1dSJustin T. Gibbs /* 34938b8a9b1dSJustin T. Gibbs * Decrement the freeze count so that a single 34948b8a9b1dSJustin T. Gibbs * completion is still sufficient to unfreeze 34958b8a9b1dSJustin T. Gibbs * the queue. 34968b8a9b1dSJustin T. Gibbs */ 34978b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.flags &= ~CAM_DEV_QFREEZE; 34988b8a9b1dSJustin T. Gibbs } else { 34998b8a9b1dSJustin T. Gibbs 35008b8a9b1dSJustin T. Gibbs dev->flags |= CAM_DEV_REL_ON_COMPLETE; 35018b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.flags |= CAM_DEV_QFREEZE; 35028b8a9b1dSJustin T. Gibbs } 35038b8a9b1dSJustin T. Gibbs } 35048b8a9b1dSJustin T. Gibbs 35058b8a9b1dSJustin T. Gibbs if ((crs->release_flags & RELSIM_RELEASE_AFTER_QEMPTY) != 0) { 35068b8a9b1dSJustin T. Gibbs 35078b8a9b1dSJustin T. Gibbs if ((dev->flags & CAM_DEV_REL_ON_QUEUE_EMPTY) != 0 35088b8a9b1dSJustin T. Gibbs || (dev->ccbq.dev_active == 0)) { 35098b8a9b1dSJustin T. Gibbs 35108b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.flags &= ~CAM_DEV_QFREEZE; 35118b8a9b1dSJustin T. Gibbs } else { 35128b8a9b1dSJustin T. Gibbs 35138b8a9b1dSJustin T. Gibbs dev->flags |= CAM_DEV_REL_ON_QUEUE_EMPTY; 35148b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.flags |= CAM_DEV_QFREEZE; 35158b8a9b1dSJustin T. Gibbs } 35168b8a9b1dSJustin T. Gibbs } 35178b8a9b1dSJustin T. Gibbs 35188b8a9b1dSJustin T. Gibbs if ((start_ccb->ccb_h.flags & CAM_DEV_QFREEZE) == 0) { 35198b8a9b1dSJustin T. Gibbs 35202cefde5fSJustin T. Gibbs xpt_release_devq(crs->ccb_h.path, /*count*/1, 35218b8a9b1dSJustin T. Gibbs /*run_queue*/TRUE); 35228b8a9b1dSJustin T. Gibbs } 35238b8a9b1dSJustin T. Gibbs start_ccb->crs.qfrozen_cnt = dev->qfrozen_cnt; 35248b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.status = CAM_REQ_CMP; 35258b8a9b1dSJustin T. Gibbs break; 35268b8a9b1dSJustin T. Gibbs } 35278b8a9b1dSJustin T. Gibbs case XPT_SCAN_BUS: 35288b8a9b1dSJustin T. Gibbs xpt_scan_bus(start_ccb->ccb_h.path->periph, start_ccb); 35298b8a9b1dSJustin T. Gibbs break; 35308b8a9b1dSJustin T. Gibbs case XPT_SCAN_LUN: 35318b8a9b1dSJustin T. Gibbs xpt_scan_lun(start_ccb->ccb_h.path->periph, 35328b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.path, start_ccb->crcn.flags, 35338b8a9b1dSJustin T. Gibbs start_ccb); 35348b8a9b1dSJustin T. Gibbs break; 35358b8a9b1dSJustin T. Gibbs case XPT_DEBUG: { 35368b8a9b1dSJustin T. Gibbs #ifdef CAMDEBUG 35372cefde5fSJustin T. Gibbs #ifdef CAM_DEBUG_DELAY 35382cefde5fSJustin T. Gibbs cam_debug_delay = CAM_DEBUG_DELAY; 35392cefde5fSJustin T. Gibbs #endif 35408b8a9b1dSJustin T. Gibbs cam_dflags = start_ccb->cdbg.flags; 35418b8a9b1dSJustin T. Gibbs if (cam_dpath != NULL) { 35428b8a9b1dSJustin T. Gibbs xpt_free_path(cam_dpath); 35438b8a9b1dSJustin T. Gibbs cam_dpath = NULL; 35448b8a9b1dSJustin T. Gibbs } 35458b8a9b1dSJustin T. Gibbs 35468b8a9b1dSJustin T. Gibbs if (cam_dflags != CAM_DEBUG_NONE) { 35478b8a9b1dSJustin T. Gibbs if (xpt_create_path(&cam_dpath, xpt_periph, 35488b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.path_id, 35498b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.target_id, 35508b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.target_lun) != 35518b8a9b1dSJustin T. Gibbs CAM_REQ_CMP) { 35528b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.status = CAM_RESRC_UNAVAIL; 35538b8a9b1dSJustin T. Gibbs cam_dflags = CAM_DEBUG_NONE; 3554aa872be6SMatt Jacob } else { 35558b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.status = CAM_REQ_CMP; 3556f0d9af51SMatt Jacob xpt_print(cam_dpath, "debugging flags now %x\n", 3557f0d9af51SMatt Jacob cam_dflags); 3558aa872be6SMatt Jacob } 35598b8a9b1dSJustin T. Gibbs } else { 35608b8a9b1dSJustin T. Gibbs cam_dpath = NULL; 35618b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.status = CAM_REQ_CMP; 35628b8a9b1dSJustin T. Gibbs } 35638b8a9b1dSJustin T. Gibbs #else /* !CAMDEBUG */ 35648b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.status = CAM_FUNC_NOTAVAIL; 35658b8a9b1dSJustin T. Gibbs #endif /* CAMDEBUG */ 35668b8a9b1dSJustin T. Gibbs break; 35678b8a9b1dSJustin T. Gibbs } 35688b8a9b1dSJustin T. Gibbs case XPT_NOOP: 356987cfaf0eSJustin T. Gibbs if ((start_ccb->ccb_h.flags & CAM_DEV_QFREEZE) != 0) 357087cfaf0eSJustin T. Gibbs xpt_freeze_devq(start_ccb->ccb_h.path, 1); 35718b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.status = CAM_REQ_CMP; 35728b8a9b1dSJustin T. Gibbs break; 35738b8a9b1dSJustin T. Gibbs default: 35748b8a9b1dSJustin T. Gibbs case XPT_SDEV_TYPE: 35758b8a9b1dSJustin T. Gibbs case XPT_TERM_IO: 35768b8a9b1dSJustin T. Gibbs case XPT_ENG_INQ: 35778b8a9b1dSJustin T. Gibbs /* XXX Implement */ 35788b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.status = CAM_PROVIDE_FAIL; 35798b8a9b1dSJustin T. Gibbs break; 35808b8a9b1dSJustin T. Gibbs } 35818b8a9b1dSJustin T. Gibbs } 35828b8a9b1dSJustin T. Gibbs 35838b8a9b1dSJustin T. Gibbs void 35848b8a9b1dSJustin T. Gibbs xpt_polled_action(union ccb *start_ccb) 35858b8a9b1dSJustin T. Gibbs { 35868b8a9b1dSJustin T. Gibbs u_int32_t timeout; 35878b8a9b1dSJustin T. Gibbs struct cam_sim *sim; 35888b8a9b1dSJustin T. Gibbs struct cam_devq *devq; 35898b8a9b1dSJustin T. Gibbs struct cam_ed *dev; 35908b8a9b1dSJustin T. Gibbs 359168153f43SScott Long 35928b8a9b1dSJustin T. Gibbs timeout = start_ccb->ccb_h.timeout; 35938b8a9b1dSJustin T. Gibbs sim = start_ccb->ccb_h.path->bus->sim; 35948b8a9b1dSJustin T. Gibbs devq = sim->devq; 35958b8a9b1dSJustin T. Gibbs dev = start_ccb->ccb_h.path->device; 35968b8a9b1dSJustin T. Gibbs 35972b83592fSScott Long mtx_assert(sim->mtx, MA_OWNED); 35988b8a9b1dSJustin T. Gibbs 35998b8a9b1dSJustin T. Gibbs /* 36008b8a9b1dSJustin T. Gibbs * Steal an opening so that no other queued requests 36018b8a9b1dSJustin T. Gibbs * can get it before us while we simulate interrupts. 36028b8a9b1dSJustin T. Gibbs */ 36038b8a9b1dSJustin T. Gibbs dev->ccbq.devq_openings--; 36048b8a9b1dSJustin T. Gibbs dev->ccbq.dev_openings--; 36058b8a9b1dSJustin T. Gibbs 3606d3ef3454SIan Dowse while(((devq != NULL && devq->send_openings <= 0) || 3607d3ef3454SIan Dowse dev->ccbq.dev_openings < 0) && (--timeout > 0)) { 36088b8a9b1dSJustin T. Gibbs DELAY(1000); 36098b8a9b1dSJustin T. Gibbs (*(sim->sim_poll))(sim); 36109758cc83SScott Long camisr_runqueue(&sim->sim_doneq); 36118b8a9b1dSJustin T. Gibbs } 36128b8a9b1dSJustin T. Gibbs 36138b8a9b1dSJustin T. Gibbs dev->ccbq.devq_openings++; 36148b8a9b1dSJustin T. Gibbs dev->ccbq.dev_openings++; 36158b8a9b1dSJustin T. Gibbs 36168b8a9b1dSJustin T. Gibbs if (timeout != 0) { 36178b8a9b1dSJustin T. Gibbs xpt_action(start_ccb); 36188b8a9b1dSJustin T. Gibbs while(--timeout > 0) { 36198b8a9b1dSJustin T. Gibbs (*(sim->sim_poll))(sim); 36209758cc83SScott Long camisr_runqueue(&sim->sim_doneq); 36218b8a9b1dSJustin T. Gibbs if ((start_ccb->ccb_h.status & CAM_STATUS_MASK) 36228b8a9b1dSJustin T. Gibbs != CAM_REQ_INPROG) 36238b8a9b1dSJustin T. Gibbs break; 36248b8a9b1dSJustin T. Gibbs DELAY(1000); 36258b8a9b1dSJustin T. Gibbs } 36268b8a9b1dSJustin T. Gibbs if (timeout == 0) { 36278b8a9b1dSJustin T. Gibbs /* 36288b8a9b1dSJustin T. Gibbs * XXX Is it worth adding a sim_timeout entry 36298b8a9b1dSJustin T. Gibbs * point so we can attempt recovery? If 36308b8a9b1dSJustin T. Gibbs * this is only used for dumps, I don't think 36318b8a9b1dSJustin T. Gibbs * it is. 36328b8a9b1dSJustin T. Gibbs */ 36338b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.status = CAM_CMD_TIMEOUT; 36348b8a9b1dSJustin T. Gibbs } 36358b8a9b1dSJustin T. Gibbs } else { 36368b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.status = CAM_RESRC_UNAVAIL; 36378b8a9b1dSJustin T. Gibbs } 36388b8a9b1dSJustin T. Gibbs } 36398b8a9b1dSJustin T. Gibbs 36408b8a9b1dSJustin T. Gibbs /* 36418b8a9b1dSJustin T. Gibbs * Schedule a peripheral driver to receive a ccb when it's 36428b8a9b1dSJustin T. Gibbs * target device has space for more transactions. 36438b8a9b1dSJustin T. Gibbs */ 36448b8a9b1dSJustin T. Gibbs void 36458b8a9b1dSJustin T. Gibbs xpt_schedule(struct cam_periph *perph, u_int32_t new_priority) 36468b8a9b1dSJustin T. Gibbs { 36478b8a9b1dSJustin T. Gibbs struct cam_ed *device; 3648d3ef3454SIan Dowse union ccb *work_ccb; 36498b8a9b1dSJustin T. Gibbs int runq; 36508b8a9b1dSJustin T. Gibbs 36512b83592fSScott Long mtx_assert(perph->sim->mtx, MA_OWNED); 365268153f43SScott Long 36538b8a9b1dSJustin T. Gibbs CAM_DEBUG(perph->path, CAM_DEBUG_TRACE, ("xpt_schedule\n")); 36548b8a9b1dSJustin T. Gibbs device = perph->path->device; 36558b8a9b1dSJustin T. Gibbs if (periph_is_queued(perph)) { 36568b8a9b1dSJustin T. Gibbs /* Simply reorder based on new priority */ 36578b8a9b1dSJustin T. Gibbs CAM_DEBUG(perph->path, CAM_DEBUG_SUBTRACE, 36588b8a9b1dSJustin T. Gibbs (" change priority to %d\n", new_priority)); 36598b8a9b1dSJustin T. Gibbs if (new_priority < perph->pinfo.priority) { 36608b8a9b1dSJustin T. Gibbs camq_change_priority(&device->drvq, 36618b8a9b1dSJustin T. Gibbs perph->pinfo.index, 36628b8a9b1dSJustin T. Gibbs new_priority); 36638b8a9b1dSJustin T. Gibbs } 36648b8a9b1dSJustin T. Gibbs runq = 0; 3665d3ef3454SIan Dowse } else if (SIM_DEAD(perph->path->bus->sim)) { 3666d3ef3454SIan Dowse /* The SIM is gone so just call periph_start directly. */ 3667d3ef3454SIan Dowse work_ccb = xpt_get_ccb(perph->path->device); 3668d3ef3454SIan Dowse if (work_ccb == NULL) 3669d3ef3454SIan Dowse return; /* XXX */ 3670d3ef3454SIan Dowse xpt_setup_ccb(&work_ccb->ccb_h, perph->path, new_priority); 3671d3ef3454SIan Dowse perph->pinfo.priority = new_priority; 3672d3ef3454SIan Dowse perph->periph_start(perph, work_ccb); 3673d3ef3454SIan Dowse return; 36748b8a9b1dSJustin T. Gibbs } else { 36758b8a9b1dSJustin T. Gibbs /* New entry on the queue */ 36768b8a9b1dSJustin T. Gibbs CAM_DEBUG(perph->path, CAM_DEBUG_SUBTRACE, 36778b8a9b1dSJustin T. Gibbs (" added periph to queue\n")); 36788b8a9b1dSJustin T. Gibbs perph->pinfo.priority = new_priority; 36798bad620dSJustin T. Gibbs perph->pinfo.generation = ++device->drvq.generation; 36808b8a9b1dSJustin T. Gibbs camq_insert(&device->drvq, &perph->pinfo); 36818b8a9b1dSJustin T. Gibbs runq = xpt_schedule_dev_allocq(perph->path->bus, device); 36828b8a9b1dSJustin T. Gibbs } 36838b8a9b1dSJustin T. Gibbs if (runq != 0) { 36848b8a9b1dSJustin T. Gibbs CAM_DEBUG(perph->path, CAM_DEBUG_SUBTRACE, 36858b8a9b1dSJustin T. Gibbs (" calling xpt_run_devq\n")); 36868b8a9b1dSJustin T. Gibbs xpt_run_dev_allocq(perph->path->bus); 36878b8a9b1dSJustin T. Gibbs } 36888b8a9b1dSJustin T. Gibbs } 36898b8a9b1dSJustin T. Gibbs 36908b8a9b1dSJustin T. Gibbs 36918b8a9b1dSJustin T. Gibbs /* 36928b8a9b1dSJustin T. Gibbs * Schedule a device to run on a given queue. 36938b8a9b1dSJustin T. Gibbs * If the device was inserted as a new entry on the queue, 36948b8a9b1dSJustin T. Gibbs * return 1 meaning the device queue should be run. If we 36958b8a9b1dSJustin T. Gibbs * were already queued, implying someone else has already 36968b8a9b1dSJustin T. Gibbs * started the queue, return 0 so the caller doesn't attempt 369777dc25ccSScott Long * to run the queue. 36988b8a9b1dSJustin T. Gibbs */ 36998b8a9b1dSJustin T. Gibbs static int 37008b8a9b1dSJustin T. Gibbs xpt_schedule_dev(struct camq *queue, cam_pinfo *pinfo, 37018b8a9b1dSJustin T. Gibbs u_int32_t new_priority) 37028b8a9b1dSJustin T. Gibbs { 37038b8a9b1dSJustin T. Gibbs int retval; 37048b8a9b1dSJustin T. Gibbs u_int32_t old_priority; 37058b8a9b1dSJustin T. Gibbs 3706aa872be6SMatt Jacob CAM_DEBUG_PRINT(CAM_DEBUG_XPT, ("xpt_schedule_dev\n")); 37078b8a9b1dSJustin T. Gibbs 37088b8a9b1dSJustin T. Gibbs old_priority = pinfo->priority; 37098b8a9b1dSJustin T. Gibbs 37108b8a9b1dSJustin T. Gibbs /* 37118b8a9b1dSJustin T. Gibbs * Are we already queued? 37128b8a9b1dSJustin T. Gibbs */ 37138b8a9b1dSJustin T. Gibbs if (pinfo->index != CAM_UNQUEUED_INDEX) { 37148b8a9b1dSJustin T. Gibbs /* Simply reorder based on new priority */ 37158b8a9b1dSJustin T. Gibbs if (new_priority < old_priority) { 37168b8a9b1dSJustin T. Gibbs camq_change_priority(queue, pinfo->index, 37178b8a9b1dSJustin T. Gibbs new_priority); 3718aa872be6SMatt Jacob CAM_DEBUG_PRINT(CAM_DEBUG_XPT, 37198b8a9b1dSJustin T. Gibbs ("changed priority to %d\n", 37208b8a9b1dSJustin T. Gibbs new_priority)); 37218b8a9b1dSJustin T. Gibbs } 37228b8a9b1dSJustin T. Gibbs retval = 0; 37238b8a9b1dSJustin T. Gibbs } else { 37248b8a9b1dSJustin T. Gibbs /* New entry on the queue */ 37258b8a9b1dSJustin T. Gibbs if (new_priority < old_priority) 37268b8a9b1dSJustin T. Gibbs pinfo->priority = new_priority; 37278b8a9b1dSJustin T. Gibbs 3728aa872be6SMatt Jacob CAM_DEBUG_PRINT(CAM_DEBUG_XPT, 37298b8a9b1dSJustin T. Gibbs ("Inserting onto queue\n")); 37308bad620dSJustin T. Gibbs pinfo->generation = ++queue->generation; 37318b8a9b1dSJustin T. Gibbs camq_insert(queue, pinfo); 37328b8a9b1dSJustin T. Gibbs retval = 1; 37338b8a9b1dSJustin T. Gibbs } 37348b8a9b1dSJustin T. Gibbs return (retval); 37358b8a9b1dSJustin T. Gibbs } 37368b8a9b1dSJustin T. Gibbs 37378b8a9b1dSJustin T. Gibbs static void 37388b8a9b1dSJustin T. Gibbs xpt_run_dev_allocq(struct cam_eb *bus) 37398b8a9b1dSJustin T. Gibbs { 37408b8a9b1dSJustin T. Gibbs struct cam_devq *devq; 37418b8a9b1dSJustin T. Gibbs 3742aa872be6SMatt Jacob CAM_DEBUG_PRINT(CAM_DEBUG_XPT, ("xpt_run_dev_allocq\n")); 37438b8a9b1dSJustin T. Gibbs devq = bus->sim->devq; 37448b8a9b1dSJustin T. Gibbs 3745aa872be6SMatt Jacob CAM_DEBUG_PRINT(CAM_DEBUG_XPT, 37468b8a9b1dSJustin T. Gibbs (" qfrozen_cnt == 0x%x, entries == %d, " 37478b8a9b1dSJustin T. Gibbs "openings == %d, active == %d\n", 37488b8a9b1dSJustin T. Gibbs devq->alloc_queue.qfrozen_cnt, 37498b8a9b1dSJustin T. Gibbs devq->alloc_queue.entries, 37508b8a9b1dSJustin T. Gibbs devq->alloc_openings, 37518b8a9b1dSJustin T. Gibbs devq->alloc_active)); 37528b8a9b1dSJustin T. Gibbs 37538b8a9b1dSJustin T. Gibbs devq->alloc_queue.qfrozen_cnt++; 37548b8a9b1dSJustin T. Gibbs while ((devq->alloc_queue.entries > 0) 37558b8a9b1dSJustin T. Gibbs && (devq->alloc_openings > 0) 37568b8a9b1dSJustin T. Gibbs && (devq->alloc_queue.qfrozen_cnt <= 1)) { 37578b8a9b1dSJustin T. Gibbs struct cam_ed_qinfo *qinfo; 37588b8a9b1dSJustin T. Gibbs struct cam_ed *device; 37598b8a9b1dSJustin T. Gibbs union ccb *work_ccb; 37608b8a9b1dSJustin T. Gibbs struct cam_periph *drv; 37618b8a9b1dSJustin T. Gibbs struct camq *drvq; 37628b8a9b1dSJustin T. Gibbs 37638b8a9b1dSJustin T. Gibbs qinfo = (struct cam_ed_qinfo *)camq_remove(&devq->alloc_queue, 37645a526431SJustin T. Gibbs CAMQ_HEAD); 37658b8a9b1dSJustin T. Gibbs device = qinfo->device; 37668b8a9b1dSJustin T. Gibbs 3767aa872be6SMatt Jacob CAM_DEBUG_PRINT(CAM_DEBUG_XPT, 376850642f18SKenneth D. Merry ("running device %p\n", device)); 37698b8a9b1dSJustin T. Gibbs 37708b8a9b1dSJustin T. Gibbs drvq = &device->drvq; 37718b8a9b1dSJustin T. Gibbs 37728b8a9b1dSJustin T. Gibbs #ifdef CAMDEBUG 37738b8a9b1dSJustin T. Gibbs if (drvq->entries <= 0) { 37748b8a9b1dSJustin T. Gibbs panic("xpt_run_dev_allocq: " 37758b8a9b1dSJustin T. Gibbs "Device on queue without any work to do"); 37768b8a9b1dSJustin T. Gibbs } 37778b8a9b1dSJustin T. Gibbs #endif 37788b8a9b1dSJustin T. Gibbs if ((work_ccb = xpt_get_ccb(device)) != NULL) { 37798b8a9b1dSJustin T. Gibbs devq->alloc_openings--; 37808b8a9b1dSJustin T. Gibbs devq->alloc_active++; 37815a526431SJustin T. Gibbs drv = (struct cam_periph*)camq_remove(drvq, CAMQ_HEAD); 37828b8a9b1dSJustin T. Gibbs xpt_setup_ccb(&work_ccb->ccb_h, drv->path, 37838b8a9b1dSJustin T. Gibbs drv->pinfo.priority); 3784aa872be6SMatt Jacob CAM_DEBUG_PRINT(CAM_DEBUG_XPT, 37858b8a9b1dSJustin T. Gibbs ("calling periph start\n")); 37868b8a9b1dSJustin T. Gibbs drv->periph_start(drv, work_ccb); 37878b8a9b1dSJustin T. Gibbs } else { 37888b8a9b1dSJustin T. Gibbs /* 37898b8a9b1dSJustin T. Gibbs * Malloc failure in alloc_ccb 37908b8a9b1dSJustin T. Gibbs */ 37918b8a9b1dSJustin T. Gibbs /* 37928b8a9b1dSJustin T. Gibbs * XXX add us to a list to be run from free_ccb 37938b8a9b1dSJustin T. Gibbs * if we don't have any ccbs active on this 37948b8a9b1dSJustin T. Gibbs * device queue otherwise we may never get run 37958b8a9b1dSJustin T. Gibbs * again. 37968b8a9b1dSJustin T. Gibbs */ 37978b8a9b1dSJustin T. Gibbs break; 37988b8a9b1dSJustin T. Gibbs } 37998b8a9b1dSJustin T. Gibbs 38008b8a9b1dSJustin T. Gibbs if (drvq->entries > 0) { 38018b8a9b1dSJustin T. Gibbs /* We have more work. Attempt to reschedule */ 38028b8a9b1dSJustin T. Gibbs xpt_schedule_dev_allocq(bus, device); 38038b8a9b1dSJustin T. Gibbs } 38048b8a9b1dSJustin T. Gibbs } 38058b8a9b1dSJustin T. Gibbs devq->alloc_queue.qfrozen_cnt--; 38068b8a9b1dSJustin T. Gibbs } 38078b8a9b1dSJustin T. Gibbs 38088b8a9b1dSJustin T. Gibbs static void 38098b8a9b1dSJustin T. Gibbs xpt_run_dev_sendq(struct cam_eb *bus) 38108b8a9b1dSJustin T. Gibbs { 38118b8a9b1dSJustin T. Gibbs struct cam_devq *devq; 38128b8a9b1dSJustin T. Gibbs 3813aa872be6SMatt Jacob CAM_DEBUG_PRINT(CAM_DEBUG_XPT, ("xpt_run_dev_sendq\n")); 38148b8a9b1dSJustin T. Gibbs 38158b8a9b1dSJustin T. Gibbs devq = bus->sim->devq; 38168b8a9b1dSJustin T. Gibbs 38178b8a9b1dSJustin T. Gibbs devq->send_queue.qfrozen_cnt++; 38188b8a9b1dSJustin T. Gibbs while ((devq->send_queue.entries > 0) 38198b8a9b1dSJustin T. Gibbs && (devq->send_openings > 0)) { 38208b8a9b1dSJustin T. Gibbs struct cam_ed_qinfo *qinfo; 38218b8a9b1dSJustin T. Gibbs struct cam_ed *device; 38228b8a9b1dSJustin T. Gibbs union ccb *work_ccb; 38238b8a9b1dSJustin T. Gibbs struct cam_sim *sim; 38248b8a9b1dSJustin T. Gibbs 38258b8a9b1dSJustin T. Gibbs if (devq->send_queue.qfrozen_cnt > 1) { 38268b8a9b1dSJustin T. Gibbs break; 38278b8a9b1dSJustin T. Gibbs } 38288b8a9b1dSJustin T. Gibbs 38298b8a9b1dSJustin T. Gibbs qinfo = (struct cam_ed_qinfo *)camq_remove(&devq->send_queue, 38305a526431SJustin T. Gibbs CAMQ_HEAD); 38318b8a9b1dSJustin T. Gibbs device = qinfo->device; 38328b8a9b1dSJustin T. Gibbs 38338b8a9b1dSJustin T. Gibbs /* 38348b8a9b1dSJustin T. Gibbs * If the device has been "frozen", don't attempt 38358b8a9b1dSJustin T. Gibbs * to run it. 38368b8a9b1dSJustin T. Gibbs */ 38378b8a9b1dSJustin T. Gibbs if (device->qfrozen_cnt > 0) { 38388b8a9b1dSJustin T. Gibbs continue; 38398b8a9b1dSJustin T. Gibbs } 38408b8a9b1dSJustin T. Gibbs 3841aa872be6SMatt Jacob CAM_DEBUG_PRINT(CAM_DEBUG_XPT, 384250642f18SKenneth D. Merry ("running device %p\n", device)); 38438b8a9b1dSJustin T. Gibbs 38445a526431SJustin T. Gibbs work_ccb = cam_ccbq_peek_ccb(&device->ccbq, CAMQ_HEAD); 38458b8a9b1dSJustin T. Gibbs if (work_ccb == NULL) { 384657b89bbcSNate Lawson printf("device on run queue with no ccbs???\n"); 38478b8a9b1dSJustin T. Gibbs continue; 38488b8a9b1dSJustin T. Gibbs } 38498b8a9b1dSJustin T. Gibbs 38508b8a9b1dSJustin T. Gibbs if ((work_ccb->ccb_h.flags & CAM_HIGH_POWER) != 0) { 38518b8a9b1dSJustin T. Gibbs 38522b83592fSScott Long mtx_lock(&xsoftc.xpt_lock); 38532b83592fSScott Long if (xsoftc.num_highpower <= 0) { 38548b8a9b1dSJustin T. Gibbs /* 38558b8a9b1dSJustin T. Gibbs * We got a high power command, but we 38568b8a9b1dSJustin T. Gibbs * don't have any available slots. Freeze 38578b8a9b1dSJustin T. Gibbs * the device queue until we have a slot 38588b8a9b1dSJustin T. Gibbs * available. 38598b8a9b1dSJustin T. Gibbs */ 38608b8a9b1dSJustin T. Gibbs device->qfrozen_cnt++; 38612b83592fSScott Long STAILQ_INSERT_TAIL(&xsoftc.highpowerq, 38628b8a9b1dSJustin T. Gibbs &work_ccb->ccb_h, 38638b8a9b1dSJustin T. Gibbs xpt_links.stqe); 38648b8a9b1dSJustin T. Gibbs 3865469f9f44SScott Long mtx_unlock(&xsoftc.xpt_lock); 38668b8a9b1dSJustin T. Gibbs continue; 38678b8a9b1dSJustin T. Gibbs } else { 38688b8a9b1dSJustin T. Gibbs /* 38698b8a9b1dSJustin T. Gibbs * Consume a high power slot while 38708b8a9b1dSJustin T. Gibbs * this ccb runs. 38718b8a9b1dSJustin T. Gibbs */ 38722b83592fSScott Long xsoftc.num_highpower--; 38738b8a9b1dSJustin T. Gibbs } 38742b83592fSScott Long mtx_unlock(&xsoftc.xpt_lock); 38758b8a9b1dSJustin T. Gibbs } 38768b8a9b1dSJustin T. Gibbs devq->active_dev = device; 38778b8a9b1dSJustin T. Gibbs cam_ccbq_remove_ccb(&device->ccbq, work_ccb); 38788b8a9b1dSJustin T. Gibbs 38798b8a9b1dSJustin T. Gibbs cam_ccbq_send_ccb(&device->ccbq, work_ccb); 38808b8a9b1dSJustin T. Gibbs 38818b8a9b1dSJustin T. Gibbs devq->send_openings--; 38828b8a9b1dSJustin T. Gibbs devq->send_active++; 38838b8a9b1dSJustin T. Gibbs 38845a526431SJustin T. Gibbs if (device->ccbq.queue.entries > 0) 38858b8a9b1dSJustin T. Gibbs xpt_schedule_dev_sendq(bus, device); 38868b8a9b1dSJustin T. Gibbs 38878b8a9b1dSJustin T. Gibbs if (work_ccb && (work_ccb->ccb_h.flags & CAM_DEV_QFREEZE) != 0){ 38888b8a9b1dSJustin T. Gibbs /* 38898b8a9b1dSJustin T. Gibbs * The client wants to freeze the queue 38908b8a9b1dSJustin T. Gibbs * after this CCB is sent. 38918b8a9b1dSJustin T. Gibbs */ 38928b8a9b1dSJustin T. Gibbs device->qfrozen_cnt++; 38938b8a9b1dSJustin T. Gibbs } 38948b8a9b1dSJustin T. Gibbs 3895a4eb4f16SMatt Jacob /* In Target mode, the peripheral driver knows best... */ 3896a4eb4f16SMatt Jacob if (work_ccb->ccb_h.func_code == XPT_SCSI_IO) { 3897a4eb4f16SMatt Jacob if ((device->inq_flags & SID_CmdQue) != 0 3898a4eb4f16SMatt Jacob && work_ccb->csio.tag_action != CAM_TAG_ACTION_NONE) 38998b8a9b1dSJustin T. Gibbs work_ccb->ccb_h.flags |= CAM_TAG_ACTION_VALID; 39008b8a9b1dSJustin T. Gibbs else 39018b8a9b1dSJustin T. Gibbs /* 3902a4eb4f16SMatt Jacob * Clear this in case of a retried CCB that 3903a4eb4f16SMatt Jacob * failed due to a rejected tag. 39048b8a9b1dSJustin T. Gibbs */ 39058b8a9b1dSJustin T. Gibbs work_ccb->ccb_h.flags &= ~CAM_TAG_ACTION_VALID; 3906a4eb4f16SMatt Jacob } 39078b8a9b1dSJustin T. Gibbs 39088b8a9b1dSJustin T. Gibbs /* 39098b8a9b1dSJustin T. Gibbs * Device queues can be shared among multiple sim instances 39108b8a9b1dSJustin T. Gibbs * that reside on different busses. Use the SIM in the queue 39118b8a9b1dSJustin T. Gibbs * CCB's path, rather than the one in the bus that was passed 39128b8a9b1dSJustin T. Gibbs * into this function. 39138b8a9b1dSJustin T. Gibbs */ 39148b8a9b1dSJustin T. Gibbs sim = work_ccb->ccb_h.path->bus->sim; 39158b8a9b1dSJustin T. Gibbs (*(sim->sim_action))(sim, work_ccb); 39168b8a9b1dSJustin T. Gibbs 39178b8a9b1dSJustin T. Gibbs devq->active_dev = NULL; 39188b8a9b1dSJustin T. Gibbs } 39198b8a9b1dSJustin T. Gibbs devq->send_queue.qfrozen_cnt--; 39208b8a9b1dSJustin T. Gibbs } 39218b8a9b1dSJustin T. Gibbs 39228b8a9b1dSJustin T. Gibbs /* 39238b8a9b1dSJustin T. Gibbs * This function merges stuff from the slave ccb into the master ccb, while 39248b8a9b1dSJustin T. Gibbs * keeping important fields in the master ccb constant. 39258b8a9b1dSJustin T. Gibbs */ 39268b8a9b1dSJustin T. Gibbs void 39278b8a9b1dSJustin T. Gibbs xpt_merge_ccb(union ccb *master_ccb, union ccb *slave_ccb) 39288b8a9b1dSJustin T. Gibbs { 392968153f43SScott Long 39308b8a9b1dSJustin T. Gibbs /* 39318b8a9b1dSJustin T. Gibbs * Pull fields that are valid for peripheral drivers to set 39328b8a9b1dSJustin T. Gibbs * into the master CCB along with the CCB "payload". 39338b8a9b1dSJustin T. Gibbs */ 39348b8a9b1dSJustin T. Gibbs master_ccb->ccb_h.retry_count = slave_ccb->ccb_h.retry_count; 39358b8a9b1dSJustin T. Gibbs master_ccb->ccb_h.func_code = slave_ccb->ccb_h.func_code; 39368b8a9b1dSJustin T. Gibbs master_ccb->ccb_h.timeout = slave_ccb->ccb_h.timeout; 39378b8a9b1dSJustin T. Gibbs master_ccb->ccb_h.flags = slave_ccb->ccb_h.flags; 39388b8a9b1dSJustin T. Gibbs bcopy(&(&slave_ccb->ccb_h)[1], &(&master_ccb->ccb_h)[1], 39398b8a9b1dSJustin T. Gibbs sizeof(union ccb) - sizeof(struct ccb_hdr)); 39408b8a9b1dSJustin T. Gibbs } 39418b8a9b1dSJustin T. Gibbs 39428b8a9b1dSJustin T. Gibbs void 39438b8a9b1dSJustin T. Gibbs xpt_setup_ccb(struct ccb_hdr *ccb_h, struct cam_path *path, u_int32_t priority) 39448b8a9b1dSJustin T. Gibbs { 394568153f43SScott Long 39468b8a9b1dSJustin T. Gibbs CAM_DEBUG(path, CAM_DEBUG_TRACE, ("xpt_setup_ccb\n")); 39478b8a9b1dSJustin T. Gibbs ccb_h->pinfo.priority = priority; 39488b8a9b1dSJustin T. Gibbs ccb_h->path = path; 39498b8a9b1dSJustin T. Gibbs ccb_h->path_id = path->bus->path_id; 39508b8a9b1dSJustin T. Gibbs if (path->target) 39518b8a9b1dSJustin T. Gibbs ccb_h->target_id = path->target->target_id; 39528b8a9b1dSJustin T. Gibbs else 39538b8a9b1dSJustin T. Gibbs ccb_h->target_id = CAM_TARGET_WILDCARD; 39548b8a9b1dSJustin T. Gibbs if (path->device) { 39558b8a9b1dSJustin T. Gibbs ccb_h->target_lun = path->device->lun_id; 39568bad620dSJustin T. Gibbs ccb_h->pinfo.generation = ++path->device->ccbq.queue.generation; 39578b8a9b1dSJustin T. Gibbs } else { 39588b8a9b1dSJustin T. Gibbs ccb_h->target_lun = CAM_TARGET_WILDCARD; 39598b8a9b1dSJustin T. Gibbs } 39608b8a9b1dSJustin T. Gibbs ccb_h->pinfo.index = CAM_UNQUEUED_INDEX; 39618b8a9b1dSJustin T. Gibbs ccb_h->flags = 0; 39628b8a9b1dSJustin T. Gibbs } 39638b8a9b1dSJustin T. Gibbs 39648b8a9b1dSJustin T. Gibbs /* Path manipulation functions */ 39658b8a9b1dSJustin T. Gibbs cam_status 39668b8a9b1dSJustin T. Gibbs xpt_create_path(struct cam_path **new_path_ptr, struct cam_periph *perph, 39678b8a9b1dSJustin T. Gibbs path_id_t path_id, target_id_t target_id, lun_id_t lun_id) 39688b8a9b1dSJustin T. Gibbs { 39698b8a9b1dSJustin T. Gibbs struct cam_path *path; 39708b8a9b1dSJustin T. Gibbs cam_status status; 39718b8a9b1dSJustin T. Gibbs 3972362abc44STai-hwa Liang path = (struct cam_path *)malloc(sizeof(*path), M_CAMXPT, M_NOWAIT); 39738b8a9b1dSJustin T. Gibbs 39748b8a9b1dSJustin T. Gibbs if (path == NULL) { 39758b8a9b1dSJustin T. Gibbs status = CAM_RESRC_UNAVAIL; 39768b8a9b1dSJustin T. Gibbs return(status); 39778b8a9b1dSJustin T. Gibbs } 39788b8a9b1dSJustin T. Gibbs status = xpt_compile_path(path, perph, path_id, target_id, lun_id); 39798b8a9b1dSJustin T. Gibbs if (status != CAM_REQ_CMP) { 3980362abc44STai-hwa Liang free(path, M_CAMXPT); 39818b8a9b1dSJustin T. Gibbs path = NULL; 39828b8a9b1dSJustin T. Gibbs } 39838b8a9b1dSJustin T. Gibbs *new_path_ptr = path; 39848b8a9b1dSJustin T. Gibbs return (status); 39858b8a9b1dSJustin T. Gibbs } 39868b8a9b1dSJustin T. Gibbs 39872b83592fSScott Long cam_status 39882b83592fSScott Long xpt_create_path_unlocked(struct cam_path **new_path_ptr, 39892b83592fSScott Long struct cam_periph *periph, path_id_t path_id, 39902b83592fSScott Long target_id_t target_id, lun_id_t lun_id) 39912b83592fSScott Long { 39922b83592fSScott Long struct cam_path *path; 39932b83592fSScott Long struct cam_eb *bus = NULL; 39942b83592fSScott Long cam_status status; 39952b83592fSScott Long int need_unlock = 0; 39962b83592fSScott Long 39972b83592fSScott Long path = (struct cam_path *)malloc(sizeof(*path), M_CAMXPT, M_WAITOK); 39982b83592fSScott Long 39992b83592fSScott Long if (path_id != CAM_BUS_WILDCARD) { 40002b83592fSScott Long bus = xpt_find_bus(path_id); 40012b83592fSScott Long if (bus != NULL) { 40022b83592fSScott Long need_unlock = 1; 400311e4faceSScott Long CAM_SIM_LOCK(bus->sim); 40042b83592fSScott Long } 40052b83592fSScott Long } 40062b83592fSScott Long status = xpt_compile_path(path, periph, path_id, target_id, lun_id); 40072b83592fSScott Long if (need_unlock) 400811e4faceSScott Long CAM_SIM_UNLOCK(bus->sim); 40092b83592fSScott Long if (status != CAM_REQ_CMP) { 40102b83592fSScott Long free(path, M_CAMXPT); 40112b83592fSScott Long path = NULL; 40122b83592fSScott Long } 40132b83592fSScott Long *new_path_ptr = path; 40142b83592fSScott Long return (status); 40152b83592fSScott Long } 40162b83592fSScott Long 40178b8a9b1dSJustin T. Gibbs static cam_status 40188b8a9b1dSJustin T. Gibbs xpt_compile_path(struct cam_path *new_path, struct cam_periph *perph, 40198b8a9b1dSJustin T. Gibbs path_id_t path_id, target_id_t target_id, lun_id_t lun_id) 40208b8a9b1dSJustin T. Gibbs { 40218b8a9b1dSJustin T. Gibbs struct cam_eb *bus; 40228b8a9b1dSJustin T. Gibbs struct cam_et *target; 40238b8a9b1dSJustin T. Gibbs struct cam_ed *device; 40248b8a9b1dSJustin T. Gibbs cam_status status; 40258b8a9b1dSJustin T. Gibbs 40268b8a9b1dSJustin T. Gibbs status = CAM_REQ_CMP; /* Completed without error */ 40278b8a9b1dSJustin T. Gibbs target = NULL; /* Wildcarded */ 40288b8a9b1dSJustin T. Gibbs device = NULL; /* Wildcarded */ 4029a5479bc5SJustin T. Gibbs 4030a5479bc5SJustin T. Gibbs /* 4031a5479bc5SJustin T. Gibbs * We will potentially modify the EDT, so block interrupts 4032a5479bc5SJustin T. Gibbs * that may attempt to create cam paths. 4033a5479bc5SJustin T. Gibbs */ 40348b8a9b1dSJustin T. Gibbs bus = xpt_find_bus(path_id); 40358b8a9b1dSJustin T. Gibbs if (bus == NULL) { 40368b8a9b1dSJustin T. Gibbs status = CAM_PATH_INVALID; 4037c8bead2aSJustin T. Gibbs } else { 40388b8a9b1dSJustin T. Gibbs target = xpt_find_target(bus, target_id); 40398b8a9b1dSJustin T. Gibbs if (target == NULL) { 40408b8a9b1dSJustin T. Gibbs /* Create one */ 40418b8a9b1dSJustin T. Gibbs struct cam_et *new_target; 40428b8a9b1dSJustin T. Gibbs 40438b8a9b1dSJustin T. Gibbs new_target = xpt_alloc_target(bus, target_id); 40448b8a9b1dSJustin T. Gibbs if (new_target == NULL) { 40458b8a9b1dSJustin T. Gibbs status = CAM_RESRC_UNAVAIL; 40468b8a9b1dSJustin T. Gibbs } else { 40478b8a9b1dSJustin T. Gibbs target = new_target; 40488b8a9b1dSJustin T. Gibbs } 40498b8a9b1dSJustin T. Gibbs } 4050c8bead2aSJustin T. Gibbs if (target != NULL) { 40518b8a9b1dSJustin T. Gibbs device = xpt_find_device(target, lun_id); 40528b8a9b1dSJustin T. Gibbs if (device == NULL) { 40538b8a9b1dSJustin T. Gibbs /* Create one */ 40548b8a9b1dSJustin T. Gibbs struct cam_ed *new_device; 40558b8a9b1dSJustin T. Gibbs 40568b8a9b1dSJustin T. Gibbs new_device = xpt_alloc_device(bus, 40578b8a9b1dSJustin T. Gibbs target, 40588b8a9b1dSJustin T. Gibbs lun_id); 40598b8a9b1dSJustin T. Gibbs if (new_device == NULL) { 40608b8a9b1dSJustin T. Gibbs status = CAM_RESRC_UNAVAIL; 40618b8a9b1dSJustin T. Gibbs } else { 40628b8a9b1dSJustin T. Gibbs device = new_device; 40638b8a9b1dSJustin T. Gibbs } 40648b8a9b1dSJustin T. Gibbs } 40658b8a9b1dSJustin T. Gibbs } 40668b8a9b1dSJustin T. Gibbs } 40678b8a9b1dSJustin T. Gibbs 40688b8a9b1dSJustin T. Gibbs /* 40698b8a9b1dSJustin T. Gibbs * Only touch the user's data if we are successful. 40708b8a9b1dSJustin T. Gibbs */ 40718b8a9b1dSJustin T. Gibbs if (status == CAM_REQ_CMP) { 40728b8a9b1dSJustin T. Gibbs new_path->periph = perph; 40738b8a9b1dSJustin T. Gibbs new_path->bus = bus; 40748b8a9b1dSJustin T. Gibbs new_path->target = target; 40758b8a9b1dSJustin T. Gibbs new_path->device = device; 40768b8a9b1dSJustin T. Gibbs CAM_DEBUG(new_path, CAM_DEBUG_TRACE, ("xpt_compile_path\n")); 40778b8a9b1dSJustin T. Gibbs } else { 40788b8a9b1dSJustin T. Gibbs if (device != NULL) 40798b8a9b1dSJustin T. Gibbs xpt_release_device(bus, target, device); 40808b8a9b1dSJustin T. Gibbs if (target != NULL) 40818b8a9b1dSJustin T. Gibbs xpt_release_target(bus, target); 4082a5479bc5SJustin T. Gibbs if (bus != NULL) 4083a5479bc5SJustin T. Gibbs xpt_release_bus(bus); 40848b8a9b1dSJustin T. Gibbs } 40858b8a9b1dSJustin T. Gibbs return (status); 40868b8a9b1dSJustin T. Gibbs } 40878b8a9b1dSJustin T. Gibbs 40888b8a9b1dSJustin T. Gibbs static void 40898b8a9b1dSJustin T. Gibbs xpt_release_path(struct cam_path *path) 40908b8a9b1dSJustin T. Gibbs { 40918b8a9b1dSJustin T. Gibbs CAM_DEBUG(path, CAM_DEBUG_TRACE, ("xpt_release_path\n")); 40929dd03ecfSJustin T. Gibbs if (path->device != NULL) { 40938b8a9b1dSJustin T. Gibbs xpt_release_device(path->bus, path->target, path->device); 40949dd03ecfSJustin T. Gibbs path->device = NULL; 40959dd03ecfSJustin T. Gibbs } 40969dd03ecfSJustin T. Gibbs if (path->target != NULL) { 40978b8a9b1dSJustin T. Gibbs xpt_release_target(path->bus, path->target); 40989dd03ecfSJustin T. Gibbs path->target = NULL; 40999dd03ecfSJustin T. Gibbs } 41009dd03ecfSJustin T. Gibbs if (path->bus != NULL) { 41019dd03ecfSJustin T. Gibbs xpt_release_bus(path->bus); 41029dd03ecfSJustin T. Gibbs path->bus = NULL; 41039dd03ecfSJustin T. Gibbs } 41048b8a9b1dSJustin T. Gibbs } 41058b8a9b1dSJustin T. Gibbs 41068b8a9b1dSJustin T. Gibbs void 41078b8a9b1dSJustin T. Gibbs xpt_free_path(struct cam_path *path) 41088b8a9b1dSJustin T. Gibbs { 410968153f43SScott Long 41108b8a9b1dSJustin T. Gibbs CAM_DEBUG(path, CAM_DEBUG_TRACE, ("xpt_free_path\n")); 41118b8a9b1dSJustin T. Gibbs xpt_release_path(path); 4112362abc44STai-hwa Liang free(path, M_CAMXPT); 41138b8a9b1dSJustin T. Gibbs } 41148b8a9b1dSJustin T. Gibbs 41158b8a9b1dSJustin T. Gibbs 41168b8a9b1dSJustin T. Gibbs /* 41172cefde5fSJustin T. Gibbs * Return -1 for failure, 0 for exact match, 1 for match with wildcards 41182cefde5fSJustin T. Gibbs * in path1, 2 for match with wildcards in path2. 41198b8a9b1dSJustin T. Gibbs */ 41208b8a9b1dSJustin T. Gibbs int 41218b8a9b1dSJustin T. Gibbs xpt_path_comp(struct cam_path *path1, struct cam_path *path2) 41228b8a9b1dSJustin T. Gibbs { 41238b8a9b1dSJustin T. Gibbs int retval = 0; 41248b8a9b1dSJustin T. Gibbs 41258b8a9b1dSJustin T. Gibbs if (path1->bus != path2->bus) { 41262cefde5fSJustin T. Gibbs if (path1->bus->path_id == CAM_BUS_WILDCARD) 41278b8a9b1dSJustin T. Gibbs retval = 1; 41282cefde5fSJustin T. Gibbs else if (path2->bus->path_id == CAM_BUS_WILDCARD) 41292cefde5fSJustin T. Gibbs retval = 2; 41308b8a9b1dSJustin T. Gibbs else 41318b8a9b1dSJustin T. Gibbs return (-1); 41328b8a9b1dSJustin T. Gibbs } 41338b8a9b1dSJustin T. Gibbs if (path1->target != path2->target) { 41342cefde5fSJustin T. Gibbs if (path1->target->target_id == CAM_TARGET_WILDCARD) { 41352cefde5fSJustin T. Gibbs if (retval == 0) 41368b8a9b1dSJustin T. Gibbs retval = 1; 41372cefde5fSJustin T. Gibbs } else if (path2->target->target_id == CAM_TARGET_WILDCARD) 41382cefde5fSJustin T. Gibbs retval = 2; 41398b8a9b1dSJustin T. Gibbs else 41408b8a9b1dSJustin T. Gibbs return (-1); 41418b8a9b1dSJustin T. Gibbs } 41428b8a9b1dSJustin T. Gibbs if (path1->device != path2->device) { 41432cefde5fSJustin T. Gibbs if (path1->device->lun_id == CAM_LUN_WILDCARD) { 41442cefde5fSJustin T. Gibbs if (retval == 0) 41458b8a9b1dSJustin T. Gibbs retval = 1; 41462cefde5fSJustin T. Gibbs } else if (path2->device->lun_id == CAM_LUN_WILDCARD) 41472cefde5fSJustin T. Gibbs retval = 2; 41488b8a9b1dSJustin T. Gibbs else 41498b8a9b1dSJustin T. Gibbs return (-1); 41508b8a9b1dSJustin T. Gibbs } 41518b8a9b1dSJustin T. Gibbs return (retval); 41528b8a9b1dSJustin T. Gibbs } 41538b8a9b1dSJustin T. Gibbs 41548b8a9b1dSJustin T. Gibbs void 41558b8a9b1dSJustin T. Gibbs xpt_print_path(struct cam_path *path) 41568b8a9b1dSJustin T. Gibbs { 415768153f43SScott Long 41588b8a9b1dSJustin T. Gibbs if (path == NULL) 41598b8a9b1dSJustin T. Gibbs printf("(nopath): "); 41608b8a9b1dSJustin T. Gibbs else { 41618b8a9b1dSJustin T. Gibbs if (path->periph != NULL) 41628b8a9b1dSJustin T. Gibbs printf("(%s%d:", path->periph->periph_name, 41638b8a9b1dSJustin T. Gibbs path->periph->unit_number); 41648b8a9b1dSJustin T. Gibbs else 41658b8a9b1dSJustin T. Gibbs printf("(noperiph:"); 41668b8a9b1dSJustin T. Gibbs 41678b8a9b1dSJustin T. Gibbs if (path->bus != NULL) 41688b8a9b1dSJustin T. Gibbs printf("%s%d:%d:", path->bus->sim->sim_name, 41698b8a9b1dSJustin T. Gibbs path->bus->sim->unit_number, 41708b8a9b1dSJustin T. Gibbs path->bus->sim->bus_id); 41718b8a9b1dSJustin T. Gibbs else 41728b8a9b1dSJustin T. Gibbs printf("nobus:"); 41738b8a9b1dSJustin T. Gibbs 41748b8a9b1dSJustin T. Gibbs if (path->target != NULL) 41758b8a9b1dSJustin T. Gibbs printf("%d:", path->target->target_id); 41768b8a9b1dSJustin T. Gibbs else 41778b8a9b1dSJustin T. Gibbs printf("X:"); 41788b8a9b1dSJustin T. Gibbs 41798b8a9b1dSJustin T. Gibbs if (path->device != NULL) 41808b8a9b1dSJustin T. Gibbs printf("%d): ", path->device->lun_id); 41818b8a9b1dSJustin T. Gibbs else 41828b8a9b1dSJustin T. Gibbs printf("X): "); 41838b8a9b1dSJustin T. Gibbs } 41848b8a9b1dSJustin T. Gibbs } 41858b8a9b1dSJustin T. Gibbs 4186f0d9af51SMatt Jacob void 4187f0d9af51SMatt Jacob xpt_print(struct cam_path *path, const char *fmt, ...) 4188f0d9af51SMatt Jacob { 4189f0d9af51SMatt Jacob va_list ap; 4190f0d9af51SMatt Jacob xpt_print_path(path); 4191f0d9af51SMatt Jacob va_start(ap, fmt); 4192f0d9af51SMatt Jacob vprintf(fmt, ap); 4193f0d9af51SMatt Jacob va_end(ap); 4194f0d9af51SMatt Jacob } 4195f0d9af51SMatt Jacob 41963393f8daSKenneth D. Merry int 41973393f8daSKenneth D. Merry xpt_path_string(struct cam_path *path, char *str, size_t str_len) 41983393f8daSKenneth D. Merry { 41993393f8daSKenneth D. Merry struct sbuf sb; 42003393f8daSKenneth D. Merry 42012b83592fSScott Long mtx_assert(path->bus->sim->mtx, MA_OWNED); 420268153f43SScott Long 42033393f8daSKenneth D. Merry sbuf_new(&sb, str, str_len, 0); 42043393f8daSKenneth D. Merry 42053393f8daSKenneth D. Merry if (path == NULL) 42063393f8daSKenneth D. Merry sbuf_printf(&sb, "(nopath): "); 42073393f8daSKenneth D. Merry else { 42083393f8daSKenneth D. Merry if (path->periph != NULL) 42093393f8daSKenneth D. Merry sbuf_printf(&sb, "(%s%d:", path->periph->periph_name, 42103393f8daSKenneth D. Merry path->periph->unit_number); 42113393f8daSKenneth D. Merry else 42123393f8daSKenneth D. Merry sbuf_printf(&sb, "(noperiph:"); 42133393f8daSKenneth D. Merry 42143393f8daSKenneth D. Merry if (path->bus != NULL) 42153393f8daSKenneth D. Merry sbuf_printf(&sb, "%s%d:%d:", path->bus->sim->sim_name, 42163393f8daSKenneth D. Merry path->bus->sim->unit_number, 42173393f8daSKenneth D. Merry path->bus->sim->bus_id); 42183393f8daSKenneth D. Merry else 42193393f8daSKenneth D. Merry sbuf_printf(&sb, "nobus:"); 42203393f8daSKenneth D. Merry 42213393f8daSKenneth D. Merry if (path->target != NULL) 42223393f8daSKenneth D. Merry sbuf_printf(&sb, "%d:", path->target->target_id); 42233393f8daSKenneth D. Merry else 42243393f8daSKenneth D. Merry sbuf_printf(&sb, "X:"); 42253393f8daSKenneth D. Merry 42263393f8daSKenneth D. Merry if (path->device != NULL) 42273393f8daSKenneth D. Merry sbuf_printf(&sb, "%d): ", path->device->lun_id); 42283393f8daSKenneth D. Merry else 42293393f8daSKenneth D. Merry sbuf_printf(&sb, "X): "); 42303393f8daSKenneth D. Merry } 42313393f8daSKenneth D. Merry sbuf_finish(&sb); 42323393f8daSKenneth D. Merry 42333393f8daSKenneth D. Merry return(sbuf_len(&sb)); 42343393f8daSKenneth D. Merry } 42353393f8daSKenneth D. Merry 42368b8a9b1dSJustin T. Gibbs path_id_t 42378b8a9b1dSJustin T. Gibbs xpt_path_path_id(struct cam_path *path) 42388b8a9b1dSJustin T. Gibbs { 42392b83592fSScott Long mtx_assert(path->bus->sim->mtx, MA_OWNED); 424068153f43SScott Long 42418b8a9b1dSJustin T. Gibbs return(path->bus->path_id); 42428b8a9b1dSJustin T. Gibbs } 42438b8a9b1dSJustin T. Gibbs 42448b8a9b1dSJustin T. Gibbs target_id_t 42458b8a9b1dSJustin T. Gibbs xpt_path_target_id(struct cam_path *path) 42468b8a9b1dSJustin T. Gibbs { 42472b83592fSScott Long mtx_assert(path->bus->sim->mtx, MA_OWNED); 424868153f43SScott Long 42498b8a9b1dSJustin T. Gibbs if (path->target != NULL) 42508b8a9b1dSJustin T. Gibbs return (path->target->target_id); 42518b8a9b1dSJustin T. Gibbs else 42528b8a9b1dSJustin T. Gibbs return (CAM_TARGET_WILDCARD); 42538b8a9b1dSJustin T. Gibbs } 42548b8a9b1dSJustin T. Gibbs 42558b8a9b1dSJustin T. Gibbs lun_id_t 42568b8a9b1dSJustin T. Gibbs xpt_path_lun_id(struct cam_path *path) 42578b8a9b1dSJustin T. Gibbs { 42582b83592fSScott Long mtx_assert(path->bus->sim->mtx, MA_OWNED); 425968153f43SScott Long 42608b8a9b1dSJustin T. Gibbs if (path->device != NULL) 42618b8a9b1dSJustin T. Gibbs return (path->device->lun_id); 42628b8a9b1dSJustin T. Gibbs else 42638b8a9b1dSJustin T. Gibbs return (CAM_LUN_WILDCARD); 42648b8a9b1dSJustin T. Gibbs } 42658b8a9b1dSJustin T. Gibbs 42668b8a9b1dSJustin T. Gibbs struct cam_sim * 42678b8a9b1dSJustin T. Gibbs xpt_path_sim(struct cam_path *path) 42688b8a9b1dSJustin T. Gibbs { 426968153f43SScott Long 42708b8a9b1dSJustin T. Gibbs return (path->bus->sim); 42718b8a9b1dSJustin T. Gibbs } 42728b8a9b1dSJustin T. Gibbs 42738b8a9b1dSJustin T. Gibbs struct cam_periph* 42748b8a9b1dSJustin T. Gibbs xpt_path_periph(struct cam_path *path) 42758b8a9b1dSJustin T. Gibbs { 42762b83592fSScott Long mtx_assert(path->bus->sim->mtx, MA_OWNED); 427768153f43SScott Long 42788b8a9b1dSJustin T. Gibbs return (path->periph); 42798b8a9b1dSJustin T. Gibbs } 42808b8a9b1dSJustin T. Gibbs 42818b8a9b1dSJustin T. Gibbs /* 42828b8a9b1dSJustin T. Gibbs * Release a CAM control block for the caller. Remit the cost of the structure 42838b8a9b1dSJustin T. Gibbs * to the device referenced by the path. If the this device had no 'credits' 42848b8a9b1dSJustin T. Gibbs * and peripheral drivers have registered async callbacks for this notification 42858b8a9b1dSJustin T. Gibbs * call them now. 42868b8a9b1dSJustin T. Gibbs */ 42878b8a9b1dSJustin T. Gibbs void 42888b8a9b1dSJustin T. Gibbs xpt_release_ccb(union ccb *free_ccb) 42898b8a9b1dSJustin T. Gibbs { 42908b8a9b1dSJustin T. Gibbs struct cam_path *path; 42918b8a9b1dSJustin T. Gibbs struct cam_ed *device; 42928b8a9b1dSJustin T. Gibbs struct cam_eb *bus; 42932b83592fSScott Long struct cam_sim *sim; 429468153f43SScott Long 4295aa872be6SMatt Jacob CAM_DEBUG_PRINT(CAM_DEBUG_XPT, ("xpt_release_ccb\n")); 42968b8a9b1dSJustin T. Gibbs path = free_ccb->ccb_h.path; 42978b8a9b1dSJustin T. Gibbs device = path->device; 42988b8a9b1dSJustin T. Gibbs bus = path->bus; 42992b83592fSScott Long sim = bus->sim; 43002b83592fSScott Long 43012b83592fSScott Long mtx_assert(sim->mtx, MA_OWNED); 43022b83592fSScott Long 43038b8a9b1dSJustin T. Gibbs cam_ccbq_release_opening(&device->ccbq); 43042b83592fSScott Long if (sim->ccb_count > sim->max_ccbs) { 43058b8a9b1dSJustin T. Gibbs xpt_free_ccb(free_ccb); 43062b83592fSScott Long sim->ccb_count--; 43078b8a9b1dSJustin T. Gibbs } else { 43082b83592fSScott Long SLIST_INSERT_HEAD(&sim->ccb_freeq, &free_ccb->ccb_h, 43092b83592fSScott Long xpt_links.sle); 43108b8a9b1dSJustin T. Gibbs } 43112b83592fSScott Long if (sim->devq == NULL) { 4312d3ef3454SIan Dowse return; 4313d3ef3454SIan Dowse } 43142b83592fSScott Long sim->devq->alloc_openings++; 43152b83592fSScott Long sim->devq->alloc_active--; 43168b8a9b1dSJustin T. Gibbs /* XXX Turn this into an inline function - xpt_run_device?? */ 43178b8a9b1dSJustin T. Gibbs if ((device_is_alloc_queued(device) == 0) 43188b8a9b1dSJustin T. Gibbs && (device->drvq.entries > 0)) { 43198b8a9b1dSJustin T. Gibbs xpt_schedule_dev_allocq(bus, device); 43208b8a9b1dSJustin T. Gibbs } 43212b83592fSScott Long if (dev_allocq_is_runnable(sim->devq)) 43228b8a9b1dSJustin T. Gibbs xpt_run_dev_allocq(bus); 43238b8a9b1dSJustin T. Gibbs } 43248b8a9b1dSJustin T. Gibbs 43258b8a9b1dSJustin T. Gibbs /* Functions accessed by SIM drivers */ 43268b8a9b1dSJustin T. Gibbs 43278b8a9b1dSJustin T. Gibbs /* 43288b8a9b1dSJustin T. Gibbs * A sim structure, listing the SIM entry points and instance 43298b8a9b1dSJustin T. Gibbs * identification info is passed to xpt_bus_register to hook the SIM 43308b8a9b1dSJustin T. Gibbs * into the CAM framework. xpt_bus_register creates a cam_eb entry 43318b8a9b1dSJustin T. Gibbs * for this new bus and places it in the array of busses and assigns 43328b8a9b1dSJustin T. Gibbs * it a path_id. The path_id may be influenced by "hard wiring" 43338b8a9b1dSJustin T. Gibbs * information specified by the user. Once interrupt services are 43348b8a9b1dSJustin T. Gibbs * availible, the bus will be probed. 43358b8a9b1dSJustin T. Gibbs */ 43368b8a9b1dSJustin T. Gibbs int32_t 4337b50569b7SScott Long xpt_bus_register(struct cam_sim *sim, device_t parent, u_int32_t bus) 43388b8a9b1dSJustin T. Gibbs { 43398b8a9b1dSJustin T. Gibbs struct cam_eb *new_bus; 4340434bbf6eSJustin T. Gibbs struct cam_eb *old_bus; 43418b8a9b1dSJustin T. Gibbs struct ccb_pathinq cpi; 43428b8a9b1dSJustin T. Gibbs 43432b83592fSScott Long mtx_assert(sim->mtx, MA_OWNED); 434468153f43SScott Long 43458b8a9b1dSJustin T. Gibbs sim->bus_id = bus; 43468b8a9b1dSJustin T. Gibbs new_bus = (struct cam_eb *)malloc(sizeof(*new_bus), 4347362abc44STai-hwa Liang M_CAMXPT, M_NOWAIT); 43488b8a9b1dSJustin T. Gibbs if (new_bus == NULL) { 43498b8a9b1dSJustin T. Gibbs /* Couldn't satisfy request */ 43508b8a9b1dSJustin T. Gibbs return (CAM_RESRC_UNAVAIL); 43518b8a9b1dSJustin T. Gibbs } 43528b8a9b1dSJustin T. Gibbs 43538b8a9b1dSJustin T. Gibbs if (strcmp(sim->sim_name, "xpt") != 0) { 43548b8a9b1dSJustin T. Gibbs 4355434bbf6eSJustin T. Gibbs sim->path_id = 4356434bbf6eSJustin T. Gibbs xptpathid(sim->sim_name, sim->unit_number, sim->bus_id); 43578b8a9b1dSJustin T. Gibbs } 43588b8a9b1dSJustin T. Gibbs 4359434bbf6eSJustin T. Gibbs TAILQ_INIT(&new_bus->et_entries); 43608b8a9b1dSJustin T. Gibbs new_bus->path_id = sim->path_id; 43618b8a9b1dSJustin T. Gibbs new_bus->sim = sim; 436287cfaf0eSJustin T. Gibbs timevalclear(&new_bus->last_reset); 4363434bbf6eSJustin T. Gibbs new_bus->flags = 0; 4364a5479bc5SJustin T. Gibbs new_bus->refcount = 1; /* Held until a bus_deregister event */ 4365434bbf6eSJustin T. Gibbs new_bus->generation = 0; 43662b83592fSScott Long mtx_lock(&xsoftc.xpt_topo_lock); 43672b83592fSScott Long old_bus = TAILQ_FIRST(&xsoftc.xpt_busses); 4368434bbf6eSJustin T. Gibbs while (old_bus != NULL 4369434bbf6eSJustin T. Gibbs && old_bus->path_id < new_bus->path_id) 4370434bbf6eSJustin T. Gibbs old_bus = TAILQ_NEXT(old_bus, links); 4371434bbf6eSJustin T. Gibbs if (old_bus != NULL) 4372434bbf6eSJustin T. Gibbs TAILQ_INSERT_BEFORE(old_bus, new_bus, links); 4373434bbf6eSJustin T. Gibbs else 43742b83592fSScott Long TAILQ_INSERT_TAIL(&xsoftc.xpt_busses, new_bus, links); 43752b83592fSScott Long xsoftc.bus_generation++; 43762b83592fSScott Long mtx_unlock(&xsoftc.xpt_topo_lock); 43778b8a9b1dSJustin T. Gibbs 43788b8a9b1dSJustin T. Gibbs /* Notify interested parties */ 43798b8a9b1dSJustin T. Gibbs if (sim->path_id != CAM_XPT_PATH_ID) { 43808b8a9b1dSJustin T. Gibbs struct cam_path path; 43818b8a9b1dSJustin T. Gibbs 43828b8a9b1dSJustin T. Gibbs xpt_compile_path(&path, /*periph*/NULL, sim->path_id, 43838b8a9b1dSJustin T. Gibbs CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD); 43848b8a9b1dSJustin T. Gibbs xpt_setup_ccb(&cpi.ccb_h, &path, /*priority*/1); 43858b8a9b1dSJustin T. Gibbs cpi.ccb_h.func_code = XPT_PATH_INQ; 43868b8a9b1dSJustin T. Gibbs xpt_action((union ccb *)&cpi); 43873393f8daSKenneth D. Merry xpt_async(AC_PATH_REGISTERED, &path, &cpi); 43888b8a9b1dSJustin T. Gibbs xpt_release_path(&path); 43898b8a9b1dSJustin T. Gibbs } 43908b8a9b1dSJustin T. Gibbs return (CAM_SUCCESS); 43918b8a9b1dSJustin T. Gibbs } 43928b8a9b1dSJustin T. Gibbs 4393434bbf6eSJustin T. Gibbs int32_t 4394434bbf6eSJustin T. Gibbs xpt_bus_deregister(path_id_t pathid) 43958b8a9b1dSJustin T. Gibbs { 4396434bbf6eSJustin T. Gibbs struct cam_path bus_path; 4397d3ef3454SIan Dowse struct cam_ed *device; 4398d3ef3454SIan Dowse struct cam_ed_qinfo *qinfo; 4399d3ef3454SIan Dowse struct cam_devq *devq; 4400d3ef3454SIan Dowse struct cam_periph *periph; 4401d3ef3454SIan Dowse struct cam_sim *ccbsim; 4402d3ef3454SIan Dowse union ccb *work_ccb; 4403434bbf6eSJustin T. Gibbs cam_status status; 4404434bbf6eSJustin T. Gibbs 440568153f43SScott Long 4406434bbf6eSJustin T. Gibbs status = xpt_compile_path(&bus_path, NULL, pathid, 4407434bbf6eSJustin T. Gibbs CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD); 4408434bbf6eSJustin T. Gibbs if (status != CAM_REQ_CMP) 4409434bbf6eSJustin T. Gibbs return (status); 4410434bbf6eSJustin T. Gibbs 4411434bbf6eSJustin T. Gibbs xpt_async(AC_LOST_DEVICE, &bus_path, NULL); 4412434bbf6eSJustin T. Gibbs xpt_async(AC_PATH_DEREGISTERED, &bus_path, NULL); 4413434bbf6eSJustin T. Gibbs 4414d3ef3454SIan Dowse /* The SIM may be gone, so use a dummy SIM for any stray operations. */ 4415d3ef3454SIan Dowse devq = bus_path.bus->sim->devq; 44169758cc83SScott Long ccbsim = bus_path.bus->sim; 4417d3ef3454SIan Dowse bus_path.bus->sim = &cam_dead_sim; 4418d3ef3454SIan Dowse 4419d3ef3454SIan Dowse /* Execute any pending operations now. */ 4420d3ef3454SIan Dowse while ((qinfo = (struct cam_ed_qinfo *)camq_remove(&devq->send_queue, 4421d3ef3454SIan Dowse CAMQ_HEAD)) != NULL || 4422d3ef3454SIan Dowse (qinfo = (struct cam_ed_qinfo *)camq_remove(&devq->alloc_queue, 4423d3ef3454SIan Dowse CAMQ_HEAD)) != NULL) { 4424d3ef3454SIan Dowse do { 4425d3ef3454SIan Dowse device = qinfo->device; 4426d3ef3454SIan Dowse work_ccb = cam_ccbq_peek_ccb(&device->ccbq, CAMQ_HEAD); 4427d3ef3454SIan Dowse if (work_ccb != NULL) { 4428d3ef3454SIan Dowse devq->active_dev = device; 4429d3ef3454SIan Dowse cam_ccbq_remove_ccb(&device->ccbq, work_ccb); 4430d3ef3454SIan Dowse cam_ccbq_send_ccb(&device->ccbq, work_ccb); 4431d3ef3454SIan Dowse (*(ccbsim->sim_action))(ccbsim, work_ccb); 4432d3ef3454SIan Dowse } 4433d3ef3454SIan Dowse 4434d3ef3454SIan Dowse periph = (struct cam_periph *)camq_remove(&device->drvq, 4435d3ef3454SIan Dowse CAMQ_HEAD); 4436d3ef3454SIan Dowse if (periph != NULL) 4437d3ef3454SIan Dowse xpt_schedule(periph, periph->pinfo.priority); 4438d3ef3454SIan Dowse } while (work_ccb != NULL || periph != NULL); 4439d3ef3454SIan Dowse } 4440d3ef3454SIan Dowse 4441d3ef3454SIan Dowse /* Make sure all completed CCBs are processed. */ 44429758cc83SScott Long while (!TAILQ_EMPTY(&ccbsim->sim_doneq)) { 44439758cc83SScott Long camisr_runqueue(&ccbsim->sim_doneq); 4444d3ef3454SIan Dowse 4445d3ef3454SIan Dowse /* Repeat the async's for the benefit of any new devices. */ 4446d3ef3454SIan Dowse xpt_async(AC_LOST_DEVICE, &bus_path, NULL); 4447d3ef3454SIan Dowse xpt_async(AC_PATH_DEREGISTERED, &bus_path, NULL); 4448d3ef3454SIan Dowse } 4449d3ef3454SIan Dowse 4450434bbf6eSJustin T. Gibbs /* Release the reference count held while registered. */ 4451434bbf6eSJustin T. Gibbs xpt_release_bus(bus_path.bus); 4452434bbf6eSJustin T. Gibbs xpt_release_path(&bus_path); 4453434bbf6eSJustin T. Gibbs 4454434bbf6eSJustin T. Gibbs return (CAM_REQ_CMP); 4455434bbf6eSJustin T. Gibbs } 4456434bbf6eSJustin T. Gibbs 4457434bbf6eSJustin T. Gibbs static path_id_t 4458434bbf6eSJustin T. Gibbs xptnextfreepathid(void) 4459434bbf6eSJustin T. Gibbs { 4460434bbf6eSJustin T. Gibbs struct cam_eb *bus; 4461434bbf6eSJustin T. Gibbs path_id_t pathid; 44622398f0cdSPeter Wemm const char *strval; 44638b8a9b1dSJustin T. Gibbs 4464434bbf6eSJustin T. Gibbs pathid = 0; 44652b83592fSScott Long mtx_lock(&xsoftc.xpt_topo_lock); 44662b83592fSScott Long bus = TAILQ_FIRST(&xsoftc.xpt_busses); 4467434bbf6eSJustin T. Gibbs retry: 4468434bbf6eSJustin T. Gibbs /* Find an unoccupied pathid */ 44699e6461a2SMatt Jacob while (bus != NULL && bus->path_id <= pathid) { 4470434bbf6eSJustin T. Gibbs if (bus->path_id == pathid) 4471434bbf6eSJustin T. Gibbs pathid++; 4472434bbf6eSJustin T. Gibbs bus = TAILQ_NEXT(bus, links); 4473434bbf6eSJustin T. Gibbs } 44742b83592fSScott Long mtx_unlock(&xsoftc.xpt_topo_lock); 4475434bbf6eSJustin T. Gibbs 4476434bbf6eSJustin T. Gibbs /* 4477434bbf6eSJustin T. Gibbs * Ensure that this pathid is not reserved for 4478434bbf6eSJustin T. Gibbs * a bus that may be registered in the future. 4479434bbf6eSJustin T. Gibbs */ 448075f51904SPeter Wemm if (resource_string_value("scbus", pathid, "at", &strval) == 0) { 4481434bbf6eSJustin T. Gibbs ++pathid; 44828b8a9b1dSJustin T. Gibbs /* Start the search over */ 44832b83592fSScott Long mtx_lock(&xsoftc.xpt_topo_lock); 4484434bbf6eSJustin T. Gibbs goto retry; 44858b8a9b1dSJustin T. Gibbs } 4486434bbf6eSJustin T. Gibbs return (pathid); 44878b8a9b1dSJustin T. Gibbs } 44888b8a9b1dSJustin T. Gibbs 4489434bbf6eSJustin T. Gibbs static path_id_t 4490434bbf6eSJustin T. Gibbs xptpathid(const char *sim_name, int sim_unit, int sim_bus) 44918b8a9b1dSJustin T. Gibbs { 44928b8a9b1dSJustin T. Gibbs path_id_t pathid; 449375f51904SPeter Wemm int i, dunit, val; 4494642f0c46SPeter Wemm char buf[32]; 44952398f0cdSPeter Wemm const char *dname; 44968b8a9b1dSJustin T. Gibbs 44978b8a9b1dSJustin T. Gibbs pathid = CAM_XPT_PATH_ID; 449875f51904SPeter Wemm snprintf(buf, sizeof(buf), "%s%d", sim_name, sim_unit); 44992398f0cdSPeter Wemm i = 0; 45002398f0cdSPeter Wemm while ((resource_find_match(&i, &dname, &dunit, "at", buf)) == 0) { 45012398f0cdSPeter Wemm if (strcmp(dname, "scbus")) { 4502642f0c46SPeter Wemm /* Avoid a bit of foot shooting. */ 4503642f0c46SPeter Wemm continue; 4504642f0c46SPeter Wemm } 450575f51904SPeter Wemm if (dunit < 0) /* unwired?! */ 45068b8a9b1dSJustin T. Gibbs continue; 450775f51904SPeter Wemm if (resource_int_value("scbus", dunit, "bus", &val) == 0) { 450875f51904SPeter Wemm if (sim_bus == val) { 450975f51904SPeter Wemm pathid = dunit; 45108b8a9b1dSJustin T. Gibbs break; 45118b8a9b1dSJustin T. Gibbs } 45128b8a9b1dSJustin T. Gibbs } else if (sim_bus == 0) { 45138b8a9b1dSJustin T. Gibbs /* Unspecified matches bus 0 */ 451475f51904SPeter Wemm pathid = dunit; 45158b8a9b1dSJustin T. Gibbs break; 45168b8a9b1dSJustin T. Gibbs } else { 45178b8a9b1dSJustin T. Gibbs printf("Ambiguous scbus configuration for %s%d " 45188b8a9b1dSJustin T. Gibbs "bus %d, cannot wire down. The kernel " 45198b8a9b1dSJustin T. Gibbs "config entry for scbus%d should " 45208b8a9b1dSJustin T. Gibbs "specify a controller bus.\n" 45218b8a9b1dSJustin T. Gibbs "Scbus will be assigned dynamically.\n", 452275f51904SPeter Wemm sim_name, sim_unit, sim_bus, dunit); 45238b8a9b1dSJustin T. Gibbs break; 45248b8a9b1dSJustin T. Gibbs } 45258b8a9b1dSJustin T. Gibbs } 45268b8a9b1dSJustin T. Gibbs 4527434bbf6eSJustin T. Gibbs if (pathid == CAM_XPT_PATH_ID) 4528434bbf6eSJustin T. Gibbs pathid = xptnextfreepathid(); 45298b8a9b1dSJustin T. Gibbs return (pathid); 45308b8a9b1dSJustin T. Gibbs } 45318b8a9b1dSJustin T. Gibbs 45328b8a9b1dSJustin T. Gibbs void 45338b8a9b1dSJustin T. Gibbs xpt_async(u_int32_t async_code, struct cam_path *path, void *async_arg) 45348b8a9b1dSJustin T. Gibbs { 45358b8a9b1dSJustin T. Gibbs struct cam_eb *bus; 45368b8a9b1dSJustin T. Gibbs struct cam_et *target, *next_target; 45378b8a9b1dSJustin T. Gibbs struct cam_ed *device, *next_device; 45388b8a9b1dSJustin T. Gibbs 45392b83592fSScott Long mtx_assert(path->bus->sim->mtx, MA_OWNED); 454068153f43SScott Long 45418b8a9b1dSJustin T. Gibbs CAM_DEBUG(path, CAM_DEBUG_TRACE, ("xpt_async\n")); 45428b8a9b1dSJustin T. Gibbs 4543a5479bc5SJustin T. Gibbs /* 4544a5479bc5SJustin T. Gibbs * Most async events come from a CAM interrupt context. In 4545a5479bc5SJustin T. Gibbs * a few cases, the error recovery code at the peripheral layer, 4546a5479bc5SJustin T. Gibbs * which may run from our SWI or a process context, may signal 454777dc25ccSScott Long * deferred events with a call to xpt_async. 4548a5479bc5SJustin T. Gibbs */ 45498b8a9b1dSJustin T. Gibbs 45508b8a9b1dSJustin T. Gibbs bus = path->bus; 45518b8a9b1dSJustin T. Gibbs 45528b8a9b1dSJustin T. Gibbs if (async_code == AC_BUS_RESET) { 455387cfaf0eSJustin T. Gibbs /* Update our notion of when the last reset occurred */ 455487cfaf0eSJustin T. Gibbs microtime(&bus->last_reset); 45558b8a9b1dSJustin T. Gibbs } 45568b8a9b1dSJustin T. Gibbs 45578b8a9b1dSJustin T. Gibbs for (target = TAILQ_FIRST(&bus->et_entries); 45588b8a9b1dSJustin T. Gibbs target != NULL; 45598b8a9b1dSJustin T. Gibbs target = next_target) { 45608b8a9b1dSJustin T. Gibbs 45618b8a9b1dSJustin T. Gibbs next_target = TAILQ_NEXT(target, links); 45628b8a9b1dSJustin T. Gibbs 45638b8a9b1dSJustin T. Gibbs if (path->target != target 45642f22d08dSJustin T. Gibbs && path->target->target_id != CAM_TARGET_WILDCARD 45652f22d08dSJustin T. Gibbs && target->target_id != CAM_TARGET_WILDCARD) 45668b8a9b1dSJustin T. Gibbs continue; 45678b8a9b1dSJustin T. Gibbs 456887cfaf0eSJustin T. Gibbs if (async_code == AC_SENT_BDR) { 456987cfaf0eSJustin T. Gibbs /* Update our notion of when the last reset occurred */ 457087cfaf0eSJustin T. Gibbs microtime(&path->target->last_reset); 457187cfaf0eSJustin T. Gibbs } 457287cfaf0eSJustin T. Gibbs 45738b8a9b1dSJustin T. Gibbs for (device = TAILQ_FIRST(&target->ed_entries); 45748b8a9b1dSJustin T. Gibbs device != NULL; 45758b8a9b1dSJustin T. Gibbs device = next_device) { 45768b8a9b1dSJustin T. Gibbs 45778b8a9b1dSJustin T. Gibbs next_device = TAILQ_NEXT(device, links); 45788b8a9b1dSJustin T. Gibbs 45798b8a9b1dSJustin T. Gibbs if (path->device != device 45802f22d08dSJustin T. Gibbs && path->device->lun_id != CAM_LUN_WILDCARD 45812f22d08dSJustin T. Gibbs && device->lun_id != CAM_LUN_WILDCARD) 45828b8a9b1dSJustin T. Gibbs continue; 45838b8a9b1dSJustin T. Gibbs 45842f22d08dSJustin T. Gibbs xpt_dev_async(async_code, bus, target, 45852f22d08dSJustin T. Gibbs device, async_arg); 45868b8a9b1dSJustin T. Gibbs 45872f22d08dSJustin T. Gibbs xpt_async_bcast(&device->asyncs, async_code, 45882f22d08dSJustin T. Gibbs path, async_arg); 45898b8a9b1dSJustin T. Gibbs } 45908b8a9b1dSJustin T. Gibbs } 4591c8bead2aSJustin T. Gibbs 4592c8bead2aSJustin T. Gibbs /* 4593c8bead2aSJustin T. Gibbs * If this wasn't a fully wildcarded async, tell all 4594c8bead2aSJustin T. Gibbs * clients that want all async events. 4595c8bead2aSJustin T. Gibbs */ 4596c8bead2aSJustin T. Gibbs if (bus != xpt_periph->path->bus) 4597c8bead2aSJustin T. Gibbs xpt_async_bcast(&xpt_periph->path->device->asyncs, async_code, 45988b8a9b1dSJustin T. Gibbs path, async_arg); 45998b8a9b1dSJustin T. Gibbs } 46008b8a9b1dSJustin T. Gibbs 46018b8a9b1dSJustin T. Gibbs static void 46028b8a9b1dSJustin T. Gibbs xpt_async_bcast(struct async_list *async_head, 46038b8a9b1dSJustin T. Gibbs u_int32_t async_code, 46048b8a9b1dSJustin T. Gibbs struct cam_path *path, void *async_arg) 46058b8a9b1dSJustin T. Gibbs { 46068b8a9b1dSJustin T. Gibbs struct async_node *cur_entry; 46078b8a9b1dSJustin T. Gibbs 46088b8a9b1dSJustin T. Gibbs cur_entry = SLIST_FIRST(async_head); 46098b8a9b1dSJustin T. Gibbs while (cur_entry != NULL) { 46108b8a9b1dSJustin T. Gibbs struct async_node *next_entry; 46118b8a9b1dSJustin T. Gibbs /* 46128b8a9b1dSJustin T. Gibbs * Grab the next list entry before we call the current 46138b8a9b1dSJustin T. Gibbs * entry's callback. This is because the callback function 46148b8a9b1dSJustin T. Gibbs * can delete its async callback entry. 46158b8a9b1dSJustin T. Gibbs */ 46168b8a9b1dSJustin T. Gibbs next_entry = SLIST_NEXT(cur_entry, links); 46178b8a9b1dSJustin T. Gibbs if ((cur_entry->event_enable & async_code) != 0) 46188b8a9b1dSJustin T. Gibbs cur_entry->callback(cur_entry->callback_arg, 46198b8a9b1dSJustin T. Gibbs async_code, path, 46208b8a9b1dSJustin T. Gibbs async_arg); 46218b8a9b1dSJustin T. Gibbs cur_entry = next_entry; 46228b8a9b1dSJustin T. Gibbs } 46238b8a9b1dSJustin T. Gibbs } 46248b8a9b1dSJustin T. Gibbs 46252f22d08dSJustin T. Gibbs /* 46262f22d08dSJustin T. Gibbs * Handle any per-device event notifications that require action by the XPT. 46272f22d08dSJustin T. Gibbs */ 46282f22d08dSJustin T. Gibbs static void 46292f22d08dSJustin T. Gibbs xpt_dev_async(u_int32_t async_code, struct cam_eb *bus, struct cam_et *target, 46302f22d08dSJustin T. Gibbs struct cam_ed *device, void *async_arg) 46312f22d08dSJustin T. Gibbs { 46322f22d08dSJustin T. Gibbs cam_status status; 46332f22d08dSJustin T. Gibbs struct cam_path newpath; 46342f22d08dSJustin T. Gibbs 46352f22d08dSJustin T. Gibbs /* 46362f22d08dSJustin T. Gibbs * We only need to handle events for real devices. 46372f22d08dSJustin T. Gibbs */ 46382f22d08dSJustin T. Gibbs if (target->target_id == CAM_TARGET_WILDCARD 46392f22d08dSJustin T. Gibbs || device->lun_id == CAM_LUN_WILDCARD) 46402f22d08dSJustin T. Gibbs return; 46412f22d08dSJustin T. Gibbs 46422f22d08dSJustin T. Gibbs /* 46432f22d08dSJustin T. Gibbs * We need our own path with wildcards expanded to 46442f22d08dSJustin T. Gibbs * handle certain types of events. 46452f22d08dSJustin T. Gibbs */ 46462f22d08dSJustin T. Gibbs if ((async_code == AC_SENT_BDR) 46472f22d08dSJustin T. Gibbs || (async_code == AC_BUS_RESET) 46482f22d08dSJustin T. Gibbs || (async_code == AC_INQ_CHANGED)) 46492f22d08dSJustin T. Gibbs status = xpt_compile_path(&newpath, NULL, 46502f22d08dSJustin T. Gibbs bus->path_id, 46512f22d08dSJustin T. Gibbs target->target_id, 46522f22d08dSJustin T. Gibbs device->lun_id); 46532f22d08dSJustin T. Gibbs else 46542f22d08dSJustin T. Gibbs status = CAM_REQ_CMP_ERR; 46552f22d08dSJustin T. Gibbs 46562f22d08dSJustin T. Gibbs if (status == CAM_REQ_CMP) { 46572f22d08dSJustin T. Gibbs 46582f22d08dSJustin T. Gibbs /* 46592f22d08dSJustin T. Gibbs * Allow transfer negotiation to occur in a 46602f22d08dSJustin T. Gibbs * tag free environment. 46612f22d08dSJustin T. Gibbs */ 46622f22d08dSJustin T. Gibbs if (async_code == AC_SENT_BDR 46632f22d08dSJustin T. Gibbs || async_code == AC_BUS_RESET) 46642f22d08dSJustin T. Gibbs xpt_toggle_tags(&newpath); 46652f22d08dSJustin T. Gibbs 46662f22d08dSJustin T. Gibbs if (async_code == AC_INQ_CHANGED) { 46672f22d08dSJustin T. Gibbs /* 46682f22d08dSJustin T. Gibbs * We've sent a start unit command, or 46692f22d08dSJustin T. Gibbs * something similar to a device that 46702f22d08dSJustin T. Gibbs * may have caused its inquiry data to 46712f22d08dSJustin T. Gibbs * change. So we re-scan the device to 46722f22d08dSJustin T. Gibbs * refresh the inquiry data for it. 46732f22d08dSJustin T. Gibbs */ 46742f22d08dSJustin T. Gibbs xpt_scan_lun(newpath.periph, &newpath, 46752f22d08dSJustin T. Gibbs CAM_EXPECT_INQ_CHANGE, NULL); 46762f22d08dSJustin T. Gibbs } 46772f22d08dSJustin T. Gibbs xpt_release_path(&newpath); 46782f22d08dSJustin T. Gibbs } else if (async_code == AC_LOST_DEVICE) { 46792f22d08dSJustin T. Gibbs device->flags |= CAM_DEV_UNCONFIGURED; 46802f22d08dSJustin T. Gibbs } else if (async_code == AC_TRANSFER_NEG) { 46812f22d08dSJustin T. Gibbs struct ccb_trans_settings *settings; 46822f22d08dSJustin T. Gibbs 46832f22d08dSJustin T. Gibbs settings = (struct ccb_trans_settings *)async_arg; 46842f22d08dSJustin T. Gibbs xpt_set_transfer_settings(settings, device, 46852f22d08dSJustin T. Gibbs /*async_update*/TRUE); 46862f22d08dSJustin T. Gibbs } 46872f22d08dSJustin T. Gibbs } 46882f22d08dSJustin T. Gibbs 46898b8a9b1dSJustin T. Gibbs u_int32_t 46908b8a9b1dSJustin T. Gibbs xpt_freeze_devq(struct cam_path *path, u_int count) 46918b8a9b1dSJustin T. Gibbs { 46928b8a9b1dSJustin T. Gibbs struct ccb_hdr *ccbh; 46938b8a9b1dSJustin T. Gibbs 46942b83592fSScott Long mtx_assert(path->bus->sim->mtx, MA_OWNED); 469568153f43SScott Long 46968b8a9b1dSJustin T. Gibbs path->device->qfrozen_cnt += count; 46978b8a9b1dSJustin T. Gibbs 46988b8a9b1dSJustin T. Gibbs /* 46998b8a9b1dSJustin T. Gibbs * Mark the last CCB in the queue as needing 47008b8a9b1dSJustin T. Gibbs * to be requeued if the driver hasn't 47018b8a9b1dSJustin T. Gibbs * changed it's state yet. This fixes a race 47028b8a9b1dSJustin T. Gibbs * where a ccb is just about to be queued to 47038b8a9b1dSJustin T. Gibbs * a controller driver when it's interrupt routine 47048b8a9b1dSJustin T. Gibbs * freezes the queue. To completly close the 47058b8a9b1dSJustin T. Gibbs * hole, controller drives must check to see 47068b8a9b1dSJustin T. Gibbs * if a ccb's status is still CAM_REQ_INPROG 470777dc25ccSScott Long * just before they queue 47088b8a9b1dSJustin T. Gibbs * the CCB. See ahc_action/ahc_freeze_devq for 47098b8a9b1dSJustin T. Gibbs * an example. 47108b8a9b1dSJustin T. Gibbs */ 4711bb6087e5SJustin T. Gibbs ccbh = TAILQ_LAST(&path->device->ccbq.active_ccbs, ccb_hdr_tailq); 47128b8a9b1dSJustin T. Gibbs if (ccbh && ccbh->status == CAM_REQ_INPROG) 47138b8a9b1dSJustin T. Gibbs ccbh->status = CAM_REQUEUE_REQ; 47148b8a9b1dSJustin T. Gibbs return (path->device->qfrozen_cnt); 47158b8a9b1dSJustin T. Gibbs } 47168b8a9b1dSJustin T. Gibbs 47178b8a9b1dSJustin T. Gibbs u_int32_t 47188b8a9b1dSJustin T. Gibbs xpt_freeze_simq(struct cam_sim *sim, u_int count) 47198b8a9b1dSJustin T. Gibbs { 47202b83592fSScott Long mtx_assert(sim->mtx, MA_OWNED); 472168153f43SScott Long 47228b8a9b1dSJustin T. Gibbs sim->devq->send_queue.qfrozen_cnt += count; 47238b8a9b1dSJustin T. Gibbs if (sim->devq->active_dev != NULL) { 47248b8a9b1dSJustin T. Gibbs struct ccb_hdr *ccbh; 47258b8a9b1dSJustin T. Gibbs 47268b8a9b1dSJustin T. Gibbs ccbh = TAILQ_LAST(&sim->devq->active_dev->ccbq.active_ccbs, 4727bb6087e5SJustin T. Gibbs ccb_hdr_tailq); 47288b8a9b1dSJustin T. Gibbs if (ccbh && ccbh->status == CAM_REQ_INPROG) 47298b8a9b1dSJustin T. Gibbs ccbh->status = CAM_REQUEUE_REQ; 47308b8a9b1dSJustin T. Gibbs } 47318b8a9b1dSJustin T. Gibbs return (sim->devq->send_queue.qfrozen_cnt); 47328b8a9b1dSJustin T. Gibbs } 47338b8a9b1dSJustin T. Gibbs 47348b8a9b1dSJustin T. Gibbs static void 47358b8a9b1dSJustin T. Gibbs xpt_release_devq_timeout(void *arg) 47368b8a9b1dSJustin T. Gibbs { 47378b8a9b1dSJustin T. Gibbs struct cam_ed *device; 47388b8a9b1dSJustin T. Gibbs 47398b8a9b1dSJustin T. Gibbs device = (struct cam_ed *)arg; 47408b8a9b1dSJustin T. Gibbs 47412cefde5fSJustin T. Gibbs xpt_release_devq_device(device, /*count*/1, /*run_queue*/TRUE); 47428b8a9b1dSJustin T. Gibbs } 47438b8a9b1dSJustin T. Gibbs 47448b8a9b1dSJustin T. Gibbs void 47452cefde5fSJustin T. Gibbs xpt_release_devq(struct cam_path *path, u_int count, int run_queue) 47462cefde5fSJustin T. Gibbs { 47472b83592fSScott Long mtx_assert(path->bus->sim->mtx, MA_OWNED); 474868153f43SScott Long 47492cefde5fSJustin T. Gibbs xpt_release_devq_device(path->device, count, run_queue); 47502cefde5fSJustin T. Gibbs } 47512cefde5fSJustin T. Gibbs 47522cefde5fSJustin T. Gibbs static void 47532cefde5fSJustin T. Gibbs xpt_release_devq_device(struct cam_ed *dev, u_int count, int run_queue) 47548b8a9b1dSJustin T. Gibbs { 47558b8a9b1dSJustin T. Gibbs int rundevq; 47568b8a9b1dSJustin T. Gibbs 47578b8a9b1dSJustin T. Gibbs rundevq = 0; 47588b8a9b1dSJustin T. Gibbs if (dev->qfrozen_cnt > 0) { 47598b8a9b1dSJustin T. Gibbs 47602cefde5fSJustin T. Gibbs count = (count > dev->qfrozen_cnt) ? dev->qfrozen_cnt : count; 47612cefde5fSJustin T. Gibbs dev->qfrozen_cnt -= count; 47628b8a9b1dSJustin T. Gibbs if (dev->qfrozen_cnt == 0) { 47638b8a9b1dSJustin T. Gibbs 47648b8a9b1dSJustin T. Gibbs /* 47658b8a9b1dSJustin T. Gibbs * No longer need to wait for a successful 47668b8a9b1dSJustin T. Gibbs * command completion. 47678b8a9b1dSJustin T. Gibbs */ 47688b8a9b1dSJustin T. Gibbs dev->flags &= ~CAM_DEV_REL_ON_COMPLETE; 47698b8a9b1dSJustin T. Gibbs 47708b8a9b1dSJustin T. Gibbs /* 47718b8a9b1dSJustin T. Gibbs * Remove any timeouts that might be scheduled 47728b8a9b1dSJustin T. Gibbs * to release this queue. 47738b8a9b1dSJustin T. Gibbs */ 47748b8a9b1dSJustin T. Gibbs if ((dev->flags & CAM_DEV_REL_TIMEOUT_PENDING) != 0) { 47752b83592fSScott Long callout_stop(&dev->callout); 47768b8a9b1dSJustin T. Gibbs dev->flags &= ~CAM_DEV_REL_TIMEOUT_PENDING; 47778b8a9b1dSJustin T. Gibbs } 47788b8a9b1dSJustin T. Gibbs 47798b8a9b1dSJustin T. Gibbs /* 47808b8a9b1dSJustin T. Gibbs * Now that we are unfrozen schedule the 47818b8a9b1dSJustin T. Gibbs * device so any pending transactions are 47828b8a9b1dSJustin T. Gibbs * run. 47838b8a9b1dSJustin T. Gibbs */ 47848b8a9b1dSJustin T. Gibbs if ((dev->ccbq.queue.entries > 0) 47858b8a9b1dSJustin T. Gibbs && (xpt_schedule_dev_sendq(dev->target->bus, dev)) 47868b8a9b1dSJustin T. Gibbs && (run_queue != 0)) { 47878b8a9b1dSJustin T. Gibbs rundevq = 1; 47888b8a9b1dSJustin T. Gibbs } 47898b8a9b1dSJustin T. Gibbs } 47908b8a9b1dSJustin T. Gibbs } 47918b8a9b1dSJustin T. Gibbs if (rundevq != 0) 47928b8a9b1dSJustin T. Gibbs xpt_run_dev_sendq(dev->target->bus); 47938b8a9b1dSJustin T. Gibbs } 47948b8a9b1dSJustin T. Gibbs 47958b8a9b1dSJustin T. Gibbs void 47968b8a9b1dSJustin T. Gibbs xpt_release_simq(struct cam_sim *sim, int run_queue) 47978b8a9b1dSJustin T. Gibbs { 47988b8a9b1dSJustin T. Gibbs struct camq *sendq; 47998b8a9b1dSJustin T. Gibbs 48002b83592fSScott Long mtx_assert(sim->mtx, MA_OWNED); 480168153f43SScott Long 48028b8a9b1dSJustin T. Gibbs sendq = &(sim->devq->send_queue); 48038b8a9b1dSJustin T. Gibbs if (sendq->qfrozen_cnt > 0) { 48048b8a9b1dSJustin T. Gibbs 48058b8a9b1dSJustin T. Gibbs sendq->qfrozen_cnt--; 48068b8a9b1dSJustin T. Gibbs if (sendq->qfrozen_cnt == 0) { 4807a5479bc5SJustin T. Gibbs struct cam_eb *bus; 48088b8a9b1dSJustin T. Gibbs 48098b8a9b1dSJustin T. Gibbs /* 48108b8a9b1dSJustin T. Gibbs * If there is a timeout scheduled to release this 48118b8a9b1dSJustin T. Gibbs * sim queue, remove it. The queue frozen count is 48128b8a9b1dSJustin T. Gibbs * already at 0. 48138b8a9b1dSJustin T. Gibbs */ 48148b8a9b1dSJustin T. Gibbs if ((sim->flags & CAM_SIM_REL_TIMEOUT_PENDING) != 0){ 48152b83592fSScott Long callout_stop(&sim->callout); 48168b8a9b1dSJustin T. Gibbs sim->flags &= ~CAM_SIM_REL_TIMEOUT_PENDING; 48178b8a9b1dSJustin T. Gibbs } 4818a5479bc5SJustin T. Gibbs bus = xpt_find_bus(sim->path_id); 48198b8a9b1dSJustin T. Gibbs 48208b8a9b1dSJustin T. Gibbs if (run_queue) { 48218b8a9b1dSJustin T. Gibbs /* 48228b8a9b1dSJustin T. Gibbs * Now that we are unfrozen run the send queue. 48238b8a9b1dSJustin T. Gibbs */ 4824a5479bc5SJustin T. Gibbs xpt_run_dev_sendq(bus); 48258b8a9b1dSJustin T. Gibbs } 4826a5479bc5SJustin T. Gibbs xpt_release_bus(bus); 482777dc25ccSScott Long } 482877dc25ccSScott Long } 48298b8a9b1dSJustin T. Gibbs } 48308b8a9b1dSJustin T. Gibbs 48312b83592fSScott Long /* 48322b83592fSScott Long * XXX Appears to be unused. 48332b83592fSScott Long */ 48348b8a9b1dSJustin T. Gibbs static void 48358b8a9b1dSJustin T. Gibbs xpt_release_simq_timeout(void *arg) 48368b8a9b1dSJustin T. Gibbs { 48378b8a9b1dSJustin T. Gibbs struct cam_sim *sim; 48388b8a9b1dSJustin T. Gibbs 48398b8a9b1dSJustin T. Gibbs sim = (struct cam_sim *)arg; 48408b8a9b1dSJustin T. Gibbs xpt_release_simq(sim, /* run_queue */ TRUE); 48418b8a9b1dSJustin T. Gibbs } 48428b8a9b1dSJustin T. Gibbs 48438b8a9b1dSJustin T. Gibbs void 4844a5479bc5SJustin T. Gibbs xpt_done(union ccb *done_ccb) 48458b8a9b1dSJustin T. Gibbs { 48469758cc83SScott Long struct cam_sim *sim; 48478b8a9b1dSJustin T. Gibbs 48488b8a9b1dSJustin T. Gibbs CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_TRACE, ("xpt_done\n")); 48499deea857SKenneth D. Merry if ((done_ccb->ccb_h.func_code & XPT_FC_QUEUED) != 0) { 48508b8a9b1dSJustin T. Gibbs /* 48518b8a9b1dSJustin T. Gibbs * Queue up the request for handling by our SWI handler 48528b8a9b1dSJustin T. Gibbs * any of the "non-immediate" type of ccbs. 48538b8a9b1dSJustin T. Gibbs */ 48549758cc83SScott Long sim = done_ccb->ccb_h.path->bus->sim; 48558b8a9b1dSJustin T. Gibbs switch (done_ccb->ccb_h.path->periph->type) { 48568b8a9b1dSJustin T. Gibbs case CAM_PERIPH_BIO: 48579758cc83SScott Long TAILQ_INSERT_TAIL(&sim->sim_doneq, &done_ccb->ccb_h, 48588b8a9b1dSJustin T. Gibbs sim_links.tqe); 48598b8a9b1dSJustin T. Gibbs done_ccb->ccb_h.pinfo.index = CAM_DONEQ_INDEX; 48609758cc83SScott Long if ((sim->flags & CAM_SIM_ON_DONEQ) == 0) { 48619758cc83SScott Long mtx_lock(&cam_simq_lock); 48629758cc83SScott Long TAILQ_INSERT_TAIL(&cam_simq, sim, 48639758cc83SScott Long links); 48649758cc83SScott Long sim->flags |= CAM_SIM_ON_DONEQ; 48659758cc83SScott Long mtx_unlock(&cam_simq_lock); 48669758cc83SScott Long } 48672b83592fSScott Long if ((done_ccb->ccb_h.path->periph->flags & 48682b83592fSScott Long CAM_PERIPH_POLLED) == 0) 4869c86b6ff5SJohn Baldwin swi_sched(cambio_ih, 0); 48708b8a9b1dSJustin T. Gibbs break; 48712e8f0ae6SScott Long default: 48722e8f0ae6SScott Long panic("unknown periph type %d", 48732e8f0ae6SScott Long done_ccb->ccb_h.path->periph->type); 48748b8a9b1dSJustin T. Gibbs } 48758b8a9b1dSJustin T. Gibbs } 48768b8a9b1dSJustin T. Gibbs } 48778b8a9b1dSJustin T. Gibbs 48788b8a9b1dSJustin T. Gibbs union ccb * 48798008a935SScott Long xpt_alloc_ccb() 48808b8a9b1dSJustin T. Gibbs { 48818b8a9b1dSJustin T. Gibbs union ccb *new_ccb; 48828b8a9b1dSJustin T. Gibbs 48832a30c7ddSScott Long new_ccb = malloc(sizeof(*new_ccb), M_CAMXPT, M_ZERO|M_WAITOK); 4884362abc44STai-hwa Liang return (new_ccb); 4885362abc44STai-hwa Liang } 4886362abc44STai-hwa Liang 4887362abc44STai-hwa Liang union ccb * 48888008a935SScott Long xpt_alloc_ccb_nowait() 4889362abc44STai-hwa Liang { 4890362abc44STai-hwa Liang union ccb *new_ccb; 4891362abc44STai-hwa Liang 48922a30c7ddSScott Long new_ccb = malloc(sizeof(*new_ccb), M_CAMXPT, M_ZERO|M_NOWAIT); 48938b8a9b1dSJustin T. Gibbs return (new_ccb); 48948b8a9b1dSJustin T. Gibbs } 48958b8a9b1dSJustin T. Gibbs 48968b8a9b1dSJustin T. Gibbs void 48978b8a9b1dSJustin T. Gibbs xpt_free_ccb(union ccb *free_ccb) 48988b8a9b1dSJustin T. Gibbs { 4899362abc44STai-hwa Liang free(free_ccb, M_CAMXPT); 49008b8a9b1dSJustin T. Gibbs } 49018b8a9b1dSJustin T. Gibbs 49028b8a9b1dSJustin T. Gibbs 49038b8a9b1dSJustin T. Gibbs 49048b8a9b1dSJustin T. Gibbs /* Private XPT functions */ 49058b8a9b1dSJustin T. Gibbs 49068b8a9b1dSJustin T. Gibbs /* 49078b8a9b1dSJustin T. Gibbs * Get a CAM control block for the caller. Charge the structure to the device 49088b8a9b1dSJustin T. Gibbs * referenced by the path. If the this device has no 'credits' then the 49098b8a9b1dSJustin T. Gibbs * device already has the maximum number of outstanding operations under way 49108b8a9b1dSJustin T. Gibbs * and we return NULL. If we don't have sufficient resources to allocate more 49118b8a9b1dSJustin T. Gibbs * ccbs, we also return NULL. 49128b8a9b1dSJustin T. Gibbs */ 49138b8a9b1dSJustin T. Gibbs static union ccb * 49148b8a9b1dSJustin T. Gibbs xpt_get_ccb(struct cam_ed *device) 49158b8a9b1dSJustin T. Gibbs { 49168b8a9b1dSJustin T. Gibbs union ccb *new_ccb; 49172b83592fSScott Long struct cam_sim *sim; 49188b8a9b1dSJustin T. Gibbs 49192b83592fSScott Long sim = device->sim; 49202b83592fSScott Long if ((new_ccb = (union ccb *)SLIST_FIRST(&sim->ccb_freeq)) == NULL) { 49218008a935SScott Long new_ccb = xpt_alloc_ccb_nowait(); 49228b8a9b1dSJustin T. Gibbs if (new_ccb == NULL) { 49238b8a9b1dSJustin T. Gibbs return (NULL); 49248b8a9b1dSJustin T. Gibbs } 49258008a935SScott Long if ((sim->flags & CAM_SIM_MPSAFE) == 0) 49268008a935SScott Long callout_handle_init(&new_ccb->ccb_h.timeout_ch); 49272b83592fSScott Long SLIST_INSERT_HEAD(&sim->ccb_freeq, &new_ccb->ccb_h, 49288b8a9b1dSJustin T. Gibbs xpt_links.sle); 49292b83592fSScott Long sim->ccb_count++; 49308b8a9b1dSJustin T. Gibbs } 49318b8a9b1dSJustin T. Gibbs cam_ccbq_take_opening(&device->ccbq); 49322b83592fSScott Long SLIST_REMOVE_HEAD(&sim->ccb_freeq, xpt_links.sle); 49338b8a9b1dSJustin T. Gibbs return (new_ccb); 49348b8a9b1dSJustin T. Gibbs } 49358b8a9b1dSJustin T. Gibbs 4936a5479bc5SJustin T. Gibbs static void 4937a5479bc5SJustin T. Gibbs xpt_release_bus(struct cam_eb *bus) 4938a5479bc5SJustin T. Gibbs { 4939a5479bc5SJustin T. Gibbs 4940a5479bc5SJustin T. Gibbs if ((--bus->refcount == 0) 4941a5479bc5SJustin T. Gibbs && (TAILQ_FIRST(&bus->et_entries) == NULL)) { 49422b83592fSScott Long mtx_lock(&xsoftc.xpt_topo_lock); 49432b83592fSScott Long TAILQ_REMOVE(&xsoftc.xpt_busses, bus, links); 49442b83592fSScott Long xsoftc.bus_generation++; 49452b83592fSScott Long mtx_unlock(&xsoftc.xpt_topo_lock); 4946362abc44STai-hwa Liang free(bus, M_CAMXPT); 494777dc25ccSScott Long } 4948a5479bc5SJustin T. Gibbs } 49498b8a9b1dSJustin T. Gibbs 49508b8a9b1dSJustin T. Gibbs static struct cam_et * 49518b8a9b1dSJustin T. Gibbs xpt_alloc_target(struct cam_eb *bus, target_id_t target_id) 49528b8a9b1dSJustin T. Gibbs { 49538b8a9b1dSJustin T. Gibbs struct cam_et *target; 49548b8a9b1dSJustin T. Gibbs 4955362abc44STai-hwa Liang target = (struct cam_et *)malloc(sizeof(*target), M_CAMXPT, M_NOWAIT); 49568b8a9b1dSJustin T. Gibbs if (target != NULL) { 49578b8a9b1dSJustin T. Gibbs struct cam_et *cur_target; 49588b8a9b1dSJustin T. Gibbs 4959434bbf6eSJustin T. Gibbs TAILQ_INIT(&target->ed_entries); 49608b8a9b1dSJustin T. Gibbs target->bus = bus; 49618b8a9b1dSJustin T. Gibbs target->target_id = target_id; 49628b8a9b1dSJustin T. Gibbs target->refcount = 1; 4963434bbf6eSJustin T. Gibbs target->generation = 0; 4964434bbf6eSJustin T. Gibbs timevalclear(&target->last_reset); 4965a5479bc5SJustin T. Gibbs /* 4966a5479bc5SJustin T. Gibbs * Hold a reference to our parent bus so it 4967a5479bc5SJustin T. Gibbs * will not go away before we do. 4968a5479bc5SJustin T. Gibbs */ 4969a5479bc5SJustin T. Gibbs bus->refcount++; 49708b8a9b1dSJustin T. Gibbs 49718b8a9b1dSJustin T. Gibbs /* Insertion sort into our bus's target list */ 49728b8a9b1dSJustin T. Gibbs cur_target = TAILQ_FIRST(&bus->et_entries); 49738b8a9b1dSJustin T. Gibbs while (cur_target != NULL && cur_target->target_id < target_id) 49748b8a9b1dSJustin T. Gibbs cur_target = TAILQ_NEXT(cur_target, links); 49758b8a9b1dSJustin T. Gibbs 49768b8a9b1dSJustin T. Gibbs if (cur_target != NULL) { 49778b8a9b1dSJustin T. Gibbs TAILQ_INSERT_BEFORE(cur_target, target, links); 49788b8a9b1dSJustin T. Gibbs } else { 49798b8a9b1dSJustin T. Gibbs TAILQ_INSERT_TAIL(&bus->et_entries, target, links); 49808b8a9b1dSJustin T. Gibbs } 4981a5479bc5SJustin T. Gibbs bus->generation++; 49828b8a9b1dSJustin T. Gibbs } 49838b8a9b1dSJustin T. Gibbs return (target); 49848b8a9b1dSJustin T. Gibbs } 49858b8a9b1dSJustin T. Gibbs 4986a5479bc5SJustin T. Gibbs static void 49878b8a9b1dSJustin T. Gibbs xpt_release_target(struct cam_eb *bus, struct cam_et *target) 49888b8a9b1dSJustin T. Gibbs { 4989a5479bc5SJustin T. Gibbs 49908b8a9b1dSJustin T. Gibbs if ((--target->refcount == 0) 49918b8a9b1dSJustin T. Gibbs && (TAILQ_FIRST(&target->ed_entries) == NULL)) { 49928b8a9b1dSJustin T. Gibbs TAILQ_REMOVE(&bus->et_entries, target, links); 49938b8a9b1dSJustin T. Gibbs bus->generation++; 4994362abc44STai-hwa Liang free(target, M_CAMXPT); 4995a5479bc5SJustin T. Gibbs xpt_release_bus(bus); 499677dc25ccSScott Long } 49978b8a9b1dSJustin T. Gibbs } 49988b8a9b1dSJustin T. Gibbs 49998b8a9b1dSJustin T. Gibbs static struct cam_ed * 50008b8a9b1dSJustin T. Gibbs xpt_alloc_device(struct cam_eb *bus, struct cam_et *target, lun_id_t lun_id) 50018b8a9b1dSJustin T. Gibbs { 50023393f8daSKenneth D. Merry struct cam_path path; 50038b8a9b1dSJustin T. Gibbs struct cam_ed *device; 50048b8a9b1dSJustin T. Gibbs struct cam_devq *devq; 5005a5479bc5SJustin T. Gibbs cam_status status; 50068b8a9b1dSJustin T. Gibbs 5007d3ef3454SIan Dowse if (SIM_DEAD(bus->sim)) 5008d3ef3454SIan Dowse return (NULL); 5009d3ef3454SIan Dowse 50108b8a9b1dSJustin T. Gibbs /* Make space for us in the device queue on our bus */ 50118b8a9b1dSJustin T. Gibbs devq = bus->sim->devq; 50128b8a9b1dSJustin T. Gibbs status = cam_devq_resize(devq, devq->alloc_queue.array_size + 1); 50138b8a9b1dSJustin T. Gibbs 50148b8a9b1dSJustin T. Gibbs if (status != CAM_REQ_CMP) { 50158b8a9b1dSJustin T. Gibbs device = NULL; 50168b8a9b1dSJustin T. Gibbs } else { 50178b8a9b1dSJustin T. Gibbs device = (struct cam_ed *)malloc(sizeof(*device), 5018362abc44STai-hwa Liang M_CAMXPT, M_NOWAIT); 50198b8a9b1dSJustin T. Gibbs } 50208b8a9b1dSJustin T. Gibbs 50218b8a9b1dSJustin T. Gibbs if (device != NULL) { 50228b8a9b1dSJustin T. Gibbs struct cam_ed *cur_device; 50238b8a9b1dSJustin T. Gibbs 50248b8a9b1dSJustin T. Gibbs cam_init_pinfo(&device->alloc_ccb_entry.pinfo); 50258b8a9b1dSJustin T. Gibbs device->alloc_ccb_entry.device = device; 50268b8a9b1dSJustin T. Gibbs cam_init_pinfo(&device->send_ccb_entry.pinfo); 50278b8a9b1dSJustin T. Gibbs device->send_ccb_entry.device = device; 50288b8a9b1dSJustin T. Gibbs device->target = target; 50298b8a9b1dSJustin T. Gibbs device->lun_id = lun_id; 50302b83592fSScott Long device->sim = bus->sim; 50318b8a9b1dSJustin T. Gibbs /* Initialize our queues */ 50328b8a9b1dSJustin T. Gibbs if (camq_init(&device->drvq, 0) != 0) { 5033362abc44STai-hwa Liang free(device, M_CAMXPT); 50348b8a9b1dSJustin T. Gibbs return (NULL); 50358b8a9b1dSJustin T. Gibbs } 50368b8a9b1dSJustin T. Gibbs if (cam_ccbq_init(&device->ccbq, 50378b8a9b1dSJustin T. Gibbs bus->sim->max_dev_openings) != 0) { 50388b8a9b1dSJustin T. Gibbs camq_fini(&device->drvq); 5039362abc44STai-hwa Liang free(device, M_CAMXPT); 50408b8a9b1dSJustin T. Gibbs return (NULL); 50418b8a9b1dSJustin T. Gibbs } 5042434bbf6eSJustin T. Gibbs SLIST_INIT(&device->asyncs); 5043434bbf6eSJustin T. Gibbs SLIST_INIT(&device->periphs); 5044434bbf6eSJustin T. Gibbs device->generation = 0; 5045434bbf6eSJustin T. Gibbs device->owner = NULL; 5046434bbf6eSJustin T. Gibbs /* 5047434bbf6eSJustin T. Gibbs * Take the default quirk entry until we have inquiry 5048434bbf6eSJustin T. Gibbs * data and can determine a better quirk to use. 5049434bbf6eSJustin T. Gibbs */ 5050434bbf6eSJustin T. Gibbs device->quirk = &xpt_quirk_table[xpt_quirk_table_size - 1]; 5051434bbf6eSJustin T. Gibbs bzero(&device->inq_data, sizeof(device->inq_data)); 5052434bbf6eSJustin T. Gibbs device->inq_flags = 0; 5053434bbf6eSJustin T. Gibbs device->queue_flags = 0; 5054434bbf6eSJustin T. Gibbs device->serial_num = NULL; 5055434bbf6eSJustin T. Gibbs device->serial_num_len = 0; 5056434bbf6eSJustin T. Gibbs device->qfrozen_cnt = 0; 5057434bbf6eSJustin T. Gibbs device->flags = CAM_DEV_UNCONFIGURED; 5058434bbf6eSJustin T. Gibbs device->tag_delay_count = 0; 5059df8f9080SJustin T. Gibbs device->tag_saved_openings = 0; 5060434bbf6eSJustin T. Gibbs device->refcount = 1; 50612b83592fSScott Long if (bus->sim->flags & CAM_SIM_MPSAFE) 50622b83592fSScott Long callout_init_mtx(&device->callout, bus->sim->mtx, 0); 50632b83592fSScott Long else 50642b83592fSScott Long callout_init_mtx(&device->callout, &Giant, 0); 5065434bbf6eSJustin T. Gibbs 5066434bbf6eSJustin T. Gibbs /* 5067434bbf6eSJustin T. Gibbs * Hold a reference to our parent target so it 5068434bbf6eSJustin T. Gibbs * will not go away before we do. 5069434bbf6eSJustin T. Gibbs */ 5070434bbf6eSJustin T. Gibbs target->refcount++; 5071434bbf6eSJustin T. Gibbs 50728b8a9b1dSJustin T. Gibbs /* 50738b8a9b1dSJustin T. Gibbs * XXX should be limited by number of CCBs this bus can 50748b8a9b1dSJustin T. Gibbs * do. 50758b8a9b1dSJustin T. Gibbs */ 50762b83592fSScott Long bus->sim->max_ccbs += device->ccbq.devq_openings; 50778b8a9b1dSJustin T. Gibbs /* Insertion sort into our target's device list */ 50788b8a9b1dSJustin T. Gibbs cur_device = TAILQ_FIRST(&target->ed_entries); 50798b8a9b1dSJustin T. Gibbs while (cur_device != NULL && cur_device->lun_id < lun_id) 50808b8a9b1dSJustin T. Gibbs cur_device = TAILQ_NEXT(cur_device, links); 50818b8a9b1dSJustin T. Gibbs if (cur_device != NULL) { 50828b8a9b1dSJustin T. Gibbs TAILQ_INSERT_BEFORE(cur_device, device, links); 50838b8a9b1dSJustin T. Gibbs } else { 50848b8a9b1dSJustin T. Gibbs TAILQ_INSERT_TAIL(&target->ed_entries, device, links); 50858b8a9b1dSJustin T. Gibbs } 5086a5479bc5SJustin T. Gibbs target->generation++; 50873393f8daSKenneth D. Merry if (lun_id != CAM_LUN_WILDCARD) { 50883393f8daSKenneth D. Merry xpt_compile_path(&path, 50893393f8daSKenneth D. Merry NULL, 50903393f8daSKenneth D. Merry bus->path_id, 50913393f8daSKenneth D. Merry target->target_id, 50923393f8daSKenneth D. Merry lun_id); 50933393f8daSKenneth D. Merry xpt_devise_transport(&path); 50943393f8daSKenneth D. Merry xpt_release_path(&path); 50953393f8daSKenneth D. Merry } 50968b8a9b1dSJustin T. Gibbs } 50978b8a9b1dSJustin T. Gibbs return (device); 50988b8a9b1dSJustin T. Gibbs } 50998b8a9b1dSJustin T. Gibbs 51008b8a9b1dSJustin T. Gibbs static void 51018b8a9b1dSJustin T. Gibbs xpt_release_device(struct cam_eb *bus, struct cam_et *target, 51028b8a9b1dSJustin T. Gibbs struct cam_ed *device) 51038b8a9b1dSJustin T. Gibbs { 51048b8a9b1dSJustin T. Gibbs 51058b8a9b1dSJustin T. Gibbs if ((--device->refcount == 0) 51068b8a9b1dSJustin T. Gibbs && ((device->flags & CAM_DEV_UNCONFIGURED) != 0)) { 51078b8a9b1dSJustin T. Gibbs struct cam_devq *devq; 51088b8a9b1dSJustin T. Gibbs 5109a5479bc5SJustin T. Gibbs if (device->alloc_ccb_entry.pinfo.index != CAM_UNQUEUED_INDEX 5110a5479bc5SJustin T. Gibbs || device->send_ccb_entry.pinfo.index != CAM_UNQUEUED_INDEX) 5111a5479bc5SJustin T. Gibbs panic("Removing device while still queued for ccbs"); 51122cefde5fSJustin T. Gibbs 51132cefde5fSJustin T. Gibbs if ((device->flags & CAM_DEV_REL_TIMEOUT_PENDING) != 0) 51142b83592fSScott Long callout_stop(&device->callout); 51152cefde5fSJustin T. Gibbs 51168b8a9b1dSJustin T. Gibbs TAILQ_REMOVE(&target->ed_entries, device,links); 51178b8a9b1dSJustin T. Gibbs target->generation++; 51182b83592fSScott Long bus->sim->max_ccbs -= device->ccbq.devq_openings; 5119d3ef3454SIan Dowse if (!SIM_DEAD(bus->sim)) { 51208b8a9b1dSJustin T. Gibbs /* Release our slot in the devq */ 51218b8a9b1dSJustin T. Gibbs devq = bus->sim->devq; 51228b8a9b1dSJustin T. Gibbs cam_devq_resize(devq, devq->alloc_queue.array_size - 1); 5123d3ef3454SIan Dowse } 51247c20d5d7STai-hwa Liang camq_fini(&device->drvq); 51257c20d5d7STai-hwa Liang camq_fini(&device->ccbq.queue); 5126362abc44STai-hwa Liang free(device, M_CAMXPT); 5127434bbf6eSJustin T. Gibbs xpt_release_target(bus, target); 512877dc25ccSScott Long } 51298b8a9b1dSJustin T. Gibbs } 51308b8a9b1dSJustin T. Gibbs 51318b8a9b1dSJustin T. Gibbs static u_int32_t 51328b8a9b1dSJustin T. Gibbs xpt_dev_ccbq_resize(struct cam_path *path, int newopenings) 51338b8a9b1dSJustin T. Gibbs { 51348b8a9b1dSJustin T. Gibbs int diff; 51358b8a9b1dSJustin T. Gibbs int result; 51368b8a9b1dSJustin T. Gibbs struct cam_ed *dev; 51378b8a9b1dSJustin T. Gibbs 51388b8a9b1dSJustin T. Gibbs dev = path->device; 51398b8a9b1dSJustin T. Gibbs 51408b8a9b1dSJustin T. Gibbs diff = newopenings - (dev->ccbq.dev_active + dev->ccbq.dev_openings); 51418b8a9b1dSJustin T. Gibbs result = cam_ccbq_resize(&dev->ccbq, newopenings); 51428b8a9b1dSJustin T. Gibbs if (result == CAM_REQ_CMP && (diff < 0)) { 51438b8a9b1dSJustin T. Gibbs dev->flags |= CAM_DEV_RESIZE_QUEUE_NEEDED; 51448b8a9b1dSJustin T. Gibbs } 5145df8f9080SJustin T. Gibbs if ((dev->flags & CAM_DEV_TAG_AFTER_COUNT) != 0 5146df8f9080SJustin T. Gibbs || (dev->inq_flags & SID_CmdQue) != 0) 5147df8f9080SJustin T. Gibbs dev->tag_saved_openings = newopenings; 51488b8a9b1dSJustin T. Gibbs /* Adjust the global limit */ 51492b83592fSScott Long dev->sim->max_ccbs += diff; 51508b8a9b1dSJustin T. Gibbs return (result); 51518b8a9b1dSJustin T. Gibbs } 51528b8a9b1dSJustin T. Gibbs 51538b8a9b1dSJustin T. Gibbs static struct cam_eb * 51548b8a9b1dSJustin T. Gibbs xpt_find_bus(path_id_t path_id) 51558b8a9b1dSJustin T. Gibbs { 51568b8a9b1dSJustin T. Gibbs struct cam_eb *bus; 51578b8a9b1dSJustin T. Gibbs 51582b83592fSScott Long mtx_lock(&xsoftc.xpt_topo_lock); 51592b83592fSScott Long for (bus = TAILQ_FIRST(&xsoftc.xpt_busses); 51608b8a9b1dSJustin T. Gibbs bus != NULL; 51618b8a9b1dSJustin T. Gibbs bus = TAILQ_NEXT(bus, links)) { 5162a5479bc5SJustin T. Gibbs if (bus->path_id == path_id) { 5163a5479bc5SJustin T. Gibbs bus->refcount++; 51648b8a9b1dSJustin T. Gibbs break; 51658b8a9b1dSJustin T. Gibbs } 5166a5479bc5SJustin T. Gibbs } 51672b83592fSScott Long mtx_unlock(&xsoftc.xpt_topo_lock); 51688b8a9b1dSJustin T. Gibbs return (bus); 51698b8a9b1dSJustin T. Gibbs } 51708b8a9b1dSJustin T. Gibbs 51718b8a9b1dSJustin T. Gibbs static struct cam_et * 51728b8a9b1dSJustin T. Gibbs xpt_find_target(struct cam_eb *bus, target_id_t target_id) 51738b8a9b1dSJustin T. Gibbs { 51748b8a9b1dSJustin T. Gibbs struct cam_et *target; 51758b8a9b1dSJustin T. Gibbs 51768b8a9b1dSJustin T. Gibbs for (target = TAILQ_FIRST(&bus->et_entries); 51778b8a9b1dSJustin T. Gibbs target != NULL; 51788b8a9b1dSJustin T. Gibbs target = TAILQ_NEXT(target, links)) { 51798b8a9b1dSJustin T. Gibbs if (target->target_id == target_id) { 51808b8a9b1dSJustin T. Gibbs target->refcount++; 51818b8a9b1dSJustin T. Gibbs break; 51828b8a9b1dSJustin T. Gibbs } 51838b8a9b1dSJustin T. Gibbs } 51848b8a9b1dSJustin T. Gibbs return (target); 51858b8a9b1dSJustin T. Gibbs } 51868b8a9b1dSJustin T. Gibbs 51878b8a9b1dSJustin T. Gibbs static struct cam_ed * 51888b8a9b1dSJustin T. Gibbs xpt_find_device(struct cam_et *target, lun_id_t lun_id) 51898b8a9b1dSJustin T. Gibbs { 51908b8a9b1dSJustin T. Gibbs struct cam_ed *device; 51918b8a9b1dSJustin T. Gibbs 51928b8a9b1dSJustin T. Gibbs for (device = TAILQ_FIRST(&target->ed_entries); 51938b8a9b1dSJustin T. Gibbs device != NULL; 51948b8a9b1dSJustin T. Gibbs device = TAILQ_NEXT(device, links)) { 51958b8a9b1dSJustin T. Gibbs if (device->lun_id == lun_id) { 51968b8a9b1dSJustin T. Gibbs device->refcount++; 51978b8a9b1dSJustin T. Gibbs break; 51988b8a9b1dSJustin T. Gibbs } 51998b8a9b1dSJustin T. Gibbs } 52008b8a9b1dSJustin T. Gibbs return (device); 52018b8a9b1dSJustin T. Gibbs } 52028b8a9b1dSJustin T. Gibbs 52038b8a9b1dSJustin T. Gibbs typedef struct { 52048b8a9b1dSJustin T. Gibbs union ccb *request_ccb; 52058b8a9b1dSJustin T. Gibbs struct ccb_pathinq *cpi; 5206c1c3139eSMatt Jacob int counter; 52078b8a9b1dSJustin T. Gibbs } xpt_scan_bus_info; 52088b8a9b1dSJustin T. Gibbs 52098b8a9b1dSJustin T. Gibbs /* 52108b8a9b1dSJustin T. Gibbs * To start a scan, request_ccb is an XPT_SCAN_BUS ccb. 52118b8a9b1dSJustin T. Gibbs * As the scan progresses, xpt_scan_bus is used as the 52128b8a9b1dSJustin T. Gibbs * callback on completion function. 52138b8a9b1dSJustin T. Gibbs */ 52148b8a9b1dSJustin T. Gibbs static void 52158b8a9b1dSJustin T. Gibbs xpt_scan_bus(struct cam_periph *periph, union ccb *request_ccb) 52168b8a9b1dSJustin T. Gibbs { 52178b8a9b1dSJustin T. Gibbs CAM_DEBUG(request_ccb->ccb_h.path, CAM_DEBUG_TRACE, 52188b8a9b1dSJustin T. Gibbs ("xpt_scan_bus\n")); 52198b8a9b1dSJustin T. Gibbs switch (request_ccb->ccb_h.func_code) { 52208b8a9b1dSJustin T. Gibbs case XPT_SCAN_BUS: 52218b8a9b1dSJustin T. Gibbs { 52228b8a9b1dSJustin T. Gibbs xpt_scan_bus_info *scan_info; 52238b8a9b1dSJustin T. Gibbs union ccb *work_ccb; 52248b8a9b1dSJustin T. Gibbs struct cam_path *path; 52258b8a9b1dSJustin T. Gibbs u_int i; 52268b8a9b1dSJustin T. Gibbs u_int max_target; 52278b8a9b1dSJustin T. Gibbs u_int initiator_id; 52288b8a9b1dSJustin T. Gibbs 52298b8a9b1dSJustin T. Gibbs /* Find out the characteristics of the bus */ 52308008a935SScott Long work_ccb = xpt_alloc_ccb_nowait(); 52318008a935SScott Long if (work_ccb == NULL) { 52328008a935SScott Long request_ccb->ccb_h.status = CAM_RESRC_UNAVAIL; 52338008a935SScott Long xpt_done(request_ccb); 52348008a935SScott Long return; 52358008a935SScott Long } 52368b8a9b1dSJustin T. Gibbs xpt_setup_ccb(&work_ccb->ccb_h, request_ccb->ccb_h.path, 52378b8a9b1dSJustin T. Gibbs request_ccb->ccb_h.pinfo.priority); 52388b8a9b1dSJustin T. Gibbs work_ccb->ccb_h.func_code = XPT_PATH_INQ; 52398b8a9b1dSJustin T. Gibbs xpt_action(work_ccb); 52408b8a9b1dSJustin T. Gibbs if (work_ccb->ccb_h.status != CAM_REQ_CMP) { 52418b8a9b1dSJustin T. Gibbs request_ccb->ccb_h.status = work_ccb->ccb_h.status; 52428b8a9b1dSJustin T. Gibbs xpt_free_ccb(work_ccb); 52438b8a9b1dSJustin T. Gibbs xpt_done(request_ccb); 52448b8a9b1dSJustin T. Gibbs return; 52458b8a9b1dSJustin T. Gibbs } 52468b8a9b1dSJustin T. Gibbs 524798192658SJustin T. Gibbs if ((work_ccb->cpi.hba_misc & PIM_NOINITIATOR) != 0) { 524898192658SJustin T. Gibbs /* 524998192658SJustin T. Gibbs * Can't scan the bus on an adapter that 525098192658SJustin T. Gibbs * cannot perform the initiator role. 525198192658SJustin T. Gibbs */ 525298192658SJustin T. Gibbs request_ccb->ccb_h.status = CAM_REQ_CMP; 525398192658SJustin T. Gibbs xpt_free_ccb(work_ccb); 525498192658SJustin T. Gibbs xpt_done(request_ccb); 525598192658SJustin T. Gibbs return; 525698192658SJustin T. Gibbs } 525798192658SJustin T. Gibbs 52588b8a9b1dSJustin T. Gibbs /* Save some state for use while we probe for devices */ 52598b8a9b1dSJustin T. Gibbs scan_info = (xpt_scan_bus_info *) 52600dd50e9bSScott Long malloc(sizeof(xpt_scan_bus_info), M_CAMXPT, M_NOWAIT); 52618b8a9b1dSJustin T. Gibbs scan_info->request_ccb = request_ccb; 52628b8a9b1dSJustin T. Gibbs scan_info->cpi = &work_ccb->cpi; 52638b8a9b1dSJustin T. Gibbs 52648b8a9b1dSJustin T. Gibbs /* Cache on our stack so we can work asynchronously */ 52658b8a9b1dSJustin T. Gibbs max_target = scan_info->cpi->max_target; 52668b8a9b1dSJustin T. Gibbs initiator_id = scan_info->cpi->initiator_id; 52678b8a9b1dSJustin T. Gibbs 5268c1c3139eSMatt Jacob 52698b8a9b1dSJustin T. Gibbs /* 5270c1c3139eSMatt Jacob * We can scan all targets in parallel, or do it sequentially. 52718b8a9b1dSJustin T. Gibbs */ 5272c1c3139eSMatt Jacob if (scan_info->cpi->hba_misc & PIM_SEQSCAN) { 5273c1c3139eSMatt Jacob max_target = 0; 5274c1c3139eSMatt Jacob scan_info->counter = 0; 5275c1c3139eSMatt Jacob } else { 5276c1c3139eSMatt Jacob scan_info->counter = scan_info->cpi->max_target + 1; 5277c1c3139eSMatt Jacob if (scan_info->cpi->initiator_id < scan_info->counter) { 5278c1c3139eSMatt Jacob scan_info->counter--; 5279c1c3139eSMatt Jacob } 5280c1c3139eSMatt Jacob } 52818b8a9b1dSJustin T. Gibbs 52828b8a9b1dSJustin T. Gibbs for (i = 0; i <= max_target; i++) { 52838b8a9b1dSJustin T. Gibbs cam_status status; 52848b8a9b1dSJustin T. Gibbs if (i == initiator_id) 52858b8a9b1dSJustin T. Gibbs continue; 52868b8a9b1dSJustin T. Gibbs 52878b8a9b1dSJustin T. Gibbs status = xpt_create_path(&path, xpt_periph, 52888b8a9b1dSJustin T. Gibbs request_ccb->ccb_h.path_id, 52898b8a9b1dSJustin T. Gibbs i, 0); 52908b8a9b1dSJustin T. Gibbs if (status != CAM_REQ_CMP) { 52918b8a9b1dSJustin T. Gibbs printf("xpt_scan_bus: xpt_create_path failed" 52928b8a9b1dSJustin T. Gibbs " with status %#x, bus scan halted\n", 52938b8a9b1dSJustin T. Gibbs status); 52940dd50e9bSScott Long free(scan_info, M_CAMXPT); 5295c1c3139eSMatt Jacob request_ccb->ccb_h.status = status; 5296c1c3139eSMatt Jacob xpt_free_ccb(work_ccb); 5297c1c3139eSMatt Jacob xpt_done(request_ccb); 52988b8a9b1dSJustin T. Gibbs break; 52998b8a9b1dSJustin T. Gibbs } 53008008a935SScott Long work_ccb = xpt_alloc_ccb_nowait(); 53018008a935SScott Long if (work_ccb == NULL) { 53020dd50e9bSScott Long free(scan_info, M_CAMXPT); 53038008a935SScott Long xpt_free_path(path); 53048008a935SScott Long request_ccb->ccb_h.status = CAM_RESRC_UNAVAIL; 53058008a935SScott Long xpt_done(request_ccb); 53068008a935SScott Long break; 53078008a935SScott Long } 53088b8a9b1dSJustin T. Gibbs xpt_setup_ccb(&work_ccb->ccb_h, path, 53098b8a9b1dSJustin T. Gibbs request_ccb->ccb_h.pinfo.priority); 53108b8a9b1dSJustin T. Gibbs work_ccb->ccb_h.func_code = XPT_SCAN_LUN; 53118b8a9b1dSJustin T. Gibbs work_ccb->ccb_h.cbfcnp = xpt_scan_bus; 53128b8a9b1dSJustin T. Gibbs work_ccb->ccb_h.ppriv_ptr0 = scan_info; 53138b8a9b1dSJustin T. Gibbs work_ccb->crcn.flags = request_ccb->crcn.flags; 53148b8a9b1dSJustin T. Gibbs xpt_action(work_ccb); 53158b8a9b1dSJustin T. Gibbs } 53168b8a9b1dSJustin T. Gibbs break; 53178b8a9b1dSJustin T. Gibbs } 53188b8a9b1dSJustin T. Gibbs case XPT_SCAN_LUN: 53198b8a9b1dSJustin T. Gibbs { 5320c1c3139eSMatt Jacob cam_status status; 5321c1c3139eSMatt Jacob struct cam_path *path; 53228b8a9b1dSJustin T. Gibbs xpt_scan_bus_info *scan_info; 53238b8a9b1dSJustin T. Gibbs path_id_t path_id; 53248b8a9b1dSJustin T. Gibbs target_id_t target_id; 53258b8a9b1dSJustin T. Gibbs lun_id_t lun_id; 53268b8a9b1dSJustin T. Gibbs 53278b8a9b1dSJustin T. Gibbs /* Reuse the same CCB to query if a device was really found */ 53288b8a9b1dSJustin T. Gibbs scan_info = (xpt_scan_bus_info *)request_ccb->ccb_h.ppriv_ptr0; 53298b8a9b1dSJustin T. Gibbs xpt_setup_ccb(&request_ccb->ccb_h, request_ccb->ccb_h.path, 53308b8a9b1dSJustin T. Gibbs request_ccb->ccb_h.pinfo.priority); 53318b8a9b1dSJustin T. Gibbs request_ccb->ccb_h.func_code = XPT_GDEV_TYPE; 53328b8a9b1dSJustin T. Gibbs 53338b8a9b1dSJustin T. Gibbs path_id = request_ccb->ccb_h.path_id; 53348b8a9b1dSJustin T. Gibbs target_id = request_ccb->ccb_h.target_id; 53358b8a9b1dSJustin T. Gibbs lun_id = request_ccb->ccb_h.target_lun; 53368b8a9b1dSJustin T. Gibbs xpt_action(request_ccb); 53378b8a9b1dSJustin T. Gibbs 53388b8a9b1dSJustin T. Gibbs if (request_ccb->ccb_h.status != CAM_REQ_CMP) { 53398b8a9b1dSJustin T. Gibbs struct cam_ed *device; 53408b8a9b1dSJustin T. Gibbs struct cam_et *target; 534177dc25ccSScott Long int phl; 53428b8a9b1dSJustin T. Gibbs 53438b8a9b1dSJustin T. Gibbs /* 53448b8a9b1dSJustin T. Gibbs * If we already probed lun 0 successfully, or 53458b8a9b1dSJustin T. Gibbs * we have additional configured luns on this 53468b8a9b1dSJustin T. Gibbs * target that might have "gone away", go onto 53478b8a9b1dSJustin T. Gibbs * the next lun. 53488b8a9b1dSJustin T. Gibbs */ 53498b8a9b1dSJustin T. Gibbs target = request_ccb->ccb_h.path->target; 5350b6a0d1abSMatt Jacob /* 5351b6a0d1abSMatt Jacob * We may touch devices that we don't 5352b6a0d1abSMatt Jacob * hold references too, so ensure they 5353b6a0d1abSMatt Jacob * don't disappear out from under us. 5354b6a0d1abSMatt Jacob * The target above is referenced by the 5355b6a0d1abSMatt Jacob * path in the request ccb. 5356b6a0d1abSMatt Jacob */ 5357b6a0d1abSMatt Jacob phl = 0; 53588b8a9b1dSJustin T. Gibbs device = TAILQ_FIRST(&target->ed_entries); 5359b6a0d1abSMatt Jacob if (device != NULL) { 53603b87a552SMatt Jacob phl = CAN_SRCH_HI_SPARSE(device); 5361b6a0d1abSMatt Jacob if (device->lun_id == 0) 53628b8a9b1dSJustin T. Gibbs device = TAILQ_NEXT(device, links); 5363b6a0d1abSMatt Jacob } 53648b8a9b1dSJustin T. Gibbs if ((lun_id != 0) || (device != NULL)) { 5365b6a0d1abSMatt Jacob if (lun_id < (CAM_SCSI2_MAXLUN-1) || phl) 53668b8a9b1dSJustin T. Gibbs lun_id++; 53678b8a9b1dSJustin T. Gibbs } 53688b8a9b1dSJustin T. Gibbs } else { 53698b8a9b1dSJustin T. Gibbs struct cam_ed *device; 53708b8a9b1dSJustin T. Gibbs 53718b8a9b1dSJustin T. Gibbs device = request_ccb->ccb_h.path->device; 53728b8a9b1dSJustin T. Gibbs 53738b8a9b1dSJustin T. Gibbs if ((device->quirk->quirks & CAM_QUIRK_NOLUNS) == 0) { 53748b8a9b1dSJustin T. Gibbs /* Try the next lun */ 5375f4322bc8SMatt Jacob if (lun_id < (CAM_SCSI2_MAXLUN-1) 53763b87a552SMatt Jacob || CAN_SRCH_HI_DENSE(device)) 53778b8a9b1dSJustin T. Gibbs lun_id++; 53788b8a9b1dSJustin T. Gibbs } 53798b8a9b1dSJustin T. Gibbs } 53808b8a9b1dSJustin T. Gibbs 5381c1c3139eSMatt Jacob /* 5382c1c3139eSMatt Jacob * Free the current request path- we're done with it. 5383c1c3139eSMatt Jacob */ 53848b8a9b1dSJustin T. Gibbs xpt_free_path(request_ccb->ccb_h.path); 53858b8a9b1dSJustin T. Gibbs 5386c1c3139eSMatt Jacob /* 5387c1c3139eSMatt Jacob * Check to see if we scan any further luns. 5388c1c3139eSMatt Jacob */ 5389c1c3139eSMatt Jacob if (lun_id == request_ccb->ccb_h.target_lun 53908b8a9b1dSJustin T. Gibbs || lun_id > scan_info->cpi->max_lun) { 5391c1c3139eSMatt Jacob int done; 53928b8a9b1dSJustin T. Gibbs 5393c1c3139eSMatt Jacob hop_again: 5394c1c3139eSMatt Jacob done = 0; 5395c1c3139eSMatt Jacob if (scan_info->cpi->hba_misc & PIM_SEQSCAN) { 5396c1c3139eSMatt Jacob scan_info->counter++; 5397c1c3139eSMatt Jacob if (scan_info->counter == 5398c1c3139eSMatt Jacob scan_info->cpi->initiator_id) { 5399c1c3139eSMatt Jacob scan_info->counter++; 5400c1c3139eSMatt Jacob } 5401c1c3139eSMatt Jacob if (scan_info->counter >= 5402c1c3139eSMatt Jacob scan_info->cpi->max_target+1) { 5403c1c3139eSMatt Jacob done = 1; 5404c1c3139eSMatt Jacob } 5405c1c3139eSMatt Jacob } else { 5406c1c3139eSMatt Jacob scan_info->counter--; 5407c1c3139eSMatt Jacob if (scan_info->counter == 0) { 5408c1c3139eSMatt Jacob done = 1; 5409c1c3139eSMatt Jacob } 5410c1c3139eSMatt Jacob } 5411c1c3139eSMatt Jacob if (done) { 54128b8a9b1dSJustin T. Gibbs xpt_free_ccb(request_ccb); 54138b8a9b1dSJustin T. Gibbs xpt_free_ccb((union ccb *)scan_info->cpi); 54148b8a9b1dSJustin T. Gibbs request_ccb = scan_info->request_ccb; 54150dd50e9bSScott Long free(scan_info, M_CAMXPT); 54168b8a9b1dSJustin T. Gibbs request_ccb->ccb_h.status = CAM_REQ_CMP; 54178b8a9b1dSJustin T. Gibbs xpt_done(request_ccb); 5418c1c3139eSMatt Jacob break; 54198b8a9b1dSJustin T. Gibbs } 54208b8a9b1dSJustin T. Gibbs 5421c1c3139eSMatt Jacob if ((scan_info->cpi->hba_misc & PIM_SEQSCAN) == 0) { 5422c1c3139eSMatt Jacob break; 5423c1c3139eSMatt Jacob } 54248b8a9b1dSJustin T. Gibbs status = xpt_create_path(&path, xpt_periph, 5425c1c3139eSMatt Jacob scan_info->request_ccb->ccb_h.path_id, 5426c1c3139eSMatt Jacob scan_info->counter, 0); 54278b8a9b1dSJustin T. Gibbs if (status != CAM_REQ_CMP) { 54288b8a9b1dSJustin T. Gibbs printf("xpt_scan_bus: xpt_create_path failed" 5429c1c3139eSMatt Jacob " with status %#x, bus scan halted\n", 54308b8a9b1dSJustin T. Gibbs status); 54318b8a9b1dSJustin T. Gibbs xpt_free_ccb(request_ccb); 5432c1c3139eSMatt Jacob xpt_free_ccb((union ccb *)scan_info->cpi); 54338b8a9b1dSJustin T. Gibbs request_ccb = scan_info->request_ccb; 54340dd50e9bSScott Long free(scan_info, M_CAMXPT); 5435c1c3139eSMatt Jacob request_ccb->ccb_h.status = status; 54368b8a9b1dSJustin T. Gibbs xpt_done(request_ccb); 5437ec04feb2SSam Leffler break; 54388b8a9b1dSJustin T. Gibbs } 54398b8a9b1dSJustin T. Gibbs xpt_setup_ccb(&request_ccb->ccb_h, path, 54408b8a9b1dSJustin T. Gibbs request_ccb->ccb_h.pinfo.priority); 54418b8a9b1dSJustin T. Gibbs request_ccb->ccb_h.func_code = XPT_SCAN_LUN; 54428b8a9b1dSJustin T. Gibbs request_ccb->ccb_h.cbfcnp = xpt_scan_bus; 54438b8a9b1dSJustin T. Gibbs request_ccb->ccb_h.ppriv_ptr0 = scan_info; 54448b8a9b1dSJustin T. Gibbs request_ccb->crcn.flags = 54458b8a9b1dSJustin T. Gibbs scan_info->request_ccb->crcn.flags; 5446c1c3139eSMatt Jacob } else { 5447c1c3139eSMatt Jacob status = xpt_create_path(&path, xpt_periph, 5448c1c3139eSMatt Jacob path_id, target_id, lun_id); 5449c1c3139eSMatt Jacob if (status != CAM_REQ_CMP) { 5450c1c3139eSMatt Jacob printf("xpt_scan_bus: xpt_create_path failed " 5451c1c3139eSMatt Jacob "with status %#x, halting LUN scan\n", 5452c1c3139eSMatt Jacob status); 5453c1c3139eSMatt Jacob goto hop_again; 54548b8a9b1dSJustin T. Gibbs } 5455c1c3139eSMatt Jacob xpt_setup_ccb(&request_ccb->ccb_h, path, 5456c1c3139eSMatt Jacob request_ccb->ccb_h.pinfo.priority); 5457c1c3139eSMatt Jacob request_ccb->ccb_h.func_code = XPT_SCAN_LUN; 5458c1c3139eSMatt Jacob request_ccb->ccb_h.cbfcnp = xpt_scan_bus; 5459c1c3139eSMatt Jacob request_ccb->ccb_h.ppriv_ptr0 = scan_info; 5460c1c3139eSMatt Jacob request_ccb->crcn.flags = 5461c1c3139eSMatt Jacob scan_info->request_ccb->crcn.flags; 5462c1c3139eSMatt Jacob } 5463c1c3139eSMatt Jacob xpt_action(request_ccb); 54648b8a9b1dSJustin T. Gibbs break; 54658b8a9b1dSJustin T. Gibbs } 54668b8a9b1dSJustin T. Gibbs default: 54678b8a9b1dSJustin T. Gibbs break; 54688b8a9b1dSJustin T. Gibbs } 54698b8a9b1dSJustin T. Gibbs } 54708b8a9b1dSJustin T. Gibbs 54718b8a9b1dSJustin T. Gibbs typedef enum { 54728b8a9b1dSJustin T. Gibbs PROBE_TUR, 54732afca7acSMatt Jacob PROBE_INQUIRY, /* this counts as DV0 for Basic Domain Validation */ 54749ec5d7cdSMatt Jacob PROBE_FULL_INQUIRY, 54758b8a9b1dSJustin T. Gibbs PROBE_MODE_SENSE, 54768b8a9b1dSJustin T. Gibbs PROBE_SERIAL_NUM, 54772afca7acSMatt Jacob PROBE_TUR_FOR_NEGOTIATION, 54782afca7acSMatt Jacob PROBE_INQUIRY_BASIC_DV1, 54792afca7acSMatt Jacob PROBE_INQUIRY_BASIC_DV2, 54802afca7acSMatt Jacob PROBE_DV_EXIT 54818b8a9b1dSJustin T. Gibbs } probe_action; 54828b8a9b1dSJustin T. Gibbs 54838b8a9b1dSJustin T. Gibbs typedef enum { 54848b8a9b1dSJustin T. Gibbs PROBE_INQUIRY_CKSUM = 0x01, 54858b8a9b1dSJustin T. Gibbs PROBE_SERIAL_CKSUM = 0x02, 54868b8a9b1dSJustin T. Gibbs PROBE_NO_ANNOUNCE = 0x04 54878b8a9b1dSJustin T. Gibbs } probe_flags; 54888b8a9b1dSJustin T. Gibbs 54898b8a9b1dSJustin T. Gibbs typedef struct { 5490e3975643SJake Burkholder TAILQ_HEAD(, ccb_hdr) request_ccbs; 54918b8a9b1dSJustin T. Gibbs probe_action action; 54928b8a9b1dSJustin T. Gibbs union ccb saved_ccb; 54938b8a9b1dSJustin T. Gibbs probe_flags flags; 54948b8a9b1dSJustin T. Gibbs MD5_CTX context; 54958b8a9b1dSJustin T. Gibbs u_int8_t digest[16]; 54968b8a9b1dSJustin T. Gibbs } probe_softc; 54978b8a9b1dSJustin T. Gibbs 54988b8a9b1dSJustin T. Gibbs static void 54998b8a9b1dSJustin T. Gibbs xpt_scan_lun(struct cam_periph *periph, struct cam_path *path, 55008b8a9b1dSJustin T. Gibbs cam_flags flags, union ccb *request_ccb) 55018b8a9b1dSJustin T. Gibbs { 550298192658SJustin T. Gibbs struct ccb_pathinq cpi; 55038b8a9b1dSJustin T. Gibbs cam_status status; 55048b8a9b1dSJustin T. Gibbs struct cam_path *new_path; 55058b8a9b1dSJustin T. Gibbs struct cam_periph *old_periph; 55068b8a9b1dSJustin T. Gibbs 55078b8a9b1dSJustin T. Gibbs CAM_DEBUG(request_ccb->ccb_h.path, CAM_DEBUG_TRACE, 55088b8a9b1dSJustin T. Gibbs ("xpt_scan_lun\n")); 55098b8a9b1dSJustin T. Gibbs 551098192658SJustin T. Gibbs xpt_setup_ccb(&cpi.ccb_h, path, /*priority*/1); 551198192658SJustin T. Gibbs cpi.ccb_h.func_code = XPT_PATH_INQ; 551298192658SJustin T. Gibbs xpt_action((union ccb *)&cpi); 551398192658SJustin T. Gibbs 551498192658SJustin T. Gibbs if (cpi.ccb_h.status != CAM_REQ_CMP) { 551598192658SJustin T. Gibbs if (request_ccb != NULL) { 551698192658SJustin T. Gibbs request_ccb->ccb_h.status = cpi.ccb_h.status; 551798192658SJustin T. Gibbs xpt_done(request_ccb); 551898192658SJustin T. Gibbs } 551998192658SJustin T. Gibbs return; 552098192658SJustin T. Gibbs } 552198192658SJustin T. Gibbs 552298192658SJustin T. Gibbs if ((cpi.hba_misc & PIM_NOINITIATOR) != 0) { 552398192658SJustin T. Gibbs /* 552498192658SJustin T. Gibbs * Can't scan the bus on an adapter that 552598192658SJustin T. Gibbs * cannot perform the initiator role. 552698192658SJustin T. Gibbs */ 552798192658SJustin T. Gibbs if (request_ccb != NULL) { 552898192658SJustin T. Gibbs request_ccb->ccb_h.status = CAM_REQ_CMP; 552998192658SJustin T. Gibbs xpt_done(request_ccb); 553098192658SJustin T. Gibbs } 553198192658SJustin T. Gibbs return; 553298192658SJustin T. Gibbs } 553398192658SJustin T. Gibbs 55348b8a9b1dSJustin T. Gibbs if (request_ccb == NULL) { 55350dd50e9bSScott Long request_ccb = malloc(sizeof(union ccb), M_CAMXPT, M_NOWAIT); 55368b8a9b1dSJustin T. Gibbs if (request_ccb == NULL) { 5537f0d9af51SMatt Jacob xpt_print(path, "xpt_scan_lun: can't allocate CCB, " 5538f0d9af51SMatt Jacob "can't continue\n"); 55398b8a9b1dSJustin T. Gibbs return; 55408b8a9b1dSJustin T. Gibbs } 55410dd50e9bSScott Long new_path = malloc(sizeof(*new_path), M_CAMXPT, M_NOWAIT); 55428b8a9b1dSJustin T. Gibbs if (new_path == NULL) { 5543f0d9af51SMatt Jacob xpt_print(path, "xpt_scan_lun: can't allocate path, " 5544f0d9af51SMatt Jacob "can't continue\n"); 55450dd50e9bSScott Long free(request_ccb, M_CAMXPT); 55468b8a9b1dSJustin T. Gibbs return; 55478b8a9b1dSJustin T. Gibbs } 5548fce84cb4SKenneth D. Merry status = xpt_compile_path(new_path, xpt_periph, 5549fce84cb4SKenneth D. Merry path->bus->path_id, 55508b8a9b1dSJustin T. Gibbs path->target->target_id, 55518b8a9b1dSJustin T. Gibbs path->device->lun_id); 55528b8a9b1dSJustin T. Gibbs 55538b8a9b1dSJustin T. Gibbs if (status != CAM_REQ_CMP) { 5554f0d9af51SMatt Jacob xpt_print(path, "xpt_scan_lun: can't compile path, " 5555f0d9af51SMatt Jacob "can't continue\n"); 55560dd50e9bSScott Long free(request_ccb, M_CAMXPT); 55570dd50e9bSScott Long free(new_path, M_CAMXPT); 55588b8a9b1dSJustin T. Gibbs return; 55598b8a9b1dSJustin T. Gibbs } 55608b8a9b1dSJustin T. Gibbs xpt_setup_ccb(&request_ccb->ccb_h, new_path, /*priority*/ 1); 55618b8a9b1dSJustin T. Gibbs request_ccb->ccb_h.cbfcnp = xptscandone; 55628b8a9b1dSJustin T. Gibbs request_ccb->ccb_h.func_code = XPT_SCAN_LUN; 55638b8a9b1dSJustin T. Gibbs request_ccb->crcn.flags = flags; 55648b8a9b1dSJustin T. Gibbs } 55658b8a9b1dSJustin T. Gibbs 55668b8a9b1dSJustin T. Gibbs if ((old_periph = cam_periph_find(path, "probe")) != NULL) { 55678b8a9b1dSJustin T. Gibbs probe_softc *softc; 55688b8a9b1dSJustin T. Gibbs 55698b8a9b1dSJustin T. Gibbs softc = (probe_softc *)old_periph->softc; 55708b8a9b1dSJustin T. Gibbs TAILQ_INSERT_TAIL(&softc->request_ccbs, &request_ccb->ccb_h, 55718b8a9b1dSJustin T. Gibbs periph_links.tqe); 55728b8a9b1dSJustin T. Gibbs } else { 5573ee9c90c7SKenneth D. Merry status = cam_periph_alloc(proberegister, NULL, probecleanup, 55748b8a9b1dSJustin T. Gibbs probestart, "probe", 55758b8a9b1dSJustin T. Gibbs CAM_PERIPH_BIO, 55768b8a9b1dSJustin T. Gibbs request_ccb->ccb_h.path, NULL, 0, 55778b8a9b1dSJustin T. Gibbs request_ccb); 55788b8a9b1dSJustin T. Gibbs 55798b8a9b1dSJustin T. Gibbs if (status != CAM_REQ_CMP) { 5580f0d9af51SMatt Jacob xpt_print(path, "xpt_scan_lun: cam_alloc_periph " 5581f0d9af51SMatt Jacob "returned an error, can't continue probe\n"); 55828b8a9b1dSJustin T. Gibbs request_ccb->ccb_h.status = status; 55838b8a9b1dSJustin T. Gibbs xpt_done(request_ccb); 55848b8a9b1dSJustin T. Gibbs } 55858b8a9b1dSJustin T. Gibbs } 55868b8a9b1dSJustin T. Gibbs } 55878b8a9b1dSJustin T. Gibbs 55888b8a9b1dSJustin T. Gibbs static void 55898b8a9b1dSJustin T. Gibbs xptscandone(struct cam_periph *periph, union ccb *done_ccb) 55908b8a9b1dSJustin T. Gibbs { 55918b8a9b1dSJustin T. Gibbs xpt_release_path(done_ccb->ccb_h.path); 55920dd50e9bSScott Long free(done_ccb->ccb_h.path, M_CAMXPT); 55930dd50e9bSScott Long free(done_ccb, M_CAMXPT); 55948b8a9b1dSJustin T. Gibbs } 55958b8a9b1dSJustin T. Gibbs 55968b8a9b1dSJustin T. Gibbs static cam_status 55978b8a9b1dSJustin T. Gibbs proberegister(struct cam_periph *periph, void *arg) 55988b8a9b1dSJustin T. Gibbs { 559987cfaf0eSJustin T. Gibbs union ccb *request_ccb; /* CCB representing the probe request */ 560000b08b94SMatt Jacob cam_status status; 56018b8a9b1dSJustin T. Gibbs probe_softc *softc; 56028b8a9b1dSJustin T. Gibbs 560387cfaf0eSJustin T. Gibbs request_ccb = (union ccb *)arg; 56048b8a9b1dSJustin T. Gibbs if (periph == NULL) { 56058b8a9b1dSJustin T. Gibbs printf("proberegister: periph was NULL!!\n"); 56068b8a9b1dSJustin T. Gibbs return(CAM_REQ_CMP_ERR); 56078b8a9b1dSJustin T. Gibbs } 56088b8a9b1dSJustin T. Gibbs 560987cfaf0eSJustin T. Gibbs if (request_ccb == NULL) { 5610434bbf6eSJustin T. Gibbs printf("proberegister: no probe CCB, " 5611434bbf6eSJustin T. Gibbs "can't register device\n"); 56128b8a9b1dSJustin T. Gibbs return(CAM_REQ_CMP_ERR); 56138b8a9b1dSJustin T. Gibbs } 56148b8a9b1dSJustin T. Gibbs 56150dd50e9bSScott Long softc = (probe_softc *)malloc(sizeof(*softc), M_CAMXPT, M_NOWAIT); 56168b8a9b1dSJustin T. Gibbs 56178b8a9b1dSJustin T. Gibbs if (softc == NULL) { 56188b8a9b1dSJustin T. Gibbs printf("proberegister: Unable to probe new device. " 56198b8a9b1dSJustin T. Gibbs "Unable to allocate softc\n"); 56208b8a9b1dSJustin T. Gibbs return(CAM_REQ_CMP_ERR); 56218b8a9b1dSJustin T. Gibbs } 56228b8a9b1dSJustin T. Gibbs TAILQ_INIT(&softc->request_ccbs); 562387cfaf0eSJustin T. Gibbs TAILQ_INSERT_TAIL(&softc->request_ccbs, &request_ccb->ccb_h, 562487cfaf0eSJustin T. Gibbs periph_links.tqe); 56258b8a9b1dSJustin T. Gibbs softc->flags = 0; 56268b8a9b1dSJustin T. Gibbs periph->softc = softc; 562700b08b94SMatt Jacob status = cam_periph_acquire(periph); 562800b08b94SMatt Jacob if (status != CAM_REQ_CMP) { 562900b08b94SMatt Jacob return (status); 563000b08b94SMatt Jacob } 563100b08b94SMatt Jacob 563200b08b94SMatt Jacob 563387cfaf0eSJustin T. Gibbs /* 563487cfaf0eSJustin T. Gibbs * Ensure we've waited at least a bus settle 563587cfaf0eSJustin T. Gibbs * delay before attempting to probe the device. 5636cda9006fSMatt Jacob * For HBAs that don't do bus resets, this won't make a difference. 563787cfaf0eSJustin T. Gibbs */ 563887cfaf0eSJustin T. Gibbs cam_periph_freeze_after_event(periph, &periph->path->bus->last_reset, 56393a937198SBrooks Davis scsi_delay); 56408b8a9b1dSJustin T. Gibbs probeschedule(periph); 56418b8a9b1dSJustin T. Gibbs return(CAM_REQ_CMP); 56428b8a9b1dSJustin T. Gibbs } 56438b8a9b1dSJustin T. Gibbs 56448b8a9b1dSJustin T. Gibbs static void 56458b8a9b1dSJustin T. Gibbs probeschedule(struct cam_periph *periph) 56468b8a9b1dSJustin T. Gibbs { 564787cfaf0eSJustin T. Gibbs struct ccb_pathinq cpi; 56488b8a9b1dSJustin T. Gibbs union ccb *ccb; 56498b8a9b1dSJustin T. Gibbs probe_softc *softc; 56508b8a9b1dSJustin T. Gibbs 56518b8a9b1dSJustin T. Gibbs softc = (probe_softc *)periph->softc; 56528b8a9b1dSJustin T. Gibbs ccb = (union ccb *)TAILQ_FIRST(&softc->request_ccbs); 56538b8a9b1dSJustin T. Gibbs 565487cfaf0eSJustin T. Gibbs xpt_setup_ccb(&cpi.ccb_h, periph->path, /*priority*/1); 565587cfaf0eSJustin T. Gibbs cpi.ccb_h.func_code = XPT_PATH_INQ; 565687cfaf0eSJustin T. Gibbs xpt_action((union ccb *)&cpi); 565787cfaf0eSJustin T. Gibbs 56588b8a9b1dSJustin T. Gibbs /* 56598b8a9b1dSJustin T. Gibbs * If a device has gone away and another device, or the same one, 56608b8a9b1dSJustin T. Gibbs * is back in the same place, it should have a unit attention 56618b8a9b1dSJustin T. Gibbs * condition pending. It will not report the unit attention in 56628b8a9b1dSJustin T. Gibbs * response to an inquiry, which may leave invalid transfer 56638b8a9b1dSJustin T. Gibbs * negotiations in effect. The TUR will reveal the unit attention 56648b8a9b1dSJustin T. Gibbs * condition. Only send the TUR for lun 0, since some devices 56658b8a9b1dSJustin T. Gibbs * will get confused by commands other than inquiry to non-existent 56668b8a9b1dSJustin T. Gibbs * luns. If you think a device has gone away start your scan from 56678b8a9b1dSJustin T. Gibbs * lun 0. This will insure that any bogus transfer settings are 56688b8a9b1dSJustin T. Gibbs * invalidated. 566987cfaf0eSJustin T. Gibbs * 567087cfaf0eSJustin T. Gibbs * If we haven't seen the device before and the controller supports 567187cfaf0eSJustin T. Gibbs * some kind of transfer negotiation, negotiate with the first 567287cfaf0eSJustin T. Gibbs * sent command if no bus reset was performed at startup. This 567387cfaf0eSJustin T. Gibbs * ensures that the device is not confused by transfer negotiation 567487cfaf0eSJustin T. Gibbs * settings left over by loader or BIOS action. 56758b8a9b1dSJustin T. Gibbs */ 56768b8a9b1dSJustin T. Gibbs if (((ccb->ccb_h.path->device->flags & CAM_DEV_UNCONFIGURED) == 0) 567787cfaf0eSJustin T. Gibbs && (ccb->ccb_h.target_lun == 0)) { 56788b8a9b1dSJustin T. Gibbs softc->action = PROBE_TUR; 567987cfaf0eSJustin T. Gibbs } else if ((cpi.hba_inquiry & (PI_WIDE_32|PI_WIDE_16|PI_SDTR_ABLE)) != 0 568087cfaf0eSJustin T. Gibbs && (cpi.hba_misc & PIM_NOBUSRESET) != 0) { 568187cfaf0eSJustin T. Gibbs proberequestdefaultnegotiation(periph); 56828b8a9b1dSJustin T. Gibbs softc->action = PROBE_INQUIRY; 568387cfaf0eSJustin T. Gibbs } else { 568487cfaf0eSJustin T. Gibbs softc->action = PROBE_INQUIRY; 568587cfaf0eSJustin T. Gibbs } 56868b8a9b1dSJustin T. Gibbs 56878b8a9b1dSJustin T. Gibbs if (ccb->crcn.flags & CAM_EXPECT_INQ_CHANGE) 56888b8a9b1dSJustin T. Gibbs softc->flags |= PROBE_NO_ANNOUNCE; 56898b8a9b1dSJustin T. Gibbs else 56908b8a9b1dSJustin T. Gibbs softc->flags &= ~PROBE_NO_ANNOUNCE; 56918b8a9b1dSJustin T. Gibbs 56928b8a9b1dSJustin T. Gibbs xpt_schedule(periph, ccb->ccb_h.pinfo.priority); 56938b8a9b1dSJustin T. Gibbs } 56948b8a9b1dSJustin T. Gibbs 56958b8a9b1dSJustin T. Gibbs static void 56968b8a9b1dSJustin T. Gibbs probestart(struct cam_periph *periph, union ccb *start_ccb) 56978b8a9b1dSJustin T. Gibbs { 56988b8a9b1dSJustin T. Gibbs /* Probe the device that our peripheral driver points to */ 56998b8a9b1dSJustin T. Gibbs struct ccb_scsiio *csio; 57008b8a9b1dSJustin T. Gibbs probe_softc *softc; 57018b8a9b1dSJustin T. Gibbs 57028b8a9b1dSJustin T. Gibbs CAM_DEBUG(start_ccb->ccb_h.path, CAM_DEBUG_TRACE, ("probestart\n")); 57038b8a9b1dSJustin T. Gibbs 57048b8a9b1dSJustin T. Gibbs softc = (probe_softc *)periph->softc; 57058b8a9b1dSJustin T. Gibbs csio = &start_ccb->csio; 57068b8a9b1dSJustin T. Gibbs 57078b8a9b1dSJustin T. Gibbs switch (softc->action) { 57088b8a9b1dSJustin T. Gibbs case PROBE_TUR: 57098b8a9b1dSJustin T. Gibbs case PROBE_TUR_FOR_NEGOTIATION: 57102afca7acSMatt Jacob case PROBE_DV_EXIT: 57118b8a9b1dSJustin T. Gibbs { 57128b8a9b1dSJustin T. Gibbs scsi_test_unit_ready(csio, 57138b8a9b1dSJustin T. Gibbs /*retries*/4, 57148b8a9b1dSJustin T. Gibbs probedone, 57158b8a9b1dSJustin T. Gibbs MSG_SIMPLE_Q_TAG, 57168b8a9b1dSJustin T. Gibbs SSD_FULL_SIZE, 5717e471e974SJustin T. Gibbs /*timeout*/60000); 57188b8a9b1dSJustin T. Gibbs break; 57198b8a9b1dSJustin T. Gibbs } 57208b8a9b1dSJustin T. Gibbs case PROBE_INQUIRY: 57219ec5d7cdSMatt Jacob case PROBE_FULL_INQUIRY: 57222afca7acSMatt Jacob case PROBE_INQUIRY_BASIC_DV1: 57232afca7acSMatt Jacob case PROBE_INQUIRY_BASIC_DV2: 57248b8a9b1dSJustin T. Gibbs { 5725c19cf05dSMatt Jacob u_int inquiry_len; 57268b8a9b1dSJustin T. Gibbs struct scsi_inquiry_data *inq_buf; 57278b8a9b1dSJustin T. Gibbs 57288b8a9b1dSJustin T. Gibbs inq_buf = &periph->path->device->inq_data; 57292afca7acSMatt Jacob 57308b8a9b1dSJustin T. Gibbs /* 57318b8a9b1dSJustin T. Gibbs * If the device is currently configured, we calculate an 57328b8a9b1dSJustin T. Gibbs * MD5 checksum of the inquiry data, and if the serial number 57338b8a9b1dSJustin T. Gibbs * length is greater than 0, add the serial number data 57348b8a9b1dSJustin T. Gibbs * into the checksum as well. Once the inquiry and the 57358b8a9b1dSJustin T. Gibbs * serial number check finish, we attempt to figure out 57368b8a9b1dSJustin T. Gibbs * whether we still have the same device. 57378b8a9b1dSJustin T. Gibbs */ 57388b8a9b1dSJustin T. Gibbs if ((periph->path->device->flags & CAM_DEV_UNCONFIGURED) == 0) { 57398b8a9b1dSJustin T. Gibbs 57408b8a9b1dSJustin T. Gibbs MD5Init(&softc->context); 57418b8a9b1dSJustin T. Gibbs MD5Update(&softc->context, (unsigned char *)inq_buf, 57428b8a9b1dSJustin T. Gibbs sizeof(struct scsi_inquiry_data)); 57438b8a9b1dSJustin T. Gibbs softc->flags |= PROBE_INQUIRY_CKSUM; 57448b8a9b1dSJustin T. Gibbs if (periph->path->device->serial_num_len > 0) { 57458b8a9b1dSJustin T. Gibbs MD5Update(&softc->context, 57468b8a9b1dSJustin T. Gibbs periph->path->device->serial_num, 57478b8a9b1dSJustin T. Gibbs periph->path->device->serial_num_len); 57488b8a9b1dSJustin T. Gibbs softc->flags |= PROBE_SERIAL_CKSUM; 57498b8a9b1dSJustin T. Gibbs } 57508b8a9b1dSJustin T. Gibbs MD5Final(softc->digest, &softc->context); 57518b8a9b1dSJustin T. Gibbs } 57528b8a9b1dSJustin T. Gibbs 57539ec5d7cdSMatt Jacob if (softc->action == PROBE_INQUIRY) 5754c19cf05dSMatt Jacob inquiry_len = SHORT_INQUIRY_LENGTH; 5755c19cf05dSMatt Jacob else 57562afca7acSMatt Jacob inquiry_len = SID_ADDITIONAL_LENGTH(inq_buf); 5757709a936fSJustin T. Gibbs 5758709a936fSJustin T. Gibbs /* 5759709a936fSJustin T. Gibbs * Some parallel SCSI devices fail to send an 5760709a936fSJustin T. Gibbs * ignore wide residue message when dealing with 5761709a936fSJustin T. Gibbs * odd length inquiry requests. Round up to be 5762709a936fSJustin T. Gibbs * safe. 5763709a936fSJustin T. Gibbs */ 5764709a936fSJustin T. Gibbs inquiry_len = roundup2(inquiry_len, 2); 57659ec5d7cdSMatt Jacob 57662afca7acSMatt Jacob if (softc->action == PROBE_INQUIRY_BASIC_DV1 57672afca7acSMatt Jacob || softc->action == PROBE_INQUIRY_BASIC_DV2) { 57680dd50e9bSScott Long inq_buf = malloc(inquiry_len, M_CAMXPT, M_NOWAIT); 57692afca7acSMatt Jacob } 57702afca7acSMatt Jacob if (inq_buf == NULL) { 5771f0d9af51SMatt Jacob xpt_print(periph->path, "malloc failure- skipping Basic" 5772f0d9af51SMatt Jacob "Domain Validation\n"); 57732afca7acSMatt Jacob softc->action = PROBE_DV_EXIT; 57742afca7acSMatt Jacob scsi_test_unit_ready(csio, 57752afca7acSMatt Jacob /*retries*/4, 57762afca7acSMatt Jacob probedone, 57772afca7acSMatt Jacob MSG_SIMPLE_Q_TAG, 57782afca7acSMatt Jacob SSD_FULL_SIZE, 57792afca7acSMatt Jacob /*timeout*/60000); 57802afca7acSMatt Jacob break; 57812afca7acSMatt Jacob } 57828b8a9b1dSJustin T. Gibbs scsi_inquiry(csio, 57838b8a9b1dSJustin T. Gibbs /*retries*/4, 57848b8a9b1dSJustin T. Gibbs probedone, 57858b8a9b1dSJustin T. Gibbs MSG_SIMPLE_Q_TAG, 57868b8a9b1dSJustin T. Gibbs (u_int8_t *)inq_buf, 5787c19cf05dSMatt Jacob inquiry_len, 57888b8a9b1dSJustin T. Gibbs /*evpd*/FALSE, 57898b8a9b1dSJustin T. Gibbs /*page_code*/0, 57908b8a9b1dSJustin T. Gibbs SSD_MIN_SIZE, 5791e471e974SJustin T. Gibbs /*timeout*/60 * 1000); 57928b8a9b1dSJustin T. Gibbs break; 57938b8a9b1dSJustin T. Gibbs } 57948b8a9b1dSJustin T. Gibbs case PROBE_MODE_SENSE: 57958b8a9b1dSJustin T. Gibbs { 57968b8a9b1dSJustin T. Gibbs void *mode_buf; 57978b8a9b1dSJustin T. Gibbs int mode_buf_len; 57988b8a9b1dSJustin T. Gibbs 57998b8a9b1dSJustin T. Gibbs mode_buf_len = sizeof(struct scsi_mode_header_6) 58008b8a9b1dSJustin T. Gibbs + sizeof(struct scsi_mode_blk_desc) 58018b8a9b1dSJustin T. Gibbs + sizeof(struct scsi_control_page); 58020dd50e9bSScott Long mode_buf = malloc(mode_buf_len, M_CAMXPT, M_NOWAIT); 58038b8a9b1dSJustin T. Gibbs if (mode_buf != NULL) { 58048b8a9b1dSJustin T. Gibbs scsi_mode_sense(csio, 58058b8a9b1dSJustin T. Gibbs /*retries*/4, 58068b8a9b1dSJustin T. Gibbs probedone, 58078b8a9b1dSJustin T. Gibbs MSG_SIMPLE_Q_TAG, 58088b8a9b1dSJustin T. Gibbs /*dbd*/FALSE, 58098b8a9b1dSJustin T. Gibbs SMS_PAGE_CTRL_CURRENT, 58108b8a9b1dSJustin T. Gibbs SMS_CONTROL_MODE_PAGE, 58118b8a9b1dSJustin T. Gibbs mode_buf, 58128b8a9b1dSJustin T. Gibbs mode_buf_len, 58138b8a9b1dSJustin T. Gibbs SSD_FULL_SIZE, 5814e471e974SJustin T. Gibbs /*timeout*/60000); 58158b8a9b1dSJustin T. Gibbs break; 58168b8a9b1dSJustin T. Gibbs } 5817f0d9af51SMatt Jacob xpt_print(periph->path, "Unable to mode sense control page - " 5818f0d9af51SMatt Jacob "malloc failure\n"); 58198b8a9b1dSJustin T. Gibbs softc->action = PROBE_SERIAL_NUM; 58208b8a9b1dSJustin T. Gibbs } 582107c6eac9SPoul-Henning Kamp /* FALLTHROUGH */ 58228b8a9b1dSJustin T. Gibbs case PROBE_SERIAL_NUM: 58238b8a9b1dSJustin T. Gibbs { 58248b8a9b1dSJustin T. Gibbs struct scsi_vpd_unit_serial_number *serial_buf; 58258b8a9b1dSJustin T. Gibbs struct cam_ed* device; 58268b8a9b1dSJustin T. Gibbs 58278b8a9b1dSJustin T. Gibbs serial_buf = NULL; 58288b8a9b1dSJustin T. Gibbs device = periph->path->device; 58298b8a9b1dSJustin T. Gibbs device->serial_num = NULL; 58308b8a9b1dSJustin T. Gibbs device->serial_num_len = 0; 58318b8a9b1dSJustin T. Gibbs 58328b8a9b1dSJustin T. Gibbs if ((device->quirk->quirks & CAM_QUIRK_NOSERIAL) == 0) 58338b8a9b1dSJustin T. Gibbs serial_buf = (struct scsi_vpd_unit_serial_number *) 58340dd50e9bSScott Long malloc(sizeof(*serial_buf), M_CAMXPT, 58355417ec4dSDavid Malone M_NOWAIT | M_ZERO); 58368b8a9b1dSJustin T. Gibbs 58378b8a9b1dSJustin T. Gibbs if (serial_buf != NULL) { 58388b8a9b1dSJustin T. Gibbs scsi_inquiry(csio, 58398b8a9b1dSJustin T. Gibbs /*retries*/4, 58408b8a9b1dSJustin T. Gibbs probedone, 58418b8a9b1dSJustin T. Gibbs MSG_SIMPLE_Q_TAG, 58428b8a9b1dSJustin T. Gibbs (u_int8_t *)serial_buf, 58438b8a9b1dSJustin T. Gibbs sizeof(*serial_buf), 58448b8a9b1dSJustin T. Gibbs /*evpd*/TRUE, 58458b8a9b1dSJustin T. Gibbs SVPD_UNIT_SERIAL_NUMBER, 58468b8a9b1dSJustin T. Gibbs SSD_MIN_SIZE, 5847e471e974SJustin T. Gibbs /*timeout*/60 * 1000); 58488b8a9b1dSJustin T. Gibbs break; 58498b8a9b1dSJustin T. Gibbs } 58508b8a9b1dSJustin T. Gibbs /* 58518b8a9b1dSJustin T. Gibbs * We'll have to do without, let our probedone 58528b8a9b1dSJustin T. Gibbs * routine finish up for us. 58538b8a9b1dSJustin T. Gibbs */ 58548b8a9b1dSJustin T. Gibbs start_ccb->csio.data_ptr = NULL; 58558b8a9b1dSJustin T. Gibbs probedone(periph, start_ccb); 58568b8a9b1dSJustin T. Gibbs return; 58578b8a9b1dSJustin T. Gibbs } 58588b8a9b1dSJustin T. Gibbs } 58598b8a9b1dSJustin T. Gibbs xpt_action(start_ccb); 58608b8a9b1dSJustin T. Gibbs } 58618b8a9b1dSJustin T. Gibbs 58628b8a9b1dSJustin T. Gibbs static void 586387cfaf0eSJustin T. Gibbs proberequestdefaultnegotiation(struct cam_periph *periph) 586487cfaf0eSJustin T. Gibbs { 586587cfaf0eSJustin T. Gibbs struct ccb_trans_settings cts; 586687cfaf0eSJustin T. Gibbs 586787cfaf0eSJustin T. Gibbs xpt_setup_ccb(&cts.ccb_h, periph->path, /*priority*/1); 586887cfaf0eSJustin T. Gibbs cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS; 58693393f8daSKenneth D. Merry cts.type = CTS_TYPE_USER_SETTINGS; 587087cfaf0eSJustin T. Gibbs xpt_action((union ccb *)&cts); 58710a480cf0SMatt Jacob if ((cts.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 58720a480cf0SMatt Jacob return; 58730a480cf0SMatt Jacob } 587487cfaf0eSJustin T. Gibbs cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS; 58753393f8daSKenneth D. Merry cts.type = CTS_TYPE_CURRENT_SETTINGS; 587687cfaf0eSJustin T. Gibbs xpt_action((union ccb *)&cts); 587787cfaf0eSJustin T. Gibbs } 587887cfaf0eSJustin T. Gibbs 58792afca7acSMatt Jacob /* 58802afca7acSMatt Jacob * Backoff Negotiation Code- only pertinent for SPI devices. 58812afca7acSMatt Jacob */ 58822afca7acSMatt Jacob static int 58832afca7acSMatt Jacob proberequestbackoff(struct cam_periph *periph, struct cam_ed *device) 58842afca7acSMatt Jacob { 58852afca7acSMatt Jacob struct ccb_trans_settings cts; 58862afca7acSMatt Jacob struct ccb_trans_settings_spi *spi; 58872afca7acSMatt Jacob 58882afca7acSMatt Jacob memset(&cts, 0, sizeof (cts)); 58892afca7acSMatt Jacob xpt_setup_ccb(&cts.ccb_h, periph->path, /*priority*/1); 58902afca7acSMatt Jacob cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS; 58912afca7acSMatt Jacob cts.type = CTS_TYPE_CURRENT_SETTINGS; 58922afca7acSMatt Jacob xpt_action((union ccb *)&cts); 58932afca7acSMatt Jacob if ((cts.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 58942afca7acSMatt Jacob if (bootverbose) { 5895f0d9af51SMatt Jacob xpt_print(periph->path, 5896f0d9af51SMatt Jacob "failed to get current device settings\n"); 58972afca7acSMatt Jacob } 58982afca7acSMatt Jacob return (0); 58992afca7acSMatt Jacob } 59002afca7acSMatt Jacob if (cts.transport != XPORT_SPI) { 59012afca7acSMatt Jacob if (bootverbose) { 5902f0d9af51SMatt Jacob xpt_print(periph->path, "not SPI transport\n"); 59032afca7acSMatt Jacob } 59042afca7acSMatt Jacob return (0); 59052afca7acSMatt Jacob } 59062afca7acSMatt Jacob spi = &cts.xport_specific.spi; 59072afca7acSMatt Jacob 59082afca7acSMatt Jacob /* 59092afca7acSMatt Jacob * We cannot renegotiate sync rate if we don't have one. 59102afca7acSMatt Jacob */ 59112afca7acSMatt Jacob if ((spi->valid & CTS_SPI_VALID_SYNC_RATE) == 0) { 59122afca7acSMatt Jacob if (bootverbose) { 5913f0d9af51SMatt Jacob xpt_print(periph->path, "no sync rate known\n"); 59142afca7acSMatt Jacob } 59152afca7acSMatt Jacob return (0); 59162afca7acSMatt Jacob } 59172afca7acSMatt Jacob 59182afca7acSMatt Jacob /* 59192afca7acSMatt Jacob * We'll assert that we don't have to touch PPR options- the 59202afca7acSMatt Jacob * SIM will see what we do with period and offset and adjust 59212afca7acSMatt Jacob * the PPR options as appropriate. 59222afca7acSMatt Jacob */ 59232afca7acSMatt Jacob 59242afca7acSMatt Jacob /* 59252afca7acSMatt Jacob * A sync rate with unknown or zero offset is nonsensical. 59262afca7acSMatt Jacob * A sync period of zero means Async. 59272afca7acSMatt Jacob */ 59282afca7acSMatt Jacob if ((spi->valid & CTS_SPI_VALID_SYNC_OFFSET) == 0 59292afca7acSMatt Jacob || spi->sync_offset == 0 || spi->sync_period == 0) { 59302afca7acSMatt Jacob if (bootverbose) { 5931f0d9af51SMatt Jacob xpt_print(periph->path, "no sync rate available\n"); 59322afca7acSMatt Jacob } 59332afca7acSMatt Jacob return (0); 59342afca7acSMatt Jacob } 59352afca7acSMatt Jacob 59362afca7acSMatt Jacob if (device->flags & CAM_DEV_DV_HIT_BOTTOM) { 59372afca7acSMatt Jacob CAM_DEBUG(periph->path, CAM_DEBUG_INFO, 59382afca7acSMatt Jacob ("hit async: giving up on DV\n")); 59392afca7acSMatt Jacob return (0); 59402afca7acSMatt Jacob } 59412afca7acSMatt Jacob 59422afca7acSMatt Jacob 59432afca7acSMatt Jacob /* 59442afca7acSMatt Jacob * Jump sync_period up by one, but stop at 5MHz and fall back to Async. 59452afca7acSMatt Jacob * We don't try to remember 'last' settings to see if the SIM actually 59462afca7acSMatt Jacob * gets into the speed we want to set. We check on the SIM telling 59472afca7acSMatt Jacob * us that a requested speed is bad, but otherwise don't try and 59482afca7acSMatt Jacob * check the speed due to the asynchronous and handshake nature 59492afca7acSMatt Jacob * of speed setting. 59502afca7acSMatt Jacob */ 59512afca7acSMatt Jacob spi->valid = CTS_SPI_VALID_SYNC_RATE | CTS_SPI_VALID_SYNC_OFFSET; 59522afca7acSMatt Jacob for (;;) { 59532afca7acSMatt Jacob spi->sync_period++; 59542afca7acSMatt Jacob if (spi->sync_period >= 0xf) { 59552afca7acSMatt Jacob spi->sync_period = 0; 59562afca7acSMatt Jacob spi->sync_offset = 0; 59572afca7acSMatt Jacob CAM_DEBUG(periph->path, CAM_DEBUG_INFO, 59582afca7acSMatt Jacob ("setting to async for DV\n")); 59592afca7acSMatt Jacob /* 59602afca7acSMatt Jacob * Once we hit async, we don't want to try 59612afca7acSMatt Jacob * any more settings. 59622afca7acSMatt Jacob */ 59632afca7acSMatt Jacob device->flags |= CAM_DEV_DV_HIT_BOTTOM; 59642afca7acSMatt Jacob } else if (bootverbose) { 59652afca7acSMatt Jacob CAM_DEBUG(periph->path, CAM_DEBUG_INFO, 59662afca7acSMatt Jacob ("DV: period 0x%x\n", spi->sync_period)); 59672afca7acSMatt Jacob printf("setting period to 0x%x\n", spi->sync_period); 59682afca7acSMatt Jacob } 59692afca7acSMatt Jacob cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS; 59702afca7acSMatt Jacob cts.type = CTS_TYPE_CURRENT_SETTINGS; 59712afca7acSMatt Jacob xpt_action((union ccb *)&cts); 59722afca7acSMatt Jacob if ((cts.ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) { 59732afca7acSMatt Jacob break; 59742afca7acSMatt Jacob } 59752afca7acSMatt Jacob CAM_DEBUG(periph->path, CAM_DEBUG_INFO, 59762afca7acSMatt Jacob ("DV: failed to set period 0x%x\n", spi->sync_period)); 59772afca7acSMatt Jacob if (spi->sync_period == 0) { 59782afca7acSMatt Jacob return (0); 59792afca7acSMatt Jacob } 59802afca7acSMatt Jacob } 59812afca7acSMatt Jacob return (1); 59822afca7acSMatt Jacob } 59832afca7acSMatt Jacob 598487cfaf0eSJustin T. Gibbs static void 59858b8a9b1dSJustin T. Gibbs probedone(struct cam_periph *periph, union ccb *done_ccb) 59868b8a9b1dSJustin T. Gibbs { 59878b8a9b1dSJustin T. Gibbs probe_softc *softc; 59888b8a9b1dSJustin T. Gibbs struct cam_path *path; 59898b8a9b1dSJustin T. Gibbs u_int32_t priority; 59908b8a9b1dSJustin T. Gibbs 59918b8a9b1dSJustin T. Gibbs CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_TRACE, ("probedone\n")); 59928b8a9b1dSJustin T. Gibbs 59938b8a9b1dSJustin T. Gibbs softc = (probe_softc *)periph->softc; 59948b8a9b1dSJustin T. Gibbs path = done_ccb->ccb_h.path; 59958b8a9b1dSJustin T. Gibbs priority = done_ccb->ccb_h.pinfo.priority; 59968b8a9b1dSJustin T. Gibbs 59978b8a9b1dSJustin T. Gibbs switch (softc->action) { 59988b8a9b1dSJustin T. Gibbs case PROBE_TUR: 59998b8a9b1dSJustin T. Gibbs { 60008b8a9b1dSJustin T. Gibbs if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 60018b8a9b1dSJustin T. Gibbs 60028b8a9b1dSJustin T. Gibbs if (cam_periph_error(done_ccb, 0, 60038b8a9b1dSJustin T. Gibbs SF_NO_PRINT, NULL) == ERESTART) 60048b8a9b1dSJustin T. Gibbs return; 60058b8a9b1dSJustin T. Gibbs else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) 60068b8a9b1dSJustin T. Gibbs /* Don't wedge the queue */ 60072cefde5fSJustin T. Gibbs xpt_release_devq(done_ccb->ccb_h.path, 60082cefde5fSJustin T. Gibbs /*count*/1, 60098b8a9b1dSJustin T. Gibbs /*run_queue*/TRUE); 60108b8a9b1dSJustin T. Gibbs } 60118b8a9b1dSJustin T. Gibbs softc->action = PROBE_INQUIRY; 60128b8a9b1dSJustin T. Gibbs xpt_release_ccb(done_ccb); 60138b8a9b1dSJustin T. Gibbs xpt_schedule(periph, priority); 60148b8a9b1dSJustin T. Gibbs return; 60158b8a9b1dSJustin T. Gibbs } 60168b8a9b1dSJustin T. Gibbs case PROBE_INQUIRY: 60179ec5d7cdSMatt Jacob case PROBE_FULL_INQUIRY: 60188b8a9b1dSJustin T. Gibbs { 60198b8a9b1dSJustin T. Gibbs if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) { 60208b8a9b1dSJustin T. Gibbs struct scsi_inquiry_data *inq_buf; 60218b8a9b1dSJustin T. Gibbs u_int8_t periph_qual; 60228b8a9b1dSJustin T. Gibbs 602387cfaf0eSJustin T. Gibbs path->device->flags |= CAM_DEV_INQUIRY_DATA_VALID; 60248b8a9b1dSJustin T. Gibbs inq_buf = &path->device->inq_data; 60258b8a9b1dSJustin T. Gibbs 60268b8a9b1dSJustin T. Gibbs periph_qual = SID_QUAL(inq_buf); 60279ec5d7cdSMatt Jacob 6028c19cf05dSMatt Jacob switch(periph_qual) { 6029c19cf05dSMatt Jacob case SID_QUAL_LU_CONNECTED: 6030c19cf05dSMatt Jacob { 60319a4f1a4dSJustin T. Gibbs u_int8_t len; 6032c19cf05dSMatt Jacob 60339ec5d7cdSMatt Jacob /* 6034c19cf05dSMatt Jacob * We conservatively request only 6035c19cf05dSMatt Jacob * SHORT_INQUIRY_LEN bytes of inquiry 6036c19cf05dSMatt Jacob * information during our first try 6037c19cf05dSMatt Jacob * at sending an INQUIRY. If the device 6038c19cf05dSMatt Jacob * has more information to give, 6039c19cf05dSMatt Jacob * perform a second request specifying 6040c19cf05dSMatt Jacob * the amount of information the device 6041c19cf05dSMatt Jacob * is willing to give. 60429ec5d7cdSMatt Jacob */ 60439a4f1a4dSJustin T. Gibbs len = inq_buf->additional_length 60449a4f1a4dSJustin T. Gibbs + offsetof(struct scsi_inquiry_data, 60459a4f1a4dSJustin T. Gibbs additional_length) + 1; 6046c19cf05dSMatt Jacob if (softc->action == PROBE_INQUIRY 60479a4f1a4dSJustin T. Gibbs && len > SHORT_INQUIRY_LENGTH) { 60485cd818b1SKenneth D. Merry softc->action = PROBE_FULL_INQUIRY; 60499ec5d7cdSMatt Jacob xpt_release_ccb(done_ccb); 60509ec5d7cdSMatt Jacob xpt_schedule(periph, priority); 60519ec5d7cdSMatt Jacob return; 60529ec5d7cdSMatt Jacob } 60539ec5d7cdSMatt Jacob 60548b8a9b1dSJustin T. Gibbs xpt_find_quirk(path->device); 60558b8a9b1dSJustin T. Gibbs 60563393f8daSKenneth D. Merry xpt_devise_transport(path); 60574e359f5aSMatt Jacob if (INQ_DATA_TQ_ENABLED(inq_buf)) 60585cd818b1SKenneth D. Merry softc->action = PROBE_MODE_SENSE; 60598b8a9b1dSJustin T. Gibbs else 60605cd818b1SKenneth D. Merry softc->action = PROBE_SERIAL_NUM; 60618b8a9b1dSJustin T. Gibbs 60625cd818b1SKenneth D. Merry path->device->flags &= ~CAM_DEV_UNCONFIGURED; 60638b8a9b1dSJustin T. Gibbs 60648b8a9b1dSJustin T. Gibbs xpt_release_ccb(done_ccb); 60658b8a9b1dSJustin T. Gibbs xpt_schedule(periph, priority); 60668b8a9b1dSJustin T. Gibbs return; 60678b8a9b1dSJustin T. Gibbs } 60688b8a9b1dSJustin T. Gibbs default: 60698b8a9b1dSJustin T. Gibbs break; 60708b8a9b1dSJustin T. Gibbs } 60718b8a9b1dSJustin T. Gibbs } else if (cam_periph_error(done_ccb, 0, 60728b8a9b1dSJustin T. Gibbs done_ccb->ccb_h.target_lun > 0 60738b8a9b1dSJustin T. Gibbs ? SF_RETRY_UA|SF_QUIET_IR 60748b8a9b1dSJustin T. Gibbs : SF_RETRY_UA, 60758b8a9b1dSJustin T. Gibbs &softc->saved_ccb) == ERESTART) { 60768b8a9b1dSJustin T. Gibbs return; 60778b8a9b1dSJustin T. Gibbs } else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) { 60788b8a9b1dSJustin T. Gibbs /* Don't wedge the queue */ 60792cefde5fSJustin T. Gibbs xpt_release_devq(done_ccb->ccb_h.path, /*count*/1, 60808b8a9b1dSJustin T. Gibbs /*run_queue*/TRUE); 60818b8a9b1dSJustin T. Gibbs } 60828b8a9b1dSJustin T. Gibbs /* 60838b8a9b1dSJustin T. Gibbs * If we get to this point, we got an error status back 60848b8a9b1dSJustin T. Gibbs * from the inquiry and the error status doesn't require 60858b8a9b1dSJustin T. Gibbs * automatically retrying the command. Therefore, the 60868b8a9b1dSJustin T. Gibbs * inquiry failed. If we had inquiry information before 60878b8a9b1dSJustin T. Gibbs * for this device, but this latest inquiry command failed, 60888b8a9b1dSJustin T. Gibbs * the device has probably gone away. If this device isn't 60898b8a9b1dSJustin T. Gibbs * already marked unconfigured, notify the peripheral 60908b8a9b1dSJustin T. Gibbs * drivers that this device is no more. 60918b8a9b1dSJustin T. Gibbs */ 60928b8a9b1dSJustin T. Gibbs if ((path->device->flags & CAM_DEV_UNCONFIGURED) == 0) 60938b8a9b1dSJustin T. Gibbs /* Send the async notification. */ 60948b8a9b1dSJustin T. Gibbs xpt_async(AC_LOST_DEVICE, path, NULL); 60958b8a9b1dSJustin T. Gibbs 60968b8a9b1dSJustin T. Gibbs xpt_release_ccb(done_ccb); 60978b8a9b1dSJustin T. Gibbs break; 60988b8a9b1dSJustin T. Gibbs } 60998b8a9b1dSJustin T. Gibbs case PROBE_MODE_SENSE: 61008b8a9b1dSJustin T. Gibbs { 61018b8a9b1dSJustin T. Gibbs struct ccb_scsiio *csio; 61028b8a9b1dSJustin T. Gibbs struct scsi_mode_header_6 *mode_hdr; 61038b8a9b1dSJustin T. Gibbs 61048b8a9b1dSJustin T. Gibbs csio = &done_ccb->csio; 61058b8a9b1dSJustin T. Gibbs mode_hdr = (struct scsi_mode_header_6 *)csio->data_ptr; 61068b8a9b1dSJustin T. Gibbs if ((csio->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) { 61078b8a9b1dSJustin T. Gibbs struct scsi_control_page *page; 61088b8a9b1dSJustin T. Gibbs u_int8_t *offset; 61098b8a9b1dSJustin T. Gibbs 61108b8a9b1dSJustin T. Gibbs offset = ((u_int8_t *)&mode_hdr[1]) 61118b8a9b1dSJustin T. Gibbs + mode_hdr->blk_desc_len; 61128b8a9b1dSJustin T. Gibbs page = (struct scsi_control_page *)offset; 61138b8a9b1dSJustin T. Gibbs path->device->queue_flags = page->queue_flags; 61148b8a9b1dSJustin T. Gibbs } else if (cam_periph_error(done_ccb, 0, 61158b8a9b1dSJustin T. Gibbs SF_RETRY_UA|SF_NO_PRINT, 61168b8a9b1dSJustin T. Gibbs &softc->saved_ccb) == ERESTART) { 61178b8a9b1dSJustin T. Gibbs return; 61188b8a9b1dSJustin T. Gibbs } else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) { 61198b8a9b1dSJustin T. Gibbs /* Don't wedge the queue */ 61202cefde5fSJustin T. Gibbs xpt_release_devq(done_ccb->ccb_h.path, 61212cefde5fSJustin T. Gibbs /*count*/1, /*run_queue*/TRUE); 61228b8a9b1dSJustin T. Gibbs } 61238b8a9b1dSJustin T. Gibbs xpt_release_ccb(done_ccb); 61240dd50e9bSScott Long free(mode_hdr, M_CAMXPT); 61258b8a9b1dSJustin T. Gibbs softc->action = PROBE_SERIAL_NUM; 61268b8a9b1dSJustin T. Gibbs xpt_schedule(periph, priority); 61278b8a9b1dSJustin T. Gibbs return; 61288b8a9b1dSJustin T. Gibbs } 61298b8a9b1dSJustin T. Gibbs case PROBE_SERIAL_NUM: 61308b8a9b1dSJustin T. Gibbs { 61318b8a9b1dSJustin T. Gibbs struct ccb_scsiio *csio; 61328b8a9b1dSJustin T. Gibbs struct scsi_vpd_unit_serial_number *serial_buf; 61338b8a9b1dSJustin T. Gibbs u_int32_t priority; 61348b8a9b1dSJustin T. Gibbs int changed; 61358b8a9b1dSJustin T. Gibbs int have_serialnum; 61368b8a9b1dSJustin T. Gibbs 61378b8a9b1dSJustin T. Gibbs changed = 1; 61388b8a9b1dSJustin T. Gibbs have_serialnum = 0; 61398b8a9b1dSJustin T. Gibbs csio = &done_ccb->csio; 61408b8a9b1dSJustin T. Gibbs priority = done_ccb->ccb_h.pinfo.priority; 61418b8a9b1dSJustin T. Gibbs serial_buf = 61428b8a9b1dSJustin T. Gibbs (struct scsi_vpd_unit_serial_number *)csio->data_ptr; 61438b8a9b1dSJustin T. Gibbs 61448b8a9b1dSJustin T. Gibbs /* Clean up from previous instance of this device */ 61458b8a9b1dSJustin T. Gibbs if (path->device->serial_num != NULL) { 6146362abc44STai-hwa Liang free(path->device->serial_num, M_CAMXPT); 61478b8a9b1dSJustin T. Gibbs path->device->serial_num = NULL; 61488b8a9b1dSJustin T. Gibbs path->device->serial_num_len = 0; 61498b8a9b1dSJustin T. Gibbs } 61508b8a9b1dSJustin T. Gibbs 61518b8a9b1dSJustin T. Gibbs if (serial_buf == NULL) { 61528b8a9b1dSJustin T. Gibbs /* 61538b8a9b1dSJustin T. Gibbs * Don't process the command as it was never sent 61548b8a9b1dSJustin T. Gibbs */ 61558b8a9b1dSJustin T. Gibbs } else if ((csio->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP 61568b8a9b1dSJustin T. Gibbs && (serial_buf->length > 0)) { 61578b8a9b1dSJustin T. Gibbs 61588b8a9b1dSJustin T. Gibbs have_serialnum = 1; 61598b8a9b1dSJustin T. Gibbs path->device->serial_num = 61608b8a9b1dSJustin T. Gibbs (u_int8_t *)malloc((serial_buf->length + 1), 6161362abc44STai-hwa Liang M_CAMXPT, M_NOWAIT); 61628b8a9b1dSJustin T. Gibbs if (path->device->serial_num != NULL) { 61638b8a9b1dSJustin T. Gibbs bcopy(serial_buf->serial_num, 61648b8a9b1dSJustin T. Gibbs path->device->serial_num, 61658b8a9b1dSJustin T. Gibbs serial_buf->length); 61668b8a9b1dSJustin T. Gibbs path->device->serial_num_len = 61678b8a9b1dSJustin T. Gibbs serial_buf->length; 61688b8a9b1dSJustin T. Gibbs path->device->serial_num[serial_buf->length] 61698b8a9b1dSJustin T. Gibbs = '\0'; 61708b8a9b1dSJustin T. Gibbs } 61718b8a9b1dSJustin T. Gibbs } else if (cam_periph_error(done_ccb, 0, 61728b8a9b1dSJustin T. Gibbs SF_RETRY_UA|SF_NO_PRINT, 61738b8a9b1dSJustin T. Gibbs &softc->saved_ccb) == ERESTART) { 61748b8a9b1dSJustin T. Gibbs return; 61758b8a9b1dSJustin T. Gibbs } else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) { 61768b8a9b1dSJustin T. Gibbs /* Don't wedge the queue */ 61772cefde5fSJustin T. Gibbs xpt_release_devq(done_ccb->ccb_h.path, /*count*/1, 61788b8a9b1dSJustin T. Gibbs /*run_queue*/TRUE); 61798b8a9b1dSJustin T. Gibbs } 61808b8a9b1dSJustin T. Gibbs 61818b8a9b1dSJustin T. Gibbs /* 61828b8a9b1dSJustin T. Gibbs * Let's see if we have seen this device before. 61838b8a9b1dSJustin T. Gibbs */ 61848b8a9b1dSJustin T. Gibbs if ((softc->flags & PROBE_INQUIRY_CKSUM) != 0) { 61858b8a9b1dSJustin T. Gibbs MD5_CTX context; 61868b8a9b1dSJustin T. Gibbs u_int8_t digest[16]; 61878b8a9b1dSJustin T. Gibbs 61888b8a9b1dSJustin T. Gibbs MD5Init(&context); 61898b8a9b1dSJustin T. Gibbs 61908b8a9b1dSJustin T. Gibbs MD5Update(&context, 61918b8a9b1dSJustin T. Gibbs (unsigned char *)&path->device->inq_data, 61928b8a9b1dSJustin T. Gibbs sizeof(struct scsi_inquiry_data)); 61938b8a9b1dSJustin T. Gibbs 61948b8a9b1dSJustin T. Gibbs if (have_serialnum) 61958b8a9b1dSJustin T. Gibbs MD5Update(&context, serial_buf->serial_num, 61968b8a9b1dSJustin T. Gibbs serial_buf->length); 61978b8a9b1dSJustin T. Gibbs 61988b8a9b1dSJustin T. Gibbs MD5Final(digest, &context); 61998b8a9b1dSJustin T. Gibbs if (bcmp(softc->digest, digest, 16) == 0) 62008b8a9b1dSJustin T. Gibbs changed = 0; 62018b8a9b1dSJustin T. Gibbs 62028b8a9b1dSJustin T. Gibbs /* 62038b8a9b1dSJustin T. Gibbs * XXX Do we need to do a TUR in order to ensure 62048b8a9b1dSJustin T. Gibbs * that the device really hasn't changed??? 62058b8a9b1dSJustin T. Gibbs */ 62068b8a9b1dSJustin T. Gibbs if ((changed != 0) 62078b8a9b1dSJustin T. Gibbs && ((softc->flags & PROBE_NO_ANNOUNCE) == 0)) 62088b8a9b1dSJustin T. Gibbs xpt_async(AC_LOST_DEVICE, path, NULL); 62098b8a9b1dSJustin T. Gibbs } 62108b8a9b1dSJustin T. Gibbs if (serial_buf != NULL) 62110dd50e9bSScott Long free(serial_buf, M_CAMXPT); 62128b8a9b1dSJustin T. Gibbs 62138b8a9b1dSJustin T. Gibbs if (changed != 0) { 62148b8a9b1dSJustin T. Gibbs /* 62158b8a9b1dSJustin T. Gibbs * Now that we have all the necessary 62168b8a9b1dSJustin T. Gibbs * information to safely perform transfer 62178b8a9b1dSJustin T. Gibbs * negotiations... Controllers don't perform 62188b8a9b1dSJustin T. Gibbs * any negotiation or tagged queuing until 62198b8a9b1dSJustin T. Gibbs * after the first XPT_SET_TRAN_SETTINGS ccb is 62202afca7acSMatt Jacob * received. So, on a new device, just retrieve 62218b8a9b1dSJustin T. Gibbs * the user settings, and set them as the current 62228b8a9b1dSJustin T. Gibbs * settings to set the device up. 62238b8a9b1dSJustin T. Gibbs */ 622487cfaf0eSJustin T. Gibbs proberequestdefaultnegotiation(periph); 62258b8a9b1dSJustin T. Gibbs xpt_release_ccb(done_ccb); 62268b8a9b1dSJustin T. Gibbs 62278b8a9b1dSJustin T. Gibbs /* 62288b8a9b1dSJustin T. Gibbs * Perform a TUR to allow the controller to 62298b8a9b1dSJustin T. Gibbs * perform any necessary transfer negotiation. 62308b8a9b1dSJustin T. Gibbs */ 62318b8a9b1dSJustin T. Gibbs softc->action = PROBE_TUR_FOR_NEGOTIATION; 62328b8a9b1dSJustin T. Gibbs xpt_schedule(periph, priority); 62338b8a9b1dSJustin T. Gibbs return; 62348b8a9b1dSJustin T. Gibbs } 62358b8a9b1dSJustin T. Gibbs xpt_release_ccb(done_ccb); 62368b8a9b1dSJustin T. Gibbs break; 62378b8a9b1dSJustin T. Gibbs } 62388b8a9b1dSJustin T. Gibbs case PROBE_TUR_FOR_NEGOTIATION: 62392afca7acSMatt Jacob case PROBE_DV_EXIT: 62408b8a9b1dSJustin T. Gibbs if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) { 62418b8a9b1dSJustin T. Gibbs /* Don't wedge the queue */ 62422cefde5fSJustin T. Gibbs xpt_release_devq(done_ccb->ccb_h.path, /*count*/1, 62438b8a9b1dSJustin T. Gibbs /*run_queue*/TRUE); 62448b8a9b1dSJustin T. Gibbs } 62452afca7acSMatt Jacob /* 62462afca7acSMatt Jacob * Do Domain Validation for lun 0 on devices that claim 62472afca7acSMatt Jacob * to support Synchronous Transfer modes. 62482afca7acSMatt Jacob */ 62492afca7acSMatt Jacob if (softc->action == PROBE_TUR_FOR_NEGOTIATION 62502afca7acSMatt Jacob && done_ccb->ccb_h.target_lun == 0 62512afca7acSMatt Jacob && (path->device->inq_data.flags & SID_Sync) != 0 62522afca7acSMatt Jacob && (path->device->flags & CAM_DEV_IN_DV) == 0) { 62532afca7acSMatt Jacob CAM_DEBUG(periph->path, CAM_DEBUG_INFO, 62542afca7acSMatt Jacob ("Begin Domain Validation\n")); 62552afca7acSMatt Jacob path->device->flags |= CAM_DEV_IN_DV; 62562afca7acSMatt Jacob xpt_release_ccb(done_ccb); 62572afca7acSMatt Jacob softc->action = PROBE_INQUIRY_BASIC_DV1; 62582afca7acSMatt Jacob xpt_schedule(periph, priority); 62592afca7acSMatt Jacob return; 62602afca7acSMatt Jacob } 62612afca7acSMatt Jacob if (softc->action == PROBE_DV_EXIT) { 62622afca7acSMatt Jacob CAM_DEBUG(periph->path, CAM_DEBUG_INFO, 62632afca7acSMatt Jacob ("Leave Domain Validation\n")); 62642afca7acSMatt Jacob } 62652afca7acSMatt Jacob path->device->flags &= 62662afca7acSMatt Jacob ~(CAM_DEV_UNCONFIGURED|CAM_DEV_IN_DV|CAM_DEV_DV_HIT_BOTTOM); 62678b8a9b1dSJustin T. Gibbs if ((softc->flags & PROBE_NO_ANNOUNCE) == 0) { 62688b8a9b1dSJustin T. Gibbs /* Inform the XPT that a new device has been found */ 62698b8a9b1dSJustin T. Gibbs done_ccb->ccb_h.func_code = XPT_GDEV_TYPE; 62708b8a9b1dSJustin T. Gibbs xpt_action(done_ccb); 6271df8f9080SJustin T. Gibbs xpt_async(AC_FOUND_DEVICE, done_ccb->ccb_h.path, 6272df8f9080SJustin T. Gibbs done_ccb); 62738b8a9b1dSJustin T. Gibbs } 62748b8a9b1dSJustin T. Gibbs xpt_release_ccb(done_ccb); 62758b8a9b1dSJustin T. Gibbs break; 62762afca7acSMatt Jacob case PROBE_INQUIRY_BASIC_DV1: 62772afca7acSMatt Jacob case PROBE_INQUIRY_BASIC_DV2: 62782afca7acSMatt Jacob { 62792afca7acSMatt Jacob struct scsi_inquiry_data *nbuf; 62802afca7acSMatt Jacob struct ccb_scsiio *csio; 62812afca7acSMatt Jacob 62822afca7acSMatt Jacob if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) { 62832afca7acSMatt Jacob /* Don't wedge the queue */ 62842afca7acSMatt Jacob xpt_release_devq(done_ccb->ccb_h.path, /*count*/1, 62852afca7acSMatt Jacob /*run_queue*/TRUE); 62862afca7acSMatt Jacob } 62872afca7acSMatt Jacob csio = &done_ccb->csio; 62882afca7acSMatt Jacob nbuf = (struct scsi_inquiry_data *)csio->data_ptr; 62892afca7acSMatt Jacob if (bcmp(nbuf, &path->device->inq_data, SHORT_INQUIRY_LENGTH)) { 6290f0d9af51SMatt Jacob xpt_print(path, 6291f0d9af51SMatt Jacob "inquiry data fails comparison at DV%d step\n", 62922afca7acSMatt Jacob softc->action == PROBE_INQUIRY_BASIC_DV1? 1 : 2); 62932afca7acSMatt Jacob if (proberequestbackoff(periph, path->device)) { 62942afca7acSMatt Jacob path->device->flags &= ~CAM_DEV_IN_DV; 62952afca7acSMatt Jacob softc->action = PROBE_TUR_FOR_NEGOTIATION; 62962afca7acSMatt Jacob } else { 62972afca7acSMatt Jacob /* give up */ 62982afca7acSMatt Jacob softc->action = PROBE_DV_EXIT; 62992afca7acSMatt Jacob } 63000dd50e9bSScott Long free(nbuf, M_CAMXPT); 63012afca7acSMatt Jacob xpt_release_ccb(done_ccb); 63022afca7acSMatt Jacob xpt_schedule(periph, priority); 63032afca7acSMatt Jacob return; 63042afca7acSMatt Jacob } 63050dd50e9bSScott Long free(nbuf, M_CAMXPT); 63062afca7acSMatt Jacob if (softc->action == PROBE_INQUIRY_BASIC_DV1) { 63072afca7acSMatt Jacob softc->action = PROBE_INQUIRY_BASIC_DV2; 63082afca7acSMatt Jacob xpt_release_ccb(done_ccb); 63092afca7acSMatt Jacob xpt_schedule(periph, priority); 63102afca7acSMatt Jacob return; 63112afca7acSMatt Jacob } 63122afca7acSMatt Jacob if (softc->action == PROBE_DV_EXIT) { 63132afca7acSMatt Jacob CAM_DEBUG(periph->path, CAM_DEBUG_INFO, 63142afca7acSMatt Jacob ("Leave Domain Validation Successfully\n")); 63152afca7acSMatt Jacob } 63162afca7acSMatt Jacob path->device->flags &= 63172afca7acSMatt Jacob ~(CAM_DEV_UNCONFIGURED|CAM_DEV_IN_DV|CAM_DEV_DV_HIT_BOTTOM); 63182afca7acSMatt Jacob if ((softc->flags & PROBE_NO_ANNOUNCE) == 0) { 63192afca7acSMatt Jacob /* Inform the XPT that a new device has been found */ 63202afca7acSMatt Jacob done_ccb->ccb_h.func_code = XPT_GDEV_TYPE; 63212afca7acSMatt Jacob xpt_action(done_ccb); 63222afca7acSMatt Jacob xpt_async(AC_FOUND_DEVICE, done_ccb->ccb_h.path, 63232afca7acSMatt Jacob done_ccb); 63242afca7acSMatt Jacob } 63252afca7acSMatt Jacob xpt_release_ccb(done_ccb); 63262afca7acSMatt Jacob break; 63272afca7acSMatt Jacob } 63288b8a9b1dSJustin T. Gibbs } 63298b8a9b1dSJustin T. Gibbs done_ccb = (union ccb *)TAILQ_FIRST(&softc->request_ccbs); 63308b8a9b1dSJustin T. Gibbs TAILQ_REMOVE(&softc->request_ccbs, &done_ccb->ccb_h, periph_links.tqe); 63318b8a9b1dSJustin T. Gibbs done_ccb->ccb_h.status = CAM_REQ_CMP; 63328b8a9b1dSJustin T. Gibbs xpt_done(done_ccb); 63338b8a9b1dSJustin T. Gibbs if (TAILQ_FIRST(&softc->request_ccbs) == NULL) { 63348b8a9b1dSJustin T. Gibbs cam_periph_invalidate(periph); 63358b8a9b1dSJustin T. Gibbs cam_periph_release(periph); 63368b8a9b1dSJustin T. Gibbs } else { 63378b8a9b1dSJustin T. Gibbs probeschedule(periph); 63388b8a9b1dSJustin T. Gibbs } 63398b8a9b1dSJustin T. Gibbs } 63408b8a9b1dSJustin T. Gibbs 63418b8a9b1dSJustin T. Gibbs static void 63428b8a9b1dSJustin T. Gibbs probecleanup(struct cam_periph *periph) 63438b8a9b1dSJustin T. Gibbs { 63440dd50e9bSScott Long free(periph->softc, M_CAMXPT); 63458b8a9b1dSJustin T. Gibbs } 63468b8a9b1dSJustin T. Gibbs 63478b8a9b1dSJustin T. Gibbs static void 63488b8a9b1dSJustin T. Gibbs xpt_find_quirk(struct cam_ed *device) 63498b8a9b1dSJustin T. Gibbs { 63508b8a9b1dSJustin T. Gibbs caddr_t match; 63518b8a9b1dSJustin T. Gibbs 63528b8a9b1dSJustin T. Gibbs match = cam_quirkmatch((caddr_t)&device->inq_data, 63538b8a9b1dSJustin T. Gibbs (caddr_t)xpt_quirk_table, 63548b8a9b1dSJustin T. Gibbs sizeof(xpt_quirk_table)/sizeof(*xpt_quirk_table), 63558b8a9b1dSJustin T. Gibbs sizeof(*xpt_quirk_table), scsi_inquiry_match); 63568b8a9b1dSJustin T. Gibbs 63578b8a9b1dSJustin T. Gibbs if (match == NULL) 63588b8a9b1dSJustin T. Gibbs panic("xpt_find_quirk: device didn't match wildcard entry!!"); 63598b8a9b1dSJustin T. Gibbs 63608b8a9b1dSJustin T. Gibbs device->quirk = (struct xpt_quirk_entry *)match; 63618b8a9b1dSJustin T. Gibbs } 63628b8a9b1dSJustin T. Gibbs 63633b87a552SMatt Jacob static int 63643b87a552SMatt Jacob sysctl_cam_search_luns(SYSCTL_HANDLER_ARGS) 63653b87a552SMatt Jacob { 63663b87a552SMatt Jacob int error, bool; 63673b87a552SMatt Jacob 63683b87a552SMatt Jacob bool = cam_srch_hi; 6369041b706bSDavid Malone error = sysctl_handle_int(oidp, &bool, 0, req); 63703b87a552SMatt Jacob if (error != 0 || req->newptr == NULL) 63713b87a552SMatt Jacob return (error); 63723b87a552SMatt Jacob if (bool == 0 || bool == 1) { 63733b87a552SMatt Jacob cam_srch_hi = bool; 63743b87a552SMatt Jacob return (0); 63753b87a552SMatt Jacob } else { 63763b87a552SMatt Jacob return (EINVAL); 63773b87a552SMatt Jacob } 63783b87a552SMatt Jacob } 63793b87a552SMatt Jacob 63803393f8daSKenneth D. Merry 63813393f8daSKenneth D. Merry static void 63823393f8daSKenneth D. Merry xpt_devise_transport(struct cam_path *path) 63833393f8daSKenneth D. Merry { 63843393f8daSKenneth D. Merry struct ccb_pathinq cpi; 63853393f8daSKenneth D. Merry struct ccb_trans_settings cts; 63863393f8daSKenneth D. Merry struct scsi_inquiry_data *inq_buf; 63873393f8daSKenneth D. Merry 63883393f8daSKenneth D. Merry /* Get transport information from the SIM */ 63893393f8daSKenneth D. Merry xpt_setup_ccb(&cpi.ccb_h, path, /*priority*/1); 63903393f8daSKenneth D. Merry cpi.ccb_h.func_code = XPT_PATH_INQ; 63913393f8daSKenneth D. Merry xpt_action((union ccb *)&cpi); 63923393f8daSKenneth D. Merry 63933393f8daSKenneth D. Merry inq_buf = NULL; 63943393f8daSKenneth D. Merry if ((path->device->flags & CAM_DEV_INQUIRY_DATA_VALID) != 0) 63953393f8daSKenneth D. Merry inq_buf = &path->device->inq_data; 63963393f8daSKenneth D. Merry path->device->protocol = PROTO_SCSI; 63973393f8daSKenneth D. Merry path->device->protocol_version = 63983393f8daSKenneth D. Merry inq_buf != NULL ? SID_ANSI_REV(inq_buf) : cpi.protocol_version; 63993393f8daSKenneth D. Merry path->device->transport = cpi.transport; 64003393f8daSKenneth D. Merry path->device->transport_version = cpi.transport_version; 64013393f8daSKenneth D. Merry 64023393f8daSKenneth D. Merry /* 64033393f8daSKenneth D. Merry * Any device not using SPI3 features should 64043393f8daSKenneth D. Merry * be considered SPI2 or lower. 64053393f8daSKenneth D. Merry */ 64063393f8daSKenneth D. Merry if (inq_buf != NULL) { 64073393f8daSKenneth D. Merry if (path->device->transport == XPORT_SPI 64083393f8daSKenneth D. Merry && (inq_buf->spi3data & SID_SPI_MASK) == 0 64093393f8daSKenneth D. Merry && path->device->transport_version > 2) 64103393f8daSKenneth D. Merry path->device->transport_version = 2; 64113393f8daSKenneth D. Merry } else { 64123393f8daSKenneth D. Merry struct cam_ed* otherdev; 64133393f8daSKenneth D. Merry 64143393f8daSKenneth D. Merry for (otherdev = TAILQ_FIRST(&path->target->ed_entries); 64153393f8daSKenneth D. Merry otherdev != NULL; 64163393f8daSKenneth D. Merry otherdev = TAILQ_NEXT(otherdev, links)) { 64173393f8daSKenneth D. Merry if (otherdev != path->device) 64183393f8daSKenneth D. Merry break; 64193393f8daSKenneth D. Merry } 64203393f8daSKenneth D. Merry 64213393f8daSKenneth D. Merry if (otherdev != NULL) { 64223393f8daSKenneth D. Merry /* 64233393f8daSKenneth D. Merry * Initially assume the same versioning as 64243393f8daSKenneth D. Merry * prior luns for this target. 64253393f8daSKenneth D. Merry */ 64263393f8daSKenneth D. Merry path->device->protocol_version = 64273393f8daSKenneth D. Merry otherdev->protocol_version; 64283393f8daSKenneth D. Merry path->device->transport_version = 64293393f8daSKenneth D. Merry otherdev->transport_version; 64303393f8daSKenneth D. Merry } else { 64313393f8daSKenneth D. Merry /* Until we know better, opt for safty */ 64323393f8daSKenneth D. Merry path->device->protocol_version = 2; 64333393f8daSKenneth D. Merry if (path->device->transport == XPORT_SPI) 64343393f8daSKenneth D. Merry path->device->transport_version = 2; 64353393f8daSKenneth D. Merry else 64363393f8daSKenneth D. Merry path->device->transport_version = 0; 64373393f8daSKenneth D. Merry } 64383393f8daSKenneth D. Merry } 64393393f8daSKenneth D. Merry 64403393f8daSKenneth D. Merry /* 64413393f8daSKenneth D. Merry * XXX 64423393f8daSKenneth D. Merry * For a device compliant with SPC-2 we should be able 64433393f8daSKenneth D. Merry * to determine the transport version supported by 64443393f8daSKenneth D. Merry * scrutinizing the version descriptors in the 64453393f8daSKenneth D. Merry * inquiry buffer. 64463393f8daSKenneth D. Merry */ 64473393f8daSKenneth D. Merry 64483393f8daSKenneth D. Merry /* Tell the controller what we think */ 64493393f8daSKenneth D. Merry xpt_setup_ccb(&cts.ccb_h, path, /*priority*/1); 64503393f8daSKenneth D. Merry cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS; 64513393f8daSKenneth D. Merry cts.type = CTS_TYPE_CURRENT_SETTINGS; 64523393f8daSKenneth D. Merry cts.transport = path->device->transport; 64533393f8daSKenneth D. Merry cts.transport_version = path->device->transport_version; 64543393f8daSKenneth D. Merry cts.protocol = path->device->protocol; 64553393f8daSKenneth D. Merry cts.protocol_version = path->device->protocol_version; 64563393f8daSKenneth D. Merry cts.proto_specific.valid = 0; 64573393f8daSKenneth D. Merry cts.xport_specific.valid = 0; 64583393f8daSKenneth D. Merry xpt_action((union ccb *)&cts); 64593393f8daSKenneth D. Merry } 64603393f8daSKenneth D. Merry 64613393f8daSKenneth D. Merry static void 64623393f8daSKenneth D. Merry xpt_set_transfer_settings(struct ccb_trans_settings *cts, struct cam_ed *device, 64633393f8daSKenneth D. Merry int async_update) 64643393f8daSKenneth D. Merry { 64653393f8daSKenneth D. Merry struct ccb_pathinq cpi; 64663393f8daSKenneth D. Merry struct ccb_trans_settings cur_cts; 64673393f8daSKenneth D. Merry struct ccb_trans_settings_scsi *scsi; 64683393f8daSKenneth D. Merry struct ccb_trans_settings_scsi *cur_scsi; 64693393f8daSKenneth D. Merry struct cam_sim *sim; 64703393f8daSKenneth D. Merry struct scsi_inquiry_data *inq_data; 64713393f8daSKenneth D. Merry 64723393f8daSKenneth D. Merry if (device == NULL) { 64733393f8daSKenneth D. Merry cts->ccb_h.status = CAM_PATH_INVALID; 64743393f8daSKenneth D. Merry xpt_done((union ccb *)cts); 64753393f8daSKenneth D. Merry return; 64763393f8daSKenneth D. Merry } 64773393f8daSKenneth D. Merry 64783393f8daSKenneth D. Merry if (cts->protocol == PROTO_UNKNOWN 64793393f8daSKenneth D. Merry || cts->protocol == PROTO_UNSPECIFIED) { 64803393f8daSKenneth D. Merry cts->protocol = device->protocol; 64813393f8daSKenneth D. Merry cts->protocol_version = device->protocol_version; 64823393f8daSKenneth D. Merry } 64833393f8daSKenneth D. Merry 64843393f8daSKenneth D. Merry if (cts->protocol_version == PROTO_VERSION_UNKNOWN 64853393f8daSKenneth D. Merry || cts->protocol_version == PROTO_VERSION_UNSPECIFIED) 64863393f8daSKenneth D. Merry cts->protocol_version = device->protocol_version; 64873393f8daSKenneth D. Merry 64883393f8daSKenneth D. Merry if (cts->protocol != device->protocol) { 6489f0d9af51SMatt Jacob xpt_print(cts->ccb_h.path, "Uninitialized Protocol %x:%x?\n", 64903393f8daSKenneth D. Merry cts->protocol, device->protocol); 64913393f8daSKenneth D. Merry cts->protocol = device->protocol; 64923393f8daSKenneth D. Merry } 64933393f8daSKenneth D. Merry 64943393f8daSKenneth D. Merry if (cts->protocol_version > device->protocol_version) { 64953393f8daSKenneth D. Merry if (bootverbose) { 6496f0d9af51SMatt Jacob xpt_print(cts->ccb_h.path, "Down reving Protocol " 6497f0d9af51SMatt Jacob "Version from %d to %d?\n", cts->protocol_version, 6498f0d9af51SMatt Jacob device->protocol_version); 64993393f8daSKenneth D. Merry } 65003393f8daSKenneth D. Merry cts->protocol_version = device->protocol_version; 65013393f8daSKenneth D. Merry } 65023393f8daSKenneth D. Merry 65033393f8daSKenneth D. Merry if (cts->transport == XPORT_UNKNOWN 65043393f8daSKenneth D. Merry || cts->transport == XPORT_UNSPECIFIED) { 65053393f8daSKenneth D. Merry cts->transport = device->transport; 65063393f8daSKenneth D. Merry cts->transport_version = device->transport_version; 65073393f8daSKenneth D. Merry } 65083393f8daSKenneth D. Merry 65093393f8daSKenneth D. Merry if (cts->transport_version == XPORT_VERSION_UNKNOWN 65103393f8daSKenneth D. Merry || cts->transport_version == XPORT_VERSION_UNSPECIFIED) 65113393f8daSKenneth D. Merry cts->transport_version = device->transport_version; 65123393f8daSKenneth D. Merry 65133393f8daSKenneth D. Merry if (cts->transport != device->transport) { 6514f0d9af51SMatt Jacob xpt_print(cts->ccb_h.path, "Uninitialized Transport %x:%x?\n", 65153393f8daSKenneth D. Merry cts->transport, device->transport); 65163393f8daSKenneth D. Merry cts->transport = device->transport; 65173393f8daSKenneth D. Merry } 65183393f8daSKenneth D. Merry 65193393f8daSKenneth D. Merry if (cts->transport_version > device->transport_version) { 65203393f8daSKenneth D. Merry if (bootverbose) { 6521f0d9af51SMatt Jacob xpt_print(cts->ccb_h.path, "Down reving Transport " 6522f0d9af51SMatt Jacob "Version from %d to %d?\n", cts->transport_version, 65233393f8daSKenneth D. Merry device->transport_version); 65243393f8daSKenneth D. Merry } 65253393f8daSKenneth D. Merry cts->transport_version = device->transport_version; 65263393f8daSKenneth D. Merry } 65273393f8daSKenneth D. Merry 65283393f8daSKenneth D. Merry sim = cts->ccb_h.path->bus->sim; 65293393f8daSKenneth D. Merry 65303393f8daSKenneth D. Merry /* 65313393f8daSKenneth D. Merry * Nothing more of interest to do unless 65323393f8daSKenneth D. Merry * this is a device connected via the 65333393f8daSKenneth D. Merry * SCSI protocol. 65343393f8daSKenneth D. Merry */ 65353393f8daSKenneth D. Merry if (cts->protocol != PROTO_SCSI) { 65363393f8daSKenneth D. Merry if (async_update == FALSE) 65373393f8daSKenneth D. Merry (*(sim->sim_action))(sim, (union ccb *)cts); 65383393f8daSKenneth D. Merry return; 65393393f8daSKenneth D. Merry } 65403393f8daSKenneth D. Merry 65413393f8daSKenneth D. Merry inq_data = &device->inq_data; 65423393f8daSKenneth D. Merry scsi = &cts->proto_specific.scsi; 65433393f8daSKenneth D. Merry xpt_setup_ccb(&cpi.ccb_h, cts->ccb_h.path, /*priority*/1); 65443393f8daSKenneth D. Merry cpi.ccb_h.func_code = XPT_PATH_INQ; 65453393f8daSKenneth D. Merry xpt_action((union ccb *)&cpi); 65463393f8daSKenneth D. Merry 65473393f8daSKenneth D. Merry /* SCSI specific sanity checking */ 65483393f8daSKenneth D. Merry if ((cpi.hba_inquiry & PI_TAG_ABLE) == 0 65494e359f5aSMatt Jacob || (INQ_DATA_TQ_ENABLED(inq_data)) == 0 65503393f8daSKenneth D. Merry || (device->queue_flags & SCP_QUEUE_DQUE) != 0 65513393f8daSKenneth D. Merry || (device->quirk->mintags == 0)) { 65523393f8daSKenneth D. Merry /* 65533393f8daSKenneth D. Merry * Can't tag on hardware that doesn't support tags, 65543393f8daSKenneth D. Merry * doesn't have it enabled, or has broken tag support. 65553393f8daSKenneth D. Merry */ 65563393f8daSKenneth D. Merry scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB; 65573393f8daSKenneth D. Merry } 65583393f8daSKenneth D. Merry 65593393f8daSKenneth D. Merry if (async_update == FALSE) { 65603393f8daSKenneth D. Merry /* 65613393f8daSKenneth D. Merry * Perform sanity checking against what the 65623393f8daSKenneth D. Merry * controller and device can do. 65633393f8daSKenneth D. Merry */ 65643393f8daSKenneth D. Merry xpt_setup_ccb(&cur_cts.ccb_h, cts->ccb_h.path, /*priority*/1); 65653393f8daSKenneth D. Merry cur_cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS; 65663393f8daSKenneth D. Merry cur_cts.type = cts->type; 65673393f8daSKenneth D. Merry xpt_action((union ccb *)&cur_cts); 65680a480cf0SMatt Jacob if ((cur_cts.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 65690a480cf0SMatt Jacob return; 65700a480cf0SMatt Jacob } 65713393f8daSKenneth D. Merry cur_scsi = &cur_cts.proto_specific.scsi; 65723393f8daSKenneth D. Merry if ((scsi->valid & CTS_SCSI_VALID_TQ) == 0) { 65733393f8daSKenneth D. Merry scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB; 65743393f8daSKenneth D. Merry scsi->flags |= cur_scsi->flags & CTS_SCSI_FLAGS_TAG_ENB; 65753393f8daSKenneth D. Merry } 65763393f8daSKenneth D. Merry if ((cur_scsi->valid & CTS_SCSI_VALID_TQ) == 0) 65773393f8daSKenneth D. Merry scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB; 65783393f8daSKenneth D. Merry } 65793393f8daSKenneth D. Merry 65803393f8daSKenneth D. Merry /* SPI specific sanity checking */ 6581f053d777SMatt Jacob if (cts->transport == XPORT_SPI && async_update == FALSE) { 65823393f8daSKenneth D. Merry u_int spi3caps; 65833393f8daSKenneth D. Merry struct ccb_trans_settings_spi *spi; 65843393f8daSKenneth D. Merry struct ccb_trans_settings_spi *cur_spi; 65853393f8daSKenneth D. Merry 65863393f8daSKenneth D. Merry spi = &cts->xport_specific.spi; 65873393f8daSKenneth D. Merry 65883393f8daSKenneth D. Merry cur_spi = &cur_cts.xport_specific.spi; 65893393f8daSKenneth D. Merry 65903393f8daSKenneth D. Merry /* Fill in any gaps in what the user gave us */ 65913393f8daSKenneth D. Merry if ((spi->valid & CTS_SPI_VALID_SYNC_RATE) == 0) 65923393f8daSKenneth D. Merry spi->sync_period = cur_spi->sync_period; 65933393f8daSKenneth D. Merry if ((cur_spi->valid & CTS_SPI_VALID_SYNC_RATE) == 0) 65943393f8daSKenneth D. Merry spi->sync_period = 0; 65953393f8daSKenneth D. Merry if ((spi->valid & CTS_SPI_VALID_SYNC_OFFSET) == 0) 65963393f8daSKenneth D. Merry spi->sync_offset = cur_spi->sync_offset; 65973393f8daSKenneth D. Merry if ((cur_spi->valid & CTS_SPI_VALID_SYNC_OFFSET) == 0) 65983393f8daSKenneth D. Merry spi->sync_offset = 0; 65993393f8daSKenneth D. Merry if ((spi->valid & CTS_SPI_VALID_PPR_OPTIONS) == 0) 66003393f8daSKenneth D. Merry spi->ppr_options = cur_spi->ppr_options; 66013393f8daSKenneth D. Merry if ((cur_spi->valid & CTS_SPI_VALID_PPR_OPTIONS) == 0) 66023393f8daSKenneth D. Merry spi->ppr_options = 0; 66033393f8daSKenneth D. Merry if ((spi->valid & CTS_SPI_VALID_BUS_WIDTH) == 0) 66043393f8daSKenneth D. Merry spi->bus_width = cur_spi->bus_width; 66053393f8daSKenneth D. Merry if ((cur_spi->valid & CTS_SPI_VALID_BUS_WIDTH) == 0) 66063393f8daSKenneth D. Merry spi->bus_width = 0; 66073393f8daSKenneth D. Merry if ((spi->valid & CTS_SPI_VALID_DISC) == 0) { 66083393f8daSKenneth D. Merry spi->flags &= ~CTS_SPI_FLAGS_DISC_ENB; 66093393f8daSKenneth D. Merry spi->flags |= cur_spi->flags & CTS_SPI_FLAGS_DISC_ENB; 66103393f8daSKenneth D. Merry } 66113393f8daSKenneth D. Merry if ((cur_spi->valid & CTS_SPI_VALID_DISC) == 0) 66123393f8daSKenneth D. Merry spi->flags &= ~CTS_SPI_FLAGS_DISC_ENB; 66133393f8daSKenneth D. Merry if (((device->flags & CAM_DEV_INQUIRY_DATA_VALID) != 0 66143393f8daSKenneth D. Merry && (inq_data->flags & SID_Sync) == 0 66153393f8daSKenneth D. Merry && cts->type == CTS_TYPE_CURRENT_SETTINGS) 66163393f8daSKenneth D. Merry || ((cpi.hba_inquiry & PI_SDTR_ABLE) == 0) 6617c144ae3eSMatt Jacob || (spi->sync_offset == 0) 6618c144ae3eSMatt Jacob || (spi->sync_period == 0)) { 66193393f8daSKenneth D. Merry /* Force async */ 66203393f8daSKenneth D. Merry spi->sync_period = 0; 66213393f8daSKenneth D. Merry spi->sync_offset = 0; 66223393f8daSKenneth D. Merry } 66233393f8daSKenneth D. Merry 66243393f8daSKenneth D. Merry switch (spi->bus_width) { 66253393f8daSKenneth D. Merry case MSG_EXT_WDTR_BUS_32_BIT: 66263393f8daSKenneth D. Merry if (((device->flags & CAM_DEV_INQUIRY_DATA_VALID) == 0 66273393f8daSKenneth D. Merry || (inq_data->flags & SID_WBus32) != 0 66283393f8daSKenneth D. Merry || cts->type == CTS_TYPE_USER_SETTINGS) 66293393f8daSKenneth D. Merry && (cpi.hba_inquiry & PI_WIDE_32) != 0) 66303393f8daSKenneth D. Merry break; 66313393f8daSKenneth D. Merry /* Fall Through to 16-bit */ 66323393f8daSKenneth D. Merry case MSG_EXT_WDTR_BUS_16_BIT: 66333393f8daSKenneth D. Merry if (((device->flags & CAM_DEV_INQUIRY_DATA_VALID) == 0 66343393f8daSKenneth D. Merry || (inq_data->flags & SID_WBus16) != 0 66353393f8daSKenneth D. Merry || cts->type == CTS_TYPE_USER_SETTINGS) 66363393f8daSKenneth D. Merry && (cpi.hba_inquiry & PI_WIDE_16) != 0) { 66373393f8daSKenneth D. Merry spi->bus_width = MSG_EXT_WDTR_BUS_16_BIT; 66383393f8daSKenneth D. Merry break; 66393393f8daSKenneth D. Merry } 66403393f8daSKenneth D. Merry /* Fall Through to 8-bit */ 66413393f8daSKenneth D. Merry default: /* New bus width?? */ 66423393f8daSKenneth D. Merry case MSG_EXT_WDTR_BUS_8_BIT: 66433393f8daSKenneth D. Merry /* All targets can do this */ 66443393f8daSKenneth D. Merry spi->bus_width = MSG_EXT_WDTR_BUS_8_BIT; 66453393f8daSKenneth D. Merry break; 66463393f8daSKenneth D. Merry } 66473393f8daSKenneth D. Merry 66483393f8daSKenneth D. Merry spi3caps = cpi.xport_specific.spi.ppr_options; 66493393f8daSKenneth D. Merry if ((device->flags & CAM_DEV_INQUIRY_DATA_VALID) != 0 66503393f8daSKenneth D. Merry && cts->type == CTS_TYPE_CURRENT_SETTINGS) 66513393f8daSKenneth D. Merry spi3caps &= inq_data->spi3data; 66523393f8daSKenneth D. Merry 66533393f8daSKenneth D. Merry if ((spi3caps & SID_SPI_CLOCK_DT) == 0) 66543393f8daSKenneth D. Merry spi->ppr_options &= ~MSG_EXT_PPR_DT_REQ; 66553393f8daSKenneth D. Merry 66563393f8daSKenneth D. Merry if ((spi3caps & SID_SPI_IUS) == 0) 66573393f8daSKenneth D. Merry spi->ppr_options &= ~MSG_EXT_PPR_IU_REQ; 66583393f8daSKenneth D. Merry 66593393f8daSKenneth D. Merry if ((spi3caps & SID_SPI_QAS) == 0) 66603393f8daSKenneth D. Merry spi->ppr_options &= ~MSG_EXT_PPR_QAS_REQ; 66613393f8daSKenneth D. Merry 66623393f8daSKenneth D. Merry /* No SPI Transfer settings are allowed unless we are wide */ 66633393f8daSKenneth D. Merry if (spi->bus_width == 0) 66643393f8daSKenneth D. Merry spi->ppr_options = 0; 66653393f8daSKenneth D. Merry 66663393f8daSKenneth D. Merry if ((spi->flags & CTS_SPI_FLAGS_DISC_ENB) == 0) { 66673393f8daSKenneth D. Merry /* 66683393f8daSKenneth D. Merry * Can't tag queue without disconnection. 66693393f8daSKenneth D. Merry */ 66703393f8daSKenneth D. Merry scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB; 66713393f8daSKenneth D. Merry scsi->valid |= CTS_SCSI_VALID_TQ; 66723393f8daSKenneth D. Merry } 66733393f8daSKenneth D. Merry 66743393f8daSKenneth D. Merry /* 66753393f8daSKenneth D. Merry * If we are currently performing tagged transactions to 66763393f8daSKenneth D. Merry * this device and want to change its negotiation parameters, 66773393f8daSKenneth D. Merry * go non-tagged for a bit to give the controller a chance to 66783393f8daSKenneth D. Merry * negotiate unhampered by tag messages. 66793393f8daSKenneth D. Merry */ 66803393f8daSKenneth D. Merry if (cts->type == CTS_TYPE_CURRENT_SETTINGS 66813393f8daSKenneth D. Merry && (device->inq_flags & SID_CmdQue) != 0 66823393f8daSKenneth D. Merry && (scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) != 0 66833393f8daSKenneth D. Merry && (spi->flags & (CTS_SPI_VALID_SYNC_RATE| 66843393f8daSKenneth D. Merry CTS_SPI_VALID_SYNC_OFFSET| 66853393f8daSKenneth D. Merry CTS_SPI_VALID_BUS_WIDTH)) != 0) 66863393f8daSKenneth D. Merry xpt_toggle_tags(cts->ccb_h.path); 66873393f8daSKenneth D. Merry } 66883393f8daSKenneth D. Merry 66893393f8daSKenneth D. Merry if (cts->type == CTS_TYPE_CURRENT_SETTINGS 66903393f8daSKenneth D. Merry && (scsi->valid & CTS_SCSI_VALID_TQ) != 0) { 66913393f8daSKenneth D. Merry int device_tagenb; 66923393f8daSKenneth D. Merry 66933393f8daSKenneth D. Merry /* 66943393f8daSKenneth D. Merry * If we are transitioning from tags to no-tags or 66953393f8daSKenneth D. Merry * vice-versa, we need to carefully freeze and restart 66963393f8daSKenneth D. Merry * the queue so that we don't overlap tagged and non-tagged 66973393f8daSKenneth D. Merry * commands. We also temporarily stop tags if there is 66983393f8daSKenneth D. Merry * a change in transfer negotiation settings to allow 66993393f8daSKenneth D. Merry * "tag-less" negotiation. 67003393f8daSKenneth D. Merry */ 67013393f8daSKenneth D. Merry if ((device->flags & CAM_DEV_TAG_AFTER_COUNT) != 0 67023393f8daSKenneth D. Merry || (device->inq_flags & SID_CmdQue) != 0) 67033393f8daSKenneth D. Merry device_tagenb = TRUE; 67043393f8daSKenneth D. Merry else 67053393f8daSKenneth D. Merry device_tagenb = FALSE; 67063393f8daSKenneth D. Merry 67073393f8daSKenneth D. Merry if (((scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) != 0 67083393f8daSKenneth D. Merry && device_tagenb == FALSE) 67093393f8daSKenneth D. Merry || ((scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) == 0 67103393f8daSKenneth D. Merry && device_tagenb == TRUE)) { 67113393f8daSKenneth D. Merry 67123393f8daSKenneth D. Merry if ((scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) != 0) { 67133393f8daSKenneth D. Merry /* 67143393f8daSKenneth D. Merry * Delay change to use tags until after a 67153393f8daSKenneth D. Merry * few commands have gone to this device so 67163393f8daSKenneth D. Merry * the controller has time to perform transfer 67173393f8daSKenneth D. Merry * negotiations without tagged messages getting 67183393f8daSKenneth D. Merry * in the way. 67193393f8daSKenneth D. Merry */ 67203393f8daSKenneth D. Merry device->tag_delay_count = CAM_TAG_DELAY_COUNT; 67213393f8daSKenneth D. Merry device->flags |= CAM_DEV_TAG_AFTER_COUNT; 67223393f8daSKenneth D. Merry } else { 67233393f8daSKenneth D. Merry struct ccb_relsim crs; 67243393f8daSKenneth D. Merry 67253393f8daSKenneth D. Merry xpt_freeze_devq(cts->ccb_h.path, /*count*/1); 67263393f8daSKenneth D. Merry device->inq_flags &= ~SID_CmdQue; 67273393f8daSKenneth D. Merry xpt_dev_ccbq_resize(cts->ccb_h.path, 67283393f8daSKenneth D. Merry sim->max_dev_openings); 67293393f8daSKenneth D. Merry device->flags &= ~CAM_DEV_TAG_AFTER_COUNT; 67303393f8daSKenneth D. Merry device->tag_delay_count = 0; 67313393f8daSKenneth D. Merry 67323393f8daSKenneth D. Merry xpt_setup_ccb(&crs.ccb_h, cts->ccb_h.path, 67333393f8daSKenneth D. Merry /*priority*/1); 67343393f8daSKenneth D. Merry crs.ccb_h.func_code = XPT_REL_SIMQ; 67353393f8daSKenneth D. Merry crs.release_flags = RELSIM_RELEASE_AFTER_QEMPTY; 67363393f8daSKenneth D. Merry crs.openings 67373393f8daSKenneth D. Merry = crs.release_timeout 67383393f8daSKenneth D. Merry = crs.qfrozen_cnt 67393393f8daSKenneth D. Merry = 0; 67403393f8daSKenneth D. Merry xpt_action((union ccb *)&crs); 67413393f8daSKenneth D. Merry } 67423393f8daSKenneth D. Merry } 67433393f8daSKenneth D. Merry } 67443393f8daSKenneth D. Merry if (async_update == FALSE) 67453393f8daSKenneth D. Merry (*(sim->sim_action))(sim, (union ccb *)cts); 67463393f8daSKenneth D. Merry } 67473393f8daSKenneth D. Merry 67483393f8daSKenneth D. Merry 6749fd21cc5eSJustin T. Gibbs static void 6750f0adc790SJustin T. Gibbs xpt_toggle_tags(struct cam_path *path) 6751f0adc790SJustin T. Gibbs { 675287cfaf0eSJustin T. Gibbs struct cam_ed *dev; 675387cfaf0eSJustin T. Gibbs 6754f0adc790SJustin T. Gibbs /* 6755f0adc790SJustin T. Gibbs * Give controllers a chance to renegotiate 6756f0adc790SJustin T. Gibbs * before starting tag operations. We 6757f0adc790SJustin T. Gibbs * "toggle" tagged queuing off then on 6758f0adc790SJustin T. Gibbs * which causes the tag enable command delay 6759f0adc790SJustin T. Gibbs * counter to come into effect. 6760f0adc790SJustin T. Gibbs */ 676187cfaf0eSJustin T. Gibbs dev = path->device; 676287cfaf0eSJustin T. Gibbs if ((dev->flags & CAM_DEV_TAG_AFTER_COUNT) != 0 676387cfaf0eSJustin T. Gibbs || ((dev->inq_flags & SID_CmdQue) != 0 676487cfaf0eSJustin T. Gibbs && (dev->inq_flags & (SID_Sync|SID_WBus16|SID_WBus32)) != 0)) { 6765f0adc790SJustin T. Gibbs struct ccb_trans_settings cts; 6766f0adc790SJustin T. Gibbs 6767f0adc790SJustin T. Gibbs xpt_setup_ccb(&cts.ccb_h, path, 1); 67683393f8daSKenneth D. Merry cts.protocol = PROTO_SCSI; 67693393f8daSKenneth D. Merry cts.protocol_version = PROTO_VERSION_UNSPECIFIED; 67703393f8daSKenneth D. Merry cts.transport = XPORT_UNSPECIFIED; 67713393f8daSKenneth D. Merry cts.transport_version = XPORT_VERSION_UNSPECIFIED; 67723393f8daSKenneth D. Merry cts.proto_specific.scsi.flags = 0; 67733393f8daSKenneth D. Merry cts.proto_specific.scsi.valid = CTS_SCSI_VALID_TQ; 677403e3511bSJustin T. Gibbs xpt_set_transfer_settings(&cts, path->device, 677503e3511bSJustin T. Gibbs /*async_update*/TRUE); 67763393f8daSKenneth D. Merry cts.proto_specific.scsi.flags = CTS_SCSI_FLAGS_TAG_ENB; 677703e3511bSJustin T. Gibbs xpt_set_transfer_settings(&cts, path->device, 677803e3511bSJustin T. Gibbs /*async_update*/TRUE); 6779f0adc790SJustin T. Gibbs } 6780f0adc790SJustin T. Gibbs } 6781f0adc790SJustin T. Gibbs 6782f0adc790SJustin T. Gibbs static void 6783f0adc790SJustin T. Gibbs xpt_start_tags(struct cam_path *path) 6784f0adc790SJustin T. Gibbs { 6785fd21cc5eSJustin T. Gibbs struct ccb_relsim crs; 6786fd21cc5eSJustin T. Gibbs struct cam_ed *device; 6787fd21cc5eSJustin T. Gibbs struct cam_sim *sim; 6788fd21cc5eSJustin T. Gibbs int newopenings; 6789fd21cc5eSJustin T. Gibbs 6790fd21cc5eSJustin T. Gibbs device = path->device; 6791fd21cc5eSJustin T. Gibbs sim = path->bus->sim; 6792fd21cc5eSJustin T. Gibbs device->flags &= ~CAM_DEV_TAG_AFTER_COUNT; 6793fd21cc5eSJustin T. Gibbs xpt_freeze_devq(path, /*count*/1); 6794fd21cc5eSJustin T. Gibbs device->inq_flags |= SID_CmdQue; 6795df8f9080SJustin T. Gibbs if (device->tag_saved_openings != 0) 6796df8f9080SJustin T. Gibbs newopenings = device->tag_saved_openings; 6797df8f9080SJustin T. Gibbs else 6798df8f9080SJustin T. Gibbs newopenings = min(device->quirk->maxtags, 6799df8f9080SJustin T. Gibbs sim->max_tagged_dev_openings); 6800f0adc790SJustin T. Gibbs xpt_dev_ccbq_resize(path, newopenings); 6801fd21cc5eSJustin T. Gibbs xpt_setup_ccb(&crs.ccb_h, path, /*priority*/1); 6802fd21cc5eSJustin T. Gibbs crs.ccb_h.func_code = XPT_REL_SIMQ; 6803fd21cc5eSJustin T. Gibbs crs.release_flags = RELSIM_RELEASE_AFTER_QEMPTY; 6804fd21cc5eSJustin T. Gibbs crs.openings 6805fd21cc5eSJustin T. Gibbs = crs.release_timeout 6806fd21cc5eSJustin T. Gibbs = crs.qfrozen_cnt 6807fd21cc5eSJustin T. Gibbs = 0; 6808fd21cc5eSJustin T. Gibbs xpt_action((union ccb *)&crs); 6809fd21cc5eSJustin T. Gibbs } 6810fd21cc5eSJustin T. Gibbs 68118b8a9b1dSJustin T. Gibbs static int busses_to_config; 681287cfaf0eSJustin T. Gibbs static int busses_to_reset; 68138b8a9b1dSJustin T. Gibbs 68148b8a9b1dSJustin T. Gibbs static int 68158b8a9b1dSJustin T. Gibbs xptconfigbuscountfunc(struct cam_eb *bus, void *arg) 68168b8a9b1dSJustin T. Gibbs { 68172b83592fSScott Long 68182b83592fSScott Long mtx_assert(bus->sim->mtx, MA_OWNED); 68192b83592fSScott Long 682087cfaf0eSJustin T. Gibbs if (bus->path_id != CAM_XPT_PATH_ID) { 682187cfaf0eSJustin T. Gibbs struct cam_path path; 682287cfaf0eSJustin T. Gibbs struct ccb_pathinq cpi; 682387cfaf0eSJustin T. Gibbs int can_negotiate; 682487cfaf0eSJustin T. Gibbs 68258b8a9b1dSJustin T. Gibbs busses_to_config++; 682687cfaf0eSJustin T. Gibbs xpt_compile_path(&path, NULL, bus->path_id, 682787cfaf0eSJustin T. Gibbs CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD); 682887cfaf0eSJustin T. Gibbs xpt_setup_ccb(&cpi.ccb_h, &path, /*priority*/1); 682987cfaf0eSJustin T. Gibbs cpi.ccb_h.func_code = XPT_PATH_INQ; 683087cfaf0eSJustin T. Gibbs xpt_action((union ccb *)&cpi); 683187cfaf0eSJustin T. Gibbs can_negotiate = cpi.hba_inquiry; 683287cfaf0eSJustin T. Gibbs can_negotiate &= (PI_WIDE_32|PI_WIDE_16|PI_SDTR_ABLE); 683387cfaf0eSJustin T. Gibbs if ((cpi.hba_misc & PIM_NOBUSRESET) == 0 683487cfaf0eSJustin T. Gibbs && can_negotiate) 683587cfaf0eSJustin T. Gibbs busses_to_reset++; 683687cfaf0eSJustin T. Gibbs xpt_release_path(&path); 683787cfaf0eSJustin T. Gibbs } 68388b8a9b1dSJustin T. Gibbs 68398b8a9b1dSJustin T. Gibbs return(1); 68408b8a9b1dSJustin T. Gibbs } 68418b8a9b1dSJustin T. Gibbs 68428b8a9b1dSJustin T. Gibbs static int 68438b8a9b1dSJustin T. Gibbs xptconfigfunc(struct cam_eb *bus, void *arg) 68448b8a9b1dSJustin T. Gibbs { 68458b8a9b1dSJustin T. Gibbs struct cam_path *path; 68468b8a9b1dSJustin T. Gibbs union ccb *work_ccb; 68478b8a9b1dSJustin T. Gibbs 68482b83592fSScott Long mtx_assert(bus->sim->mtx, MA_OWNED); 68492b83592fSScott Long 68508b8a9b1dSJustin T. Gibbs if (bus->path_id != CAM_XPT_PATH_ID) { 68518b8a9b1dSJustin T. Gibbs cam_status status; 685287cfaf0eSJustin T. Gibbs int can_negotiate; 68538b8a9b1dSJustin T. Gibbs 68548008a935SScott Long work_ccb = xpt_alloc_ccb_nowait(); 68558008a935SScott Long if (work_ccb == NULL) { 68568008a935SScott Long busses_to_config--; 68578008a935SScott Long xpt_finishconfig(xpt_periph, NULL); 68588008a935SScott Long return(0); 68598008a935SScott Long } 68608b8a9b1dSJustin T. Gibbs if ((status = xpt_create_path(&path, xpt_periph, bus->path_id, 68618b8a9b1dSJustin T. Gibbs CAM_TARGET_WILDCARD, 68628b8a9b1dSJustin T. Gibbs CAM_LUN_WILDCARD)) !=CAM_REQ_CMP){ 68638b8a9b1dSJustin T. Gibbs printf("xptconfigfunc: xpt_create_path failed with " 68648b8a9b1dSJustin T. Gibbs "status %#x for bus %d\n", status, bus->path_id); 68658b8a9b1dSJustin T. Gibbs printf("xptconfigfunc: halting bus configuration\n"); 68668b8a9b1dSJustin T. Gibbs xpt_free_ccb(work_ccb); 686798192658SJustin T. Gibbs busses_to_config--; 686898192658SJustin T. Gibbs xpt_finishconfig(xpt_periph, NULL); 68698b8a9b1dSJustin T. Gibbs return(0); 68708b8a9b1dSJustin T. Gibbs } 68718b8a9b1dSJustin T. Gibbs xpt_setup_ccb(&work_ccb->ccb_h, path, /*priority*/1); 687298192658SJustin T. Gibbs work_ccb->ccb_h.func_code = XPT_PATH_INQ; 687398192658SJustin T. Gibbs xpt_action(work_ccb); 687498192658SJustin T. Gibbs if (work_ccb->ccb_h.status != CAM_REQ_CMP) { 687598192658SJustin T. Gibbs printf("xptconfigfunc: CPI failed on bus %d " 687698192658SJustin T. Gibbs "with status %d\n", bus->path_id, 687798192658SJustin T. Gibbs work_ccb->ccb_h.status); 687898192658SJustin T. Gibbs xpt_finishconfig(xpt_periph, work_ccb); 687998192658SJustin T. Gibbs return(1); 688098192658SJustin T. Gibbs } 688198192658SJustin T. Gibbs 688287cfaf0eSJustin T. Gibbs can_negotiate = work_ccb->cpi.hba_inquiry; 688387cfaf0eSJustin T. Gibbs can_negotiate &= (PI_WIDE_32|PI_WIDE_16|PI_SDTR_ABLE); 688487cfaf0eSJustin T. Gibbs if ((work_ccb->cpi.hba_misc & PIM_NOBUSRESET) == 0 688587cfaf0eSJustin T. Gibbs && (can_negotiate != 0)) { 688698192658SJustin T. Gibbs xpt_setup_ccb(&work_ccb->ccb_h, path, /*priority*/1); 68878b8a9b1dSJustin T. Gibbs work_ccb->ccb_h.func_code = XPT_RESET_BUS; 68888b8a9b1dSJustin T. Gibbs work_ccb->ccb_h.cbfcnp = NULL; 68898b8a9b1dSJustin T. Gibbs CAM_DEBUG(path, CAM_DEBUG_SUBTRACE, 68908b8a9b1dSJustin T. Gibbs ("Resetting Bus\n")); 68918b8a9b1dSJustin T. Gibbs xpt_action(work_ccb); 68928b8a9b1dSJustin T. Gibbs xpt_finishconfig(xpt_periph, work_ccb); 689398192658SJustin T. Gibbs } else { 689498192658SJustin T. Gibbs /* Act as though we performed a successful BUS RESET */ 689598192658SJustin T. Gibbs work_ccb->ccb_h.func_code = XPT_RESET_BUS; 689698192658SJustin T. Gibbs xpt_finishconfig(xpt_periph, work_ccb); 689798192658SJustin T. Gibbs } 68988b8a9b1dSJustin T. Gibbs } 68998b8a9b1dSJustin T. Gibbs 69008b8a9b1dSJustin T. Gibbs return(1); 69018b8a9b1dSJustin T. Gibbs } 69028b8a9b1dSJustin T. Gibbs 69038b8a9b1dSJustin T. Gibbs static void 69048b8a9b1dSJustin T. Gibbs xpt_config(void *arg) 69058b8a9b1dSJustin T. Gibbs { 69063393f8daSKenneth D. Merry /* 69073393f8daSKenneth D. Merry * Now that interrupts are enabled, go find our devices 69083393f8daSKenneth D. Merry */ 69098b8a9b1dSJustin T. Gibbs 69108b8a9b1dSJustin T. Gibbs #ifdef CAMDEBUG 69118b8a9b1dSJustin T. Gibbs /* Setup debugging flags and path */ 69128b8a9b1dSJustin T. Gibbs #ifdef CAM_DEBUG_FLAGS 69138b8a9b1dSJustin T. Gibbs cam_dflags = CAM_DEBUG_FLAGS; 69148b8a9b1dSJustin T. Gibbs #else /* !CAM_DEBUG_FLAGS */ 69158b8a9b1dSJustin T. Gibbs cam_dflags = CAM_DEBUG_NONE; 69168b8a9b1dSJustin T. Gibbs #endif /* CAM_DEBUG_FLAGS */ 69178b8a9b1dSJustin T. Gibbs #ifdef CAM_DEBUG_BUS 69188b8a9b1dSJustin T. Gibbs if (cam_dflags != CAM_DEBUG_NONE) { 69192b83592fSScott Long /* 69202b83592fSScott Long * Locking is specifically omitted here. No SIMs have 69212b83592fSScott Long * registered yet, so xpt_create_path will only be searching 69222b83592fSScott Long * empty lists of targets and devices. 69232b83592fSScott Long */ 69248b8a9b1dSJustin T. Gibbs if (xpt_create_path(&cam_dpath, xpt_periph, 69258b8a9b1dSJustin T. Gibbs CAM_DEBUG_BUS, CAM_DEBUG_TARGET, 69268b8a9b1dSJustin T. Gibbs CAM_DEBUG_LUN) != CAM_REQ_CMP) { 69278b8a9b1dSJustin T. Gibbs printf("xpt_config: xpt_create_path() failed for debug" 69288b8a9b1dSJustin T. Gibbs " target %d:%d:%d, debugging disabled\n", 69298b8a9b1dSJustin T. Gibbs CAM_DEBUG_BUS, CAM_DEBUG_TARGET, CAM_DEBUG_LUN); 69308b8a9b1dSJustin T. Gibbs cam_dflags = CAM_DEBUG_NONE; 69318b8a9b1dSJustin T. Gibbs } 69328b8a9b1dSJustin T. Gibbs } else 69338b8a9b1dSJustin T. Gibbs cam_dpath = NULL; 69348b8a9b1dSJustin T. Gibbs #else /* !CAM_DEBUG_BUS */ 69358b8a9b1dSJustin T. Gibbs cam_dpath = NULL; 69368b8a9b1dSJustin T. Gibbs #endif /* CAM_DEBUG_BUS */ 69378b8a9b1dSJustin T. Gibbs #endif /* CAMDEBUG */ 69388b8a9b1dSJustin T. Gibbs 6939a5479bc5SJustin T. Gibbs /* 6940a5479bc5SJustin T. Gibbs * Scan all installed busses. 6941a5479bc5SJustin T. Gibbs */ 69428b8a9b1dSJustin T. Gibbs xpt_for_all_busses(xptconfigbuscountfunc, NULL); 69438b8a9b1dSJustin T. Gibbs 6944ecdf1113SJustin T. Gibbs if (busses_to_config == 0) { 6945ecdf1113SJustin T. Gibbs /* Call manually because we don't have any busses */ 69468b8a9b1dSJustin T. Gibbs xpt_finishconfig(xpt_periph, NULL); 69472863f7b1SJustin T. Gibbs } else { 69483a937198SBrooks Davis if (busses_to_reset > 0 && scsi_delay >= 2000) { 69492863f7b1SJustin T. Gibbs printf("Waiting %d seconds for SCSI " 69503a937198SBrooks Davis "devices to settle\n", scsi_delay/1000); 69512863f7b1SJustin T. Gibbs } 6952ecdf1113SJustin T. Gibbs xpt_for_all_busses(xptconfigfunc, NULL); 69538b8a9b1dSJustin T. Gibbs } 69542863f7b1SJustin T. Gibbs } 69558b8a9b1dSJustin T. Gibbs 69568b8a9b1dSJustin T. Gibbs /* 69578b8a9b1dSJustin T. Gibbs * If the given device only has one peripheral attached to it, and if that 69588b8a9b1dSJustin T. Gibbs * peripheral is the passthrough driver, announce it. This insures that the 69598b8a9b1dSJustin T. Gibbs * user sees some sort of announcement for every peripheral in their system. 69608b8a9b1dSJustin T. Gibbs */ 69618b8a9b1dSJustin T. Gibbs static int 69628b8a9b1dSJustin T. Gibbs xptpassannouncefunc(struct cam_ed *device, void *arg) 69638b8a9b1dSJustin T. Gibbs { 69648b8a9b1dSJustin T. Gibbs struct cam_periph *periph; 69658b8a9b1dSJustin T. Gibbs int i; 69668b8a9b1dSJustin T. Gibbs 69678b8a9b1dSJustin T. Gibbs for (periph = SLIST_FIRST(&device->periphs), i = 0; periph != NULL; 69688b8a9b1dSJustin T. Gibbs periph = SLIST_NEXT(periph, periph_links), i++); 69698b8a9b1dSJustin T. Gibbs 69708b8a9b1dSJustin T. Gibbs periph = SLIST_FIRST(&device->periphs); 69718b8a9b1dSJustin T. Gibbs if ((i == 1) 69728b8a9b1dSJustin T. Gibbs && (strncmp(periph->periph_name, "pass", 4) == 0)) 69738b8a9b1dSJustin T. Gibbs xpt_announce_periph(periph, NULL); 69748b8a9b1dSJustin T. Gibbs 69758b8a9b1dSJustin T. Gibbs return(1); 69768b8a9b1dSJustin T. Gibbs } 69778b8a9b1dSJustin T. Gibbs 69788b8a9b1dSJustin T. Gibbs static void 69792b83592fSScott Long xpt_finishconfig_task(void *context, int pending) 69808b8a9b1dSJustin T. Gibbs { 69818b8a9b1dSJustin T. Gibbs struct periph_driver **p_drv; 69828b8a9b1dSJustin T. Gibbs int i; 69838b8a9b1dSJustin T. Gibbs 69842b83592fSScott Long if (busses_to_config == 0) { 69852b83592fSScott Long /* Register all the peripheral drivers */ 69862b83592fSScott Long /* XXX This will have to change when we have loadable modules */ 69872b83592fSScott Long p_drv = periph_drivers; 69882b83592fSScott Long for (i = 0; p_drv[i] != NULL; i++) { 69892b83592fSScott Long (*p_drv[i]->init)(); 69902b83592fSScott Long } 69912b83592fSScott Long 69922b83592fSScott Long /* 69932b83592fSScott Long * Check for devices with no "standard" peripheral driver 69942b83592fSScott Long * attached. For any devices like that, announce the 69952b83592fSScott Long * passthrough driver so the user will see something. 69962b83592fSScott Long */ 69972b83592fSScott Long xpt_for_all_devices(xptpassannouncefunc, NULL); 69982b83592fSScott Long 69992b83592fSScott Long /* Release our hook so that the boot can continue. */ 70002b83592fSScott Long config_intrhook_disestablish(xsoftc.xpt_config_hook); 70010dd50e9bSScott Long free(xsoftc.xpt_config_hook, M_CAMXPT); 70022b83592fSScott Long xsoftc.xpt_config_hook = NULL; 70032b83592fSScott Long } 70042b83592fSScott Long 70052b83592fSScott Long free(context, M_CAMXPT); 70062b83592fSScott Long } 70072b83592fSScott Long 70082b83592fSScott Long static void 70092b83592fSScott Long xpt_finishconfig(struct cam_periph *periph, union ccb *done_ccb) 70102b83592fSScott Long { 70112b83592fSScott Long struct xpt_task *task; 70122b83592fSScott Long 70138b8a9b1dSJustin T. Gibbs if (done_ccb != NULL) { 70148b8a9b1dSJustin T. Gibbs CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_TRACE, 70158b8a9b1dSJustin T. Gibbs ("xpt_finishconfig\n")); 70168b8a9b1dSJustin T. Gibbs switch(done_ccb->ccb_h.func_code) { 70178b8a9b1dSJustin T. Gibbs case XPT_RESET_BUS: 70188b8a9b1dSJustin T. Gibbs if (done_ccb->ccb_h.status == CAM_REQ_CMP) { 70198b8a9b1dSJustin T. Gibbs done_ccb->ccb_h.func_code = XPT_SCAN_BUS; 70208b8a9b1dSJustin T. Gibbs done_ccb->ccb_h.cbfcnp = xpt_finishconfig; 7021df8f9080SJustin T. Gibbs done_ccb->crcn.flags = 0; 70228b8a9b1dSJustin T. Gibbs xpt_action(done_ccb); 70238b8a9b1dSJustin T. Gibbs return; 70248b8a9b1dSJustin T. Gibbs } 70258b8a9b1dSJustin T. Gibbs /* FALLTHROUGH */ 70268b8a9b1dSJustin T. Gibbs case XPT_SCAN_BUS: 702798192658SJustin T. Gibbs default: 70288b8a9b1dSJustin T. Gibbs xpt_free_path(done_ccb->ccb_h.path); 70298b8a9b1dSJustin T. Gibbs busses_to_config--; 70308b8a9b1dSJustin T. Gibbs break; 70318b8a9b1dSJustin T. Gibbs } 70328b8a9b1dSJustin T. Gibbs } 70338b8a9b1dSJustin T. Gibbs 70342524e4a8SScott Long if (busses_to_config == 0) { 70352b83592fSScott Long task = malloc(sizeof(struct xpt_task), M_CAMXPT, M_NOWAIT); 70362b83592fSScott Long if (task != NULL) { 70372b83592fSScott Long TASK_INIT(&task->task, 0, xpt_finishconfig_task, task); 70382b83592fSScott Long taskqueue_enqueue(taskqueue_thread, &task->task); 70398b8a9b1dSJustin T. Gibbs } 70402524e4a8SScott Long } 70418b8a9b1dSJustin T. Gibbs 70428b8a9b1dSJustin T. Gibbs if (done_ccb != NULL) 70438b8a9b1dSJustin T. Gibbs xpt_free_ccb(done_ccb); 70448b8a9b1dSJustin T. Gibbs } 70458b8a9b1dSJustin T. Gibbs 704685d92640SScott Long cam_status 704785d92640SScott Long xpt_register_async(int event, ac_callback_t *cbfunc, void *cbarg, 704885d92640SScott Long struct cam_path *path) 704985d92640SScott Long { 705085d92640SScott Long struct ccb_setasync csa; 705185d92640SScott Long cam_status status; 705285d92640SScott Long int xptpath = 0; 705385d92640SScott Long 705485d92640SScott Long if (path == NULL) { 705585d92640SScott Long mtx_lock(&xsoftc.xpt_lock); 705685d92640SScott Long status = xpt_create_path(&path, /*periph*/NULL, CAM_XPT_PATH_ID, 705785d92640SScott Long CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD); 705885d92640SScott Long if (status != CAM_REQ_CMP) { 705985d92640SScott Long mtx_unlock(&xsoftc.xpt_lock); 706085d92640SScott Long return (status); 706185d92640SScott Long } 706285d92640SScott Long xptpath = 1; 706385d92640SScott Long } 706485d92640SScott Long 706585d92640SScott Long xpt_setup_ccb(&csa.ccb_h, path, /*priority*/5); 706685d92640SScott Long csa.ccb_h.func_code = XPT_SASYNC_CB; 706785d92640SScott Long csa.event_enable = event; 706885d92640SScott Long csa.callback = cbfunc; 706985d92640SScott Long csa.callback_arg = cbarg; 707085d92640SScott Long xpt_action((union ccb *)&csa); 707185d92640SScott Long status = csa.ccb_h.status; 707285d92640SScott Long if (xptpath) { 707385d92640SScott Long xpt_free_path(path); 707485d92640SScott Long mtx_unlock(&xsoftc.xpt_lock); 707585d92640SScott Long } 707685d92640SScott Long return (status); 707785d92640SScott Long } 707885d92640SScott Long 70798b8a9b1dSJustin T. Gibbs static void 70808b8a9b1dSJustin T. Gibbs xptaction(struct cam_sim *sim, union ccb *work_ccb) 70818b8a9b1dSJustin T. Gibbs { 70828b8a9b1dSJustin T. Gibbs CAM_DEBUG(work_ccb->ccb_h.path, CAM_DEBUG_TRACE, ("xptaction\n")); 70838b8a9b1dSJustin T. Gibbs 70848b8a9b1dSJustin T. Gibbs switch (work_ccb->ccb_h.func_code) { 70858b8a9b1dSJustin T. Gibbs /* Common cases first */ 70868b8a9b1dSJustin T. Gibbs case XPT_PATH_INQ: /* Path routing inquiry */ 70878b8a9b1dSJustin T. Gibbs { 70888b8a9b1dSJustin T. Gibbs struct ccb_pathinq *cpi; 70898b8a9b1dSJustin T. Gibbs 70908b8a9b1dSJustin T. Gibbs cpi = &work_ccb->cpi; 70918b8a9b1dSJustin T. Gibbs cpi->version_num = 1; /* XXX??? */ 70928b8a9b1dSJustin T. Gibbs cpi->hba_inquiry = 0; 70938b8a9b1dSJustin T. Gibbs cpi->target_sprt = 0; 70948b8a9b1dSJustin T. Gibbs cpi->hba_misc = 0; 70958b8a9b1dSJustin T. Gibbs cpi->hba_eng_cnt = 0; 70968b8a9b1dSJustin T. Gibbs cpi->max_target = 0; 70978b8a9b1dSJustin T. Gibbs cpi->max_lun = 0; 70988b8a9b1dSJustin T. Gibbs cpi->initiator_id = 0; 70998b8a9b1dSJustin T. Gibbs strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN); 71008b8a9b1dSJustin T. Gibbs strncpy(cpi->hba_vid, "", HBA_IDLEN); 71018b8a9b1dSJustin T. Gibbs strncpy(cpi->dev_name, sim->sim_name, DEV_IDLEN); 71028b8a9b1dSJustin T. Gibbs cpi->unit_number = sim->unit_number; 71038b8a9b1dSJustin T. Gibbs cpi->bus_id = sim->bus_id; 71049deea857SKenneth D. Merry cpi->base_transfer_speed = 0; 71053393f8daSKenneth D. Merry cpi->protocol = PROTO_UNSPECIFIED; 71063393f8daSKenneth D. Merry cpi->protocol_version = PROTO_VERSION_UNSPECIFIED; 71073393f8daSKenneth D. Merry cpi->transport = XPORT_UNSPECIFIED; 71083393f8daSKenneth D. Merry cpi->transport_version = XPORT_VERSION_UNSPECIFIED; 71098b8a9b1dSJustin T. Gibbs cpi->ccb_h.status = CAM_REQ_CMP; 71108b8a9b1dSJustin T. Gibbs xpt_done(work_ccb); 71118b8a9b1dSJustin T. Gibbs break; 71128b8a9b1dSJustin T. Gibbs } 71138b8a9b1dSJustin T. Gibbs default: 71148b8a9b1dSJustin T. Gibbs work_ccb->ccb_h.status = CAM_REQ_INVALID; 71158b8a9b1dSJustin T. Gibbs xpt_done(work_ccb); 71168b8a9b1dSJustin T. Gibbs break; 71178b8a9b1dSJustin T. Gibbs } 71188b8a9b1dSJustin T. Gibbs } 71198b8a9b1dSJustin T. Gibbs 71208b8a9b1dSJustin T. Gibbs /* 7121434bbf6eSJustin T. Gibbs * The xpt as a "controller" has no interrupt sources, so polling 7122434bbf6eSJustin T. Gibbs * is a no-op. 7123434bbf6eSJustin T. Gibbs */ 7124434bbf6eSJustin T. Gibbs static void 7125434bbf6eSJustin T. Gibbs xptpoll(struct cam_sim *sim) 7126434bbf6eSJustin T. Gibbs { 7127434bbf6eSJustin T. Gibbs } 7128434bbf6eSJustin T. Gibbs 71292b83592fSScott Long void 71302b83592fSScott Long xpt_lock_buses(void) 71312b83592fSScott Long { 71322b83592fSScott Long mtx_lock(&xsoftc.xpt_topo_lock); 71332b83592fSScott Long } 71342b83592fSScott Long 71352b83592fSScott Long void 71362b83592fSScott Long xpt_unlock_buses(void) 71372b83592fSScott Long { 71382b83592fSScott Long mtx_unlock(&xsoftc.xpt_topo_lock); 71392b83592fSScott Long } 71402b83592fSScott Long 71415d754af7SMatt Jacob static void 71429758cc83SScott Long camisr(void *dummy) 71438b8a9b1dSJustin T. Gibbs { 71449758cc83SScott Long cam_simq_t queue; 71452b83592fSScott Long struct cam_sim *sim; 71468b8a9b1dSJustin T. Gibbs 71479758cc83SScott Long mtx_lock(&cam_simq_lock); 7148ef3cf714SScott Long TAILQ_INIT(&queue); 71499758cc83SScott Long TAILQ_CONCAT(&queue, &cam_simq, links); 71509758cc83SScott Long mtx_unlock(&cam_simq_lock); 7151ef3cf714SScott Long 71529758cc83SScott Long while ((sim = TAILQ_FIRST(&queue)) != NULL) { 71539758cc83SScott Long TAILQ_REMOVE(&queue, sim, links); 715411e4faceSScott Long CAM_SIM_LOCK(sim); 71559758cc83SScott Long sim->flags &= ~CAM_SIM_ON_DONEQ; 71569758cc83SScott Long camisr_runqueue(&sim->sim_doneq); 715711e4faceSScott Long CAM_SIM_UNLOCK(sim); 71589758cc83SScott Long } 71599758cc83SScott Long } 71609758cc83SScott Long 71619758cc83SScott Long static void 71629758cc83SScott Long camisr_runqueue(void *V_queue) 71639758cc83SScott Long { 71649758cc83SScott Long cam_isrq_t *queue = V_queue; 71659758cc83SScott Long struct ccb_hdr *ccb_h; 71669758cc83SScott Long 71679758cc83SScott Long while ((ccb_h = TAILQ_FIRST(queue)) != NULL) { 71688b8a9b1dSJustin T. Gibbs int runq; 71698b8a9b1dSJustin T. Gibbs 71709758cc83SScott Long TAILQ_REMOVE(queue, ccb_h, sim_links.tqe); 71718b8a9b1dSJustin T. Gibbs ccb_h->pinfo.index = CAM_UNQUEUED_INDEX; 71728b8a9b1dSJustin T. Gibbs 71738b8a9b1dSJustin T. Gibbs CAM_DEBUG(ccb_h->path, CAM_DEBUG_TRACE, 717457b89bbcSNate Lawson ("camisr\n")); 71758b8a9b1dSJustin T. Gibbs 71768b8a9b1dSJustin T. Gibbs runq = FALSE; 71778b8a9b1dSJustin T. Gibbs 71788b8a9b1dSJustin T. Gibbs if (ccb_h->flags & CAM_HIGH_POWER) { 71798b8a9b1dSJustin T. Gibbs struct highpowerlist *hphead; 71808b8a9b1dSJustin T. Gibbs union ccb *send_ccb; 71818b8a9b1dSJustin T. Gibbs 71822b83592fSScott Long mtx_lock(&xsoftc.xpt_lock); 71832b83592fSScott Long hphead = &xsoftc.highpowerq; 71848b8a9b1dSJustin T. Gibbs 71858b8a9b1dSJustin T. Gibbs send_ccb = (union ccb *)STAILQ_FIRST(hphead); 71868b8a9b1dSJustin T. Gibbs 71878b8a9b1dSJustin T. Gibbs /* 71888b8a9b1dSJustin T. Gibbs * Increment the count since this command is done. 71898b8a9b1dSJustin T. Gibbs */ 71902b83592fSScott Long xsoftc.num_highpower++; 71918b8a9b1dSJustin T. Gibbs 71928b8a9b1dSJustin T. Gibbs /* 71938b8a9b1dSJustin T. Gibbs * Any high powered commands queued up? 71948b8a9b1dSJustin T. Gibbs */ 71958b8a9b1dSJustin T. Gibbs if (send_ccb != NULL) { 71968b8a9b1dSJustin T. Gibbs 71978b8a9b1dSJustin T. Gibbs STAILQ_REMOVE_HEAD(hphead, xpt_links.stqe); 71982b83592fSScott Long mtx_unlock(&xsoftc.xpt_lock); 71998b8a9b1dSJustin T. Gibbs 72002cefde5fSJustin T. Gibbs xpt_release_devq(send_ccb->ccb_h.path, 72012cefde5fSJustin T. Gibbs /*count*/1, /*runqueue*/TRUE); 72022b83592fSScott Long } else 72032b83592fSScott Long mtx_unlock(&xsoftc.xpt_lock); 72048b8a9b1dSJustin T. Gibbs } 72052b83592fSScott Long 72069deea857SKenneth D. Merry if ((ccb_h->func_code & XPT_FC_USER_CCB) == 0) { 72078b8a9b1dSJustin T. Gibbs struct cam_ed *dev; 72088b8a9b1dSJustin T. Gibbs 72098b8a9b1dSJustin T. Gibbs dev = ccb_h->path->device; 72108b8a9b1dSJustin T. Gibbs 72118b8a9b1dSJustin T. Gibbs cam_ccbq_ccb_done(&dev->ccbq, (union ccb *)ccb_h); 72128b8a9b1dSJustin T. Gibbs 7213d3ef3454SIan Dowse if (!SIM_DEAD(ccb_h->path->bus->sim)) { 72148b8a9b1dSJustin T. Gibbs ccb_h->path->bus->sim->devq->send_active--; 72158b8a9b1dSJustin T. Gibbs ccb_h->path->bus->sim->devq->send_openings++; 7216d3ef3454SIan Dowse } 72178b8a9b1dSJustin T. Gibbs 72183393f8daSKenneth D. Merry if (((dev->flags & CAM_DEV_REL_ON_COMPLETE) != 0 72193393f8daSKenneth D. Merry && (ccb_h->status&CAM_STATUS_MASK) != CAM_REQUEUE_REQ) 72208b8a9b1dSJustin T. Gibbs || ((dev->flags & CAM_DEV_REL_ON_QUEUE_EMPTY) != 0 72218b8a9b1dSJustin T. Gibbs && (dev->ccbq.dev_active == 0))) { 72228b8a9b1dSJustin T. Gibbs 72232cefde5fSJustin T. Gibbs xpt_release_devq(ccb_h->path, /*count*/1, 72248b8a9b1dSJustin T. Gibbs /*run_queue*/TRUE); 72258b8a9b1dSJustin T. Gibbs } 72268b8a9b1dSJustin T. Gibbs 7227fd21cc5eSJustin T. Gibbs if ((dev->flags & CAM_DEV_TAG_AFTER_COUNT) != 0 7228fd21cc5eSJustin T. Gibbs && (--dev->tag_delay_count == 0)) 7229fd21cc5eSJustin T. Gibbs xpt_start_tags(ccb_h->path); 7230fd21cc5eSJustin T. Gibbs 72318b8a9b1dSJustin T. Gibbs if ((dev->ccbq.queue.entries > 0) 72328b8a9b1dSJustin T. Gibbs && (dev->qfrozen_cnt == 0) 72338b8a9b1dSJustin T. Gibbs && (device_is_send_queued(dev) == 0)) { 72348b8a9b1dSJustin T. Gibbs runq = xpt_schedule_dev_sendq(ccb_h->path->bus, 72358b8a9b1dSJustin T. Gibbs dev); 72368b8a9b1dSJustin T. Gibbs } 72378b8a9b1dSJustin T. Gibbs } 72388b8a9b1dSJustin T. Gibbs 72398b8a9b1dSJustin T. Gibbs if (ccb_h->status & CAM_RELEASE_SIMQ) { 72408b8a9b1dSJustin T. Gibbs xpt_release_simq(ccb_h->path->bus->sim, 72418b8a9b1dSJustin T. Gibbs /*run_queue*/TRUE); 7242434bbf6eSJustin T. Gibbs ccb_h->status &= ~CAM_RELEASE_SIMQ; 7243434bbf6eSJustin T. Gibbs runq = FALSE; 7244434bbf6eSJustin T. Gibbs } 7245434bbf6eSJustin T. Gibbs 7246434bbf6eSJustin T. Gibbs if ((ccb_h->flags & CAM_DEV_QFRZDIS) 72478b8a9b1dSJustin T. Gibbs && (ccb_h->status & CAM_DEV_QFRZN)) { 72482cefde5fSJustin T. Gibbs xpt_release_devq(ccb_h->path, /*count*/1, 72498b8a9b1dSJustin T. Gibbs /*run_queue*/TRUE); 72508b8a9b1dSJustin T. Gibbs ccb_h->status &= ~CAM_DEV_QFRZN; 72518b8a9b1dSJustin T. Gibbs } else if (runq) { 72528b8a9b1dSJustin T. Gibbs xpt_run_dev_sendq(ccb_h->path->bus); 72538b8a9b1dSJustin T. Gibbs } 72548b8a9b1dSJustin T. Gibbs 72558b8a9b1dSJustin T. Gibbs /* Call the peripheral driver's callback */ 7256434bbf6eSJustin T. Gibbs (*ccb_h->cbfcnp)(ccb_h->path->periph, (union ccb *)ccb_h); 72578b8a9b1dSJustin T. Gibbs } 72588b8a9b1dSJustin T. Gibbs } 7259d3ef3454SIan Dowse 7260d3ef3454SIan Dowse static void 7261d3ef3454SIan Dowse dead_sim_action(struct cam_sim *sim, union ccb *ccb) 7262d3ef3454SIan Dowse { 7263d3ef3454SIan Dowse 7264d3ef3454SIan Dowse ccb->ccb_h.status = CAM_DEV_NOT_THERE; 7265d3ef3454SIan Dowse xpt_done(ccb); 7266d3ef3454SIan Dowse } 7267d3ef3454SIan Dowse 7268d3ef3454SIan Dowse static void 7269d3ef3454SIan Dowse dead_sim_poll(struct cam_sim *sim) 7270d3ef3454SIan Dowse { 7271d3ef3454SIan Dowse } 7272