18b8a9b1dSJustin T. Gibbs /* 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 * 29c3aac50fSPeter Wemm * $FreeBSD$ 308b8a9b1dSJustin T. Gibbs */ 318b8a9b1dSJustin T. Gibbs #include <sys/param.h> 328b8a9b1dSJustin T. Gibbs #include <sys/systm.h> 338b8a9b1dSJustin T. Gibbs #include <sys/types.h> 348b8a9b1dSJustin T. Gibbs #include <sys/malloc.h> 358b8a9b1dSJustin T. Gibbs #include <sys/kernel.h> 3687cfaf0eSJustin T. Gibbs #include <sys/time.h> 378b8a9b1dSJustin T. Gibbs #include <sys/conf.h> 388b8a9b1dSJustin T. Gibbs #include <sys/fcntl.h> 398b8a9b1dSJustin T. Gibbs #include <sys/md5.h> 408b8a9b1dSJustin T. Gibbs #include <sys/devicestat.h> 415d754af7SMatt Jacob #include <sys/interrupt.h> 4275f51904SPeter Wemm #include <sys/bus.h> 438b8a9b1dSJustin T. Gibbs 448b8a9b1dSJustin T. Gibbs #ifdef PC98 458b8a9b1dSJustin T. Gibbs #include <pc98/pc98/pc98_machdep.h> /* geometry translation */ 468b8a9b1dSJustin T. Gibbs #endif 478b8a9b1dSJustin T. Gibbs 488b8a9b1dSJustin T. Gibbs #include <machine/clock.h> 498b8a9b1dSJustin T. Gibbs #include <machine/ipl.h> 508b8a9b1dSJustin T. Gibbs 518b8a9b1dSJustin T. Gibbs #include <cam/cam.h> 528b8a9b1dSJustin T. Gibbs #include <cam/cam_ccb.h> 538b8a9b1dSJustin T. Gibbs #include <cam/cam_periph.h> 548b8a9b1dSJustin T. Gibbs #include <cam/cam_sim.h> 558b8a9b1dSJustin T. Gibbs #include <cam/cam_xpt.h> 568b8a9b1dSJustin T. Gibbs #include <cam/cam_xpt_sim.h> 578b8a9b1dSJustin T. Gibbs #include <cam/cam_xpt_periph.h> 588b8a9b1dSJustin T. Gibbs #include <cam/cam_debug.h> 598b8a9b1dSJustin T. Gibbs 608b8a9b1dSJustin T. Gibbs #include <cam/scsi/scsi_all.h> 618b8a9b1dSJustin T. Gibbs #include <cam/scsi/scsi_message.h> 628b8a9b1dSJustin T. Gibbs #include <cam/scsi/scsi_pass.h> 638b8a9b1dSJustin T. Gibbs #include "opt_cam.h" 648b8a9b1dSJustin T. Gibbs 658b8a9b1dSJustin T. Gibbs /* Datastructures internal to the xpt layer */ 668b8a9b1dSJustin T. Gibbs 678b8a9b1dSJustin T. Gibbs /* 688b8a9b1dSJustin T. Gibbs * Definition of an async handler callback block. These are used to add 698b8a9b1dSJustin T. Gibbs * SIMs and peripherals to the async callback lists. 708b8a9b1dSJustin T. Gibbs */ 718b8a9b1dSJustin T. Gibbs struct async_node { 72e3975643SJake Burkholder SLIST_ENTRY(async_node) links; 738b8a9b1dSJustin T. Gibbs u_int32_t event_enable; /* Async Event enables */ 748b8a9b1dSJustin T. Gibbs void (*callback)(void *arg, u_int32_t code, 758b8a9b1dSJustin T. Gibbs struct cam_path *path, void *args); 768b8a9b1dSJustin T. Gibbs void *callback_arg; 778b8a9b1dSJustin T. Gibbs }; 788b8a9b1dSJustin T. Gibbs 79e3975643SJake Burkholder SLIST_HEAD(async_list, async_node); 80e3975643SJake Burkholder SLIST_HEAD(periph_list, cam_periph); 81e3975643SJake Burkholder static STAILQ_HEAD(highpowerlist, ccb_hdr) highpowerq; 828b8a9b1dSJustin T. Gibbs 838b8a9b1dSJustin T. Gibbs /* 848b8a9b1dSJustin T. Gibbs * This is the maximum number of high powered commands (e.g. start unit) 858b8a9b1dSJustin T. Gibbs * that can be outstanding at a particular time. 868b8a9b1dSJustin T. Gibbs */ 878b8a9b1dSJustin T. Gibbs #ifndef CAM_MAX_HIGHPOWER 888b8a9b1dSJustin T. Gibbs #define CAM_MAX_HIGHPOWER 4 898b8a9b1dSJustin T. Gibbs #endif 908b8a9b1dSJustin T. Gibbs 918b8a9b1dSJustin T. Gibbs /* number of high powered commands that can go through right now */ 928b8a9b1dSJustin T. Gibbs static int num_highpower = CAM_MAX_HIGHPOWER; 938b8a9b1dSJustin T. Gibbs 948b8a9b1dSJustin T. Gibbs /* 958b8a9b1dSJustin T. Gibbs * Structure for queueing a device in a run queue. 968b8a9b1dSJustin T. Gibbs * There is one run queue for allocating new ccbs, 978b8a9b1dSJustin T. Gibbs * and another for sending ccbs to the controller. 988b8a9b1dSJustin T. Gibbs */ 998b8a9b1dSJustin T. Gibbs struct cam_ed_qinfo { 1008b8a9b1dSJustin T. Gibbs cam_pinfo pinfo; 1018b8a9b1dSJustin T. Gibbs struct cam_ed *device; 1028b8a9b1dSJustin T. Gibbs }; 1038b8a9b1dSJustin T. Gibbs 1048b8a9b1dSJustin T. Gibbs /* 1058b8a9b1dSJustin T. Gibbs * The CAM EDT (Existing Device Table) contains the device information for 1068b8a9b1dSJustin T. Gibbs * all devices for all busses in the system. The table contains a 1078b8a9b1dSJustin T. Gibbs * cam_ed structure for each device on the bus. 1088b8a9b1dSJustin T. Gibbs */ 1098b8a9b1dSJustin T. Gibbs struct cam_ed { 110e3975643SJake Burkholder TAILQ_ENTRY(cam_ed) links; 1118b8a9b1dSJustin T. Gibbs struct cam_ed_qinfo alloc_ccb_entry; 1128b8a9b1dSJustin T. Gibbs struct cam_ed_qinfo send_ccb_entry; 1138b8a9b1dSJustin T. Gibbs struct cam_et *target; 1148b8a9b1dSJustin T. Gibbs lun_id_t lun_id; 1158b8a9b1dSJustin T. Gibbs struct camq drvq; /* 1168b8a9b1dSJustin T. Gibbs * Queue of type drivers wanting to do 1178b8a9b1dSJustin T. Gibbs * work on this device. 1188b8a9b1dSJustin T. Gibbs */ 1198b8a9b1dSJustin T. Gibbs struct cam_ccbq ccbq; /* Queue of pending ccbs */ 1208b8a9b1dSJustin T. Gibbs struct async_list asyncs; /* Async callback info for this B/T/L */ 1218b8a9b1dSJustin T. Gibbs struct periph_list periphs; /* All attached devices */ 1228b8a9b1dSJustin T. Gibbs u_int generation; /* Generation number */ 1238b8a9b1dSJustin T. Gibbs struct cam_periph *owner; /* Peripheral driver's ownership tag */ 1248b8a9b1dSJustin T. Gibbs struct xpt_quirk_entry *quirk; /* Oddities about this device */ 1258b8a9b1dSJustin T. Gibbs /* Storage for the inquiry data */ 1268b8a9b1dSJustin T. Gibbs struct scsi_inquiry_data inq_data; 1278b8a9b1dSJustin T. Gibbs u_int8_t inq_flags; /* 1288b8a9b1dSJustin T. Gibbs * Current settings for inquiry flags. 1298b8a9b1dSJustin T. Gibbs * This allows us to override settings 1308b8a9b1dSJustin T. Gibbs * like disconnection and tagged 1318b8a9b1dSJustin T. Gibbs * queuing for a device. 1328b8a9b1dSJustin T. Gibbs */ 1338b8a9b1dSJustin T. Gibbs u_int8_t queue_flags; /* Queue flags from the control page */ 1348b8a9b1dSJustin T. Gibbs u_int8_t serial_num_len; 1359ec5d7cdSMatt Jacob u_int8_t *serial_num; 1368b8a9b1dSJustin T. Gibbs u_int32_t qfrozen_cnt; 1378b8a9b1dSJustin T. Gibbs u_int32_t flags; 1388b8a9b1dSJustin T. Gibbs #define CAM_DEV_UNCONFIGURED 0x01 1398b8a9b1dSJustin T. Gibbs #define CAM_DEV_REL_TIMEOUT_PENDING 0x02 1408b8a9b1dSJustin T. Gibbs #define CAM_DEV_REL_ON_COMPLETE 0x04 1418b8a9b1dSJustin T. Gibbs #define CAM_DEV_REL_ON_QUEUE_EMPTY 0x08 1428b8a9b1dSJustin T. Gibbs #define CAM_DEV_RESIZE_QUEUE_NEEDED 0x10 143fd21cc5eSJustin T. Gibbs #define CAM_DEV_TAG_AFTER_COUNT 0x20 14487cfaf0eSJustin T. Gibbs #define CAM_DEV_INQUIRY_DATA_VALID 0x40 145fd21cc5eSJustin T. Gibbs u_int32_t tag_delay_count; 146fd21cc5eSJustin T. Gibbs #define CAM_TAG_DELAY_COUNT 5 1478b8a9b1dSJustin T. Gibbs u_int32_t refcount; 1488b8a9b1dSJustin T. Gibbs struct callout_handle c_handle; 1498b8a9b1dSJustin T. Gibbs }; 1508b8a9b1dSJustin T. Gibbs 1518b8a9b1dSJustin T. Gibbs /* 1528b8a9b1dSJustin T. Gibbs * Each target is represented by an ET (Existing Target). These 1538b8a9b1dSJustin T. Gibbs * entries are created when a target is successfully probed with an 1548b8a9b1dSJustin T. Gibbs * identify, and removed when a device fails to respond after a number 1558b8a9b1dSJustin T. Gibbs * of retries, or a bus rescan finds the device missing. 1568b8a9b1dSJustin T. Gibbs */ 1578b8a9b1dSJustin T. Gibbs struct cam_et { 158e3975643SJake Burkholder TAILQ_HEAD(, cam_ed) ed_entries; 159e3975643SJake Burkholder TAILQ_ENTRY(cam_et) links; 1608b8a9b1dSJustin T. Gibbs struct cam_eb *bus; 1618b8a9b1dSJustin T. Gibbs target_id_t target_id; 1628b8a9b1dSJustin T. Gibbs u_int32_t refcount; 1638b8a9b1dSJustin T. Gibbs u_int generation; 16487cfaf0eSJustin T. Gibbs struct timeval last_reset; 1658b8a9b1dSJustin T. Gibbs }; 1668b8a9b1dSJustin T. Gibbs 1678b8a9b1dSJustin T. Gibbs /* 1688b8a9b1dSJustin T. Gibbs * Each bus is represented by an EB (Existing Bus). These entries 1698b8a9b1dSJustin T. Gibbs * are created by calls to xpt_bus_register and deleted by calls to 1708b8a9b1dSJustin T. Gibbs * xpt_bus_deregister. 1718b8a9b1dSJustin T. Gibbs */ 1728b8a9b1dSJustin T. Gibbs struct cam_eb { 173e3975643SJake Burkholder TAILQ_HEAD(, cam_et) et_entries; 174e3975643SJake Burkholder TAILQ_ENTRY(cam_eb) links; 1758b8a9b1dSJustin T. Gibbs path_id_t path_id; 1768b8a9b1dSJustin T. Gibbs struct cam_sim *sim; 17787cfaf0eSJustin T. Gibbs struct timeval last_reset; 1788b8a9b1dSJustin T. Gibbs u_int32_t flags; 1798b8a9b1dSJustin T. Gibbs #define CAM_EB_RUNQ_SCHEDULED 0x01 180a5479bc5SJustin T. Gibbs u_int32_t refcount; 1818b8a9b1dSJustin T. Gibbs u_int generation; 1828b8a9b1dSJustin T. Gibbs }; 1838b8a9b1dSJustin T. Gibbs 1848b8a9b1dSJustin T. Gibbs struct cam_path { 1858b8a9b1dSJustin T. Gibbs struct cam_periph *periph; 1868b8a9b1dSJustin T. Gibbs struct cam_eb *bus; 1878b8a9b1dSJustin T. Gibbs struct cam_et *target; 1888b8a9b1dSJustin T. Gibbs struct cam_ed *device; 1898b8a9b1dSJustin T. Gibbs }; 1908b8a9b1dSJustin T. Gibbs 1918b8a9b1dSJustin T. Gibbs struct xpt_quirk_entry { 1928b8a9b1dSJustin T. Gibbs struct scsi_inquiry_pattern inq_pat; 1938b8a9b1dSJustin T. Gibbs u_int8_t quirks; 1948b8a9b1dSJustin T. Gibbs #define CAM_QUIRK_NOLUNS 0x01 1958b8a9b1dSJustin T. Gibbs #define CAM_QUIRK_NOSERIAL 0x02 19648f6456dSMatt Jacob #define CAM_QUIRK_HILUNS 0x04 1979deea857SKenneth D. Merry u_int mintags; 1989deea857SKenneth D. Merry u_int maxtags; 1998b8a9b1dSJustin T. Gibbs }; 20048f6456dSMatt Jacob #define CAM_SCSI2_MAXLUN 8 2018b8a9b1dSJustin T. Gibbs 2028b8a9b1dSJustin T. Gibbs typedef enum { 2038b8a9b1dSJustin T. Gibbs XPT_FLAG_OPEN = 0x01 2048b8a9b1dSJustin T. Gibbs } xpt_flags; 2058b8a9b1dSJustin T. Gibbs 2068b8a9b1dSJustin T. Gibbs struct xpt_softc { 2078b8a9b1dSJustin T. Gibbs xpt_flags flags; 2088b8a9b1dSJustin T. Gibbs u_int32_t generation; 2098b8a9b1dSJustin T. Gibbs }; 2108b8a9b1dSJustin T. Gibbs 2118b8a9b1dSJustin T. Gibbs static const char quantum[] = "QUANTUM"; 212f24c39c7SKenneth D. Merry static const char sony[] = "SONY"; 213f24c39c7SKenneth D. Merry static const char west_digital[] = "WDIGTL"; 2141f04f5abSKenneth D. Merry static const char samsung[] = "SAMSUNG"; 215560d629fSKenneth D. Merry static const char seagate[] = "SEAGATE"; 2165acba6ecSJohn-Mark Gurney static const char microp[] = "MICROP"; 2178b8a9b1dSJustin T. Gibbs 2188b8a9b1dSJustin T. Gibbs static struct xpt_quirk_entry xpt_quirk_table[] = 2198b8a9b1dSJustin T. Gibbs { 2208b8a9b1dSJustin T. Gibbs { 2218b8a9b1dSJustin T. Gibbs /* Reports QUEUE FULL for temporary resource shortages */ 2226747168dSKenneth D. Merry { T_DIRECT, SIP_MEDIA_FIXED, quantum, "XP39100*", "*" }, 2238b8a9b1dSJustin T. Gibbs /*quirks*/0, /*mintags*/24, /*maxtags*/32 2248b8a9b1dSJustin T. Gibbs }, 2258b8a9b1dSJustin T. Gibbs { 2268b8a9b1dSJustin T. Gibbs /* Reports QUEUE FULL for temporary resource shortages */ 2276747168dSKenneth D. Merry { T_DIRECT, SIP_MEDIA_FIXED, quantum, "XP34550*", "*" }, 2286747168dSKenneth D. Merry /*quirks*/0, /*mintags*/24, /*maxtags*/32 2296747168dSKenneth D. Merry }, 2306747168dSKenneth D. Merry { 2316747168dSKenneth D. Merry /* Reports QUEUE FULL for temporary resource shortages */ 2326747168dSKenneth D. Merry { T_DIRECT, SIP_MEDIA_FIXED, quantum, "XP32275*", "*" }, 2338b8a9b1dSJustin T. Gibbs /*quirks*/0, /*mintags*/24, /*maxtags*/32 2348b8a9b1dSJustin T. Gibbs }, 2358b8a9b1dSJustin T. Gibbs { 2368b8a9b1dSJustin T. Gibbs /* Broken tagged queuing drive */ 2375acba6ecSJohn-Mark Gurney { T_DIRECT, SIP_MEDIA_FIXED, microp, "4421-07*", "*" }, 2385acba6ecSJohn-Mark Gurney /*quirks*/0, /*mintags*/0, /*maxtags*/0 2395acba6ecSJohn-Mark Gurney }, 2405acba6ecSJohn-Mark Gurney { 2415acba6ecSJohn-Mark Gurney /* Broken tagged queuing drive */ 2428b8a9b1dSJustin T. Gibbs { T_DIRECT, SIP_MEDIA_FIXED, "HP", "C372*", "*" }, 2438b8a9b1dSJustin T. Gibbs /*quirks*/0, /*mintags*/0, /*maxtags*/0 2448b8a9b1dSJustin T. Gibbs }, 2458b8a9b1dSJustin T. Gibbs { 2468b8a9b1dSJustin T. Gibbs /* Broken tagged queuing drive */ 2475acba6ecSJohn-Mark Gurney { T_DIRECT, SIP_MEDIA_FIXED, microp, "3391*", "x43h" }, 2488b8a9b1dSJustin T. Gibbs /*quirks*/0, /*mintags*/0, /*maxtags*/0 2498b8a9b1dSJustin T. Gibbs }, 2508b8a9b1dSJustin T. Gibbs { 2518597eafeSKenneth D. Merry /* 2524cdd0221SKenneth D. Merry * Unfortunately, the Quantum Atlas III has the same 2534cdd0221SKenneth D. Merry * problem as the Atlas II drives above. 2544cdd0221SKenneth D. Merry * Reported by: "Johan Granlund" <johan@granlund.nu> 2554cdd0221SKenneth D. Merry * 2564cdd0221SKenneth D. Merry * For future reference, the drive with the problem was: 2574cdd0221SKenneth D. Merry * QUANTUM QM39100TD-SW N1B0 2584cdd0221SKenneth D. Merry * 2594cdd0221SKenneth D. Merry * It's possible that Quantum will fix the problem in later 2604cdd0221SKenneth D. Merry * firmware revisions. If that happens, the quirk entry 2614cdd0221SKenneth D. Merry * will need to be made specific to the firmware revisions 2624cdd0221SKenneth D. Merry * with the problem. 2634cdd0221SKenneth D. Merry * 2644cdd0221SKenneth D. Merry */ 2654cdd0221SKenneth D. Merry /* Reports QUEUE FULL for temporary resource shortages */ 2664cdd0221SKenneth D. Merry { T_DIRECT, SIP_MEDIA_FIXED, quantum, "QM39100*", "*" }, 2674cdd0221SKenneth D. Merry /*quirks*/0, /*mintags*/24, /*maxtags*/32 2684cdd0221SKenneth D. Merry }, 2694cdd0221SKenneth D. Merry { 2704cdd0221SKenneth D. Merry /* 271588b47e5SKenneth D. Merry * 18 Gig Atlas III, same problem as the 9G version. 272588b47e5SKenneth D. Merry * Reported by: Andre Albsmeier 273588b47e5SKenneth D. Merry * <andre.albsmeier@mchp.siemens.de> 274588b47e5SKenneth D. Merry * 275588b47e5SKenneth D. Merry * For future reference, the drive with the problem was: 276588b47e5SKenneth D. Merry * QUANTUM QM318000TD-S N491 277588b47e5SKenneth D. Merry */ 278588b47e5SKenneth D. Merry /* Reports QUEUE FULL for temporary resource shortages */ 279588b47e5SKenneth D. Merry { T_DIRECT, SIP_MEDIA_FIXED, quantum, "QM318000*", "*" }, 280588b47e5SKenneth D. Merry /*quirks*/0, /*mintags*/24, /*maxtags*/32 281588b47e5SKenneth D. Merry }, 282588b47e5SKenneth D. Merry { 283588b47e5SKenneth D. Merry /* 2848597eafeSKenneth D. Merry * Broken tagged queuing drive 2858597eafeSKenneth D. Merry * Reported by: Bret Ford <bford@uop.cs.uop.edu> 2868597eafeSKenneth D. Merry * and: Martin Renters <martin@tdc.on.ca> 2878597eafeSKenneth D. Merry */ 288560d629fSKenneth D. Merry { T_DIRECT, SIP_MEDIA_FIXED, seagate, "ST410800*", "71*" }, 2898597eafeSKenneth D. Merry /*quirks*/0, /*mintags*/0, /*maxtags*/0 2908597eafeSKenneth D. Merry }, 291560d629fSKenneth D. Merry /* 292c816e025SKenneth D. Merry * The Seagate Medalist Pro drives have very poor write 293c816e025SKenneth D. Merry * performance with anything more than 2 tags. 294560d629fSKenneth D. Merry * 295560d629fSKenneth D. Merry * Reported by: Paul van der Zwan <paulz@trantor.xs4all.nl> 296560d629fSKenneth D. Merry * Drive: <SEAGATE ST36530N 1444> 297c816e025SKenneth D. Merry * 298c816e025SKenneth D. Merry * Reported by: Jeremy Lea <reg@shale.csir.co.za> 299c816e025SKenneth D. Merry * Drive: <SEAGATE ST34520W 1281> 300c816e025SKenneth D. Merry * 301c816e025SKenneth D. Merry * No one has actually reported that the 9G version 302c816e025SKenneth D. Merry * (ST39140*) of the Medalist Pro has the same problem, but 303c816e025SKenneth D. Merry * we're assuming that it does because the 4G and 6.5G 304c816e025SKenneth D. Merry * versions of the drive are broken. 305560d629fSKenneth D. Merry */ 306c816e025SKenneth D. Merry { 307c816e025SKenneth D. Merry { T_DIRECT, SIP_MEDIA_FIXED, seagate, "ST34520*", "*"}, 308c816e025SKenneth D. Merry /*quirks*/0, /*mintags*/2, /*maxtags*/2 309c816e025SKenneth D. Merry }, 310c816e025SKenneth D. Merry { 311560d629fSKenneth D. Merry { T_DIRECT, SIP_MEDIA_FIXED, seagate, "ST36530*", "*"}, 312560d629fSKenneth D. Merry /*quirks*/0, /*mintags*/2, /*maxtags*/2 313560d629fSKenneth D. Merry }, 314560d629fSKenneth D. Merry { 315c816e025SKenneth D. Merry { T_DIRECT, SIP_MEDIA_FIXED, seagate, "ST39140*", "*"}, 316c816e025SKenneth D. Merry /*quirks*/0, /*mintags*/2, /*maxtags*/2 317c816e025SKenneth D. Merry }, 318c816e025SKenneth D. Merry { 319ca3b51e9SKenneth D. Merry /* 320ca3b51e9SKenneth D. Merry * Slow when tagged queueing is enabled. Write performance 321ca3b51e9SKenneth D. Merry * steadily drops off with more and more concurrent 322ca3b51e9SKenneth D. Merry * transactions. Best sequential write performance with 323ca3b51e9SKenneth D. Merry * tagged queueing turned off and write caching turned on. 324ca3b51e9SKenneth D. Merry * 325ca3b51e9SKenneth D. Merry * PR: kern/10398 326ca3b51e9SKenneth D. Merry * Submitted by: Hideaki Okada <hokada@isl.melco.co.jp> 327ca3b51e9SKenneth D. Merry * Drive: DCAS-34330 w/ "S65A" firmware. 328ca3b51e9SKenneth D. Merry * 329ca3b51e9SKenneth D. Merry * The drive with the problem had the "S65A" firmware 330ca3b51e9SKenneth D. Merry * revision, and has also been reported (by Stephen J. 331ca3b51e9SKenneth D. Merry * Roznowski <sjr@home.net>) for a drive with the "S61A" 332ca3b51e9SKenneth D. Merry * firmware revision. 333ca3b51e9SKenneth D. Merry * 334ca3b51e9SKenneth D. Merry * Although no one has reported problems with the 2 gig 335ca3b51e9SKenneth D. Merry * version of the DCAS drive, the assumption is that it 336ca3b51e9SKenneth D. Merry * has the same problems as the 4 gig version. Therefore 337ca3b51e9SKenneth D. Merry * this quirk entries disables tagged queueing for all 338ca3b51e9SKenneth D. Merry * DCAS drives. 339ca3b51e9SKenneth D. Merry */ 340ca3b51e9SKenneth D. Merry { T_DIRECT, SIP_MEDIA_FIXED, "IBM", "DCAS*", "*" }, 341ca3b51e9SKenneth D. Merry /*quirks*/0, /*mintags*/0, /*maxtags*/0 342ca3b51e9SKenneth D. Merry }, 343ca3b51e9SKenneth D. Merry { 3448b8a9b1dSJustin T. Gibbs /* Broken tagged queuing drive */ 3458b8a9b1dSJustin T. Gibbs { T_DIRECT, SIP_MEDIA_REMOVABLE, "iomega", "jaz*", "*" }, 3468b8a9b1dSJustin T. Gibbs /*quirks*/0, /*mintags*/0, /*maxtags*/0 3478b8a9b1dSJustin T. Gibbs }, 3488b8a9b1dSJustin T. Gibbs { 3492ba01e6fSJustin T. Gibbs /* Broken tagged queuing drive */ 3506dd76100SKenneth D. Merry { T_DIRECT, SIP_MEDIA_FIXED, "CONNER", "CFP2107*", "*" }, 3512ba01e6fSJustin T. Gibbs /*quirks*/0, /*mintags*/0, /*maxtags*/0 3522ba01e6fSJustin T. Gibbs }, 3532ba01e6fSJustin T. Gibbs { 354e471e974SJustin T. Gibbs /* 3551f04f5abSKenneth D. Merry * Broken tagged queuing drive. 3561f04f5abSKenneth D. Merry * Submitted by: 3571f04f5abSKenneth D. Merry * NAKAJI Hiroyuki <nakaji@zeisei.dpri.kyoto-u.ac.jp> 3581f04f5abSKenneth D. Merry * in PR kern/9535 3591f04f5abSKenneth D. Merry */ 3601f04f5abSKenneth D. Merry { T_DIRECT, SIP_MEDIA_FIXED, samsung, "WN34324U*", "*" }, 3611f04f5abSKenneth D. Merry /*quirks*/0, /*mintags*/0, /*maxtags*/0 3621f04f5abSKenneth D. Merry }, 3631f04f5abSKenneth D. Merry { 3641f04f5abSKenneth D. Merry /* 365f24c39c7SKenneth D. Merry * Slow when tagged queueing is enabled. (1.5MB/sec versus 366f24c39c7SKenneth D. Merry * 8MB/sec.) 367f24c39c7SKenneth D. Merry * Submitted by: Andrew Gallatin <gallatin@cs.duke.edu> 368ca3b51e9SKenneth D. Merry * Best performance with these drives is achieved with 369ca3b51e9SKenneth D. Merry * tagged queueing turned off, and write caching turned on. 370f24c39c7SKenneth D. Merry */ 371f24c39c7SKenneth D. Merry { T_DIRECT, SIP_MEDIA_FIXED, west_digital, "WDE*", "*" }, 372f24c39c7SKenneth D. Merry /*quirks*/0, /*mintags*/0, /*maxtags*/0 373f24c39c7SKenneth D. Merry }, 374f24c39c7SKenneth D. Merry { 375f24c39c7SKenneth D. Merry /* 376f24c39c7SKenneth D. Merry * Slow when tagged queueing is enabled. (1.5MB/sec versus 377f24c39c7SKenneth D. Merry * 8MB/sec.) 378f24c39c7SKenneth D. Merry * Submitted by: Andrew Gallatin <gallatin@cs.duke.edu> 379ca3b51e9SKenneth D. Merry * Best performance with these drives is achieved with 380ca3b51e9SKenneth D. Merry * tagged queueing turned off, and write caching turned on. 381f24c39c7SKenneth D. Merry */ 382f24c39c7SKenneth D. Merry { T_DIRECT, SIP_MEDIA_FIXED, west_digital, "ENTERPRISE", "*" }, 383f24c39c7SKenneth D. Merry /*quirks*/0, /*mintags*/0, /*maxtags*/0 384f24c39c7SKenneth D. Merry }, 385f24c39c7SKenneth D. Merry { 386f24c39c7SKenneth D. Merry /* 387e471e974SJustin T. Gibbs * Doesn't handle queue full condition correctly, 388e471e974SJustin T. Gibbs * so we need to limit maxtags to what the device 389e471e974SJustin T. Gibbs * can handle instead of determining this automatically. 390e471e974SJustin T. Gibbs */ 3911f04f5abSKenneth D. Merry { T_DIRECT, SIP_MEDIA_FIXED, samsung, "WN321010S*", "*" }, 392fd21cc5eSJustin T. Gibbs /*quirks*/0, /*mintags*/2, /*maxtags*/32 393e471e974SJustin T. Gibbs }, 394e471e974SJustin T. Gibbs { 3958b8a9b1dSJustin T. Gibbs /* Really only one LUN */ 3964b4c702bSMatt Jacob { T_ENCLOSURE, SIP_MEDIA_FIXED, "SUN", "SENA*", "*" }, 3978b8a9b1dSJustin T. Gibbs CAM_QUIRK_NOLUNS, /*mintags*/0, /*maxtags*/0 3988b8a9b1dSJustin T. Gibbs }, 3998b8a9b1dSJustin T. Gibbs { 400fd21cc5eSJustin T. Gibbs /* I can't believe we need a quirk for DPT volumes. */ 4014b4c702bSMatt Jacob { T_ANY, SIP_MEDIA_FIXED|SIP_MEDIA_REMOVABLE, "DPT", "*", "*" }, 402fd21cc5eSJustin T. Gibbs CAM_QUIRK_NOSERIAL|CAM_QUIRK_NOLUNS, 403fd21cc5eSJustin T. Gibbs /*mintags*/0, /*maxtags*/255 404fd21cc5eSJustin T. Gibbs }, 405fd21cc5eSJustin T. Gibbs { 406f24c39c7SKenneth D. Merry /* 40725e5ca27SKenneth D. Merry * Many Sony CDROM drives don't like multi-LUN probing. 408f24c39c7SKenneth D. Merry */ 4094b4c702bSMatt Jacob { T_CDROM, SIP_MEDIA_REMOVABLE, sony, "CD-ROM CDU*", "*" }, 410f24c39c7SKenneth D. Merry CAM_QUIRK_NOLUNS, /*mintags*/0, /*maxtags*/0 411f24c39c7SKenneth D. Merry }, 412f24c39c7SKenneth D. Merry { 413f24c39c7SKenneth D. Merry /* 414f24c39c7SKenneth D. Merry * This drive doesn't like multiple LUN probing. 415f24c39c7SKenneth D. Merry * Submitted by: Parag Patel <parag@cgt.com> 416f24c39c7SKenneth D. Merry */ 4174b4c702bSMatt Jacob { T_WORM, SIP_MEDIA_REMOVABLE, sony, "CD-R CDU9*", "*" }, 418f24c39c7SKenneth D. Merry CAM_QUIRK_NOLUNS, /*mintags*/0, /*maxtags*/0 419f24c39c7SKenneth D. Merry }, 420f24c39c7SKenneth D. Merry { 421ca2b07adSKenneth D. Merry { T_WORM, SIP_MEDIA_REMOVABLE, "YAMAHA", "CDR100*", "*" }, 422ca2b07adSKenneth D. Merry CAM_QUIRK_NOLUNS, /*mintags*/0, /*maxtags*/0 423ca2b07adSKenneth D. Merry }, 424ca2b07adSKenneth D. Merry { 425b1d26455SKenneth D. Merry /* 426b1d26455SKenneth D. Merry * The 8200 doesn't like multi-lun probing, and probably 427b1d26455SKenneth D. Merry * don't like serial number requests either. 428b1d26455SKenneth D. Merry */ 429b1d26455SKenneth D. Merry { 430b1d26455SKenneth D. Merry T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "EXABYTE", 431b1d26455SKenneth D. Merry "EXB-8200*", "*" 432b1d26455SKenneth D. Merry }, 433b1d26455SKenneth D. Merry CAM_QUIRK_NOSERIAL|CAM_QUIRK_NOLUNS, /*mintags*/0, /*maxtags*/0 434b1d26455SKenneth D. Merry }, 435b1d26455SKenneth D. Merry { 43636230d67SJoerg Wunsch /* 437a6cb9949SKenneth D. Merry * These Hitachi drives don't like multi-lun probing. 438a6cb9949SKenneth D. Merry * The PR submitter has a DK319H, but says that the Linux 439a6cb9949SKenneth D. Merry * kernel has a similar work-around for the DK312 and DK314, 440a6cb9949SKenneth D. Merry * so all DK31* drives are quirked here. 441a6cb9949SKenneth D. Merry * PR: misc/18793 442a6cb9949SKenneth D. Merry * Submitted by: Paul Haddad <paul@pth.com> 443a6cb9949SKenneth D. Merry */ 444a6cb9949SKenneth D. Merry { T_DIRECT, SIP_MEDIA_FIXED, "HITACHI", "DK31*", "*" }, 445a6cb9949SKenneth D. Merry CAM_QUIRK_NOLUNS, /*mintags*/2, /*maxtags*/255 446a6cb9949SKenneth D. Merry }, 447a6cb9949SKenneth D. Merry { 448a6cb9949SKenneth D. Merry /* 44936230d67SJoerg Wunsch * This old revision of the TDC3600 is also SCSI-1, and 45036230d67SJoerg Wunsch * hangs upon serial number probing. 45136230d67SJoerg Wunsch */ 45236230d67SJoerg Wunsch { 45336230d67SJoerg Wunsch T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "TANDBERG", 45436230d67SJoerg Wunsch " TDC 3600", "U07:" 45536230d67SJoerg Wunsch }, 45636230d67SJoerg Wunsch CAM_QUIRK_NOSERIAL, /*mintags*/0, /*maxtags*/0 45736230d67SJoerg Wunsch }, 45836230d67SJoerg Wunsch { 4592c3cca96SMatt Jacob /* 4602c3cca96SMatt Jacob * Would repond to all LUNs if asked for. 4612c3cca96SMatt Jacob */ 4622c3cca96SMatt Jacob { 4632c3cca96SMatt Jacob T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "CALIPER", 4642c3cca96SMatt Jacob "CP150", "*" 4652c3cca96SMatt Jacob }, 4662c3cca96SMatt Jacob CAM_QUIRK_NOLUNS, /*mintags*/0, /*maxtags*/0 4672c3cca96SMatt Jacob }, 4682c3cca96SMatt Jacob { 469040816ecSMatt Jacob /* 470040816ecSMatt Jacob * Would repond to all LUNs if asked for. 471040816ecSMatt Jacob */ 472040816ecSMatt Jacob { 473040816ecSMatt Jacob T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "KENNEDY", 474040816ecSMatt Jacob "96X2*", "*" 475040816ecSMatt Jacob }, 476040816ecSMatt Jacob CAM_QUIRK_NOLUNS, /*mintags*/0, /*maxtags*/0 477040816ecSMatt Jacob }, 478040816ecSMatt Jacob { 4794b4c702bSMatt Jacob /* Submitted by: Matthew Dodd <winter@jurai.net> */ 4804b4c702bSMatt Jacob { T_PROCESSOR, SIP_MEDIA_FIXED, "Cabletrn", "EA41*", "*" }, 4814b4c702bSMatt Jacob CAM_QUIRK_NOLUNS, /*mintags*/0, /*maxtags*/0 4824b4c702bSMatt Jacob }, 4834b4c702bSMatt Jacob { 4844b4c702bSMatt Jacob /* Submitted by: Matthew Dodd <winter@jurai.net> */ 4854b4c702bSMatt Jacob { T_PROCESSOR, SIP_MEDIA_FIXED, "CABLETRN", "EA41*", "*" }, 4864b4c702bSMatt Jacob CAM_QUIRK_NOLUNS, /*mintags*/0, /*maxtags*/0 4874b4c702bSMatt Jacob }, 4884b4c702bSMatt Jacob { 489da6efda6SDavid Greenman /* TeraSolutions special settings for TRC-22 RAID */ 490da6efda6SDavid Greenman { T_DIRECT, SIP_MEDIA_FIXED, "TERASOLU", "TRC-22", "*" }, 491da6efda6SDavid Greenman /*quirks*/0, /*mintags*/55, /*maxtags*/255 492da6efda6SDavid Greenman }, 493da6efda6SDavid Greenman { 4948b8a9b1dSJustin T. Gibbs /* Default tagged queuing parameters for all devices */ 4958b8a9b1dSJustin T. Gibbs { 4968b8a9b1dSJustin T. Gibbs T_ANY, SIP_MEDIA_REMOVABLE|SIP_MEDIA_FIXED, 4978b8a9b1dSJustin T. Gibbs /*vendor*/"*", /*product*/"*", /*revision*/"*" 4988b8a9b1dSJustin T. Gibbs }, 499fd21cc5eSJustin T. Gibbs /*quirks*/0, /*mintags*/2, /*maxtags*/255 5008b8a9b1dSJustin T. Gibbs }, 5018b8a9b1dSJustin T. Gibbs }; 502fd21cc5eSJustin T. Gibbs 50387cfaf0eSJustin T. Gibbs static const int xpt_quirk_table_size = 50487cfaf0eSJustin T. Gibbs sizeof(xpt_quirk_table) / sizeof(*xpt_quirk_table); 50587cfaf0eSJustin T. Gibbs 5068b8a9b1dSJustin T. Gibbs typedef enum { 5078b8a9b1dSJustin T. Gibbs DM_RET_COPY = 0x01, 5088b8a9b1dSJustin T. Gibbs DM_RET_FLAG_MASK = 0x0f, 5098b8a9b1dSJustin T. Gibbs DM_RET_NONE = 0x00, 5108b8a9b1dSJustin T. Gibbs DM_RET_STOP = 0x10, 5118b8a9b1dSJustin T. Gibbs DM_RET_DESCEND = 0x20, 5128b8a9b1dSJustin T. Gibbs DM_RET_ERROR = 0x30, 5138b8a9b1dSJustin T. Gibbs DM_RET_ACTION_MASK = 0xf0 5148b8a9b1dSJustin T. Gibbs } dev_match_ret; 5158b8a9b1dSJustin T. Gibbs 5168b8a9b1dSJustin T. Gibbs typedef enum { 5178b8a9b1dSJustin T. Gibbs XPT_DEPTH_BUS, 5188b8a9b1dSJustin T. Gibbs XPT_DEPTH_TARGET, 5198b8a9b1dSJustin T. Gibbs XPT_DEPTH_DEVICE, 5208b8a9b1dSJustin T. Gibbs XPT_DEPTH_PERIPH 5218b8a9b1dSJustin T. Gibbs } xpt_traverse_depth; 5228b8a9b1dSJustin T. Gibbs 5238b8a9b1dSJustin T. Gibbs struct xpt_traverse_config { 5248b8a9b1dSJustin T. Gibbs xpt_traverse_depth depth; 5258b8a9b1dSJustin T. Gibbs void *tr_func; 5268b8a9b1dSJustin T. Gibbs void *tr_arg; 5278b8a9b1dSJustin T. Gibbs }; 5288b8a9b1dSJustin T. Gibbs 5298b8a9b1dSJustin T. Gibbs typedef int xpt_busfunc_t (struct cam_eb *bus, void *arg); 5308b8a9b1dSJustin T. Gibbs typedef int xpt_targetfunc_t (struct cam_et *target, void *arg); 5318b8a9b1dSJustin T. Gibbs typedef int xpt_devicefunc_t (struct cam_ed *device, void *arg); 5328b8a9b1dSJustin T. Gibbs typedef int xpt_periphfunc_t (struct cam_periph *periph, void *arg); 5338b8a9b1dSJustin T. Gibbs typedef int xpt_pdrvfunc_t (struct periph_driver **pdrv, void *arg); 5348b8a9b1dSJustin T. Gibbs 5358b8a9b1dSJustin T. Gibbs /* Transport layer configuration information */ 5368b8a9b1dSJustin T. Gibbs static struct xpt_softc xsoftc; 5378b8a9b1dSJustin T. Gibbs 5388b8a9b1dSJustin T. Gibbs /* Queues for our software interrupt handler */ 539e3975643SJake Burkholder typedef TAILQ_HEAD(cam_isrq, ccb_hdr) cam_isrq_t; 5408b8a9b1dSJustin T. Gibbs static cam_isrq_t cam_bioq; 5418b8a9b1dSJustin T. Gibbs static cam_isrq_t cam_netq; 5428b8a9b1dSJustin T. Gibbs 5438b8a9b1dSJustin T. Gibbs /* "Pool" of inactive ccbs managed by xpt_alloc_ccb and xpt_free_ccb */ 544e3975643SJake Burkholder static SLIST_HEAD(,ccb_hdr) ccb_freeq; 5458b8a9b1dSJustin T. Gibbs static u_int xpt_max_ccbs; /* 5468b8a9b1dSJustin T. Gibbs * Maximum size of ccb pool. Modified as 5478b8a9b1dSJustin T. Gibbs * devices are added/removed or have their 5488b8a9b1dSJustin T. Gibbs * opening counts changed. 5498b8a9b1dSJustin T. Gibbs */ 5508b8a9b1dSJustin T. Gibbs static u_int xpt_ccb_count; /* Current count of allocated ccbs */ 5518b8a9b1dSJustin T. Gibbs 5529a1c8571SNick Hibma struct cam_periph *xpt_periph; 5539a1c8571SNick Hibma 5548b8a9b1dSJustin T. Gibbs static periph_init_t xpt_periph_init; 5558b8a9b1dSJustin T. Gibbs 5568b8a9b1dSJustin T. Gibbs static periph_init_t probe_periph_init; 5578b8a9b1dSJustin T. Gibbs 5588b8a9b1dSJustin T. Gibbs static struct periph_driver xpt_driver = 5598b8a9b1dSJustin T. Gibbs { 5608b8a9b1dSJustin T. Gibbs xpt_periph_init, "xpt", 5618b8a9b1dSJustin T. Gibbs TAILQ_HEAD_INITIALIZER(xpt_driver.units) 5628b8a9b1dSJustin T. Gibbs }; 5638b8a9b1dSJustin T. Gibbs 5648b8a9b1dSJustin T. Gibbs static struct periph_driver probe_driver = 5658b8a9b1dSJustin T. Gibbs { 5668b8a9b1dSJustin T. Gibbs probe_periph_init, "probe", 5678b8a9b1dSJustin T. Gibbs TAILQ_HEAD_INITIALIZER(probe_driver.units) 5688b8a9b1dSJustin T. Gibbs }; 5698b8a9b1dSJustin T. Gibbs 5708b8a9b1dSJustin T. Gibbs DATA_SET(periphdriver_set, xpt_driver); 5718b8a9b1dSJustin T. Gibbs DATA_SET(periphdriver_set, probe_driver); 5728b8a9b1dSJustin T. Gibbs 5738b8a9b1dSJustin T. Gibbs #define XPT_CDEV_MAJOR 104 5748b8a9b1dSJustin T. Gibbs 5758b8a9b1dSJustin T. Gibbs static d_open_t xptopen; 5768b8a9b1dSJustin T. Gibbs static d_close_t xptclose; 5778b8a9b1dSJustin T. Gibbs static d_ioctl_t xptioctl; 5788b8a9b1dSJustin T. Gibbs 5794e2f199eSPoul-Henning Kamp static struct cdevsw xpt_cdevsw = { 5804e2f199eSPoul-Henning Kamp /* open */ xptopen, 5814e2f199eSPoul-Henning Kamp /* close */ xptclose, 5824e2f199eSPoul-Henning Kamp /* read */ noread, 5834e2f199eSPoul-Henning Kamp /* write */ nowrite, 5844e2f199eSPoul-Henning Kamp /* ioctl */ xptioctl, 5854e2f199eSPoul-Henning Kamp /* poll */ nopoll, 5864e2f199eSPoul-Henning Kamp /* mmap */ nommap, 5874e2f199eSPoul-Henning Kamp /* strategy */ nostrategy, 5884e2f199eSPoul-Henning Kamp /* name */ "xpt", 5894e2f199eSPoul-Henning Kamp /* maj */ XPT_CDEV_MAJOR, 5904e2f199eSPoul-Henning Kamp /* dump */ nodump, 5914e2f199eSPoul-Henning Kamp /* psize */ nopsize, 5924e2f199eSPoul-Henning Kamp /* flags */ 0, 5934e2f199eSPoul-Henning Kamp /* bmaj */ -1 5948b8a9b1dSJustin T. Gibbs }; 5958b8a9b1dSJustin T. Gibbs 5968b8a9b1dSJustin T. Gibbs static struct intr_config_hook *xpt_config_hook; 5978b8a9b1dSJustin T. Gibbs 5988b8a9b1dSJustin T. Gibbs /* Registered busses */ 599e3975643SJake Burkholder static TAILQ_HEAD(,cam_eb) xpt_busses; 6008b8a9b1dSJustin T. Gibbs static u_int bus_generation; 6018b8a9b1dSJustin T. Gibbs 6028b8a9b1dSJustin T. Gibbs /* Storage for debugging datastructures */ 6038b8a9b1dSJustin T. Gibbs #ifdef CAMDEBUG 6048b8a9b1dSJustin T. Gibbs struct cam_path *cam_dpath; 6058b8a9b1dSJustin T. Gibbs u_int32_t cam_dflags; 6062cefde5fSJustin T. Gibbs u_int32_t cam_debug_delay; 6078b8a9b1dSJustin T. Gibbs #endif 6088b8a9b1dSJustin T. Gibbs 6098b8a9b1dSJustin T. Gibbs #if defined(CAM_DEBUG_FLAGS) && !defined(CAMDEBUG) 6108b8a9b1dSJustin T. Gibbs #error "You must have options CAMDEBUG to use options CAM_DEBUG_FLAGS" 6118b8a9b1dSJustin T. Gibbs #endif 6128b8a9b1dSJustin T. Gibbs 6138b8a9b1dSJustin T. Gibbs /* 6148b8a9b1dSJustin T. Gibbs * In order to enable the CAM_DEBUG_* options, the user must have CAMDEBUG 6158b8a9b1dSJustin T. Gibbs * enabled. Also, the user must have either none, or all of CAM_DEBUG_BUS, 6168b8a9b1dSJustin T. Gibbs * CAM_DEBUG_TARGET, and CAM_DEBUG_LUN specified. 6178b8a9b1dSJustin T. Gibbs */ 6188b8a9b1dSJustin T. Gibbs #if defined(CAM_DEBUG_BUS) || defined(CAM_DEBUG_TARGET) \ 6198b8a9b1dSJustin T. Gibbs || defined(CAM_DEBUG_LUN) 6208b8a9b1dSJustin T. Gibbs #ifdef CAMDEBUG 6218b8a9b1dSJustin T. Gibbs #if !defined(CAM_DEBUG_BUS) || !defined(CAM_DEBUG_TARGET) \ 6228b8a9b1dSJustin T. Gibbs || !defined(CAM_DEBUG_LUN) 6238b8a9b1dSJustin T. Gibbs #error "You must define all or none of CAM_DEBUG_BUS, CAM_DEBUG_TARGET \ 6248b8a9b1dSJustin T. Gibbs and CAM_DEBUG_LUN" 6258b8a9b1dSJustin T. Gibbs #endif /* !CAM_DEBUG_BUS || !CAM_DEBUG_TARGET || !CAM_DEBUG_LUN */ 6268b8a9b1dSJustin T. Gibbs #else /* !CAMDEBUG */ 6278b8a9b1dSJustin T. Gibbs #error "You must use options CAMDEBUG if you use the CAM_DEBUG_* options" 6288b8a9b1dSJustin T. Gibbs #endif /* CAMDEBUG */ 6298b8a9b1dSJustin T. Gibbs #endif /* CAM_DEBUG_BUS || CAM_DEBUG_TARGET || CAM_DEBUG_LUN */ 6308b8a9b1dSJustin T. Gibbs 6316d2a8f1cSPeter Wemm /* Our boot-time initialization hook */ 6326d2a8f1cSPeter Wemm static void xpt_init(void *); 6336d2a8f1cSPeter Wemm SYSINIT(cam, SI_SUB_CONFIGURE, SI_ORDER_SECOND, xpt_init, NULL); 6348b8a9b1dSJustin T. Gibbs 6358b8a9b1dSJustin T. Gibbs static cam_status xpt_compile_path(struct cam_path *new_path, 6368b8a9b1dSJustin T. Gibbs struct cam_periph *perph, 6378b8a9b1dSJustin T. Gibbs path_id_t path_id, 6388b8a9b1dSJustin T. Gibbs target_id_t target_id, 6398b8a9b1dSJustin T. Gibbs lun_id_t lun_id); 6408b8a9b1dSJustin T. Gibbs 6418b8a9b1dSJustin T. Gibbs static void xpt_release_path(struct cam_path *path); 6428b8a9b1dSJustin T. Gibbs 6438b8a9b1dSJustin T. Gibbs static void xpt_async_bcast(struct async_list *async_head, 6448b8a9b1dSJustin T. Gibbs u_int32_t async_code, 6458b8a9b1dSJustin T. Gibbs struct cam_path *path, 6468b8a9b1dSJustin T. Gibbs void *async_arg); 647434bbf6eSJustin T. Gibbs static path_id_t xptnextfreepathid(void); 648434bbf6eSJustin T. Gibbs static path_id_t xptpathid(const char *sim_name, int sim_unit, int sim_bus); 6498b8a9b1dSJustin T. Gibbs static union ccb *xpt_get_ccb(struct cam_ed *device); 6508b8a9b1dSJustin T. Gibbs static int xpt_schedule_dev(struct camq *queue, cam_pinfo *dev_pinfo, 6518b8a9b1dSJustin T. Gibbs u_int32_t new_priority); 6528b8a9b1dSJustin T. Gibbs static void xpt_run_dev_allocq(struct cam_eb *bus); 6538b8a9b1dSJustin T. Gibbs static void xpt_run_dev_sendq(struct cam_eb *bus); 6548b8a9b1dSJustin T. Gibbs static timeout_t xpt_release_devq_timeout; 6558b8a9b1dSJustin T. Gibbs static timeout_t xpt_release_simq_timeout; 656a5479bc5SJustin T. Gibbs static void xpt_release_bus(struct cam_eb *bus); 6572cefde5fSJustin T. Gibbs static void xpt_release_devq_device(struct cam_ed *dev, u_int count, 6582cefde5fSJustin T. Gibbs int run_queue); 6598b8a9b1dSJustin T. Gibbs static struct cam_et* 6608b8a9b1dSJustin T. Gibbs xpt_alloc_target(struct cam_eb *bus, target_id_t target_id); 6618b8a9b1dSJustin T. Gibbs static void xpt_release_target(struct cam_eb *bus, struct cam_et *target); 6628b8a9b1dSJustin T. Gibbs static struct cam_ed* 6638b8a9b1dSJustin T. Gibbs xpt_alloc_device(struct cam_eb *bus, struct cam_et *target, 6648b8a9b1dSJustin T. Gibbs lun_id_t lun_id); 6658b8a9b1dSJustin T. Gibbs static void xpt_release_device(struct cam_eb *bus, struct cam_et *target, 6668b8a9b1dSJustin T. Gibbs struct cam_ed *device); 6678b8a9b1dSJustin T. Gibbs static u_int32_t xpt_dev_ccbq_resize(struct cam_path *path, int newopenings); 6688b8a9b1dSJustin T. Gibbs static struct cam_eb* 6698b8a9b1dSJustin T. Gibbs xpt_find_bus(path_id_t path_id); 6708b8a9b1dSJustin T. Gibbs static struct cam_et* 6718b8a9b1dSJustin T. Gibbs xpt_find_target(struct cam_eb *bus, target_id_t target_id); 6728b8a9b1dSJustin T. Gibbs static struct cam_ed* 6738b8a9b1dSJustin T. Gibbs xpt_find_device(struct cam_et *target, lun_id_t lun_id); 6748b8a9b1dSJustin T. Gibbs static void xpt_scan_bus(struct cam_periph *periph, union ccb *ccb); 6758b8a9b1dSJustin T. Gibbs static void xpt_scan_lun(struct cam_periph *periph, 6768b8a9b1dSJustin T. Gibbs struct cam_path *path, cam_flags flags, 6778b8a9b1dSJustin T. Gibbs union ccb *ccb); 6788b8a9b1dSJustin T. Gibbs static void xptscandone(struct cam_periph *periph, union ccb *done_ccb); 6798b8a9b1dSJustin T. Gibbs static xpt_busfunc_t xptconfigbuscountfunc; 6808b8a9b1dSJustin T. Gibbs static xpt_busfunc_t xptconfigfunc; 6818b8a9b1dSJustin T. Gibbs static void xpt_config(void *arg); 6828b8a9b1dSJustin T. Gibbs static xpt_devicefunc_t xptpassannouncefunc; 6838b8a9b1dSJustin T. Gibbs static void xpt_finishconfig(struct cam_periph *periph, union ccb *ccb); 6848b8a9b1dSJustin T. Gibbs static void xptaction(struct cam_sim *sim, union ccb *work_ccb); 685434bbf6eSJustin T. Gibbs static void xptpoll(struct cam_sim *sim); 6865d754af7SMatt Jacob static swihand_t swi_camnet; 6875d754af7SMatt Jacob static swihand_t swi_cambio; 6888b8a9b1dSJustin T. Gibbs static void camisr(cam_isrq_t *queue); 6898b8a9b1dSJustin T. Gibbs #if 0 6908b8a9b1dSJustin T. Gibbs static void xptstart(struct cam_periph *periph, union ccb *work_ccb); 6918b8a9b1dSJustin T. Gibbs static void xptasync(struct cam_periph *periph, 6928b8a9b1dSJustin T. Gibbs u_int32_t code, cam_path *path); 6938b8a9b1dSJustin T. Gibbs #endif 6948b8a9b1dSJustin T. Gibbs static dev_match_ret xptbusmatch(struct dev_match_pattern *patterns, 6958b8a9b1dSJustin T. Gibbs int num_patterns, struct cam_eb *bus); 6968b8a9b1dSJustin T. Gibbs static dev_match_ret xptdevicematch(struct dev_match_pattern *patterns, 6978b8a9b1dSJustin T. Gibbs int num_patterns, struct cam_ed *device); 6988b8a9b1dSJustin T. Gibbs static dev_match_ret xptperiphmatch(struct dev_match_pattern *patterns, 6998b8a9b1dSJustin T. Gibbs int num_patterns, 7008b8a9b1dSJustin T. Gibbs struct cam_periph *periph); 7018b8a9b1dSJustin T. Gibbs static xpt_busfunc_t xptedtbusfunc; 7028b8a9b1dSJustin T. Gibbs static xpt_targetfunc_t xptedttargetfunc; 7038b8a9b1dSJustin T. Gibbs static xpt_devicefunc_t xptedtdevicefunc; 7048b8a9b1dSJustin T. Gibbs static xpt_periphfunc_t xptedtperiphfunc; 7058b8a9b1dSJustin T. Gibbs static xpt_pdrvfunc_t xptplistpdrvfunc; 7068b8a9b1dSJustin T. Gibbs static xpt_periphfunc_t xptplistperiphfunc; 7078b8a9b1dSJustin T. Gibbs static int xptedtmatch(struct ccb_dev_match *cdm); 7088b8a9b1dSJustin T. Gibbs static int xptperiphlistmatch(struct ccb_dev_match *cdm); 7098b8a9b1dSJustin T. Gibbs static int xptbustraverse(struct cam_eb *start_bus, 7108b8a9b1dSJustin T. Gibbs xpt_busfunc_t *tr_func, void *arg); 7118b8a9b1dSJustin T. Gibbs static int xpttargettraverse(struct cam_eb *bus, 7128b8a9b1dSJustin T. Gibbs struct cam_et *start_target, 7138b8a9b1dSJustin T. Gibbs xpt_targetfunc_t *tr_func, void *arg); 7148b8a9b1dSJustin T. Gibbs static int xptdevicetraverse(struct cam_et *target, 7158b8a9b1dSJustin T. Gibbs struct cam_ed *start_device, 7168b8a9b1dSJustin T. Gibbs xpt_devicefunc_t *tr_func, void *arg); 7178b8a9b1dSJustin T. Gibbs static int xptperiphtraverse(struct cam_ed *device, 7188b8a9b1dSJustin T. Gibbs struct cam_periph *start_periph, 7198b8a9b1dSJustin T. Gibbs xpt_periphfunc_t *tr_func, void *arg); 7208b8a9b1dSJustin T. Gibbs static int xptpdrvtraverse(struct periph_driver **start_pdrv, 7218b8a9b1dSJustin T. Gibbs xpt_pdrvfunc_t *tr_func, void *arg); 7228b8a9b1dSJustin T. Gibbs static int xptpdperiphtraverse(struct periph_driver **pdrv, 7238b8a9b1dSJustin T. Gibbs struct cam_periph *start_periph, 7248b8a9b1dSJustin T. Gibbs xpt_periphfunc_t *tr_func, 7258b8a9b1dSJustin T. Gibbs void *arg); 7268b8a9b1dSJustin T. Gibbs static xpt_busfunc_t xptdefbusfunc; 7278b8a9b1dSJustin T. Gibbs static xpt_targetfunc_t xptdeftargetfunc; 7288b8a9b1dSJustin T. Gibbs static xpt_devicefunc_t xptdefdevicefunc; 7298b8a9b1dSJustin T. Gibbs static xpt_periphfunc_t xptdefperiphfunc; 7308b8a9b1dSJustin T. Gibbs static int xpt_for_all_busses(xpt_busfunc_t *tr_func, void *arg); 731bfc0eb0fSKenneth D. Merry #ifdef notusedyet 7328b8a9b1dSJustin T. Gibbs static int xpt_for_all_targets(xpt_targetfunc_t *tr_func, 7338b8a9b1dSJustin T. Gibbs void *arg); 734bfc0eb0fSKenneth D. Merry #endif 7358b8a9b1dSJustin T. Gibbs static int xpt_for_all_devices(xpt_devicefunc_t *tr_func, 7368b8a9b1dSJustin T. Gibbs void *arg); 737bfc0eb0fSKenneth D. Merry #ifdef notusedyet 7388b8a9b1dSJustin T. Gibbs static int xpt_for_all_periphs(xpt_periphfunc_t *tr_func, 7398b8a9b1dSJustin T. Gibbs void *arg); 740bfc0eb0fSKenneth D. Merry #endif 7418b8a9b1dSJustin T. Gibbs static xpt_devicefunc_t xptsetasyncfunc; 7428b8a9b1dSJustin T. Gibbs static xpt_busfunc_t xptsetasyncbusfunc; 7438b8a9b1dSJustin T. Gibbs static cam_status xptregister(struct cam_periph *periph, 7448b8a9b1dSJustin T. Gibbs void *arg); 7458b8a9b1dSJustin T. Gibbs static cam_status proberegister(struct cam_periph *periph, 7468b8a9b1dSJustin T. Gibbs void *arg); 7478b8a9b1dSJustin T. Gibbs static void probeschedule(struct cam_periph *probe_periph); 7488b8a9b1dSJustin T. Gibbs static void probestart(struct cam_periph *periph, union ccb *start_ccb); 74987cfaf0eSJustin T. Gibbs static void proberequestdefaultnegotiation(struct cam_periph *periph); 7508b8a9b1dSJustin T. Gibbs static void probedone(struct cam_periph *periph, union ccb *done_ccb); 7518b8a9b1dSJustin T. Gibbs static void probecleanup(struct cam_periph *periph); 7528b8a9b1dSJustin T. Gibbs static void xpt_find_quirk(struct cam_ed *device); 7538b8a9b1dSJustin T. Gibbs static void xpt_set_transfer_settings(struct ccb_trans_settings *cts, 75403e3511bSJustin T. Gibbs struct cam_ed *device, 7558b8a9b1dSJustin T. Gibbs int async_update); 756f0adc790SJustin T. Gibbs static void xpt_toggle_tags(struct cam_path *path); 757fd21cc5eSJustin T. Gibbs static void xpt_start_tags(struct cam_path *path); 7588b8a9b1dSJustin T. Gibbs static __inline int xpt_schedule_dev_allocq(struct cam_eb *bus, 7598b8a9b1dSJustin T. Gibbs struct cam_ed *dev); 7608b8a9b1dSJustin T. Gibbs static __inline int xpt_schedule_dev_sendq(struct cam_eb *bus, 7618b8a9b1dSJustin T. Gibbs struct cam_ed *dev); 7628b8a9b1dSJustin T. Gibbs static __inline int periph_is_queued(struct cam_periph *periph); 7638b8a9b1dSJustin T. Gibbs static __inline int device_is_alloc_queued(struct cam_ed *device); 7648b8a9b1dSJustin T. Gibbs static __inline int device_is_send_queued(struct cam_ed *device); 7658b8a9b1dSJustin T. Gibbs static __inline int dev_allocq_is_runnable(struct cam_devq *devq); 7668b8a9b1dSJustin T. Gibbs 7678b8a9b1dSJustin T. Gibbs static __inline int 7688b8a9b1dSJustin T. Gibbs xpt_schedule_dev_allocq(struct cam_eb *bus, struct cam_ed *dev) 7698b8a9b1dSJustin T. Gibbs { 7708b8a9b1dSJustin T. Gibbs int retval; 7718b8a9b1dSJustin T. Gibbs 7728b8a9b1dSJustin T. Gibbs if (dev->ccbq.devq_openings > 0) { 7738b8a9b1dSJustin T. Gibbs if ((dev->flags & CAM_DEV_RESIZE_QUEUE_NEEDED) != 0) { 7748b8a9b1dSJustin T. Gibbs cam_ccbq_resize(&dev->ccbq, 7758b8a9b1dSJustin T. Gibbs dev->ccbq.dev_openings 7768b8a9b1dSJustin T. Gibbs + dev->ccbq.dev_active); 7778b8a9b1dSJustin T. Gibbs dev->flags &= ~CAM_DEV_RESIZE_QUEUE_NEEDED; 7788b8a9b1dSJustin T. Gibbs } 7795a526431SJustin T. Gibbs /* 7805a526431SJustin T. Gibbs * The priority of a device waiting for CCB resources 7815a526431SJustin T. Gibbs * is that of the the highest priority peripheral driver 7825a526431SJustin T. Gibbs * enqueued. 7835a526431SJustin T. Gibbs */ 7848b8a9b1dSJustin T. Gibbs retval = xpt_schedule_dev(&bus->sim->devq->alloc_queue, 7858b8a9b1dSJustin T. Gibbs &dev->alloc_ccb_entry.pinfo, 7865a526431SJustin T. Gibbs CAMQ_GET_HEAD(&dev->drvq)->priority); 7878b8a9b1dSJustin T. Gibbs } else { 7888b8a9b1dSJustin T. Gibbs retval = 0; 7898b8a9b1dSJustin T. Gibbs } 7908b8a9b1dSJustin T. Gibbs 7918b8a9b1dSJustin T. Gibbs return (retval); 7928b8a9b1dSJustin T. Gibbs } 7938b8a9b1dSJustin T. Gibbs 7948b8a9b1dSJustin T. Gibbs static __inline int 7958b8a9b1dSJustin T. Gibbs xpt_schedule_dev_sendq(struct cam_eb *bus, struct cam_ed *dev) 7968b8a9b1dSJustin T. Gibbs { 7978b8a9b1dSJustin T. Gibbs int retval; 7988b8a9b1dSJustin T. Gibbs 7998b8a9b1dSJustin T. Gibbs if (dev->ccbq.dev_openings > 0) { 8005a526431SJustin T. Gibbs /* 8015a526431SJustin T. Gibbs * The priority of a device waiting for controller 8025a526431SJustin T. Gibbs * resources is that of the the highest priority CCB 8035a526431SJustin T. Gibbs * enqueued. 8045a526431SJustin T. Gibbs */ 8055a526431SJustin T. Gibbs retval = 8065a526431SJustin T. Gibbs xpt_schedule_dev(&bus->sim->devq->send_queue, 8078b8a9b1dSJustin T. Gibbs &dev->send_ccb_entry.pinfo, 8085a526431SJustin T. Gibbs CAMQ_GET_HEAD(&dev->ccbq.queue)->priority); 8098b8a9b1dSJustin T. Gibbs } else { 8108b8a9b1dSJustin T. Gibbs retval = 0; 8118b8a9b1dSJustin T. Gibbs } 8128b8a9b1dSJustin T. Gibbs return (retval); 8138b8a9b1dSJustin T. Gibbs } 8148b8a9b1dSJustin T. Gibbs 8158b8a9b1dSJustin T. Gibbs static __inline int 8168b8a9b1dSJustin T. Gibbs periph_is_queued(struct cam_periph *periph) 8178b8a9b1dSJustin T. Gibbs { 8188b8a9b1dSJustin T. Gibbs return (periph->pinfo.index != CAM_UNQUEUED_INDEX); 8198b8a9b1dSJustin T. Gibbs } 8208b8a9b1dSJustin T. Gibbs 8218b8a9b1dSJustin T. Gibbs static __inline int 8228b8a9b1dSJustin T. Gibbs device_is_alloc_queued(struct cam_ed *device) 8238b8a9b1dSJustin T. Gibbs { 8248b8a9b1dSJustin T. Gibbs return (device->alloc_ccb_entry.pinfo.index != CAM_UNQUEUED_INDEX); 8258b8a9b1dSJustin T. Gibbs } 8268b8a9b1dSJustin T. Gibbs 8278b8a9b1dSJustin T. Gibbs static __inline int 8288b8a9b1dSJustin T. Gibbs device_is_send_queued(struct cam_ed *device) 8298b8a9b1dSJustin T. Gibbs { 8308b8a9b1dSJustin T. Gibbs return (device->send_ccb_entry.pinfo.index != CAM_UNQUEUED_INDEX); 8318b8a9b1dSJustin T. Gibbs } 8328b8a9b1dSJustin T. Gibbs 8338b8a9b1dSJustin T. Gibbs static __inline int 8348b8a9b1dSJustin T. Gibbs dev_allocq_is_runnable(struct cam_devq *devq) 8358b8a9b1dSJustin T. Gibbs { 8368b8a9b1dSJustin T. Gibbs /* 8378b8a9b1dSJustin T. Gibbs * Have work to do. 8388b8a9b1dSJustin T. Gibbs * Have space to do more work. 8398b8a9b1dSJustin T. Gibbs * Allowed to do work. 8408b8a9b1dSJustin T. Gibbs */ 8418b8a9b1dSJustin T. Gibbs return ((devq->alloc_queue.qfrozen_cnt == 0) 8428b8a9b1dSJustin T. Gibbs && (devq->alloc_queue.entries > 0) 8438b8a9b1dSJustin T. Gibbs && (devq->alloc_openings > 0)); 8448b8a9b1dSJustin T. Gibbs } 8458b8a9b1dSJustin T. Gibbs 8468b8a9b1dSJustin T. Gibbs static void 8478b8a9b1dSJustin T. Gibbs xpt_periph_init() 8488b8a9b1dSJustin T. Gibbs { 84973d26919SKenneth D. Merry make_dev(&xpt_cdevsw, 0, UID_ROOT, GID_OPERATOR, 0600, "xpt0"); 8508b8a9b1dSJustin T. Gibbs } 8518b8a9b1dSJustin T. Gibbs 8528b8a9b1dSJustin T. Gibbs static void 8538b8a9b1dSJustin T. Gibbs probe_periph_init() 8548b8a9b1dSJustin T. Gibbs { 8558b8a9b1dSJustin T. Gibbs } 8568b8a9b1dSJustin T. Gibbs 8578b8a9b1dSJustin T. Gibbs 8588b8a9b1dSJustin T. Gibbs static void 8598b8a9b1dSJustin T. Gibbs xptdone(struct cam_periph *periph, union ccb *done_ccb) 8608b8a9b1dSJustin T. Gibbs { 8618b8a9b1dSJustin T. Gibbs /* Caller will release the CCB */ 8628b8a9b1dSJustin T. Gibbs wakeup(&done_ccb->ccb_h.cbfcnp); 8638b8a9b1dSJustin T. Gibbs } 8648b8a9b1dSJustin T. Gibbs 8658b8a9b1dSJustin T. Gibbs static int 8668b8a9b1dSJustin T. Gibbs xptopen(dev_t dev, int flags, int fmt, struct proc *p) 8678b8a9b1dSJustin T. Gibbs { 8688b8a9b1dSJustin T. Gibbs int unit; 8698b8a9b1dSJustin T. Gibbs 8708b8a9b1dSJustin T. Gibbs unit = minor(dev) & 0xff; 8718b8a9b1dSJustin T. Gibbs 8728b8a9b1dSJustin T. Gibbs /* 87366a0780eSKenneth D. Merry * Only allow read-write access. 87466a0780eSKenneth D. Merry */ 87566a0780eSKenneth D. Merry if (((flags & FWRITE) == 0) || ((flags & FREAD) == 0)) 87666a0780eSKenneth D. Merry return(EPERM); 87766a0780eSKenneth D. Merry 87866a0780eSKenneth D. Merry /* 8798b8a9b1dSJustin T. Gibbs * We don't allow nonblocking access. 8808b8a9b1dSJustin T. Gibbs */ 8818b8a9b1dSJustin T. Gibbs if ((flags & O_NONBLOCK) != 0) { 8828b8a9b1dSJustin T. Gibbs printf("xpt%d: can't do nonblocking accesss\n", unit); 8838b8a9b1dSJustin T. Gibbs return(ENODEV); 8848b8a9b1dSJustin T. Gibbs } 8858b8a9b1dSJustin T. Gibbs 8868b8a9b1dSJustin T. Gibbs /* 8878b8a9b1dSJustin T. Gibbs * We only have one transport layer right now. If someone accesses 8888b8a9b1dSJustin T. Gibbs * us via something other than minor number 1, point out their 8898b8a9b1dSJustin T. Gibbs * mistake. 8908b8a9b1dSJustin T. Gibbs */ 8918b8a9b1dSJustin T. Gibbs if (unit != 0) { 8928b8a9b1dSJustin T. Gibbs printf("xptopen: got invalid xpt unit %d\n", unit); 8938b8a9b1dSJustin T. Gibbs return(ENXIO); 8948b8a9b1dSJustin T. Gibbs } 8958b8a9b1dSJustin T. Gibbs 8968b8a9b1dSJustin T. Gibbs /* Mark ourselves open */ 8978b8a9b1dSJustin T. Gibbs xsoftc.flags |= XPT_FLAG_OPEN; 8988b8a9b1dSJustin T. Gibbs 8998b8a9b1dSJustin T. Gibbs return(0); 9008b8a9b1dSJustin T. Gibbs } 9018b8a9b1dSJustin T. Gibbs 9028b8a9b1dSJustin T. Gibbs static int 9038b8a9b1dSJustin T. Gibbs xptclose(dev_t dev, int flag, int fmt, struct proc *p) 9048b8a9b1dSJustin T. Gibbs { 9058b8a9b1dSJustin T. Gibbs int unit; 9068b8a9b1dSJustin T. Gibbs 9078b8a9b1dSJustin T. Gibbs unit = minor(dev) & 0xff; 9088b8a9b1dSJustin T. Gibbs 9098b8a9b1dSJustin T. Gibbs /* 9108b8a9b1dSJustin T. Gibbs * We only have one transport layer right now. If someone accesses 9118b8a9b1dSJustin T. Gibbs * us via something other than minor number 1, point out their 9128b8a9b1dSJustin T. Gibbs * mistake. 9138b8a9b1dSJustin T. Gibbs */ 9148b8a9b1dSJustin T. Gibbs if (unit != 0) { 9158b8a9b1dSJustin T. Gibbs printf("xptclose: got invalid xpt unit %d\n", unit); 9168b8a9b1dSJustin T. Gibbs return(ENXIO); 9178b8a9b1dSJustin T. Gibbs } 9188b8a9b1dSJustin T. Gibbs 9198b8a9b1dSJustin T. Gibbs /* Mark ourselves closed */ 9208b8a9b1dSJustin T. Gibbs xsoftc.flags &= ~XPT_FLAG_OPEN; 9218b8a9b1dSJustin T. Gibbs 9228b8a9b1dSJustin T. Gibbs return(0); 9238b8a9b1dSJustin T. Gibbs } 9248b8a9b1dSJustin T. Gibbs 9258b8a9b1dSJustin T. Gibbs static int 9268b8a9b1dSJustin T. Gibbs xptioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p) 9278b8a9b1dSJustin T. Gibbs { 9288b8a9b1dSJustin T. Gibbs int unit, error; 9298b8a9b1dSJustin T. Gibbs 9308b8a9b1dSJustin T. Gibbs error = 0; 9318b8a9b1dSJustin T. Gibbs unit = minor(dev) & 0xff; 9328b8a9b1dSJustin T. Gibbs 9338b8a9b1dSJustin T. Gibbs /* 9348b8a9b1dSJustin T. Gibbs * We only have one transport layer right now. If someone accesses 9358b8a9b1dSJustin T. Gibbs * us via something other than minor number 1, point out their 9368b8a9b1dSJustin T. Gibbs * mistake. 9378b8a9b1dSJustin T. Gibbs */ 9388b8a9b1dSJustin T. Gibbs if (unit != 0) { 9398b8a9b1dSJustin T. Gibbs printf("xptioctl: got invalid xpt unit %d\n", unit); 9408b8a9b1dSJustin T. Gibbs return(ENXIO); 9418b8a9b1dSJustin T. Gibbs } 9428b8a9b1dSJustin T. Gibbs 9438b8a9b1dSJustin T. Gibbs switch(cmd) { 9448b8a9b1dSJustin T. Gibbs /* 9458b8a9b1dSJustin T. Gibbs * For the transport layer CAMIOCOMMAND ioctl, we really only want 9468b8a9b1dSJustin T. Gibbs * to accept CCB types that don't quite make sense to send through a 9478b8a9b1dSJustin T. Gibbs * passthrough driver. 9488b8a9b1dSJustin T. Gibbs */ 9498b8a9b1dSJustin T. Gibbs case CAMIOCOMMAND: { 9508b8a9b1dSJustin T. Gibbs union ccb *ccb; 9518b8a9b1dSJustin T. Gibbs union ccb *inccb; 9528b8a9b1dSJustin T. Gibbs 9538b8a9b1dSJustin T. Gibbs inccb = (union ccb *)addr; 9548b8a9b1dSJustin T. Gibbs 9558b8a9b1dSJustin T. Gibbs switch(inccb->ccb_h.func_code) { 9568b8a9b1dSJustin T. Gibbs case XPT_SCAN_BUS: 9578b8a9b1dSJustin T. Gibbs case XPT_RESET_BUS: 9588b8a9b1dSJustin T. Gibbs if ((inccb->ccb_h.target_id != CAM_TARGET_WILDCARD) 9598b8a9b1dSJustin T. Gibbs || (inccb->ccb_h.target_lun != CAM_LUN_WILDCARD)) { 9608b8a9b1dSJustin T. Gibbs error = EINVAL; 9618b8a9b1dSJustin T. Gibbs break; 9628b8a9b1dSJustin T. Gibbs } 9638b8a9b1dSJustin T. Gibbs /* FALLTHROUGH */ 9648b8a9b1dSJustin T. Gibbs case XPT_SCAN_LUN: 9658b8a9b1dSJustin T. Gibbs 9668b8a9b1dSJustin T. Gibbs ccb = xpt_alloc_ccb(); 9678b8a9b1dSJustin T. Gibbs 9688b8a9b1dSJustin T. Gibbs /* 9698b8a9b1dSJustin T. Gibbs * Create a path using the bus, target, and lun the 9708b8a9b1dSJustin T. Gibbs * user passed in. 9718b8a9b1dSJustin T. Gibbs */ 9728b8a9b1dSJustin T. Gibbs if (xpt_create_path(&ccb->ccb_h.path, xpt_periph, 9738b8a9b1dSJustin T. Gibbs inccb->ccb_h.path_id, 9748b8a9b1dSJustin T. Gibbs inccb->ccb_h.target_id, 9758b8a9b1dSJustin T. Gibbs inccb->ccb_h.target_lun) != 9768b8a9b1dSJustin T. Gibbs CAM_REQ_CMP){ 9778b8a9b1dSJustin T. Gibbs error = EINVAL; 9788b8a9b1dSJustin T. Gibbs xpt_free_ccb(ccb); 9798b8a9b1dSJustin T. Gibbs break; 9808b8a9b1dSJustin T. Gibbs } 9818b8a9b1dSJustin T. Gibbs /* Ensure all of our fields are correct */ 9828b8a9b1dSJustin T. Gibbs xpt_setup_ccb(&ccb->ccb_h, ccb->ccb_h.path, 9838b8a9b1dSJustin T. Gibbs inccb->ccb_h.pinfo.priority); 9848b8a9b1dSJustin T. Gibbs xpt_merge_ccb(ccb, inccb); 9858b8a9b1dSJustin T. Gibbs ccb->ccb_h.cbfcnp = xptdone; 9868b8a9b1dSJustin T. Gibbs cam_periph_runccb(ccb, NULL, 0, 0, NULL); 9878b8a9b1dSJustin T. Gibbs bcopy(ccb, inccb, sizeof(union ccb)); 9888b8a9b1dSJustin T. Gibbs xpt_free_path(ccb->ccb_h.path); 9898b8a9b1dSJustin T. Gibbs xpt_free_ccb(ccb); 9908b8a9b1dSJustin T. Gibbs break; 9918b8a9b1dSJustin T. Gibbs 9928b8a9b1dSJustin T. Gibbs case XPT_DEBUG: { 9938b8a9b1dSJustin T. Gibbs union ccb ccb; 9948b8a9b1dSJustin T. Gibbs 9958b8a9b1dSJustin T. Gibbs /* 996aa872be6SMatt Jacob * This is an immediate CCB, so it's okay to 9978b8a9b1dSJustin T. Gibbs * allocate it on the stack. 9988b8a9b1dSJustin T. Gibbs */ 9998b8a9b1dSJustin T. Gibbs 10008b8a9b1dSJustin T. Gibbs /* 10018b8a9b1dSJustin T. Gibbs * Create a path using the bus, target, and lun the 10028b8a9b1dSJustin T. Gibbs * user passed in. 10038b8a9b1dSJustin T. Gibbs */ 10048b8a9b1dSJustin T. Gibbs if (xpt_create_path(&ccb.ccb_h.path, xpt_periph, 10058b8a9b1dSJustin T. Gibbs inccb->ccb_h.path_id, 10068b8a9b1dSJustin T. Gibbs inccb->ccb_h.target_id, 10078b8a9b1dSJustin T. Gibbs inccb->ccb_h.target_lun) != 10088b8a9b1dSJustin T. Gibbs CAM_REQ_CMP){ 10098b8a9b1dSJustin T. Gibbs error = EINVAL; 10108b8a9b1dSJustin T. Gibbs break; 10118b8a9b1dSJustin T. Gibbs } 10128b8a9b1dSJustin T. Gibbs /* Ensure all of our fields are correct */ 10138b8a9b1dSJustin T. Gibbs xpt_setup_ccb(&ccb.ccb_h, ccb.ccb_h.path, 10148b8a9b1dSJustin T. Gibbs inccb->ccb_h.pinfo.priority); 10158b8a9b1dSJustin T. Gibbs xpt_merge_ccb(&ccb, inccb); 10168b8a9b1dSJustin T. Gibbs ccb.ccb_h.cbfcnp = xptdone; 10178b8a9b1dSJustin T. Gibbs xpt_action(&ccb); 10188b8a9b1dSJustin T. Gibbs bcopy(&ccb, inccb, sizeof(union ccb)); 10198b8a9b1dSJustin T. Gibbs xpt_free_path(ccb.ccb_h.path); 10208b8a9b1dSJustin T. Gibbs break; 10218b8a9b1dSJustin T. Gibbs 10228b8a9b1dSJustin T. Gibbs } 10238b8a9b1dSJustin T. Gibbs case XPT_DEV_MATCH: { 10248b8a9b1dSJustin T. Gibbs struct cam_periph_map_info mapinfo; 102559190eaaSKenneth D. Merry struct cam_path *old_path; 10268b8a9b1dSJustin T. Gibbs 10278b8a9b1dSJustin T. Gibbs /* 10288b8a9b1dSJustin T. Gibbs * We can't deal with physical addresses for this 10298b8a9b1dSJustin T. Gibbs * type of transaction. 10308b8a9b1dSJustin T. Gibbs */ 10318b8a9b1dSJustin T. Gibbs if (inccb->ccb_h.flags & CAM_DATA_PHYS) { 10328b8a9b1dSJustin T. Gibbs error = EINVAL; 10338b8a9b1dSJustin T. Gibbs break; 10348b8a9b1dSJustin T. Gibbs } 103559190eaaSKenneth D. Merry 103659190eaaSKenneth D. Merry /* 103759190eaaSKenneth D. Merry * Save this in case the caller had it set to 103859190eaaSKenneth D. Merry * something in particular. 103959190eaaSKenneth D. Merry */ 104059190eaaSKenneth D. Merry old_path = inccb->ccb_h.path; 104159190eaaSKenneth D. Merry 104259190eaaSKenneth D. Merry /* 104359190eaaSKenneth D. Merry * We really don't need a path for the matching 104459190eaaSKenneth D. Merry * code. The path is needed because of the 104559190eaaSKenneth D. Merry * debugging statements in xpt_action(). They 104659190eaaSKenneth D. Merry * assume that the CCB has a valid path. 104759190eaaSKenneth D. Merry */ 104859190eaaSKenneth D. Merry inccb->ccb_h.path = xpt_periph->path; 104959190eaaSKenneth D. Merry 10508b8a9b1dSJustin T. Gibbs bzero(&mapinfo, sizeof(mapinfo)); 10518b8a9b1dSJustin T. Gibbs 10528b8a9b1dSJustin T. Gibbs /* 10538b8a9b1dSJustin T. Gibbs * Map the pattern and match buffers into kernel 10548b8a9b1dSJustin T. Gibbs * virtual address space. 10558b8a9b1dSJustin T. Gibbs */ 10568b8a9b1dSJustin T. Gibbs error = cam_periph_mapmem(inccb, &mapinfo); 10578b8a9b1dSJustin T. Gibbs 105859190eaaSKenneth D. Merry if (error) { 105959190eaaSKenneth D. Merry inccb->ccb_h.path = old_path; 10608b8a9b1dSJustin T. Gibbs break; 106159190eaaSKenneth D. Merry } 10628b8a9b1dSJustin T. Gibbs 10638b8a9b1dSJustin T. Gibbs /* 10648b8a9b1dSJustin T. Gibbs * This is an immediate CCB, we can send it on directly. 10658b8a9b1dSJustin T. Gibbs */ 10668b8a9b1dSJustin T. Gibbs xpt_action(inccb); 10678b8a9b1dSJustin T. Gibbs 10688b8a9b1dSJustin T. Gibbs /* 10698b8a9b1dSJustin T. Gibbs * Map the buffers back into user space. 10708b8a9b1dSJustin T. Gibbs */ 10718b8a9b1dSJustin T. Gibbs cam_periph_unmapmem(inccb, &mapinfo); 10728b8a9b1dSJustin T. Gibbs 107359190eaaSKenneth D. Merry inccb->ccb_h.path = old_path; 107459190eaaSKenneth D. Merry 10758b8a9b1dSJustin T. Gibbs error = 0; 10768b8a9b1dSJustin T. Gibbs break; 10778b8a9b1dSJustin T. Gibbs } 10788b8a9b1dSJustin T. Gibbs default: 10798b8a9b1dSJustin T. Gibbs error = EINVAL; 10808b8a9b1dSJustin T. Gibbs break; 10818b8a9b1dSJustin T. Gibbs } 10828b8a9b1dSJustin T. Gibbs break; 10838b8a9b1dSJustin T. Gibbs } 10848b8a9b1dSJustin T. Gibbs /* 10858b8a9b1dSJustin T. Gibbs * This is the getpassthru ioctl. It takes a XPT_GDEVLIST ccb as input, 10868b8a9b1dSJustin T. Gibbs * with the periphal driver name and unit name filled in. The other 10878b8a9b1dSJustin T. Gibbs * fields don't really matter as input. The passthrough driver name 10888b8a9b1dSJustin T. Gibbs * ("pass"), and unit number are passed back in the ccb. The current 10898b8a9b1dSJustin T. Gibbs * device generation number, and the index into the device peripheral 10908b8a9b1dSJustin T. Gibbs * driver list, and the status are also passed back. Note that 10918b8a9b1dSJustin T. Gibbs * since we do everything in one pass, unlike the XPT_GDEVLIST ccb, 10928b8a9b1dSJustin T. Gibbs * we never return a status of CAM_GDEVLIST_LIST_CHANGED. It is 10938b8a9b1dSJustin T. Gibbs * (or rather should be) impossible for the device peripheral driver 10948b8a9b1dSJustin T. Gibbs * list to change since we look at the whole thing in one pass, and 1095a5479bc5SJustin T. Gibbs * we do it with splcam protection. 10968b8a9b1dSJustin T. Gibbs * 10978b8a9b1dSJustin T. Gibbs */ 10988b8a9b1dSJustin T. Gibbs case CAMGETPASSTHRU: { 10998b8a9b1dSJustin T. Gibbs union ccb *ccb; 11008b8a9b1dSJustin T. Gibbs struct cam_periph *periph; 11018b8a9b1dSJustin T. Gibbs struct periph_driver **p_drv; 11028b8a9b1dSJustin T. Gibbs char *name; 11038b8a9b1dSJustin T. Gibbs int unit; 11048b8a9b1dSJustin T. Gibbs int cur_generation; 1105621a60d4SKenneth D. Merry int base_periph_found; 11068b8a9b1dSJustin T. Gibbs int splbreaknum; 11078b8a9b1dSJustin T. Gibbs int s; 11088b8a9b1dSJustin T. Gibbs 11098b8a9b1dSJustin T. Gibbs ccb = (union ccb *)addr; 11108b8a9b1dSJustin T. Gibbs unit = ccb->cgdl.unit_number; 11118b8a9b1dSJustin T. Gibbs name = ccb->cgdl.periph_name; 11128b8a9b1dSJustin T. Gibbs /* 11138b8a9b1dSJustin T. Gibbs * Every 100 devices, we want to drop our spl protection to 11148b8a9b1dSJustin T. Gibbs * give the software interrupt handler a chance to run. 11158b8a9b1dSJustin T. Gibbs * Most systems won't run into this check, but this should 11168b8a9b1dSJustin T. Gibbs * avoid starvation in the software interrupt handler in 11178b8a9b1dSJustin T. Gibbs * large systems. 11188b8a9b1dSJustin T. Gibbs */ 11198b8a9b1dSJustin T. Gibbs splbreaknum = 100; 11208b8a9b1dSJustin T. Gibbs 11218b8a9b1dSJustin T. Gibbs ccb = (union ccb *)addr; 11228b8a9b1dSJustin T. Gibbs 1123621a60d4SKenneth D. Merry base_periph_found = 0; 1124621a60d4SKenneth D. Merry 11258b8a9b1dSJustin T. Gibbs /* 11268b8a9b1dSJustin T. Gibbs * Sanity check -- make sure we don't get a null peripheral 11278b8a9b1dSJustin T. Gibbs * driver name. 11288b8a9b1dSJustin T. Gibbs */ 11298b8a9b1dSJustin T. Gibbs if (*ccb->cgdl.periph_name == '\0') { 11308b8a9b1dSJustin T. Gibbs error = EINVAL; 11318b8a9b1dSJustin T. Gibbs break; 11328b8a9b1dSJustin T. Gibbs } 11338b8a9b1dSJustin T. Gibbs 11348b8a9b1dSJustin T. Gibbs /* Keep the list from changing while we traverse it */ 1135a5479bc5SJustin T. Gibbs s = splcam(); 11368b8a9b1dSJustin T. Gibbs ptstartover: 11378b8a9b1dSJustin T. Gibbs cur_generation = xsoftc.generation; 11388b8a9b1dSJustin T. Gibbs 11398b8a9b1dSJustin T. Gibbs /* first find our driver in the list of drivers */ 11408b8a9b1dSJustin T. Gibbs for (p_drv = (struct periph_driver **)periphdriver_set.ls_items; 11418b8a9b1dSJustin T. Gibbs *p_drv != NULL; p_drv++) 11428b8a9b1dSJustin T. Gibbs if (strcmp((*p_drv)->driver_name, name) == 0) 11438b8a9b1dSJustin T. Gibbs break; 11448b8a9b1dSJustin T. Gibbs 11458b8a9b1dSJustin T. Gibbs if (*p_drv == NULL) { 11468b8a9b1dSJustin T. Gibbs splx(s); 11478b8a9b1dSJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_CMP_ERR; 11488b8a9b1dSJustin T. Gibbs ccb->cgdl.status = CAM_GDEVLIST_ERROR; 11498b8a9b1dSJustin T. Gibbs *ccb->cgdl.periph_name = '\0'; 11508b8a9b1dSJustin T. Gibbs ccb->cgdl.unit_number = 0; 11518b8a9b1dSJustin T. Gibbs error = ENOENT; 11528b8a9b1dSJustin T. Gibbs break; 11538b8a9b1dSJustin T. Gibbs } 11548b8a9b1dSJustin T. Gibbs 11558b8a9b1dSJustin T. Gibbs /* 11568b8a9b1dSJustin T. Gibbs * Run through every peripheral instance of this driver 11578b8a9b1dSJustin T. Gibbs * and check to see whether it matches the unit passed 11588b8a9b1dSJustin T. Gibbs * in by the user. If it does, get out of the loops and 11598b8a9b1dSJustin T. Gibbs * find the passthrough driver associated with that 11608b8a9b1dSJustin T. Gibbs * peripheral driver. 11618b8a9b1dSJustin T. Gibbs */ 11628b8a9b1dSJustin T. Gibbs for (periph = TAILQ_FIRST(&(*p_drv)->units); periph != NULL; 11638b8a9b1dSJustin T. Gibbs periph = TAILQ_NEXT(periph, unit_links)) { 11648b8a9b1dSJustin T. Gibbs 11658b8a9b1dSJustin T. Gibbs if (periph->unit_number == unit) { 11668b8a9b1dSJustin T. Gibbs break; 11678b8a9b1dSJustin T. Gibbs } else if (--splbreaknum == 0) { 11688b8a9b1dSJustin T. Gibbs splx(s); 1169a5479bc5SJustin T. Gibbs s = splcam(); 11708b8a9b1dSJustin T. Gibbs splbreaknum = 100; 11718b8a9b1dSJustin T. Gibbs if (cur_generation != xsoftc.generation) 11728b8a9b1dSJustin T. Gibbs goto ptstartover; 11738b8a9b1dSJustin T. Gibbs } 11748b8a9b1dSJustin T. Gibbs } 11758b8a9b1dSJustin T. Gibbs /* 11768b8a9b1dSJustin T. Gibbs * If we found the peripheral driver that the user passed 11778b8a9b1dSJustin T. Gibbs * in, go through all of the peripheral drivers for that 11788b8a9b1dSJustin T. Gibbs * particular device and look for a passthrough driver. 11798b8a9b1dSJustin T. Gibbs */ 11808b8a9b1dSJustin T. Gibbs if (periph != NULL) { 11818b8a9b1dSJustin T. Gibbs struct cam_ed *device; 11828b8a9b1dSJustin T. Gibbs int i; 11838b8a9b1dSJustin T. Gibbs 1184621a60d4SKenneth D. Merry base_periph_found = 1; 11858b8a9b1dSJustin T. Gibbs device = periph->path->device; 11868b8a9b1dSJustin T. Gibbs for (i = 0, periph = device->periphs.slh_first; 11878b8a9b1dSJustin T. Gibbs periph != NULL; 11888b8a9b1dSJustin T. Gibbs periph = periph->periph_links.sle_next, i++) { 11898b8a9b1dSJustin T. Gibbs /* 11908b8a9b1dSJustin T. Gibbs * Check to see whether we have a 11918b8a9b1dSJustin T. Gibbs * passthrough device or not. 11928b8a9b1dSJustin T. Gibbs */ 11938b8a9b1dSJustin T. Gibbs if (strcmp(periph->periph_name, "pass") == 0) { 11948b8a9b1dSJustin T. Gibbs /* 11958b8a9b1dSJustin T. Gibbs * Fill in the getdevlist fields. 11968b8a9b1dSJustin T. Gibbs */ 11978b8a9b1dSJustin T. Gibbs strcpy(ccb->cgdl.periph_name, 11988b8a9b1dSJustin T. Gibbs periph->periph_name); 11998b8a9b1dSJustin T. Gibbs ccb->cgdl.unit_number = 12008b8a9b1dSJustin T. Gibbs periph->unit_number; 12018b8a9b1dSJustin T. Gibbs if (periph->periph_links.sle_next) 12028b8a9b1dSJustin T. Gibbs ccb->cgdl.status = 12038b8a9b1dSJustin T. Gibbs CAM_GDEVLIST_MORE_DEVS; 12048b8a9b1dSJustin T. Gibbs else 12058b8a9b1dSJustin T. Gibbs ccb->cgdl.status = 12068b8a9b1dSJustin T. Gibbs CAM_GDEVLIST_LAST_DEVICE; 12078b8a9b1dSJustin T. Gibbs ccb->cgdl.generation = 12088b8a9b1dSJustin T. Gibbs device->generation; 12098b8a9b1dSJustin T. Gibbs ccb->cgdl.index = i; 12108b8a9b1dSJustin T. Gibbs /* 12118b8a9b1dSJustin T. Gibbs * Fill in some CCB header fields 12128b8a9b1dSJustin T. Gibbs * that the user may want. 12138b8a9b1dSJustin T. Gibbs */ 12148b8a9b1dSJustin T. Gibbs ccb->ccb_h.path_id = 12158b8a9b1dSJustin T. Gibbs periph->path->bus->path_id; 12168b8a9b1dSJustin T. Gibbs ccb->ccb_h.target_id = 12178b8a9b1dSJustin T. Gibbs periph->path->target->target_id; 12188b8a9b1dSJustin T. Gibbs ccb->ccb_h.target_lun = 12198b8a9b1dSJustin T. Gibbs periph->path->device->lun_id; 12208b8a9b1dSJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_CMP; 12218b8a9b1dSJustin T. Gibbs break; 12228b8a9b1dSJustin T. Gibbs } 12238b8a9b1dSJustin T. Gibbs } 12248b8a9b1dSJustin T. Gibbs } 12258b8a9b1dSJustin T. Gibbs 12268b8a9b1dSJustin T. Gibbs /* 12278b8a9b1dSJustin T. Gibbs * If the periph is null here, one of two things has 12288b8a9b1dSJustin T. Gibbs * happened. The first possibility is that we couldn't 12298b8a9b1dSJustin T. Gibbs * find the unit number of the particular peripheral driver 12308b8a9b1dSJustin T. Gibbs * that the user is asking about. e.g. the user asks for 12318b8a9b1dSJustin T. Gibbs * the passthrough driver for "da11". We find the list of 12328b8a9b1dSJustin T. Gibbs * "da" peripherals all right, but there is no unit 11. 12338b8a9b1dSJustin T. Gibbs * The other possibility is that we went through the list 12348b8a9b1dSJustin T. Gibbs * of peripheral drivers attached to the device structure, 12358b8a9b1dSJustin T. Gibbs * but didn't find one with the name "pass". Either way, 12368b8a9b1dSJustin T. Gibbs * we return ENOENT, since we couldn't find something. 12378b8a9b1dSJustin T. Gibbs */ 12388b8a9b1dSJustin T. Gibbs if (periph == NULL) { 12398b8a9b1dSJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_CMP_ERR; 12408b8a9b1dSJustin T. Gibbs ccb->cgdl.status = CAM_GDEVLIST_ERROR; 12418b8a9b1dSJustin T. Gibbs *ccb->cgdl.periph_name = '\0'; 12428b8a9b1dSJustin T. Gibbs ccb->cgdl.unit_number = 0; 12438b8a9b1dSJustin T. Gibbs error = ENOENT; 1244621a60d4SKenneth D. Merry /* 1245621a60d4SKenneth D. Merry * It is unfortunate that this is even necessary, 1246621a60d4SKenneth D. Merry * but there are many, many clueless users out there. 1247621a60d4SKenneth D. Merry * If this is true, the user is looking for the 1248621a60d4SKenneth D. Merry * passthrough driver, but doesn't have one in his 1249621a60d4SKenneth D. Merry * kernel. 1250621a60d4SKenneth D. Merry */ 1251621a60d4SKenneth D. Merry if (base_periph_found == 1) { 1252621a60d4SKenneth D. Merry printf("xptioctl: pass driver is not in the " 1253621a60d4SKenneth D. Merry "kernel\n"); 1254621a60d4SKenneth D. Merry printf("xptioctl: put \"device pass0\" in " 1255621a60d4SKenneth D. Merry "your kernel config file\n"); 1256621a60d4SKenneth D. Merry } 12578b8a9b1dSJustin T. Gibbs } 12588b8a9b1dSJustin T. Gibbs splx(s); 12598b8a9b1dSJustin T. Gibbs break; 12608b8a9b1dSJustin T. Gibbs } 12618b8a9b1dSJustin T. Gibbs default: 12628b8a9b1dSJustin T. Gibbs error = ENOTTY; 12638b8a9b1dSJustin T. Gibbs break; 12648b8a9b1dSJustin T. Gibbs } 12658b8a9b1dSJustin T. Gibbs 12668b8a9b1dSJustin T. Gibbs return(error); 12678b8a9b1dSJustin T. Gibbs } 12688b8a9b1dSJustin T. Gibbs 12698b8a9b1dSJustin T. Gibbs /* Functions accessed by the peripheral drivers */ 1270667d00a7SMatt Jacob static void 12716d2a8f1cSPeter Wemm xpt_init(dummy) 12726d2a8f1cSPeter Wemm void *dummy; 12738b8a9b1dSJustin T. Gibbs { 12748b8a9b1dSJustin T. Gibbs struct cam_sim *xpt_sim; 12758b8a9b1dSJustin T. Gibbs struct cam_path *path; 1276434bbf6eSJustin T. Gibbs struct cam_devq *devq; 12778b8a9b1dSJustin T. Gibbs cam_status status; 12788b8a9b1dSJustin T. Gibbs 12798b8a9b1dSJustin T. Gibbs TAILQ_INIT(&xpt_busses); 12808b8a9b1dSJustin T. Gibbs TAILQ_INIT(&cam_bioq); 12818b8a9b1dSJustin T. Gibbs TAILQ_INIT(&cam_netq); 12828b8a9b1dSJustin T. Gibbs SLIST_INIT(&ccb_freeq); 12838b8a9b1dSJustin T. Gibbs STAILQ_INIT(&highpowerq); 12848b8a9b1dSJustin T. Gibbs 12858b8a9b1dSJustin T. Gibbs /* 12868b8a9b1dSJustin T. Gibbs * The xpt layer is, itself, the equivelent of a SIM. 12878b8a9b1dSJustin T. Gibbs * Allow 16 ccbs in the ccb pool for it. This should 12888b8a9b1dSJustin T. Gibbs * give decent parallelism when we probe busses and 12898b8a9b1dSJustin T. Gibbs * perform other XPT functions. 12908b8a9b1dSJustin T. Gibbs */ 1291434bbf6eSJustin T. Gibbs devq = cam_simq_alloc(16); 1292434bbf6eSJustin T. Gibbs xpt_sim = cam_sim_alloc(xptaction, 1293434bbf6eSJustin T. Gibbs xptpoll, 1294434bbf6eSJustin T. Gibbs "xpt", 1295434bbf6eSJustin T. Gibbs /*softc*/NULL, 1296434bbf6eSJustin T. Gibbs /*unit*/0, 1297434bbf6eSJustin T. Gibbs /*max_dev_transactions*/0, 1298434bbf6eSJustin T. Gibbs /*max_tagged_dev_transactions*/0, 1299434bbf6eSJustin T. Gibbs devq); 13008b8a9b1dSJustin T. Gibbs xpt_max_ccbs = 16; 13018b8a9b1dSJustin T. Gibbs 1302434bbf6eSJustin T. Gibbs xpt_bus_register(xpt_sim, /*bus #*/0); 13038b8a9b1dSJustin T. Gibbs 13048b8a9b1dSJustin T. Gibbs /* 13058b8a9b1dSJustin T. Gibbs * Looking at the XPT from the SIM layer, the XPT is 13068b8a9b1dSJustin T. Gibbs * the equivelent of a peripheral driver. Allocate 13078b8a9b1dSJustin T. Gibbs * a peripheral driver entry for us. 13088b8a9b1dSJustin T. Gibbs */ 13098b8a9b1dSJustin T. Gibbs if ((status = xpt_create_path(&path, NULL, CAM_XPT_PATH_ID, 13108b8a9b1dSJustin T. Gibbs CAM_TARGET_WILDCARD, 13118b8a9b1dSJustin T. Gibbs CAM_LUN_WILDCARD)) != CAM_REQ_CMP) { 13128b8a9b1dSJustin T. Gibbs printf("xpt_init: xpt_create_path failed with status %#x," 13138b8a9b1dSJustin T. Gibbs " failing attach\n", status); 13148b8a9b1dSJustin T. Gibbs return; 13158b8a9b1dSJustin T. Gibbs } 13168b8a9b1dSJustin T. Gibbs 1317ee9c90c7SKenneth D. Merry cam_periph_alloc(xptregister, NULL, NULL, NULL, "xpt", CAM_PERIPH_BIO, 13188b8a9b1dSJustin T. Gibbs path, NULL, 0, NULL); 13198b8a9b1dSJustin T. Gibbs xpt_free_path(path); 13208b8a9b1dSJustin T. Gibbs 13218b8a9b1dSJustin T. Gibbs xpt_sim->softc = xpt_periph; 13228b8a9b1dSJustin T. Gibbs 13238b8a9b1dSJustin T. Gibbs /* 13248b8a9b1dSJustin T. Gibbs * Register a callback for when interrupts are enabled. 13258b8a9b1dSJustin T. Gibbs */ 13268b8a9b1dSJustin T. Gibbs xpt_config_hook = 13278b8a9b1dSJustin T. Gibbs (struct intr_config_hook *)malloc(sizeof(struct intr_config_hook), 13288b8a9b1dSJustin T. Gibbs M_TEMP, M_NOWAIT); 13298b8a9b1dSJustin T. Gibbs if (xpt_config_hook == NULL) { 13308b8a9b1dSJustin T. Gibbs printf("xpt_init: Cannot malloc config hook " 13318b8a9b1dSJustin T. Gibbs "- failing attach\n"); 13328b8a9b1dSJustin T. Gibbs return; 13338b8a9b1dSJustin T. Gibbs } 13348b8a9b1dSJustin T. Gibbs bzero(xpt_config_hook, sizeof(*xpt_config_hook)); 13358b8a9b1dSJustin T. Gibbs 13368b8a9b1dSJustin T. Gibbs xpt_config_hook->ich_func = xpt_config; 13378b8a9b1dSJustin T. Gibbs if (config_intrhook_establish(xpt_config_hook) != 0) { 13388b8a9b1dSJustin T. Gibbs free (xpt_config_hook, M_TEMP); 13398b8a9b1dSJustin T. Gibbs printf("xpt_init: config_intrhook_establish failed " 13408b8a9b1dSJustin T. Gibbs "- failing attach\n"); 13418b8a9b1dSJustin T. Gibbs } 13428b8a9b1dSJustin T. Gibbs 13438b8a9b1dSJustin T. Gibbs /* Install our software interrupt handlers */ 13445d754af7SMatt Jacob register_swi(SWI_CAMNET, swi_camnet); 13455d754af7SMatt Jacob register_swi(SWI_CAMBIO, swi_cambio); 13468b8a9b1dSJustin T. Gibbs } 13478b8a9b1dSJustin T. Gibbs 13488b8a9b1dSJustin T. Gibbs static cam_status 13498b8a9b1dSJustin T. Gibbs xptregister(struct cam_periph *periph, void *arg) 13508b8a9b1dSJustin T. Gibbs { 13518b8a9b1dSJustin T. Gibbs if (periph == NULL) { 13528b8a9b1dSJustin T. Gibbs printf("xptregister: periph was NULL!!\n"); 13538b8a9b1dSJustin T. Gibbs return(CAM_REQ_CMP_ERR); 13548b8a9b1dSJustin T. Gibbs } 13558b8a9b1dSJustin T. Gibbs 13568b8a9b1dSJustin T. Gibbs periph->softc = NULL; 13578b8a9b1dSJustin T. Gibbs 13588b8a9b1dSJustin T. Gibbs xpt_periph = periph; 13598b8a9b1dSJustin T. Gibbs 13608b8a9b1dSJustin T. Gibbs return(CAM_REQ_CMP); 13618b8a9b1dSJustin T. Gibbs } 13628b8a9b1dSJustin T. Gibbs 13638b8a9b1dSJustin T. Gibbs int32_t 13648b8a9b1dSJustin T. Gibbs xpt_add_periph(struct cam_periph *periph) 13658b8a9b1dSJustin T. Gibbs { 13668b8a9b1dSJustin T. Gibbs struct cam_ed *device; 13678b8a9b1dSJustin T. Gibbs int32_t status; 13688b8a9b1dSJustin T. Gibbs struct periph_list *periph_head; 13698b8a9b1dSJustin T. Gibbs 13708b8a9b1dSJustin T. Gibbs device = periph->path->device; 13718b8a9b1dSJustin T. Gibbs 13728b8a9b1dSJustin T. Gibbs periph_head = &device->periphs; 13738b8a9b1dSJustin T. Gibbs 13748b8a9b1dSJustin T. Gibbs status = CAM_REQ_CMP; 13758b8a9b1dSJustin T. Gibbs 13768b8a9b1dSJustin T. Gibbs if (device != NULL) { 13778b8a9b1dSJustin T. Gibbs int s; 13788b8a9b1dSJustin T. Gibbs 13798b8a9b1dSJustin T. Gibbs /* 13808b8a9b1dSJustin T. Gibbs * Make room for this peripheral 13818b8a9b1dSJustin T. Gibbs * so it will fit in the queue 13828b8a9b1dSJustin T. Gibbs * when it's scheduled to run 13838b8a9b1dSJustin T. Gibbs */ 13848b8a9b1dSJustin T. Gibbs s = splsoftcam(); 13858b8a9b1dSJustin T. Gibbs status = camq_resize(&device->drvq, 13868b8a9b1dSJustin T. Gibbs device->drvq.array_size + 1); 13878b8a9b1dSJustin T. Gibbs 13888b8a9b1dSJustin T. Gibbs device->generation++; 13898b8a9b1dSJustin T. Gibbs 13908b8a9b1dSJustin T. Gibbs SLIST_INSERT_HEAD(periph_head, periph, periph_links); 13918b8a9b1dSJustin T. Gibbs 13928b8a9b1dSJustin T. Gibbs splx(s); 13938b8a9b1dSJustin T. Gibbs } 13948b8a9b1dSJustin T. Gibbs 13958b8a9b1dSJustin T. Gibbs xsoftc.generation++; 13968b8a9b1dSJustin T. Gibbs 13978b8a9b1dSJustin T. Gibbs return (status); 13988b8a9b1dSJustin T. Gibbs } 13998b8a9b1dSJustin T. Gibbs 14008b8a9b1dSJustin T. Gibbs void 14018b8a9b1dSJustin T. Gibbs xpt_remove_periph(struct cam_periph *periph) 14028b8a9b1dSJustin T. Gibbs { 14038b8a9b1dSJustin T. Gibbs struct cam_ed *device; 14048b8a9b1dSJustin T. Gibbs 14058b8a9b1dSJustin T. Gibbs device = periph->path->device; 14068b8a9b1dSJustin T. Gibbs 14078b8a9b1dSJustin T. Gibbs if (device != NULL) { 14088b8a9b1dSJustin T. Gibbs int s; 14098b8a9b1dSJustin T. Gibbs struct periph_list *periph_head; 14108b8a9b1dSJustin T. Gibbs 14118b8a9b1dSJustin T. Gibbs periph_head = &device->periphs; 14128b8a9b1dSJustin T. Gibbs 14138b8a9b1dSJustin T. Gibbs /* Release the slot for this peripheral */ 14148b8a9b1dSJustin T. Gibbs s = splsoftcam(); 14158b8a9b1dSJustin T. Gibbs camq_resize(&device->drvq, device->drvq.array_size - 1); 14168b8a9b1dSJustin T. Gibbs 14178b8a9b1dSJustin T. Gibbs device->generation++; 14188b8a9b1dSJustin T. Gibbs 1419e3975643SJake Burkholder SLIST_REMOVE(periph_head, periph, cam_periph, periph_links); 14208b8a9b1dSJustin T. Gibbs 14218b8a9b1dSJustin T. Gibbs splx(s); 14228b8a9b1dSJustin T. Gibbs } 14238b8a9b1dSJustin T. Gibbs 14248b8a9b1dSJustin T. Gibbs xsoftc.generation++; 14258b8a9b1dSJustin T. Gibbs 14268b8a9b1dSJustin T. Gibbs } 14278b8a9b1dSJustin T. Gibbs 14288b8a9b1dSJustin T. Gibbs void 14298b8a9b1dSJustin T. Gibbs xpt_announce_periph(struct cam_periph *periph, char *announce_string) 14308b8a9b1dSJustin T. Gibbs { 14318b8a9b1dSJustin T. Gibbs int s; 14328b8a9b1dSJustin T. Gibbs u_int mb; 14338b8a9b1dSJustin T. Gibbs struct cam_path *path; 14348b8a9b1dSJustin T. Gibbs struct ccb_trans_settings cts; 14358b8a9b1dSJustin T. Gibbs 14368b8a9b1dSJustin T. Gibbs path = periph->path; 14378b8a9b1dSJustin T. Gibbs /* 14388b8a9b1dSJustin T. Gibbs * To ensure that this is printed in one piece, 14398b8a9b1dSJustin T. Gibbs * mask out CAM interrupts. 14408b8a9b1dSJustin T. Gibbs */ 14418b8a9b1dSJustin T. Gibbs s = splsoftcam(); 14428b8a9b1dSJustin T. Gibbs printf("%s%d at %s%d bus %d target %d lun %d\n", 14438b8a9b1dSJustin T. Gibbs periph->periph_name, periph->unit_number, 14448b8a9b1dSJustin T. Gibbs path->bus->sim->sim_name, 14458b8a9b1dSJustin T. Gibbs path->bus->sim->unit_number, 14468b8a9b1dSJustin T. Gibbs path->bus->sim->bus_id, 14478b8a9b1dSJustin T. Gibbs path->target->target_id, 14488b8a9b1dSJustin T. Gibbs path->device->lun_id); 14498b8a9b1dSJustin T. Gibbs printf("%s%d: ", periph->periph_name, periph->unit_number); 14508b8a9b1dSJustin T. Gibbs scsi_print_inquiry(&path->device->inq_data); 14518b8a9b1dSJustin T. Gibbs if ((bootverbose) 14528b8a9b1dSJustin T. Gibbs && (path->device->serial_num_len > 0)) { 14538b8a9b1dSJustin T. Gibbs /* Don't wrap the screen - print only the first 60 chars */ 14548b8a9b1dSJustin T. Gibbs printf("%s%d: Serial Number %.60s\n", periph->periph_name, 14558b8a9b1dSJustin T. Gibbs periph->unit_number, path->device->serial_num); 14568b8a9b1dSJustin T. Gibbs } 14578b8a9b1dSJustin T. Gibbs xpt_setup_ccb(&cts.ccb_h, path, /*priority*/1); 14588b8a9b1dSJustin T. Gibbs cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS; 14598b8a9b1dSJustin T. Gibbs cts.flags = CCB_TRANS_CURRENT_SETTINGS; 14608b8a9b1dSJustin T. Gibbs xpt_action((union ccb*)&cts); 14618b8a9b1dSJustin T. Gibbs if (cts.ccb_h.status == CAM_REQ_CMP) { 14628b8a9b1dSJustin T. Gibbs u_int speed; 14638b8a9b1dSJustin T. Gibbs u_int freq; 14648b8a9b1dSJustin T. Gibbs 14658b8a9b1dSJustin T. Gibbs if ((cts.valid & CCB_TRANS_SYNC_OFFSET_VALID) != 0 14668b8a9b1dSJustin T. Gibbs && cts.sync_offset != 0) { 14678b8a9b1dSJustin T. Gibbs freq = scsi_calc_syncsrate(cts.sync_period); 14688b8a9b1dSJustin T. Gibbs speed = freq; 14698b8a9b1dSJustin T. Gibbs } else { 14709deea857SKenneth D. Merry struct ccb_pathinq cpi; 14719deea857SKenneth D. Merry 14729deea857SKenneth D. Merry /* Ask the SIM for its base transfer speed */ 14739deea857SKenneth D. Merry xpt_setup_ccb(&cpi.ccb_h, path, /*priority*/1); 14749deea857SKenneth D. Merry cpi.ccb_h.func_code = XPT_PATH_INQ; 14759deea857SKenneth D. Merry xpt_action((union ccb *)&cpi); 14769deea857SKenneth D. Merry 14779deea857SKenneth D. Merry speed = cpi.base_transfer_speed; 14788b8a9b1dSJustin T. Gibbs freq = 0; 14798b8a9b1dSJustin T. Gibbs } 14808b8a9b1dSJustin T. Gibbs if ((cts.valid & CCB_TRANS_BUS_WIDTH_VALID) != 0) 14818b8a9b1dSJustin T. Gibbs speed *= (0x01 << cts.bus_width); 14828b8a9b1dSJustin T. Gibbs mb = speed / 1000; 14838b8a9b1dSJustin T. Gibbs if (mb > 0) 1484588b47e5SKenneth D. Merry printf("%s%d: %d.%03dMB/s transfers", 1485588b47e5SKenneth D. Merry periph->periph_name, periph->unit_number, 1486588b47e5SKenneth D. Merry mb, speed % 1000); 14878b8a9b1dSJustin T. Gibbs else 14888b8a9b1dSJustin T. Gibbs printf("%s%d: %dKB/s transfers", periph->periph_name, 14890cdabce0SNick Hibma periph->unit_number, speed); 14908b8a9b1dSJustin T. Gibbs if ((cts.valid & CCB_TRANS_SYNC_OFFSET_VALID) != 0 14918b8a9b1dSJustin T. Gibbs && cts.sync_offset != 0) { 1492588b47e5SKenneth D. Merry printf(" (%d.%03dMHz, offset %d", freq / 1000, 14938b8a9b1dSJustin T. Gibbs freq % 1000, cts.sync_offset); 14948b8a9b1dSJustin T. Gibbs } 14958b8a9b1dSJustin T. Gibbs if ((cts.valid & CCB_TRANS_BUS_WIDTH_VALID) != 0 14968b8a9b1dSJustin T. Gibbs && cts.bus_width > 0) { 14978b8a9b1dSJustin T. Gibbs if ((cts.valid & CCB_TRANS_SYNC_OFFSET_VALID) != 0 14988b8a9b1dSJustin T. Gibbs && cts.sync_offset != 0) { 14998b8a9b1dSJustin T. Gibbs printf(", "); 15008b8a9b1dSJustin T. Gibbs } else { 15018b8a9b1dSJustin T. Gibbs printf(" ("); 15028b8a9b1dSJustin T. Gibbs } 15038b8a9b1dSJustin T. Gibbs printf("%dbit)", 8 * (0x01 << cts.bus_width)); 15048b8a9b1dSJustin T. Gibbs } else if ((cts.valid & CCB_TRANS_SYNC_OFFSET_VALID) != 0 15058b8a9b1dSJustin T. Gibbs && cts.sync_offset != 0) { 15068b8a9b1dSJustin T. Gibbs printf(")"); 15078b8a9b1dSJustin T. Gibbs } 1508fd21cc5eSJustin T. Gibbs 1509fd21cc5eSJustin T. Gibbs if (path->device->inq_flags & SID_CmdQue 1510fd21cc5eSJustin T. Gibbs || path->device->flags & CAM_DEV_TAG_AFTER_COUNT) { 15118b8a9b1dSJustin T. Gibbs printf(", Tagged Queueing Enabled"); 15128b8a9b1dSJustin T. Gibbs } 15138b8a9b1dSJustin T. Gibbs 15148b8a9b1dSJustin T. Gibbs printf("\n"); 15152ba01e6fSJustin T. Gibbs } else if (path->device->inq_flags & SID_CmdQue 15162ba01e6fSJustin T. Gibbs || path->device->flags & CAM_DEV_TAG_AFTER_COUNT) { 15178b8a9b1dSJustin T. Gibbs printf("%s%d: Tagged Queueing Enabled\n", 15188b8a9b1dSJustin T. Gibbs periph->periph_name, periph->unit_number); 15198b8a9b1dSJustin T. Gibbs } 15208b8a9b1dSJustin T. Gibbs 15218b8a9b1dSJustin T. Gibbs /* 15228b8a9b1dSJustin T. Gibbs * We only want to print the caller's announce string if they've 15238b8a9b1dSJustin T. Gibbs * passed one in.. 15248b8a9b1dSJustin T. Gibbs */ 15258b8a9b1dSJustin T. Gibbs if (announce_string != NULL) 15268b8a9b1dSJustin T. Gibbs printf("%s%d: %s\n", periph->periph_name, 15278b8a9b1dSJustin T. Gibbs periph->unit_number, announce_string); 15288b8a9b1dSJustin T. Gibbs splx(s); 15298b8a9b1dSJustin T. Gibbs } 15308b8a9b1dSJustin T. Gibbs 15318b8a9b1dSJustin T. Gibbs 15328b8a9b1dSJustin T. Gibbs static dev_match_ret 15338b8a9b1dSJustin T. Gibbs xptbusmatch(struct dev_match_pattern *patterns, int num_patterns, 15348b8a9b1dSJustin T. Gibbs struct cam_eb *bus) 15358b8a9b1dSJustin T. Gibbs { 15368b8a9b1dSJustin T. Gibbs dev_match_ret retval; 15378b8a9b1dSJustin T. Gibbs int i; 15388b8a9b1dSJustin T. Gibbs 15398b8a9b1dSJustin T. Gibbs retval = DM_RET_NONE; 15408b8a9b1dSJustin T. Gibbs 15418b8a9b1dSJustin T. Gibbs /* 15428b8a9b1dSJustin T. Gibbs * If we aren't given something to match against, that's an error. 15438b8a9b1dSJustin T. Gibbs */ 15448b8a9b1dSJustin T. Gibbs if (bus == NULL) 15458b8a9b1dSJustin T. Gibbs return(DM_RET_ERROR); 15468b8a9b1dSJustin T. Gibbs 15478b8a9b1dSJustin T. Gibbs /* 15488b8a9b1dSJustin T. Gibbs * If there are no match entries, then this bus matches no 15498b8a9b1dSJustin T. Gibbs * matter what. 15508b8a9b1dSJustin T. Gibbs */ 15518b8a9b1dSJustin T. Gibbs if ((patterns == NULL) || (num_patterns == 0)) 15528b8a9b1dSJustin T. Gibbs return(DM_RET_DESCEND | DM_RET_COPY); 15538b8a9b1dSJustin T. Gibbs 15548b8a9b1dSJustin T. Gibbs for (i = 0; i < num_patterns; i++) { 15558b8a9b1dSJustin T. Gibbs struct bus_match_pattern *cur_pattern; 15568b8a9b1dSJustin T. Gibbs 15578b8a9b1dSJustin T. Gibbs /* 15588b8a9b1dSJustin T. Gibbs * If the pattern in question isn't for a bus node, we 15598b8a9b1dSJustin T. Gibbs * aren't interested. However, we do indicate to the 15608b8a9b1dSJustin T. Gibbs * calling routine that we should continue descending the 15618b8a9b1dSJustin T. Gibbs * tree, since the user wants to match against lower-level 15628b8a9b1dSJustin T. Gibbs * EDT elements. 15638b8a9b1dSJustin T. Gibbs */ 15648b8a9b1dSJustin T. Gibbs if (patterns[i].type != DEV_MATCH_BUS) { 15658b8a9b1dSJustin T. Gibbs if ((retval & DM_RET_ACTION_MASK) == DM_RET_NONE) 15668b8a9b1dSJustin T. Gibbs retval |= DM_RET_DESCEND; 15678b8a9b1dSJustin T. Gibbs continue; 15688b8a9b1dSJustin T. Gibbs } 15698b8a9b1dSJustin T. Gibbs 15708b8a9b1dSJustin T. Gibbs cur_pattern = &patterns[i].pattern.bus_pattern; 15718b8a9b1dSJustin T. Gibbs 15728b8a9b1dSJustin T. Gibbs /* 15738b8a9b1dSJustin T. Gibbs * If they want to match any bus node, we give them any 15748b8a9b1dSJustin T. Gibbs * device node. 15758b8a9b1dSJustin T. Gibbs */ 15768b8a9b1dSJustin T. Gibbs if (cur_pattern->flags == BUS_MATCH_ANY) { 15778b8a9b1dSJustin T. Gibbs /* set the copy flag */ 15788b8a9b1dSJustin T. Gibbs retval |= DM_RET_COPY; 15798b8a9b1dSJustin T. Gibbs 15808b8a9b1dSJustin T. Gibbs /* 15818b8a9b1dSJustin T. Gibbs * If we've already decided on an action, go ahead 15828b8a9b1dSJustin T. Gibbs * and return. 15838b8a9b1dSJustin T. Gibbs */ 15848b8a9b1dSJustin T. Gibbs if ((retval & DM_RET_ACTION_MASK) != DM_RET_NONE) 15858b8a9b1dSJustin T. Gibbs return(retval); 15868b8a9b1dSJustin T. Gibbs } 15878b8a9b1dSJustin T. Gibbs 15888b8a9b1dSJustin T. Gibbs /* 15898b8a9b1dSJustin T. Gibbs * Not sure why someone would do this... 15908b8a9b1dSJustin T. Gibbs */ 15918b8a9b1dSJustin T. Gibbs if (cur_pattern->flags == BUS_MATCH_NONE) 15928b8a9b1dSJustin T. Gibbs continue; 15938b8a9b1dSJustin T. Gibbs 15948b8a9b1dSJustin T. Gibbs if (((cur_pattern->flags & BUS_MATCH_PATH) != 0) 15958b8a9b1dSJustin T. Gibbs && (cur_pattern->path_id != bus->path_id)) 15968b8a9b1dSJustin T. Gibbs continue; 15978b8a9b1dSJustin T. Gibbs 15988b8a9b1dSJustin T. Gibbs if (((cur_pattern->flags & BUS_MATCH_BUS_ID) != 0) 15998b8a9b1dSJustin T. Gibbs && (cur_pattern->bus_id != bus->sim->bus_id)) 16008b8a9b1dSJustin T. Gibbs continue; 16018b8a9b1dSJustin T. Gibbs 16028b8a9b1dSJustin T. Gibbs if (((cur_pattern->flags & BUS_MATCH_UNIT) != 0) 16038b8a9b1dSJustin T. Gibbs && (cur_pattern->unit_number != bus->sim->unit_number)) 16048b8a9b1dSJustin T. Gibbs continue; 16058b8a9b1dSJustin T. Gibbs 16068b8a9b1dSJustin T. Gibbs if (((cur_pattern->flags & BUS_MATCH_NAME) != 0) 16078b8a9b1dSJustin T. Gibbs && (strncmp(cur_pattern->dev_name, bus->sim->sim_name, 16088b8a9b1dSJustin T. Gibbs DEV_IDLEN) != 0)) 16098b8a9b1dSJustin T. Gibbs continue; 16108b8a9b1dSJustin T. Gibbs 16118b8a9b1dSJustin T. Gibbs /* 16128b8a9b1dSJustin T. Gibbs * If we get to this point, the user definitely wants 16138b8a9b1dSJustin T. Gibbs * information on this bus. So tell the caller to copy the 16148b8a9b1dSJustin T. Gibbs * data out. 16158b8a9b1dSJustin T. Gibbs */ 16168b8a9b1dSJustin T. Gibbs retval |= DM_RET_COPY; 16178b8a9b1dSJustin T. Gibbs 16188b8a9b1dSJustin T. Gibbs /* 16198b8a9b1dSJustin T. Gibbs * If the return action has been set to descend, then we 16208b8a9b1dSJustin T. Gibbs * know that we've already seen a non-bus matching 16218b8a9b1dSJustin T. Gibbs * expression, therefore we need to further descend the tree. 16228b8a9b1dSJustin T. Gibbs * This won't change by continuing around the loop, so we 16238b8a9b1dSJustin T. Gibbs * go ahead and return. If we haven't seen a non-bus 16248b8a9b1dSJustin T. Gibbs * matching expression, we keep going around the loop until 16258b8a9b1dSJustin T. Gibbs * we exhaust the matching expressions. We'll set the stop 16268b8a9b1dSJustin T. Gibbs * flag once we fall out of the loop. 16278b8a9b1dSJustin T. Gibbs */ 16288b8a9b1dSJustin T. Gibbs if ((retval & DM_RET_ACTION_MASK) == DM_RET_DESCEND) 16298b8a9b1dSJustin T. Gibbs return(retval); 16308b8a9b1dSJustin T. Gibbs } 16318b8a9b1dSJustin T. Gibbs 16328b8a9b1dSJustin T. Gibbs /* 16338b8a9b1dSJustin T. Gibbs * If the return action hasn't been set to descend yet, that means 16348b8a9b1dSJustin T. Gibbs * we haven't seen anything other than bus matching patterns. So 16358b8a9b1dSJustin T. Gibbs * tell the caller to stop descending the tree -- the user doesn't 16368b8a9b1dSJustin T. Gibbs * want to match against lower level tree elements. 16378b8a9b1dSJustin T. Gibbs */ 16388b8a9b1dSJustin T. Gibbs if ((retval & DM_RET_ACTION_MASK) == DM_RET_NONE) 16398b8a9b1dSJustin T. Gibbs retval |= DM_RET_STOP; 16408b8a9b1dSJustin T. Gibbs 16418b8a9b1dSJustin T. Gibbs return(retval); 16428b8a9b1dSJustin T. Gibbs } 16438b8a9b1dSJustin T. Gibbs 16448b8a9b1dSJustin T. Gibbs static dev_match_ret 16458b8a9b1dSJustin T. Gibbs xptdevicematch(struct dev_match_pattern *patterns, int num_patterns, 16468b8a9b1dSJustin T. Gibbs struct cam_ed *device) 16478b8a9b1dSJustin T. Gibbs { 16488b8a9b1dSJustin T. Gibbs dev_match_ret retval; 16498b8a9b1dSJustin T. Gibbs int i; 16508b8a9b1dSJustin T. Gibbs 16518b8a9b1dSJustin T. Gibbs retval = DM_RET_NONE; 16528b8a9b1dSJustin T. Gibbs 16538b8a9b1dSJustin T. Gibbs /* 16548b8a9b1dSJustin T. Gibbs * If we aren't given something to match against, that's an error. 16558b8a9b1dSJustin T. Gibbs */ 16568b8a9b1dSJustin T. Gibbs if (device == NULL) 16578b8a9b1dSJustin T. Gibbs return(DM_RET_ERROR); 16588b8a9b1dSJustin T. Gibbs 16598b8a9b1dSJustin T. Gibbs /* 16608b8a9b1dSJustin T. Gibbs * If there are no match entries, then this device matches no 16618b8a9b1dSJustin T. Gibbs * matter what. 16628b8a9b1dSJustin T. Gibbs */ 16638b8a9b1dSJustin T. Gibbs if ((patterns == NULL) || (patterns == 0)) 16648b8a9b1dSJustin T. Gibbs return(DM_RET_DESCEND | DM_RET_COPY); 16658b8a9b1dSJustin T. Gibbs 16668b8a9b1dSJustin T. Gibbs for (i = 0; i < num_patterns; i++) { 16678b8a9b1dSJustin T. Gibbs struct device_match_pattern *cur_pattern; 16688b8a9b1dSJustin T. Gibbs 16698b8a9b1dSJustin T. Gibbs /* 16708b8a9b1dSJustin T. Gibbs * If the pattern in question isn't for a device node, we 16718b8a9b1dSJustin T. Gibbs * aren't interested. 16728b8a9b1dSJustin T. Gibbs */ 16738b8a9b1dSJustin T. Gibbs if (patterns[i].type != DEV_MATCH_DEVICE) { 16748b8a9b1dSJustin T. Gibbs if ((patterns[i].type == DEV_MATCH_PERIPH) 16758b8a9b1dSJustin T. Gibbs && ((retval & DM_RET_ACTION_MASK) == DM_RET_NONE)) 16768b8a9b1dSJustin T. Gibbs retval |= DM_RET_DESCEND; 16778b8a9b1dSJustin T. Gibbs continue; 16788b8a9b1dSJustin T. Gibbs } 16798b8a9b1dSJustin T. Gibbs 16808b8a9b1dSJustin T. Gibbs cur_pattern = &patterns[i].pattern.device_pattern; 16818b8a9b1dSJustin T. Gibbs 16828b8a9b1dSJustin T. Gibbs /* 16838b8a9b1dSJustin T. Gibbs * If they want to match any device node, we give them any 16848b8a9b1dSJustin T. Gibbs * device node. 16858b8a9b1dSJustin T. Gibbs */ 16868b8a9b1dSJustin T. Gibbs if (cur_pattern->flags == DEV_MATCH_ANY) { 16878b8a9b1dSJustin T. Gibbs /* set the copy flag */ 16888b8a9b1dSJustin T. Gibbs retval |= DM_RET_COPY; 16898b8a9b1dSJustin T. Gibbs 16908b8a9b1dSJustin T. Gibbs 16918b8a9b1dSJustin T. Gibbs /* 16928b8a9b1dSJustin T. Gibbs * If we've already decided on an action, go ahead 16938b8a9b1dSJustin T. Gibbs * and return. 16948b8a9b1dSJustin T. Gibbs */ 16958b8a9b1dSJustin T. Gibbs if ((retval & DM_RET_ACTION_MASK) != DM_RET_NONE) 16968b8a9b1dSJustin T. Gibbs return(retval); 16978b8a9b1dSJustin T. Gibbs } 16988b8a9b1dSJustin T. Gibbs 16998b8a9b1dSJustin T. Gibbs /* 17008b8a9b1dSJustin T. Gibbs * Not sure why someone would do this... 17018b8a9b1dSJustin T. Gibbs */ 17028b8a9b1dSJustin T. Gibbs if (cur_pattern->flags == DEV_MATCH_NONE) 17038b8a9b1dSJustin T. Gibbs continue; 17048b8a9b1dSJustin T. Gibbs 17058b8a9b1dSJustin T. Gibbs if (((cur_pattern->flags & DEV_MATCH_PATH) != 0) 17068b8a9b1dSJustin T. Gibbs && (cur_pattern->path_id != device->target->bus->path_id)) 17078b8a9b1dSJustin T. Gibbs continue; 17088b8a9b1dSJustin T. Gibbs 17098b8a9b1dSJustin T. Gibbs if (((cur_pattern->flags & DEV_MATCH_TARGET) != 0) 17108b8a9b1dSJustin T. Gibbs && (cur_pattern->target_id != device->target->target_id)) 17118b8a9b1dSJustin T. Gibbs continue; 17128b8a9b1dSJustin T. Gibbs 17138b8a9b1dSJustin T. Gibbs if (((cur_pattern->flags & DEV_MATCH_LUN) != 0) 17148b8a9b1dSJustin T. Gibbs && (cur_pattern->target_lun != device->lun_id)) 17158b8a9b1dSJustin T. Gibbs continue; 17168b8a9b1dSJustin T. Gibbs 17178b8a9b1dSJustin T. Gibbs if (((cur_pattern->flags & DEV_MATCH_INQUIRY) != 0) 17188b8a9b1dSJustin T. Gibbs && (cam_quirkmatch((caddr_t)&device->inq_data, 17198b8a9b1dSJustin T. Gibbs (caddr_t)&cur_pattern->inq_pat, 17208b8a9b1dSJustin T. Gibbs 1, sizeof(cur_pattern->inq_pat), 17218b8a9b1dSJustin T. Gibbs scsi_static_inquiry_match) == NULL)) 17228b8a9b1dSJustin T. Gibbs continue; 17238b8a9b1dSJustin T. Gibbs 17248b8a9b1dSJustin T. Gibbs /* 17258b8a9b1dSJustin T. Gibbs * If we get to this point, the user definitely wants 17268b8a9b1dSJustin T. Gibbs * information on this device. So tell the caller to copy 17278b8a9b1dSJustin T. Gibbs * the data out. 17288b8a9b1dSJustin T. Gibbs */ 17298b8a9b1dSJustin T. Gibbs retval |= DM_RET_COPY; 17308b8a9b1dSJustin T. Gibbs 17318b8a9b1dSJustin T. Gibbs /* 17328b8a9b1dSJustin T. Gibbs * If the return action has been set to descend, then we 17338b8a9b1dSJustin T. Gibbs * know that we've already seen a peripheral matching 17348b8a9b1dSJustin T. Gibbs * expression, therefore we need to further descend the tree. 17358b8a9b1dSJustin T. Gibbs * This won't change by continuing around the loop, so we 17368b8a9b1dSJustin T. Gibbs * go ahead and return. If we haven't seen a peripheral 17378b8a9b1dSJustin T. Gibbs * matching expression, we keep going around the loop until 17388b8a9b1dSJustin T. Gibbs * we exhaust the matching expressions. We'll set the stop 17398b8a9b1dSJustin T. Gibbs * flag once we fall out of the loop. 17408b8a9b1dSJustin T. Gibbs */ 17418b8a9b1dSJustin T. Gibbs if ((retval & DM_RET_ACTION_MASK) == DM_RET_DESCEND) 17428b8a9b1dSJustin T. Gibbs return(retval); 17438b8a9b1dSJustin T. Gibbs } 17448b8a9b1dSJustin T. Gibbs 17458b8a9b1dSJustin T. Gibbs /* 17468b8a9b1dSJustin T. Gibbs * If the return action hasn't been set to descend yet, that means 17478b8a9b1dSJustin T. Gibbs * we haven't seen any peripheral matching patterns. So tell the 17488b8a9b1dSJustin T. Gibbs * caller to stop descending the tree -- the user doesn't want to 17498b8a9b1dSJustin T. Gibbs * match against lower level tree elements. 17508b8a9b1dSJustin T. Gibbs */ 17518b8a9b1dSJustin T. Gibbs if ((retval & DM_RET_ACTION_MASK) == DM_RET_NONE) 17528b8a9b1dSJustin T. Gibbs retval |= DM_RET_STOP; 17538b8a9b1dSJustin T. Gibbs 17548b8a9b1dSJustin T. Gibbs return(retval); 17558b8a9b1dSJustin T. Gibbs } 17568b8a9b1dSJustin T. Gibbs 17578b8a9b1dSJustin T. Gibbs /* 17588b8a9b1dSJustin T. Gibbs * Match a single peripheral against any number of match patterns. 17598b8a9b1dSJustin T. Gibbs */ 17608b8a9b1dSJustin T. Gibbs static dev_match_ret 17618b8a9b1dSJustin T. Gibbs xptperiphmatch(struct dev_match_pattern *patterns, int num_patterns, 17628b8a9b1dSJustin T. Gibbs struct cam_periph *periph) 17638b8a9b1dSJustin T. Gibbs { 17648b8a9b1dSJustin T. Gibbs dev_match_ret retval; 17658b8a9b1dSJustin T. Gibbs int i; 17668b8a9b1dSJustin T. Gibbs 17678b8a9b1dSJustin T. Gibbs /* 17688b8a9b1dSJustin T. Gibbs * If we aren't given something to match against, that's an error. 17698b8a9b1dSJustin T. Gibbs */ 17708b8a9b1dSJustin T. Gibbs if (periph == NULL) 17718b8a9b1dSJustin T. Gibbs return(DM_RET_ERROR); 17728b8a9b1dSJustin T. Gibbs 17738b8a9b1dSJustin T. Gibbs /* 17748b8a9b1dSJustin T. Gibbs * If there are no match entries, then this peripheral matches no 17758b8a9b1dSJustin T. Gibbs * matter what. 17768b8a9b1dSJustin T. Gibbs */ 17778b8a9b1dSJustin T. Gibbs if ((patterns == NULL) || (num_patterns == 0)) 17788b8a9b1dSJustin T. Gibbs return(DM_RET_STOP | DM_RET_COPY); 17798b8a9b1dSJustin T. Gibbs 17808b8a9b1dSJustin T. Gibbs /* 17818b8a9b1dSJustin T. Gibbs * There aren't any nodes below a peripheral node, so there's no 17828b8a9b1dSJustin T. Gibbs * reason to descend the tree any further. 17838b8a9b1dSJustin T. Gibbs */ 17848b8a9b1dSJustin T. Gibbs retval = DM_RET_STOP; 17858b8a9b1dSJustin T. Gibbs 17868b8a9b1dSJustin T. Gibbs for (i = 0; i < num_patterns; i++) { 17878b8a9b1dSJustin T. Gibbs struct periph_match_pattern *cur_pattern; 17888b8a9b1dSJustin T. Gibbs 17898b8a9b1dSJustin T. Gibbs /* 17908b8a9b1dSJustin T. Gibbs * If the pattern in question isn't for a peripheral, we 17918b8a9b1dSJustin T. Gibbs * aren't interested. 17928b8a9b1dSJustin T. Gibbs */ 17938b8a9b1dSJustin T. Gibbs if (patterns[i].type != DEV_MATCH_PERIPH) 17948b8a9b1dSJustin T. Gibbs continue; 17958b8a9b1dSJustin T. Gibbs 17968b8a9b1dSJustin T. Gibbs cur_pattern = &patterns[i].pattern.periph_pattern; 17978b8a9b1dSJustin T. Gibbs 17988b8a9b1dSJustin T. Gibbs /* 17998b8a9b1dSJustin T. Gibbs * If they want to match on anything, then we will do so. 18008b8a9b1dSJustin T. Gibbs */ 18018b8a9b1dSJustin T. Gibbs if (cur_pattern->flags == PERIPH_MATCH_ANY) { 18028b8a9b1dSJustin T. Gibbs /* set the copy flag */ 18038b8a9b1dSJustin T. Gibbs retval |= DM_RET_COPY; 18048b8a9b1dSJustin T. Gibbs 18058b8a9b1dSJustin T. Gibbs /* 18068b8a9b1dSJustin T. Gibbs * We've already set the return action to stop, 18078b8a9b1dSJustin T. Gibbs * since there are no nodes below peripherals in 18088b8a9b1dSJustin T. Gibbs * the tree. 18098b8a9b1dSJustin T. Gibbs */ 18108b8a9b1dSJustin T. Gibbs return(retval); 18118b8a9b1dSJustin T. Gibbs } 18128b8a9b1dSJustin T. Gibbs 18138b8a9b1dSJustin T. Gibbs /* 18148b8a9b1dSJustin T. Gibbs * Not sure why someone would do this... 18158b8a9b1dSJustin T. Gibbs */ 18168b8a9b1dSJustin T. Gibbs if (cur_pattern->flags == PERIPH_MATCH_NONE) 18178b8a9b1dSJustin T. Gibbs continue; 18188b8a9b1dSJustin T. Gibbs 18198b8a9b1dSJustin T. Gibbs if (((cur_pattern->flags & PERIPH_MATCH_PATH) != 0) 18208b8a9b1dSJustin T. Gibbs && (cur_pattern->path_id != periph->path->bus->path_id)) 18218b8a9b1dSJustin T. Gibbs continue; 18228b8a9b1dSJustin T. Gibbs 18238b8a9b1dSJustin T. Gibbs /* 18248b8a9b1dSJustin T. Gibbs * For the target and lun id's, we have to make sure the 18258b8a9b1dSJustin T. Gibbs * target and lun pointers aren't NULL. The xpt peripheral 18268b8a9b1dSJustin T. Gibbs * has a wildcard target and device. 18278b8a9b1dSJustin T. Gibbs */ 18288b8a9b1dSJustin T. Gibbs if (((cur_pattern->flags & PERIPH_MATCH_TARGET) != 0) 18298b8a9b1dSJustin T. Gibbs && ((periph->path->target == NULL) 18308b8a9b1dSJustin T. Gibbs ||(cur_pattern->target_id != periph->path->target->target_id))) 18318b8a9b1dSJustin T. Gibbs continue; 18328b8a9b1dSJustin T. Gibbs 18338b8a9b1dSJustin T. Gibbs if (((cur_pattern->flags & PERIPH_MATCH_LUN) != 0) 18348b8a9b1dSJustin T. Gibbs && ((periph->path->device == NULL) 18358b8a9b1dSJustin T. Gibbs || (cur_pattern->target_lun != periph->path->device->lun_id))) 18368b8a9b1dSJustin T. Gibbs continue; 18378b8a9b1dSJustin T. Gibbs 18388b8a9b1dSJustin T. Gibbs if (((cur_pattern->flags & PERIPH_MATCH_UNIT) != 0) 18398b8a9b1dSJustin T. Gibbs && (cur_pattern->unit_number != periph->unit_number)) 18408b8a9b1dSJustin T. Gibbs continue; 18418b8a9b1dSJustin T. Gibbs 18428b8a9b1dSJustin T. Gibbs if (((cur_pattern->flags & PERIPH_MATCH_NAME) != 0) 18438b8a9b1dSJustin T. Gibbs && (strncmp(cur_pattern->periph_name, periph->periph_name, 18448b8a9b1dSJustin T. Gibbs DEV_IDLEN) != 0)) 18458b8a9b1dSJustin T. Gibbs continue; 18468b8a9b1dSJustin T. Gibbs 18478b8a9b1dSJustin T. Gibbs /* 18488b8a9b1dSJustin T. Gibbs * If we get to this point, the user definitely wants 18498b8a9b1dSJustin T. Gibbs * information on this peripheral. So tell the caller to 18508b8a9b1dSJustin T. Gibbs * copy the data out. 18518b8a9b1dSJustin T. Gibbs */ 18528b8a9b1dSJustin T. Gibbs retval |= DM_RET_COPY; 18538b8a9b1dSJustin T. Gibbs 18548b8a9b1dSJustin T. Gibbs /* 18558b8a9b1dSJustin T. Gibbs * The return action has already been set to stop, since 18568b8a9b1dSJustin T. Gibbs * peripherals don't have any nodes below them in the EDT. 18578b8a9b1dSJustin T. Gibbs */ 18588b8a9b1dSJustin T. Gibbs return(retval); 18598b8a9b1dSJustin T. Gibbs } 18608b8a9b1dSJustin T. Gibbs 18618b8a9b1dSJustin T. Gibbs /* 18628b8a9b1dSJustin T. Gibbs * If we get to this point, the peripheral that was passed in 18638b8a9b1dSJustin T. Gibbs * doesn't match any of the patterns. 18648b8a9b1dSJustin T. Gibbs */ 18658b8a9b1dSJustin T. Gibbs return(retval); 18668b8a9b1dSJustin T. Gibbs } 18678b8a9b1dSJustin T. Gibbs 18688b8a9b1dSJustin T. Gibbs static int 18698b8a9b1dSJustin T. Gibbs xptedtbusfunc(struct cam_eb *bus, void *arg) 18708b8a9b1dSJustin T. Gibbs { 18718b8a9b1dSJustin T. Gibbs struct ccb_dev_match *cdm; 18728b8a9b1dSJustin T. Gibbs dev_match_ret retval; 18738b8a9b1dSJustin T. Gibbs 18748b8a9b1dSJustin T. Gibbs cdm = (struct ccb_dev_match *)arg; 18758b8a9b1dSJustin T. Gibbs 18768b8a9b1dSJustin T. Gibbs /* 18778b8a9b1dSJustin T. Gibbs * If our position is for something deeper in the tree, that means 18788b8a9b1dSJustin T. Gibbs * that we've already seen this node. So, we keep going down. 18798b8a9b1dSJustin T. Gibbs */ 18808b8a9b1dSJustin T. Gibbs if ((cdm->pos.position_type & CAM_DEV_POS_BUS) 18818b8a9b1dSJustin T. Gibbs && (cdm->pos.cookie.bus == bus) 18828b8a9b1dSJustin T. Gibbs && (cdm->pos.position_type & CAM_DEV_POS_TARGET) 18838b8a9b1dSJustin T. Gibbs && (cdm->pos.cookie.target != NULL)) 18848b8a9b1dSJustin T. Gibbs retval = DM_RET_DESCEND; 18858b8a9b1dSJustin T. Gibbs else 18868b8a9b1dSJustin T. Gibbs retval = xptbusmatch(cdm->patterns, cdm->num_patterns, bus); 18878b8a9b1dSJustin T. Gibbs 18888b8a9b1dSJustin T. Gibbs /* 18898b8a9b1dSJustin T. Gibbs * If we got an error, bail out of the search. 18908b8a9b1dSJustin T. Gibbs */ 18918b8a9b1dSJustin T. Gibbs if ((retval & DM_RET_ACTION_MASK) == DM_RET_ERROR) { 18928b8a9b1dSJustin T. Gibbs cdm->status = CAM_DEV_MATCH_ERROR; 18938b8a9b1dSJustin T. Gibbs return(0); 18948b8a9b1dSJustin T. Gibbs } 18958b8a9b1dSJustin T. Gibbs 18968b8a9b1dSJustin T. Gibbs /* 18978b8a9b1dSJustin T. Gibbs * If the copy flag is set, copy this bus out. 18988b8a9b1dSJustin T. Gibbs */ 18998b8a9b1dSJustin T. Gibbs if (retval & DM_RET_COPY) { 19008b8a9b1dSJustin T. Gibbs int spaceleft, j; 19018b8a9b1dSJustin T. Gibbs 19028b8a9b1dSJustin T. Gibbs spaceleft = cdm->match_buf_len - (cdm->num_matches * 19038b8a9b1dSJustin T. Gibbs sizeof(struct dev_match_result)); 19048b8a9b1dSJustin T. Gibbs 19058b8a9b1dSJustin T. Gibbs /* 19068b8a9b1dSJustin T. Gibbs * If we don't have enough space to put in another 19078b8a9b1dSJustin T. Gibbs * match result, save our position and tell the 19088b8a9b1dSJustin T. Gibbs * user there are more devices to check. 19098b8a9b1dSJustin T. Gibbs */ 19108b8a9b1dSJustin T. Gibbs if (spaceleft < sizeof(struct dev_match_result)) { 19118b8a9b1dSJustin T. Gibbs bzero(&cdm->pos, sizeof(cdm->pos)); 19128b8a9b1dSJustin T. Gibbs cdm->pos.position_type = 19138b8a9b1dSJustin T. Gibbs CAM_DEV_POS_EDT | CAM_DEV_POS_BUS; 19148b8a9b1dSJustin T. Gibbs 19158b8a9b1dSJustin T. Gibbs cdm->pos.cookie.bus = bus; 19168b8a9b1dSJustin T. Gibbs cdm->pos.generations[CAM_BUS_GENERATION]= 19178b8a9b1dSJustin T. Gibbs bus_generation; 19188b8a9b1dSJustin T. Gibbs cdm->status = CAM_DEV_MATCH_MORE; 19198b8a9b1dSJustin T. Gibbs return(0); 19208b8a9b1dSJustin T. Gibbs } 19218b8a9b1dSJustin T. Gibbs j = cdm->num_matches; 19228b8a9b1dSJustin T. Gibbs cdm->num_matches++; 19238b8a9b1dSJustin T. Gibbs cdm->matches[j].type = DEV_MATCH_BUS; 19248b8a9b1dSJustin T. Gibbs cdm->matches[j].result.bus_result.path_id = bus->path_id; 19258b8a9b1dSJustin T. Gibbs cdm->matches[j].result.bus_result.bus_id = bus->sim->bus_id; 19268b8a9b1dSJustin T. Gibbs cdm->matches[j].result.bus_result.unit_number = 19278b8a9b1dSJustin T. Gibbs bus->sim->unit_number; 19288b8a9b1dSJustin T. Gibbs strncpy(cdm->matches[j].result.bus_result.dev_name, 19298b8a9b1dSJustin T. Gibbs bus->sim->sim_name, DEV_IDLEN); 19308b8a9b1dSJustin T. Gibbs } 19318b8a9b1dSJustin T. Gibbs 19328b8a9b1dSJustin T. Gibbs /* 19338b8a9b1dSJustin T. Gibbs * If the user is only interested in busses, there's no 19348b8a9b1dSJustin T. Gibbs * reason to descend to the next level in the tree. 19358b8a9b1dSJustin T. Gibbs */ 19368b8a9b1dSJustin T. Gibbs if ((retval & DM_RET_ACTION_MASK) == DM_RET_STOP) 19378b8a9b1dSJustin T. Gibbs return(1); 19388b8a9b1dSJustin T. Gibbs 19398b8a9b1dSJustin T. Gibbs /* 19408b8a9b1dSJustin T. Gibbs * If there is a target generation recorded, check it to 19418b8a9b1dSJustin T. Gibbs * make sure the target list hasn't changed. 19428b8a9b1dSJustin T. Gibbs */ 19438b8a9b1dSJustin T. Gibbs if ((cdm->pos.position_type & CAM_DEV_POS_BUS) 19448b8a9b1dSJustin T. Gibbs && (bus == cdm->pos.cookie.bus) 19458b8a9b1dSJustin T. Gibbs && (cdm->pos.position_type & CAM_DEV_POS_TARGET) 19468b8a9b1dSJustin T. Gibbs && (cdm->pos.generations[CAM_TARGET_GENERATION] != 0) 19478b8a9b1dSJustin T. Gibbs && (cdm->pos.generations[CAM_TARGET_GENERATION] != 19488b8a9b1dSJustin T. Gibbs bus->generation)) { 19498b8a9b1dSJustin T. Gibbs cdm->status = CAM_DEV_MATCH_LIST_CHANGED; 19508b8a9b1dSJustin T. Gibbs return(0); 19518b8a9b1dSJustin T. Gibbs } 19528b8a9b1dSJustin T. Gibbs 19538b8a9b1dSJustin T. Gibbs if ((cdm->pos.position_type & CAM_DEV_POS_BUS) 19548b8a9b1dSJustin T. Gibbs && (cdm->pos.cookie.bus == bus) 19558b8a9b1dSJustin T. Gibbs && (cdm->pos.position_type & CAM_DEV_POS_TARGET) 19568b8a9b1dSJustin T. Gibbs && (cdm->pos.cookie.target != NULL)) 19578b8a9b1dSJustin T. Gibbs return(xpttargettraverse(bus, 19588b8a9b1dSJustin T. Gibbs (struct cam_et *)cdm->pos.cookie.target, 19598b8a9b1dSJustin T. Gibbs xptedttargetfunc, arg)); 19608b8a9b1dSJustin T. Gibbs else 19618b8a9b1dSJustin T. Gibbs return(xpttargettraverse(bus, NULL, xptedttargetfunc, arg)); 19628b8a9b1dSJustin T. Gibbs } 19638b8a9b1dSJustin T. Gibbs 19648b8a9b1dSJustin T. Gibbs static int 19658b8a9b1dSJustin T. Gibbs xptedttargetfunc(struct cam_et *target, void *arg) 19668b8a9b1dSJustin T. Gibbs { 19678b8a9b1dSJustin T. Gibbs struct ccb_dev_match *cdm; 19688b8a9b1dSJustin T. Gibbs 19698b8a9b1dSJustin T. Gibbs cdm = (struct ccb_dev_match *)arg; 19708b8a9b1dSJustin T. Gibbs 19718b8a9b1dSJustin T. Gibbs /* 19728b8a9b1dSJustin T. Gibbs * If there is a device list generation recorded, check it to 19738b8a9b1dSJustin T. Gibbs * make sure the device list hasn't changed. 19748b8a9b1dSJustin T. Gibbs */ 19758b8a9b1dSJustin T. Gibbs if ((cdm->pos.position_type & CAM_DEV_POS_BUS) 19768b8a9b1dSJustin T. Gibbs && (cdm->pos.cookie.bus == target->bus) 19778b8a9b1dSJustin T. Gibbs && (cdm->pos.position_type & CAM_DEV_POS_TARGET) 19788b8a9b1dSJustin T. Gibbs && (cdm->pos.cookie.target == target) 19798b8a9b1dSJustin T. Gibbs && (cdm->pos.position_type & CAM_DEV_POS_DEVICE) 19808b8a9b1dSJustin T. Gibbs && (cdm->pos.generations[CAM_DEV_GENERATION] != 0) 19818b8a9b1dSJustin T. Gibbs && (cdm->pos.generations[CAM_DEV_GENERATION] != 19828b8a9b1dSJustin T. Gibbs target->generation)) { 19838b8a9b1dSJustin T. Gibbs cdm->status = CAM_DEV_MATCH_LIST_CHANGED; 19848b8a9b1dSJustin T. Gibbs return(0); 19858b8a9b1dSJustin T. Gibbs } 19868b8a9b1dSJustin T. Gibbs 19878b8a9b1dSJustin T. Gibbs if ((cdm->pos.position_type & CAM_DEV_POS_BUS) 19888b8a9b1dSJustin T. Gibbs && (cdm->pos.cookie.bus == target->bus) 19898b8a9b1dSJustin T. Gibbs && (cdm->pos.position_type & CAM_DEV_POS_TARGET) 19908b8a9b1dSJustin T. Gibbs && (cdm->pos.cookie.target == target) 19918b8a9b1dSJustin T. Gibbs && (cdm->pos.position_type & CAM_DEV_POS_DEVICE) 19928b8a9b1dSJustin T. Gibbs && (cdm->pos.cookie.device != NULL)) 19938b8a9b1dSJustin T. Gibbs return(xptdevicetraverse(target, 19948b8a9b1dSJustin T. Gibbs (struct cam_ed *)cdm->pos.cookie.device, 19958b8a9b1dSJustin T. Gibbs xptedtdevicefunc, arg)); 19968b8a9b1dSJustin T. Gibbs else 19978b8a9b1dSJustin T. Gibbs return(xptdevicetraverse(target, NULL, xptedtdevicefunc, arg)); 19988b8a9b1dSJustin T. Gibbs } 19998b8a9b1dSJustin T. Gibbs 20008b8a9b1dSJustin T. Gibbs static int 20018b8a9b1dSJustin T. Gibbs xptedtdevicefunc(struct cam_ed *device, void *arg) 20028b8a9b1dSJustin T. Gibbs { 20038b8a9b1dSJustin T. Gibbs 20048b8a9b1dSJustin T. Gibbs struct ccb_dev_match *cdm; 20058b8a9b1dSJustin T. Gibbs dev_match_ret retval; 20068b8a9b1dSJustin T. Gibbs 20078b8a9b1dSJustin T. Gibbs cdm = (struct ccb_dev_match *)arg; 20088b8a9b1dSJustin T. Gibbs 20098b8a9b1dSJustin T. Gibbs /* 20108b8a9b1dSJustin T. Gibbs * If our position is for something deeper in the tree, that means 20118b8a9b1dSJustin T. Gibbs * that we've already seen this node. So, we keep going down. 20128b8a9b1dSJustin T. Gibbs */ 20138b8a9b1dSJustin T. Gibbs if ((cdm->pos.position_type & CAM_DEV_POS_DEVICE) 20148b8a9b1dSJustin T. Gibbs && (cdm->pos.cookie.device == device) 20158b8a9b1dSJustin T. Gibbs && (cdm->pos.position_type & CAM_DEV_POS_PERIPH) 20168b8a9b1dSJustin T. Gibbs && (cdm->pos.cookie.periph != NULL)) 20178b8a9b1dSJustin T. Gibbs retval = DM_RET_DESCEND; 20188b8a9b1dSJustin T. Gibbs else 20198b8a9b1dSJustin T. Gibbs retval = xptdevicematch(cdm->patterns, cdm->num_patterns, 20208b8a9b1dSJustin T. Gibbs device); 20218b8a9b1dSJustin T. Gibbs 20228b8a9b1dSJustin T. Gibbs if ((retval & DM_RET_ACTION_MASK) == DM_RET_ERROR) { 20238b8a9b1dSJustin T. Gibbs cdm->status = CAM_DEV_MATCH_ERROR; 20248b8a9b1dSJustin T. Gibbs return(0); 20258b8a9b1dSJustin T. Gibbs } 20268b8a9b1dSJustin T. Gibbs 20278b8a9b1dSJustin T. Gibbs /* 20288b8a9b1dSJustin T. Gibbs * If the copy flag is set, copy this device out. 20298b8a9b1dSJustin T. Gibbs */ 20308b8a9b1dSJustin T. Gibbs if (retval & DM_RET_COPY) { 20318b8a9b1dSJustin T. Gibbs int spaceleft, j; 20328b8a9b1dSJustin T. Gibbs 20338b8a9b1dSJustin T. Gibbs spaceleft = cdm->match_buf_len - (cdm->num_matches * 20348b8a9b1dSJustin T. Gibbs sizeof(struct dev_match_result)); 20358b8a9b1dSJustin T. Gibbs 20368b8a9b1dSJustin T. Gibbs /* 20378b8a9b1dSJustin T. Gibbs * If we don't have enough space to put in another 20388b8a9b1dSJustin T. Gibbs * match result, save our position and tell the 20398b8a9b1dSJustin T. Gibbs * user there are more devices to check. 20408b8a9b1dSJustin T. Gibbs */ 20418b8a9b1dSJustin T. Gibbs if (spaceleft < sizeof(struct dev_match_result)) { 20428b8a9b1dSJustin T. Gibbs bzero(&cdm->pos, sizeof(cdm->pos)); 20438b8a9b1dSJustin T. Gibbs cdm->pos.position_type = 20448b8a9b1dSJustin T. Gibbs CAM_DEV_POS_EDT | CAM_DEV_POS_BUS | 20458b8a9b1dSJustin T. Gibbs CAM_DEV_POS_TARGET | CAM_DEV_POS_DEVICE; 20468b8a9b1dSJustin T. Gibbs 20478b8a9b1dSJustin T. Gibbs cdm->pos.cookie.bus = device->target->bus; 20488b8a9b1dSJustin T. Gibbs cdm->pos.generations[CAM_BUS_GENERATION]= 20498b8a9b1dSJustin T. Gibbs bus_generation; 20508b8a9b1dSJustin T. Gibbs cdm->pos.cookie.target = device->target; 20518b8a9b1dSJustin T. Gibbs cdm->pos.generations[CAM_TARGET_GENERATION] = 20528b8a9b1dSJustin T. Gibbs device->target->bus->generation; 20538b8a9b1dSJustin T. Gibbs cdm->pos.cookie.device = device; 20548b8a9b1dSJustin T. Gibbs cdm->pos.generations[CAM_DEV_GENERATION] = 20558b8a9b1dSJustin T. Gibbs device->target->generation; 20568b8a9b1dSJustin T. Gibbs cdm->status = CAM_DEV_MATCH_MORE; 20578b8a9b1dSJustin T. Gibbs return(0); 20588b8a9b1dSJustin T. Gibbs } 20598b8a9b1dSJustin T. Gibbs j = cdm->num_matches; 20608b8a9b1dSJustin T. Gibbs cdm->num_matches++; 20618b8a9b1dSJustin T. Gibbs cdm->matches[j].type = DEV_MATCH_DEVICE; 20628b8a9b1dSJustin T. Gibbs cdm->matches[j].result.device_result.path_id = 20638b8a9b1dSJustin T. Gibbs device->target->bus->path_id; 20648b8a9b1dSJustin T. Gibbs cdm->matches[j].result.device_result.target_id = 20658b8a9b1dSJustin T. Gibbs device->target->target_id; 20668b8a9b1dSJustin T. Gibbs cdm->matches[j].result.device_result.target_lun = 20678b8a9b1dSJustin T. Gibbs device->lun_id; 20688b8a9b1dSJustin T. Gibbs bcopy(&device->inq_data, 20698b8a9b1dSJustin T. Gibbs &cdm->matches[j].result.device_result.inq_data, 20708b8a9b1dSJustin T. Gibbs sizeof(struct scsi_inquiry_data)); 20719deea857SKenneth D. Merry 20729deea857SKenneth D. Merry /* Let the user know whether this device is unconfigured */ 20739deea857SKenneth D. Merry if (device->flags & CAM_DEV_UNCONFIGURED) 20749deea857SKenneth D. Merry cdm->matches[j].result.device_result.flags = 20759deea857SKenneth D. Merry DEV_RESULT_UNCONFIGURED; 20769deea857SKenneth D. Merry else 20779deea857SKenneth D. Merry cdm->matches[j].result.device_result.flags = 20789deea857SKenneth D. Merry DEV_RESULT_NOFLAG; 20798b8a9b1dSJustin T. Gibbs } 20808b8a9b1dSJustin T. Gibbs 20818b8a9b1dSJustin T. Gibbs /* 20828b8a9b1dSJustin T. Gibbs * If the user isn't interested in peripherals, don't descend 20838b8a9b1dSJustin T. Gibbs * the tree any further. 20848b8a9b1dSJustin T. Gibbs */ 20858b8a9b1dSJustin T. Gibbs if ((retval & DM_RET_ACTION_MASK) == DM_RET_STOP) 20868b8a9b1dSJustin T. Gibbs return(1); 20878b8a9b1dSJustin T. Gibbs 20888b8a9b1dSJustin T. Gibbs /* 20898b8a9b1dSJustin T. Gibbs * If there is a peripheral list generation recorded, make sure 20908b8a9b1dSJustin T. Gibbs * it hasn't changed. 20918b8a9b1dSJustin T. Gibbs */ 20928b8a9b1dSJustin T. Gibbs if ((cdm->pos.position_type & CAM_DEV_POS_BUS) 20938b8a9b1dSJustin T. Gibbs && (device->target->bus == cdm->pos.cookie.bus) 20948b8a9b1dSJustin T. Gibbs && (cdm->pos.position_type & CAM_DEV_POS_TARGET) 20958b8a9b1dSJustin T. Gibbs && (device->target == cdm->pos.cookie.target) 20968b8a9b1dSJustin T. Gibbs && (cdm->pos.position_type & CAM_DEV_POS_DEVICE) 20978b8a9b1dSJustin T. Gibbs && (device == cdm->pos.cookie.device) 20988b8a9b1dSJustin T. Gibbs && (cdm->pos.position_type & CAM_DEV_POS_PERIPH) 20998b8a9b1dSJustin T. Gibbs && (cdm->pos.generations[CAM_PERIPH_GENERATION] != 0) 21008b8a9b1dSJustin T. Gibbs && (cdm->pos.generations[CAM_PERIPH_GENERATION] != 21018b8a9b1dSJustin T. Gibbs device->generation)){ 21028b8a9b1dSJustin T. Gibbs cdm->status = CAM_DEV_MATCH_LIST_CHANGED; 21038b8a9b1dSJustin T. Gibbs return(0); 21048b8a9b1dSJustin T. Gibbs } 21058b8a9b1dSJustin T. Gibbs 21068b8a9b1dSJustin T. Gibbs if ((cdm->pos.position_type & CAM_DEV_POS_BUS) 21078b8a9b1dSJustin T. Gibbs && (cdm->pos.cookie.bus == device->target->bus) 21088b8a9b1dSJustin T. Gibbs && (cdm->pos.position_type & CAM_DEV_POS_TARGET) 21098b8a9b1dSJustin T. Gibbs && (cdm->pos.cookie.target == device->target) 21108b8a9b1dSJustin T. Gibbs && (cdm->pos.position_type & CAM_DEV_POS_DEVICE) 21118b8a9b1dSJustin T. Gibbs && (cdm->pos.cookie.device == device) 21128b8a9b1dSJustin T. Gibbs && (cdm->pos.position_type & CAM_DEV_POS_PERIPH) 21138b8a9b1dSJustin T. Gibbs && (cdm->pos.cookie.periph != NULL)) 21148b8a9b1dSJustin T. Gibbs return(xptperiphtraverse(device, 21158b8a9b1dSJustin T. Gibbs (struct cam_periph *)cdm->pos.cookie.periph, 21168b8a9b1dSJustin T. Gibbs xptedtperiphfunc, arg)); 21178b8a9b1dSJustin T. Gibbs else 21188b8a9b1dSJustin T. Gibbs return(xptperiphtraverse(device, NULL, xptedtperiphfunc, arg)); 21198b8a9b1dSJustin T. Gibbs } 21208b8a9b1dSJustin T. Gibbs 21218b8a9b1dSJustin T. Gibbs static int 21228b8a9b1dSJustin T. Gibbs xptedtperiphfunc(struct cam_periph *periph, void *arg) 21238b8a9b1dSJustin T. Gibbs { 21248b8a9b1dSJustin T. Gibbs struct ccb_dev_match *cdm; 21258b8a9b1dSJustin T. Gibbs dev_match_ret retval; 21268b8a9b1dSJustin T. Gibbs 21278b8a9b1dSJustin T. Gibbs cdm = (struct ccb_dev_match *)arg; 21288b8a9b1dSJustin T. Gibbs 21298b8a9b1dSJustin T. Gibbs retval = xptperiphmatch(cdm->patterns, cdm->num_patterns, periph); 21308b8a9b1dSJustin T. Gibbs 21318b8a9b1dSJustin T. Gibbs if ((retval & DM_RET_ACTION_MASK) == DM_RET_ERROR) { 21328b8a9b1dSJustin T. Gibbs cdm->status = CAM_DEV_MATCH_ERROR; 21338b8a9b1dSJustin T. Gibbs return(0); 21348b8a9b1dSJustin T. Gibbs } 21358b8a9b1dSJustin T. Gibbs 21368b8a9b1dSJustin T. Gibbs /* 21378b8a9b1dSJustin T. Gibbs * If the copy flag is set, copy this peripheral out. 21388b8a9b1dSJustin T. Gibbs */ 21398b8a9b1dSJustin T. Gibbs if (retval & DM_RET_COPY) { 21408b8a9b1dSJustin T. Gibbs int spaceleft, j; 21418b8a9b1dSJustin T. Gibbs 21428b8a9b1dSJustin T. Gibbs spaceleft = cdm->match_buf_len - (cdm->num_matches * 21438b8a9b1dSJustin T. Gibbs sizeof(struct dev_match_result)); 21448b8a9b1dSJustin T. Gibbs 21458b8a9b1dSJustin T. Gibbs /* 21468b8a9b1dSJustin T. Gibbs * If we don't have enough space to put in another 21478b8a9b1dSJustin T. Gibbs * match result, save our position and tell the 21488b8a9b1dSJustin T. Gibbs * user there are more devices to check. 21498b8a9b1dSJustin T. Gibbs */ 21508b8a9b1dSJustin T. Gibbs if (spaceleft < sizeof(struct dev_match_result)) { 21518b8a9b1dSJustin T. Gibbs bzero(&cdm->pos, sizeof(cdm->pos)); 21528b8a9b1dSJustin T. Gibbs cdm->pos.position_type = 21538b8a9b1dSJustin T. Gibbs CAM_DEV_POS_EDT | CAM_DEV_POS_BUS | 21548b8a9b1dSJustin T. Gibbs CAM_DEV_POS_TARGET | CAM_DEV_POS_DEVICE | 21558b8a9b1dSJustin T. Gibbs CAM_DEV_POS_PERIPH; 21568b8a9b1dSJustin T. Gibbs 21578b8a9b1dSJustin T. Gibbs cdm->pos.cookie.bus = periph->path->bus; 21588b8a9b1dSJustin T. Gibbs cdm->pos.generations[CAM_BUS_GENERATION]= 21598b8a9b1dSJustin T. Gibbs bus_generation; 21608b8a9b1dSJustin T. Gibbs cdm->pos.cookie.target = periph->path->target; 21618b8a9b1dSJustin T. Gibbs cdm->pos.generations[CAM_TARGET_GENERATION] = 21628b8a9b1dSJustin T. Gibbs periph->path->bus->generation; 21638b8a9b1dSJustin T. Gibbs cdm->pos.cookie.device = periph->path->device; 21648b8a9b1dSJustin T. Gibbs cdm->pos.generations[CAM_DEV_GENERATION] = 21658b8a9b1dSJustin T. Gibbs periph->path->target->generation; 21668b8a9b1dSJustin T. Gibbs cdm->pos.cookie.periph = periph; 21678b8a9b1dSJustin T. Gibbs cdm->pos.generations[CAM_PERIPH_GENERATION] = 21688b8a9b1dSJustin T. Gibbs periph->path->device->generation; 21698b8a9b1dSJustin T. Gibbs cdm->status = CAM_DEV_MATCH_MORE; 21708b8a9b1dSJustin T. Gibbs return(0); 21718b8a9b1dSJustin T. Gibbs } 21728b8a9b1dSJustin T. Gibbs 21738b8a9b1dSJustin T. Gibbs j = cdm->num_matches; 21748b8a9b1dSJustin T. Gibbs cdm->num_matches++; 21758b8a9b1dSJustin T. Gibbs cdm->matches[j].type = DEV_MATCH_PERIPH; 21768b8a9b1dSJustin T. Gibbs cdm->matches[j].result.periph_result.path_id = 21778b8a9b1dSJustin T. Gibbs periph->path->bus->path_id; 21788b8a9b1dSJustin T. Gibbs cdm->matches[j].result.periph_result.target_id = 21798b8a9b1dSJustin T. Gibbs periph->path->target->target_id; 21808b8a9b1dSJustin T. Gibbs cdm->matches[j].result.periph_result.target_lun = 21818b8a9b1dSJustin T. Gibbs periph->path->device->lun_id; 21828b8a9b1dSJustin T. Gibbs cdm->matches[j].result.periph_result.unit_number = 21838b8a9b1dSJustin T. Gibbs periph->unit_number; 21848b8a9b1dSJustin T. Gibbs strncpy(cdm->matches[j].result.periph_result.periph_name, 21858b8a9b1dSJustin T. Gibbs periph->periph_name, DEV_IDLEN); 21868b8a9b1dSJustin T. Gibbs } 21878b8a9b1dSJustin T. Gibbs 21888b8a9b1dSJustin T. Gibbs return(1); 21898b8a9b1dSJustin T. Gibbs } 21908b8a9b1dSJustin T. Gibbs 21918b8a9b1dSJustin T. Gibbs static int 21928b8a9b1dSJustin T. Gibbs xptedtmatch(struct ccb_dev_match *cdm) 21938b8a9b1dSJustin T. Gibbs { 21948b8a9b1dSJustin T. Gibbs int ret; 21958b8a9b1dSJustin T. Gibbs 21968b8a9b1dSJustin T. Gibbs cdm->num_matches = 0; 21978b8a9b1dSJustin T. Gibbs 21988b8a9b1dSJustin T. Gibbs /* 21998b8a9b1dSJustin T. Gibbs * Check the bus list generation. If it has changed, the user 22008b8a9b1dSJustin T. Gibbs * needs to reset everything and start over. 22018b8a9b1dSJustin T. Gibbs */ 22028b8a9b1dSJustin T. Gibbs if ((cdm->pos.position_type & CAM_DEV_POS_BUS) 22038b8a9b1dSJustin T. Gibbs && (cdm->pos.generations[CAM_BUS_GENERATION] != 0) 22048b8a9b1dSJustin T. Gibbs && (cdm->pos.generations[CAM_BUS_GENERATION] != bus_generation)) { 22058b8a9b1dSJustin T. Gibbs cdm->status = CAM_DEV_MATCH_LIST_CHANGED; 22068b8a9b1dSJustin T. Gibbs return(0); 22078b8a9b1dSJustin T. Gibbs } 22088b8a9b1dSJustin T. Gibbs 22098b8a9b1dSJustin T. Gibbs if ((cdm->pos.position_type & CAM_DEV_POS_BUS) 22108b8a9b1dSJustin T. Gibbs && (cdm->pos.cookie.bus != NULL)) 22118b8a9b1dSJustin T. Gibbs ret = xptbustraverse((struct cam_eb *)cdm->pos.cookie.bus, 22128b8a9b1dSJustin T. Gibbs xptedtbusfunc, cdm); 22138b8a9b1dSJustin T. Gibbs else 22148b8a9b1dSJustin T. Gibbs ret = xptbustraverse(NULL, xptedtbusfunc, cdm); 22158b8a9b1dSJustin T. Gibbs 22168b8a9b1dSJustin T. Gibbs /* 22178b8a9b1dSJustin T. Gibbs * If we get back 0, that means that we had to stop before fully 22188b8a9b1dSJustin T. Gibbs * traversing the EDT. It also means that one of the subroutines 22198b8a9b1dSJustin T. Gibbs * has set the status field to the proper value. If we get back 1, 22208b8a9b1dSJustin T. Gibbs * we've fully traversed the EDT and copied out any matching entries. 22218b8a9b1dSJustin T. Gibbs */ 22228b8a9b1dSJustin T. Gibbs if (ret == 1) 22238b8a9b1dSJustin T. Gibbs cdm->status = CAM_DEV_MATCH_LAST; 22248b8a9b1dSJustin T. Gibbs 22258b8a9b1dSJustin T. Gibbs return(ret); 22268b8a9b1dSJustin T. Gibbs } 22278b8a9b1dSJustin T. Gibbs 22288b8a9b1dSJustin T. Gibbs static int 22298b8a9b1dSJustin T. Gibbs xptplistpdrvfunc(struct periph_driver **pdrv, void *arg) 22308b8a9b1dSJustin T. Gibbs { 22318b8a9b1dSJustin T. Gibbs struct ccb_dev_match *cdm; 22328b8a9b1dSJustin T. Gibbs 22338b8a9b1dSJustin T. Gibbs cdm = (struct ccb_dev_match *)arg; 22348b8a9b1dSJustin T. Gibbs 22358b8a9b1dSJustin T. Gibbs if ((cdm->pos.position_type & CAM_DEV_POS_PDPTR) 22368b8a9b1dSJustin T. Gibbs && (cdm->pos.cookie.pdrv == pdrv) 22378b8a9b1dSJustin T. Gibbs && (cdm->pos.position_type & CAM_DEV_POS_PERIPH) 22388b8a9b1dSJustin T. Gibbs && (cdm->pos.generations[CAM_PERIPH_GENERATION] != 0) 22398b8a9b1dSJustin T. Gibbs && (cdm->pos.generations[CAM_PERIPH_GENERATION] != 22408b8a9b1dSJustin T. Gibbs (*pdrv)->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_PDPTR) 22468b8a9b1dSJustin T. Gibbs && (cdm->pos.cookie.pdrv == pdrv) 22478b8a9b1dSJustin T. Gibbs && (cdm->pos.position_type & CAM_DEV_POS_PERIPH) 22488b8a9b1dSJustin T. Gibbs && (cdm->pos.cookie.periph != NULL)) 22498b8a9b1dSJustin T. Gibbs return(xptpdperiphtraverse(pdrv, 22508b8a9b1dSJustin T. Gibbs (struct cam_periph *)cdm->pos.cookie.periph, 22518b8a9b1dSJustin T. Gibbs xptplistperiphfunc, arg)); 22528b8a9b1dSJustin T. Gibbs else 22538b8a9b1dSJustin T. Gibbs return(xptpdperiphtraverse(pdrv, NULL,xptplistperiphfunc, arg)); 22548b8a9b1dSJustin T. Gibbs } 22558b8a9b1dSJustin T. Gibbs 22568b8a9b1dSJustin T. Gibbs static int 22578b8a9b1dSJustin T. Gibbs xptplistperiphfunc(struct cam_periph *periph, void *arg) 22588b8a9b1dSJustin T. Gibbs { 22598b8a9b1dSJustin T. Gibbs struct ccb_dev_match *cdm; 22608b8a9b1dSJustin T. Gibbs dev_match_ret retval; 22618b8a9b1dSJustin T. Gibbs 22628b8a9b1dSJustin T. Gibbs cdm = (struct ccb_dev_match *)arg; 22638b8a9b1dSJustin T. Gibbs 22648b8a9b1dSJustin T. Gibbs retval = xptperiphmatch(cdm->patterns, cdm->num_patterns, periph); 22658b8a9b1dSJustin T. Gibbs 22668b8a9b1dSJustin T. Gibbs if ((retval & DM_RET_ACTION_MASK) == DM_RET_ERROR) { 22678b8a9b1dSJustin T. Gibbs cdm->status = CAM_DEV_MATCH_ERROR; 22688b8a9b1dSJustin T. Gibbs return(0); 22698b8a9b1dSJustin T. Gibbs } 22708b8a9b1dSJustin T. Gibbs 22718b8a9b1dSJustin T. Gibbs /* 22728b8a9b1dSJustin T. Gibbs * If the copy flag is set, copy this peripheral out. 22738b8a9b1dSJustin T. Gibbs */ 22748b8a9b1dSJustin T. Gibbs if (retval & DM_RET_COPY) { 22758b8a9b1dSJustin T. Gibbs int spaceleft, j; 22768b8a9b1dSJustin T. Gibbs 22778b8a9b1dSJustin T. Gibbs spaceleft = cdm->match_buf_len - (cdm->num_matches * 22788b8a9b1dSJustin T. Gibbs sizeof(struct dev_match_result)); 22798b8a9b1dSJustin T. Gibbs 22808b8a9b1dSJustin T. Gibbs /* 22818b8a9b1dSJustin T. Gibbs * If we don't have enough space to put in another 22828b8a9b1dSJustin T. Gibbs * match result, save our position and tell the 22838b8a9b1dSJustin T. Gibbs * user there are more devices to check. 22848b8a9b1dSJustin T. Gibbs */ 22858b8a9b1dSJustin T. Gibbs if (spaceleft < sizeof(struct dev_match_result)) { 22868b8a9b1dSJustin T. Gibbs struct periph_driver **pdrv; 22878b8a9b1dSJustin T. Gibbs 22888b8a9b1dSJustin T. Gibbs pdrv = NULL; 22898b8a9b1dSJustin T. Gibbs bzero(&cdm->pos, sizeof(cdm->pos)); 22908b8a9b1dSJustin T. Gibbs cdm->pos.position_type = 22918b8a9b1dSJustin T. Gibbs CAM_DEV_POS_PDRV | CAM_DEV_POS_PDPTR | 22928b8a9b1dSJustin T. Gibbs CAM_DEV_POS_PERIPH; 22938b8a9b1dSJustin T. Gibbs 22948b8a9b1dSJustin T. Gibbs /* 22958b8a9b1dSJustin T. Gibbs * This may look a bit non-sensical, but it is 22968b8a9b1dSJustin T. Gibbs * actually quite logical. There are very few 22978b8a9b1dSJustin T. Gibbs * peripheral drivers, and bloating every peripheral 22988b8a9b1dSJustin T. Gibbs * structure with a pointer back to its parent 22998b8a9b1dSJustin T. Gibbs * peripheral driver linker set entry would cost 23008b8a9b1dSJustin T. Gibbs * more in the long run than doing this quick lookup. 23018b8a9b1dSJustin T. Gibbs */ 23028b8a9b1dSJustin T. Gibbs for (pdrv = 23038b8a9b1dSJustin T. Gibbs (struct periph_driver **)periphdriver_set.ls_items; 23048b8a9b1dSJustin T. Gibbs *pdrv != NULL; pdrv++) { 23058b8a9b1dSJustin T. Gibbs if (strcmp((*pdrv)->driver_name, 23068b8a9b1dSJustin T. Gibbs periph->periph_name) == 0) 23078b8a9b1dSJustin T. Gibbs break; 23088b8a9b1dSJustin T. Gibbs } 23098b8a9b1dSJustin T. Gibbs 23108b8a9b1dSJustin T. Gibbs if (pdrv == NULL) { 23118b8a9b1dSJustin T. Gibbs cdm->status = CAM_DEV_MATCH_ERROR; 23128b8a9b1dSJustin T. Gibbs return(0); 23138b8a9b1dSJustin T. Gibbs } 23148b8a9b1dSJustin T. Gibbs 23158b8a9b1dSJustin T. Gibbs cdm->pos.cookie.pdrv = pdrv; 23168b8a9b1dSJustin T. Gibbs /* 23178b8a9b1dSJustin T. Gibbs * The periph generation slot does double duty, as 23188b8a9b1dSJustin T. Gibbs * does the periph pointer slot. They are used for 23198b8a9b1dSJustin T. Gibbs * both edt and pdrv lookups and positioning. 23208b8a9b1dSJustin T. Gibbs */ 23218b8a9b1dSJustin T. Gibbs cdm->pos.cookie.periph = periph; 23228b8a9b1dSJustin T. Gibbs cdm->pos.generations[CAM_PERIPH_GENERATION] = 23238b8a9b1dSJustin T. Gibbs (*pdrv)->generation; 23248b8a9b1dSJustin T. Gibbs cdm->status = CAM_DEV_MATCH_MORE; 23258b8a9b1dSJustin T. Gibbs return(0); 23268b8a9b1dSJustin T. Gibbs } 23278b8a9b1dSJustin T. Gibbs 23288b8a9b1dSJustin T. Gibbs j = cdm->num_matches; 23298b8a9b1dSJustin T. Gibbs cdm->num_matches++; 23308b8a9b1dSJustin T. Gibbs cdm->matches[j].type = DEV_MATCH_PERIPH; 23318b8a9b1dSJustin T. Gibbs cdm->matches[j].result.periph_result.path_id = 23328b8a9b1dSJustin T. Gibbs periph->path->bus->path_id; 23338b8a9b1dSJustin T. Gibbs 23348b8a9b1dSJustin T. Gibbs /* 23358b8a9b1dSJustin T. Gibbs * The transport layer peripheral doesn't have a target or 23368b8a9b1dSJustin T. Gibbs * lun. 23378b8a9b1dSJustin T. Gibbs */ 23388b8a9b1dSJustin T. Gibbs if (periph->path->target) 23398b8a9b1dSJustin T. Gibbs cdm->matches[j].result.periph_result.target_id = 23408b8a9b1dSJustin T. Gibbs periph->path->target->target_id; 23418b8a9b1dSJustin T. Gibbs else 23428b8a9b1dSJustin T. Gibbs cdm->matches[j].result.periph_result.target_id = -1; 23438b8a9b1dSJustin T. Gibbs 23448b8a9b1dSJustin T. Gibbs if (periph->path->device) 23458b8a9b1dSJustin T. Gibbs cdm->matches[j].result.periph_result.target_lun = 23468b8a9b1dSJustin T. Gibbs periph->path->device->lun_id; 23478b8a9b1dSJustin T. Gibbs else 23488b8a9b1dSJustin T. Gibbs cdm->matches[j].result.periph_result.target_lun = -1; 23498b8a9b1dSJustin T. Gibbs 23508b8a9b1dSJustin T. Gibbs cdm->matches[j].result.periph_result.unit_number = 23518b8a9b1dSJustin T. Gibbs periph->unit_number; 23528b8a9b1dSJustin T. Gibbs strncpy(cdm->matches[j].result.periph_result.periph_name, 23538b8a9b1dSJustin T. Gibbs periph->periph_name, DEV_IDLEN); 23548b8a9b1dSJustin T. Gibbs } 23558b8a9b1dSJustin T. Gibbs 23568b8a9b1dSJustin T. Gibbs return(1); 23578b8a9b1dSJustin T. Gibbs } 23588b8a9b1dSJustin T. Gibbs 23598b8a9b1dSJustin T. Gibbs static int 23608b8a9b1dSJustin T. Gibbs xptperiphlistmatch(struct ccb_dev_match *cdm) 23618b8a9b1dSJustin T. Gibbs { 23628b8a9b1dSJustin T. Gibbs int ret; 23638b8a9b1dSJustin T. Gibbs 23648b8a9b1dSJustin T. Gibbs cdm->num_matches = 0; 23658b8a9b1dSJustin T. Gibbs 23668b8a9b1dSJustin T. Gibbs /* 23678b8a9b1dSJustin T. Gibbs * At this point in the edt traversal function, we check the bus 23688b8a9b1dSJustin T. Gibbs * list generation to make sure that no busses have been added or 23698b8a9b1dSJustin T. Gibbs * removed since the user last sent a XPT_DEV_MATCH ccb through. 23708b8a9b1dSJustin T. Gibbs * For the peripheral driver list traversal function, however, we 23718b8a9b1dSJustin T. Gibbs * don't have to worry about new peripheral driver types coming or 23728b8a9b1dSJustin T. Gibbs * going; they're in a linker set, and therefore can't change 23738b8a9b1dSJustin T. Gibbs * without a recompile. 23748b8a9b1dSJustin T. Gibbs */ 23758b8a9b1dSJustin T. Gibbs 23768b8a9b1dSJustin T. Gibbs if ((cdm->pos.position_type & CAM_DEV_POS_PDPTR) 23778b8a9b1dSJustin T. Gibbs && (cdm->pos.cookie.pdrv != NULL)) 23788b8a9b1dSJustin T. Gibbs ret = xptpdrvtraverse( 23798b8a9b1dSJustin T. Gibbs (struct periph_driver **)cdm->pos.cookie.pdrv, 23808b8a9b1dSJustin T. Gibbs xptplistpdrvfunc, cdm); 23818b8a9b1dSJustin T. Gibbs else 23828b8a9b1dSJustin T. Gibbs ret = xptpdrvtraverse(NULL, xptplistpdrvfunc, cdm); 23838b8a9b1dSJustin T. Gibbs 23848b8a9b1dSJustin T. Gibbs /* 23858b8a9b1dSJustin T. Gibbs * If we get back 0, that means that we had to stop before fully 23868b8a9b1dSJustin T. Gibbs * traversing the peripheral driver tree. It also means that one of 23878b8a9b1dSJustin T. Gibbs * the subroutines has set the status field to the proper value. If 23888b8a9b1dSJustin T. Gibbs * we get back 1, we've fully traversed the EDT and copied out any 23898b8a9b1dSJustin T. Gibbs * matching entries. 23908b8a9b1dSJustin T. Gibbs */ 23918b8a9b1dSJustin T. Gibbs if (ret == 1) 23928b8a9b1dSJustin T. Gibbs cdm->status = CAM_DEV_MATCH_LAST; 23938b8a9b1dSJustin T. Gibbs 23948b8a9b1dSJustin T. Gibbs return(ret); 23958b8a9b1dSJustin T. Gibbs } 23968b8a9b1dSJustin T. Gibbs 23978b8a9b1dSJustin T. Gibbs static int 23988b8a9b1dSJustin T. Gibbs xptbustraverse(struct cam_eb *start_bus, xpt_busfunc_t *tr_func, void *arg) 23998b8a9b1dSJustin T. Gibbs { 24008b8a9b1dSJustin T. Gibbs struct cam_eb *bus, *next_bus; 24018b8a9b1dSJustin T. Gibbs int retval; 24028b8a9b1dSJustin T. Gibbs 24038b8a9b1dSJustin T. Gibbs retval = 1; 24048b8a9b1dSJustin T. Gibbs 24058b8a9b1dSJustin T. Gibbs for (bus = (start_bus ? start_bus : TAILQ_FIRST(&xpt_busses)); 24068b8a9b1dSJustin T. Gibbs bus != NULL; 24078b8a9b1dSJustin T. Gibbs bus = next_bus) { 24088b8a9b1dSJustin T. Gibbs next_bus = TAILQ_NEXT(bus, links); 24098b8a9b1dSJustin T. Gibbs 24108b8a9b1dSJustin T. Gibbs retval = tr_func(bus, arg); 24118b8a9b1dSJustin T. Gibbs if (retval == 0) 24128b8a9b1dSJustin T. Gibbs return(retval); 24138b8a9b1dSJustin T. Gibbs } 24148b8a9b1dSJustin T. Gibbs 24158b8a9b1dSJustin T. Gibbs return(retval); 24168b8a9b1dSJustin T. Gibbs } 24178b8a9b1dSJustin T. Gibbs 24188b8a9b1dSJustin T. Gibbs static int 24198b8a9b1dSJustin T. Gibbs xpttargettraverse(struct cam_eb *bus, struct cam_et *start_target, 24208b8a9b1dSJustin T. Gibbs xpt_targetfunc_t *tr_func, void *arg) 24218b8a9b1dSJustin T. Gibbs { 24228b8a9b1dSJustin T. Gibbs struct cam_et *target, *next_target; 24238b8a9b1dSJustin T. Gibbs int retval; 24248b8a9b1dSJustin T. Gibbs 24258b8a9b1dSJustin T. Gibbs retval = 1; 24268b8a9b1dSJustin T. Gibbs for (target = (start_target ? start_target : 24278b8a9b1dSJustin T. Gibbs TAILQ_FIRST(&bus->et_entries)); 24288b8a9b1dSJustin T. Gibbs target != NULL; target = next_target) { 24298b8a9b1dSJustin T. Gibbs 24308b8a9b1dSJustin T. Gibbs next_target = TAILQ_NEXT(target, links); 24318b8a9b1dSJustin T. Gibbs 24328b8a9b1dSJustin T. Gibbs retval = tr_func(target, arg); 24338b8a9b1dSJustin T. Gibbs 24348b8a9b1dSJustin T. Gibbs if (retval == 0) 24358b8a9b1dSJustin T. Gibbs return(retval); 24368b8a9b1dSJustin T. Gibbs } 24378b8a9b1dSJustin T. Gibbs 24388b8a9b1dSJustin T. Gibbs return(retval); 24398b8a9b1dSJustin T. Gibbs } 24408b8a9b1dSJustin T. Gibbs 24418b8a9b1dSJustin T. Gibbs static int 24428b8a9b1dSJustin T. Gibbs xptdevicetraverse(struct cam_et *target, struct cam_ed *start_device, 24438b8a9b1dSJustin T. Gibbs xpt_devicefunc_t *tr_func, void *arg) 24448b8a9b1dSJustin T. Gibbs { 24458b8a9b1dSJustin T. Gibbs struct cam_ed *device, *next_device; 24468b8a9b1dSJustin T. Gibbs int retval; 24478b8a9b1dSJustin T. Gibbs 24488b8a9b1dSJustin T. Gibbs retval = 1; 24498b8a9b1dSJustin T. Gibbs for (device = (start_device ? start_device : 24508b8a9b1dSJustin T. Gibbs TAILQ_FIRST(&target->ed_entries)); 24518b8a9b1dSJustin T. Gibbs device != NULL; 24528b8a9b1dSJustin T. Gibbs device = next_device) { 24538b8a9b1dSJustin T. Gibbs 24548b8a9b1dSJustin T. Gibbs next_device = TAILQ_NEXT(device, links); 24558b8a9b1dSJustin T. Gibbs 24568b8a9b1dSJustin T. Gibbs retval = tr_func(device, arg); 24578b8a9b1dSJustin T. Gibbs 24588b8a9b1dSJustin T. Gibbs if (retval == 0) 24598b8a9b1dSJustin T. Gibbs return(retval); 24608b8a9b1dSJustin T. Gibbs } 24618b8a9b1dSJustin T. Gibbs 24628b8a9b1dSJustin T. Gibbs return(retval); 24638b8a9b1dSJustin T. Gibbs } 24648b8a9b1dSJustin T. Gibbs 24658b8a9b1dSJustin T. Gibbs static int 24668b8a9b1dSJustin T. Gibbs xptperiphtraverse(struct cam_ed *device, struct cam_periph *start_periph, 24678b8a9b1dSJustin T. Gibbs xpt_periphfunc_t *tr_func, void *arg) 24688b8a9b1dSJustin T. Gibbs { 24698b8a9b1dSJustin T. Gibbs struct cam_periph *periph, *next_periph; 24708b8a9b1dSJustin T. Gibbs int retval; 24718b8a9b1dSJustin T. Gibbs 24728b8a9b1dSJustin T. Gibbs retval = 1; 24738b8a9b1dSJustin T. Gibbs 24748b8a9b1dSJustin T. Gibbs for (periph = (start_periph ? start_periph : 24758b8a9b1dSJustin T. Gibbs SLIST_FIRST(&device->periphs)); 24768b8a9b1dSJustin T. Gibbs periph != NULL; 24778b8a9b1dSJustin T. Gibbs periph = next_periph) { 24788b8a9b1dSJustin T. Gibbs 24798b8a9b1dSJustin T. Gibbs next_periph = SLIST_NEXT(periph, periph_links); 24808b8a9b1dSJustin T. Gibbs 24818b8a9b1dSJustin T. Gibbs retval = tr_func(periph, arg); 24828b8a9b1dSJustin T. Gibbs if (retval == 0) 24838b8a9b1dSJustin T. Gibbs return(retval); 24848b8a9b1dSJustin T. Gibbs } 24858b8a9b1dSJustin T. Gibbs 24868b8a9b1dSJustin T. Gibbs return(retval); 24878b8a9b1dSJustin T. Gibbs } 24888b8a9b1dSJustin T. Gibbs 24898b8a9b1dSJustin T. Gibbs static int 24908b8a9b1dSJustin T. Gibbs xptpdrvtraverse(struct periph_driver **start_pdrv, 24918b8a9b1dSJustin T. Gibbs xpt_pdrvfunc_t *tr_func, void *arg) 24928b8a9b1dSJustin T. Gibbs { 24938b8a9b1dSJustin T. Gibbs struct periph_driver **pdrv; 24948b8a9b1dSJustin T. Gibbs int retval; 24958b8a9b1dSJustin T. Gibbs 24968b8a9b1dSJustin T. Gibbs retval = 1; 24978b8a9b1dSJustin T. Gibbs 24988b8a9b1dSJustin T. Gibbs /* 24998b8a9b1dSJustin T. Gibbs * We don't traverse the peripheral driver list like we do the 25008b8a9b1dSJustin T. Gibbs * other lists, because it is a linker set, and therefore cannot be 25018b8a9b1dSJustin T. Gibbs * changed during runtime. If the peripheral driver list is ever 25028b8a9b1dSJustin T. Gibbs * re-done to be something other than a linker set (i.e. it can 25038b8a9b1dSJustin T. Gibbs * change while the system is running), the list traversal should 25048b8a9b1dSJustin T. Gibbs * be modified to work like the other traversal functions. 25058b8a9b1dSJustin T. Gibbs */ 25068b8a9b1dSJustin T. Gibbs for (pdrv = (start_pdrv ? start_pdrv : 25078b8a9b1dSJustin T. Gibbs (struct periph_driver **)periphdriver_set.ls_items); 25088b8a9b1dSJustin T. Gibbs *pdrv != NULL; pdrv++) { 25098b8a9b1dSJustin T. Gibbs retval = tr_func(pdrv, arg); 25108b8a9b1dSJustin T. Gibbs 25118b8a9b1dSJustin T. Gibbs if (retval == 0) 25128b8a9b1dSJustin T. Gibbs return(retval); 25138b8a9b1dSJustin T. Gibbs } 25148b8a9b1dSJustin T. Gibbs 25158b8a9b1dSJustin T. Gibbs return(retval); 25168b8a9b1dSJustin T. Gibbs } 25178b8a9b1dSJustin T. Gibbs 25188b8a9b1dSJustin T. Gibbs static int 25198b8a9b1dSJustin T. Gibbs xptpdperiphtraverse(struct periph_driver **pdrv, 25208b8a9b1dSJustin T. Gibbs struct cam_periph *start_periph, 25218b8a9b1dSJustin T. Gibbs xpt_periphfunc_t *tr_func, void *arg) 25228b8a9b1dSJustin T. Gibbs { 25238b8a9b1dSJustin T. Gibbs struct cam_periph *periph, *next_periph; 25248b8a9b1dSJustin T. Gibbs int retval; 25258b8a9b1dSJustin T. Gibbs 25268b8a9b1dSJustin T. Gibbs retval = 1; 25278b8a9b1dSJustin T. Gibbs 25288b8a9b1dSJustin T. Gibbs for (periph = (start_periph ? start_periph : 25298b8a9b1dSJustin T. Gibbs TAILQ_FIRST(&(*pdrv)->units)); periph != NULL; 25308b8a9b1dSJustin T. Gibbs periph = next_periph) { 25318b8a9b1dSJustin T. Gibbs 25328b8a9b1dSJustin T. Gibbs next_periph = TAILQ_NEXT(periph, unit_links); 25338b8a9b1dSJustin T. Gibbs 25348b8a9b1dSJustin T. Gibbs retval = tr_func(periph, arg); 25358b8a9b1dSJustin T. Gibbs if (retval == 0) 25368b8a9b1dSJustin T. Gibbs return(retval); 25378b8a9b1dSJustin T. Gibbs } 25388b8a9b1dSJustin T. Gibbs return(retval); 25398b8a9b1dSJustin T. Gibbs } 25408b8a9b1dSJustin T. Gibbs 25418b8a9b1dSJustin T. Gibbs static int 25428b8a9b1dSJustin T. Gibbs xptdefbusfunc(struct cam_eb *bus, void *arg) 25438b8a9b1dSJustin T. Gibbs { 25448b8a9b1dSJustin T. Gibbs struct xpt_traverse_config *tr_config; 25458b8a9b1dSJustin T. Gibbs 25468b8a9b1dSJustin T. Gibbs tr_config = (struct xpt_traverse_config *)arg; 25478b8a9b1dSJustin T. Gibbs 25488b8a9b1dSJustin T. Gibbs if (tr_config->depth == XPT_DEPTH_BUS) { 25498b8a9b1dSJustin T. Gibbs xpt_busfunc_t *tr_func; 25508b8a9b1dSJustin T. Gibbs 25518b8a9b1dSJustin T. Gibbs tr_func = (xpt_busfunc_t *)tr_config->tr_func; 25528b8a9b1dSJustin T. Gibbs 25538b8a9b1dSJustin T. Gibbs return(tr_func(bus, tr_config->tr_arg)); 25548b8a9b1dSJustin T. Gibbs } else 25558b8a9b1dSJustin T. Gibbs return(xpttargettraverse(bus, NULL, xptdeftargetfunc, arg)); 25568b8a9b1dSJustin T. Gibbs } 25578b8a9b1dSJustin T. Gibbs 25588b8a9b1dSJustin T. Gibbs static int 25598b8a9b1dSJustin T. Gibbs xptdeftargetfunc(struct cam_et *target, void *arg) 25608b8a9b1dSJustin T. Gibbs { 25618b8a9b1dSJustin T. Gibbs struct xpt_traverse_config *tr_config; 25628b8a9b1dSJustin T. Gibbs 25638b8a9b1dSJustin T. Gibbs tr_config = (struct xpt_traverse_config *)arg; 25648b8a9b1dSJustin T. Gibbs 25658b8a9b1dSJustin T. Gibbs if (tr_config->depth == XPT_DEPTH_TARGET) { 25668b8a9b1dSJustin T. Gibbs xpt_targetfunc_t *tr_func; 25678b8a9b1dSJustin T. Gibbs 25688b8a9b1dSJustin T. Gibbs tr_func = (xpt_targetfunc_t *)tr_config->tr_func; 25698b8a9b1dSJustin T. Gibbs 25708b8a9b1dSJustin T. Gibbs return(tr_func(target, tr_config->tr_arg)); 25718b8a9b1dSJustin T. Gibbs } else 25728b8a9b1dSJustin T. Gibbs return(xptdevicetraverse(target, NULL, xptdefdevicefunc, arg)); 25738b8a9b1dSJustin T. Gibbs } 25748b8a9b1dSJustin T. Gibbs 25758b8a9b1dSJustin T. Gibbs static int 25768b8a9b1dSJustin T. Gibbs xptdefdevicefunc(struct cam_ed *device, void *arg) 25778b8a9b1dSJustin T. Gibbs { 25788b8a9b1dSJustin T. Gibbs struct xpt_traverse_config *tr_config; 25798b8a9b1dSJustin T. Gibbs 25808b8a9b1dSJustin T. Gibbs tr_config = (struct xpt_traverse_config *)arg; 25818b8a9b1dSJustin T. Gibbs 25828b8a9b1dSJustin T. Gibbs if (tr_config->depth == XPT_DEPTH_DEVICE) { 25838b8a9b1dSJustin T. Gibbs xpt_devicefunc_t *tr_func; 25848b8a9b1dSJustin T. Gibbs 25858b8a9b1dSJustin T. Gibbs tr_func = (xpt_devicefunc_t *)tr_config->tr_func; 25868b8a9b1dSJustin T. Gibbs 25878b8a9b1dSJustin T. Gibbs return(tr_func(device, tr_config->tr_arg)); 25888b8a9b1dSJustin T. Gibbs } else 25898b8a9b1dSJustin T. Gibbs return(xptperiphtraverse(device, NULL, xptdefperiphfunc, arg)); 25908b8a9b1dSJustin T. Gibbs } 25918b8a9b1dSJustin T. Gibbs 25928b8a9b1dSJustin T. Gibbs static int 25938b8a9b1dSJustin T. Gibbs xptdefperiphfunc(struct cam_periph *periph, void *arg) 25948b8a9b1dSJustin T. Gibbs { 25958b8a9b1dSJustin T. Gibbs struct xpt_traverse_config *tr_config; 25968b8a9b1dSJustin T. Gibbs xpt_periphfunc_t *tr_func; 25978b8a9b1dSJustin T. Gibbs 25988b8a9b1dSJustin T. Gibbs tr_config = (struct xpt_traverse_config *)arg; 25998b8a9b1dSJustin T. Gibbs 26008b8a9b1dSJustin T. Gibbs tr_func = (xpt_periphfunc_t *)tr_config->tr_func; 26018b8a9b1dSJustin T. Gibbs 26028b8a9b1dSJustin T. Gibbs /* 26038b8a9b1dSJustin T. Gibbs * Unlike the other default functions, we don't check for depth 26048b8a9b1dSJustin T. Gibbs * here. The peripheral driver level is the last level in the EDT, 26058b8a9b1dSJustin T. Gibbs * so if we're here, we should execute the function in question. 26068b8a9b1dSJustin T. Gibbs */ 26078b8a9b1dSJustin T. Gibbs return(tr_func(periph, tr_config->tr_arg)); 26088b8a9b1dSJustin T. Gibbs } 26098b8a9b1dSJustin T. Gibbs 26108b8a9b1dSJustin T. Gibbs /* 26118b8a9b1dSJustin T. Gibbs * Execute the given function for every bus in the EDT. 26128b8a9b1dSJustin T. Gibbs */ 26138b8a9b1dSJustin T. Gibbs static int 26148b8a9b1dSJustin T. Gibbs xpt_for_all_busses(xpt_busfunc_t *tr_func, void *arg) 26158b8a9b1dSJustin T. Gibbs { 26168b8a9b1dSJustin T. Gibbs struct xpt_traverse_config tr_config; 26178b8a9b1dSJustin T. Gibbs 26188b8a9b1dSJustin T. Gibbs tr_config.depth = XPT_DEPTH_BUS; 26198b8a9b1dSJustin T. Gibbs tr_config.tr_func = tr_func; 26208b8a9b1dSJustin T. Gibbs tr_config.tr_arg = arg; 26218b8a9b1dSJustin T. Gibbs 26228b8a9b1dSJustin T. Gibbs return(xptbustraverse(NULL, xptdefbusfunc, &tr_config)); 26238b8a9b1dSJustin T. Gibbs } 26248b8a9b1dSJustin T. Gibbs 2625bfc0eb0fSKenneth D. Merry #ifdef notusedyet 26268b8a9b1dSJustin T. Gibbs /* 26278b8a9b1dSJustin T. Gibbs * Execute the given function for every target in the EDT. 26288b8a9b1dSJustin T. Gibbs */ 26298b8a9b1dSJustin T. Gibbs static int 26308b8a9b1dSJustin T. Gibbs xpt_for_all_targets(xpt_targetfunc_t *tr_func, void *arg) 26318b8a9b1dSJustin T. Gibbs { 26328b8a9b1dSJustin T. Gibbs struct xpt_traverse_config tr_config; 26338b8a9b1dSJustin T. Gibbs 26348b8a9b1dSJustin T. Gibbs tr_config.depth = XPT_DEPTH_TARGET; 26358b8a9b1dSJustin T. Gibbs tr_config.tr_func = tr_func; 26368b8a9b1dSJustin T. Gibbs tr_config.tr_arg = arg; 26378b8a9b1dSJustin T. Gibbs 26388b8a9b1dSJustin T. Gibbs return(xptbustraverse(NULL, xptdefbusfunc, &tr_config)); 26398b8a9b1dSJustin T. Gibbs } 2640bfc0eb0fSKenneth D. Merry #endif /* notusedyet */ 26418b8a9b1dSJustin T. Gibbs 26428b8a9b1dSJustin T. Gibbs /* 26438b8a9b1dSJustin T. Gibbs * Execute the given function for every device in the EDT. 26448b8a9b1dSJustin T. Gibbs */ 26458b8a9b1dSJustin T. Gibbs static int 26468b8a9b1dSJustin T. Gibbs xpt_for_all_devices(xpt_devicefunc_t *tr_func, void *arg) 26478b8a9b1dSJustin T. Gibbs { 26488b8a9b1dSJustin T. Gibbs struct xpt_traverse_config tr_config; 26498b8a9b1dSJustin T. Gibbs 26508b8a9b1dSJustin T. Gibbs tr_config.depth = XPT_DEPTH_DEVICE; 26518b8a9b1dSJustin T. Gibbs tr_config.tr_func = tr_func; 26528b8a9b1dSJustin T. Gibbs tr_config.tr_arg = arg; 26538b8a9b1dSJustin T. Gibbs 26548b8a9b1dSJustin T. Gibbs return(xptbustraverse(NULL, xptdefbusfunc, &tr_config)); 26558b8a9b1dSJustin T. Gibbs } 26568b8a9b1dSJustin T. Gibbs 2657bfc0eb0fSKenneth D. Merry #ifdef notusedyet 26588b8a9b1dSJustin T. Gibbs /* 26598b8a9b1dSJustin T. Gibbs * Execute the given function for every peripheral in the EDT. 26608b8a9b1dSJustin T. Gibbs */ 26618b8a9b1dSJustin T. Gibbs static int 26628b8a9b1dSJustin T. Gibbs xpt_for_all_periphs(xpt_periphfunc_t *tr_func, void *arg) 26638b8a9b1dSJustin T. Gibbs { 26648b8a9b1dSJustin T. Gibbs struct xpt_traverse_config tr_config; 26658b8a9b1dSJustin T. Gibbs 26668b8a9b1dSJustin T. Gibbs tr_config.depth = XPT_DEPTH_PERIPH; 26678b8a9b1dSJustin T. Gibbs tr_config.tr_func = tr_func; 26688b8a9b1dSJustin T. Gibbs tr_config.tr_arg = arg; 26698b8a9b1dSJustin T. Gibbs 26708b8a9b1dSJustin T. Gibbs return(xptbustraverse(NULL, xptdefbusfunc, &tr_config)); 26718b8a9b1dSJustin T. Gibbs } 2672bfc0eb0fSKenneth D. Merry #endif /* notusedyet */ 26738b8a9b1dSJustin T. Gibbs 26748b8a9b1dSJustin T. Gibbs static int 26758b8a9b1dSJustin T. Gibbs xptsetasyncfunc(struct cam_ed *device, void *arg) 26768b8a9b1dSJustin T. Gibbs { 26778b8a9b1dSJustin T. Gibbs struct cam_path path; 26788b8a9b1dSJustin T. Gibbs struct ccb_getdev cgd; 26798b8a9b1dSJustin T. Gibbs struct async_node *cur_entry; 26808b8a9b1dSJustin T. Gibbs 26818b8a9b1dSJustin T. Gibbs cur_entry = (struct async_node *)arg; 26828b8a9b1dSJustin T. Gibbs 2683c8bead2aSJustin T. Gibbs /* 2684c8bead2aSJustin T. Gibbs * Don't report unconfigured devices (Wildcard devs, 2685c8bead2aSJustin T. Gibbs * devices only for target mode, device instances 2686c8bead2aSJustin T. Gibbs * that have been invalidated but are waiting for 2687c8bead2aSJustin T. Gibbs * their last reference count to be released). 2688c8bead2aSJustin T. Gibbs */ 2689c8bead2aSJustin T. Gibbs if ((device->flags & CAM_DEV_UNCONFIGURED) != 0) 2690c8bead2aSJustin T. Gibbs return (1); 2691c8bead2aSJustin T. Gibbs 26928b8a9b1dSJustin T. Gibbs xpt_compile_path(&path, 26938b8a9b1dSJustin T. Gibbs NULL, 26948b8a9b1dSJustin T. Gibbs device->target->bus->path_id, 26958b8a9b1dSJustin T. Gibbs device->target->target_id, 26968b8a9b1dSJustin T. Gibbs device->lun_id); 26978b8a9b1dSJustin T. Gibbs xpt_setup_ccb(&cgd.ccb_h, &path, /*priority*/1); 26988b8a9b1dSJustin T. Gibbs cgd.ccb_h.func_code = XPT_GDEV_TYPE; 26998b8a9b1dSJustin T. Gibbs xpt_action((union ccb *)&cgd); 27008b8a9b1dSJustin T. Gibbs cur_entry->callback(cur_entry->callback_arg, 27018b8a9b1dSJustin T. Gibbs AC_FOUND_DEVICE, 27028b8a9b1dSJustin T. Gibbs &path, &cgd); 27038b8a9b1dSJustin T. Gibbs xpt_release_path(&path); 27048b8a9b1dSJustin T. Gibbs 27058b8a9b1dSJustin T. Gibbs return(1); 27068b8a9b1dSJustin T. Gibbs } 2707c8bead2aSJustin T. Gibbs 27088b8a9b1dSJustin T. Gibbs static int 27098b8a9b1dSJustin T. Gibbs xptsetasyncbusfunc(struct cam_eb *bus, void *arg) 27108b8a9b1dSJustin T. Gibbs { 27118b8a9b1dSJustin T. Gibbs struct cam_path path; 27128b8a9b1dSJustin T. Gibbs struct ccb_pathinq cpi; 27138b8a9b1dSJustin T. Gibbs struct async_node *cur_entry; 27148b8a9b1dSJustin T. Gibbs 27158b8a9b1dSJustin T. Gibbs cur_entry = (struct async_node *)arg; 27168b8a9b1dSJustin T. Gibbs 27178b8a9b1dSJustin T. Gibbs xpt_compile_path(&path, /*periph*/NULL, 27188b8a9b1dSJustin T. Gibbs bus->sim->path_id, 27198b8a9b1dSJustin T. Gibbs CAM_TARGET_WILDCARD, 27208b8a9b1dSJustin T. Gibbs CAM_LUN_WILDCARD); 27218b8a9b1dSJustin T. Gibbs xpt_setup_ccb(&cpi.ccb_h, &path, /*priority*/1); 27228b8a9b1dSJustin T. Gibbs cpi.ccb_h.func_code = XPT_PATH_INQ; 27238b8a9b1dSJustin T. Gibbs xpt_action((union ccb *)&cpi); 27248b8a9b1dSJustin T. Gibbs cur_entry->callback(cur_entry->callback_arg, 27258b8a9b1dSJustin T. Gibbs AC_PATH_REGISTERED, 27268b8a9b1dSJustin T. Gibbs &path, &cpi); 27278b8a9b1dSJustin T. Gibbs xpt_release_path(&path); 27288b8a9b1dSJustin T. Gibbs 27298b8a9b1dSJustin T. Gibbs return(1); 27308b8a9b1dSJustin T. Gibbs } 27318b8a9b1dSJustin T. Gibbs 27328b8a9b1dSJustin T. Gibbs void 27338b8a9b1dSJustin T. Gibbs xpt_action(union ccb *start_ccb) 27348b8a9b1dSJustin T. Gibbs { 27359911ecf9SJustin T. Gibbs int iopl; 27369911ecf9SJustin T. Gibbs 27378b8a9b1dSJustin T. Gibbs CAM_DEBUG(start_ccb->ccb_h.path, CAM_DEBUG_TRACE, ("xpt_action\n")); 27388b8a9b1dSJustin T. Gibbs 27398b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.status = CAM_REQ_INPROG; 27408b8a9b1dSJustin T. Gibbs 27419911ecf9SJustin T. Gibbs iopl = splsoftcam(); 27428b8a9b1dSJustin T. Gibbs switch (start_ccb->ccb_h.func_code) { 27438b8a9b1dSJustin T. Gibbs case XPT_SCSI_IO: 2744d05caa00SKenneth D. Merry { 2745d05caa00SKenneth D. Merry #ifdef CAMDEBUG 2746d05caa00SKenneth D. Merry char cdb_str[(SCSI_MAX_CDBLEN * 3) + 1]; 2747d05caa00SKenneth D. Merry struct cam_path *path; 2748d05caa00SKenneth D. Merry 2749d05caa00SKenneth D. Merry path = start_ccb->ccb_h.path; 2750d05caa00SKenneth D. Merry #endif 2751d05caa00SKenneth D. Merry 27528b8a9b1dSJustin T. Gibbs /* 27538b8a9b1dSJustin T. Gibbs * For the sake of compatibility with SCSI-1 27548b8a9b1dSJustin T. Gibbs * devices that may not understand the identify 27558b8a9b1dSJustin T. Gibbs * message, we include lun information in the 27568b8a9b1dSJustin T. Gibbs * second byte of all commands. SCSI-1 specifies 27578b8a9b1dSJustin T. Gibbs * that luns are a 3 bit value and reserves only 3 27588b8a9b1dSJustin T. Gibbs * bits for lun information in the CDB. Later 27598b8a9b1dSJustin T. Gibbs * revisions of the SCSI spec allow for more than 8 27608b8a9b1dSJustin T. Gibbs * luns, but have deprecated lun information in the 27618b8a9b1dSJustin T. Gibbs * CDB. So, if the lun won't fit, we must omit. 27628b8a9b1dSJustin T. Gibbs * 27638b8a9b1dSJustin T. Gibbs * Also be aware that during initial probing for devices, 27648b8a9b1dSJustin T. Gibbs * the inquiry information is unknown but initialized to 0. 27658b8a9b1dSJustin T. Gibbs * This means that this code will be exercised while probing 27668b8a9b1dSJustin T. Gibbs * devices with an ANSI revision greater than 2. 27678b8a9b1dSJustin T. Gibbs */ 27688b8a9b1dSJustin T. Gibbs if (SID_ANSI_REV(&start_ccb->ccb_h.path->device->inq_data) <= 2 27698b8a9b1dSJustin T. Gibbs && start_ccb->ccb_h.target_lun < 8 27708b8a9b1dSJustin T. Gibbs && (start_ccb->ccb_h.flags & CAM_CDB_POINTER) == 0) { 27718b8a9b1dSJustin T. Gibbs 27728b8a9b1dSJustin T. Gibbs start_ccb->csio.cdb_io.cdb_bytes[1] |= 27738b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.target_lun << 5; 27748b8a9b1dSJustin T. Gibbs } 27758b8a9b1dSJustin T. Gibbs start_ccb->csio.scsi_status = SCSI_STATUS_OK; 2776d05caa00SKenneth D. Merry CAM_DEBUG(path, CAM_DEBUG_CDB,("%s. CDB: %s\n", 2777d05caa00SKenneth D. Merry scsi_op_desc(start_ccb->csio.cdb_io.cdb_bytes[0], 2778d05caa00SKenneth D. Merry &path->device->inq_data), 2779d05caa00SKenneth D. Merry scsi_cdb_string(start_ccb->csio.cdb_io.cdb_bytes, 278050642f18SKenneth D. Merry cdb_str, sizeof(cdb_str)))); 27812cefde5fSJustin T. Gibbs /* FALLTHROUGH */ 2782d05caa00SKenneth D. Merry } 27838b8a9b1dSJustin T. Gibbs case XPT_TARGET_IO: 27848b8a9b1dSJustin T. Gibbs case XPT_CONT_TARGET_IO: 27852cefde5fSJustin T. Gibbs start_ccb->csio.sense_resid = 0; 27862cefde5fSJustin T. Gibbs start_ccb->csio.resid = 0; 27872cefde5fSJustin T. Gibbs /* FALLTHROUGH */ 278810e1cf63SKenneth D. Merry case XPT_RESET_DEV: 27898b8a9b1dSJustin T. Gibbs case XPT_ENG_EXEC: 27908b8a9b1dSJustin T. Gibbs { 27918b8a9b1dSJustin T. Gibbs struct cam_path *path; 27928b8a9b1dSJustin T. Gibbs int s; 27938b8a9b1dSJustin T. Gibbs int runq; 27948b8a9b1dSJustin T. Gibbs 27958b8a9b1dSJustin T. Gibbs path = start_ccb->ccb_h.path; 27968b8a9b1dSJustin T. Gibbs s = splsoftcam(); 27978b8a9b1dSJustin T. Gibbs 27988b8a9b1dSJustin T. Gibbs cam_ccbq_insert_ccb(&path->device->ccbq, start_ccb); 27998b8a9b1dSJustin T. Gibbs if (path->device->qfrozen_cnt == 0) 28008b8a9b1dSJustin T. Gibbs runq = xpt_schedule_dev_sendq(path->bus, path->device); 28018b8a9b1dSJustin T. Gibbs else 28028b8a9b1dSJustin T. Gibbs runq = 0; 28038b8a9b1dSJustin T. Gibbs splx(s); 28048b8a9b1dSJustin T. Gibbs if (runq != 0) 28058b8a9b1dSJustin T. Gibbs xpt_run_dev_sendq(path->bus); 28068b8a9b1dSJustin T. Gibbs break; 28078b8a9b1dSJustin T. Gibbs } 28088b8a9b1dSJustin T. Gibbs case XPT_SET_TRAN_SETTINGS: 28098b8a9b1dSJustin T. Gibbs { 28108b8a9b1dSJustin T. Gibbs xpt_set_transfer_settings(&start_ccb->cts, 281103e3511bSJustin T. Gibbs start_ccb->ccb_h.path->device, 28128b8a9b1dSJustin T. Gibbs /*async_update*/FALSE); 28138b8a9b1dSJustin T. Gibbs break; 28148b8a9b1dSJustin T. Gibbs } 28158b8a9b1dSJustin T. Gibbs case XPT_CALC_GEOMETRY: 28162cefde5fSJustin T. Gibbs { 28172cefde5fSJustin T. Gibbs struct cam_sim *sim; 28182cefde5fSJustin T. Gibbs 28198b8a9b1dSJustin T. Gibbs /* Filter out garbage */ 28208b8a9b1dSJustin T. Gibbs if (start_ccb->ccg.block_size == 0 28218b8a9b1dSJustin T. Gibbs || start_ccb->ccg.volume_size == 0) { 28228b8a9b1dSJustin T. Gibbs start_ccb->ccg.cylinders = 0; 28238b8a9b1dSJustin T. Gibbs start_ccb->ccg.heads = 0; 28248b8a9b1dSJustin T. Gibbs start_ccb->ccg.secs_per_track = 0; 28258b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.status = CAM_REQ_CMP; 28268b8a9b1dSJustin T. Gibbs break; 28278b8a9b1dSJustin T. Gibbs } 28288b8a9b1dSJustin T. Gibbs #ifdef PC98 28298b8a9b1dSJustin T. Gibbs /* 28308b8a9b1dSJustin T. Gibbs * In a PC-98 system, geometry translation depens on 28318b8a9b1dSJustin T. Gibbs * the "real" device geometry obtained from mode page 4. 28328b8a9b1dSJustin T. Gibbs * SCSI geometry translation is performed in the 28338b8a9b1dSJustin T. Gibbs * initialization routine of the SCSI BIOS and the result 28348b8a9b1dSJustin T. Gibbs * stored in host memory. If the translation is available 28358b8a9b1dSJustin T. Gibbs * in host memory, use it. If not, rely on the default 28368b8a9b1dSJustin T. Gibbs * translation the device driver performs. 28378b8a9b1dSJustin T. Gibbs */ 28388b8a9b1dSJustin T. Gibbs if (scsi_da_bios_params(&start_ccb->ccg) != 0) { 28398b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.status = CAM_REQ_CMP; 28408b8a9b1dSJustin T. Gibbs break; 28418b8a9b1dSJustin T. Gibbs } 28428b8a9b1dSJustin T. Gibbs #endif 28432cefde5fSJustin T. Gibbs sim = start_ccb->ccb_h.path->bus->sim; 28442cefde5fSJustin T. Gibbs (*(sim->sim_action))(sim, start_ccb); 28452cefde5fSJustin T. Gibbs break; 28462cefde5fSJustin T. Gibbs } 2847bb6087e5SJustin T. Gibbs case XPT_ABORT: 28482cefde5fSJustin T. Gibbs { 28492cefde5fSJustin T. Gibbs union ccb* abort_ccb; 28502cefde5fSJustin T. Gibbs int s; 28512cefde5fSJustin T. Gibbs 28522cefde5fSJustin T. Gibbs abort_ccb = start_ccb->cab.abort_ccb; 28532cefde5fSJustin T. Gibbs if (XPT_FC_IS_DEV_QUEUED(abort_ccb)) { 28542cefde5fSJustin T. Gibbs 28552cefde5fSJustin T. Gibbs if (abort_ccb->ccb_h.pinfo.index >= 0) { 28562cefde5fSJustin T. Gibbs struct cam_ccbq *ccbq; 28572cefde5fSJustin T. Gibbs 28582cefde5fSJustin T. Gibbs ccbq = &abort_ccb->ccb_h.path->device->ccbq; 28592cefde5fSJustin T. Gibbs cam_ccbq_remove_ccb(ccbq, abort_ccb); 28602cefde5fSJustin T. Gibbs abort_ccb->ccb_h.status = 28612cefde5fSJustin T. Gibbs CAM_REQ_ABORTED|CAM_DEV_QFRZN; 28622cefde5fSJustin T. Gibbs xpt_freeze_devq(abort_ccb->ccb_h.path, 1); 28632cefde5fSJustin T. Gibbs s = splcam(); 28642cefde5fSJustin T. Gibbs xpt_done(abort_ccb); 28652cefde5fSJustin T. Gibbs splx(s); 28662cefde5fSJustin T. Gibbs start_ccb->ccb_h.status = CAM_REQ_CMP; 28672cefde5fSJustin T. Gibbs break; 28682cefde5fSJustin T. Gibbs } 28692cefde5fSJustin T. Gibbs if (abort_ccb->ccb_h.pinfo.index == CAM_UNQUEUED_INDEX 28702cefde5fSJustin T. Gibbs && (abort_ccb->ccb_h.status & CAM_SIM_QUEUED) == 0) { 28712cefde5fSJustin T. Gibbs /* 28722cefde5fSJustin T. Gibbs * We've caught this ccb en route to 28732cefde5fSJustin T. Gibbs * the SIM. Flag it for abort and the 28742cefde5fSJustin T. Gibbs * SIM will do so just before starting 28752cefde5fSJustin T. Gibbs * real work on the CCB. 28762cefde5fSJustin T. Gibbs */ 28772cefde5fSJustin T. Gibbs abort_ccb->ccb_h.status = 28782cefde5fSJustin T. Gibbs CAM_REQ_ABORTED|CAM_DEV_QFRZN; 28792cefde5fSJustin T. Gibbs xpt_freeze_devq(abort_ccb->ccb_h.path, 1); 28802cefde5fSJustin T. Gibbs start_ccb->ccb_h.status = CAM_REQ_CMP; 28812cefde5fSJustin T. Gibbs break; 28822cefde5fSJustin T. Gibbs } 28832cefde5fSJustin T. Gibbs } 28842cefde5fSJustin T. Gibbs if (XPT_FC_IS_QUEUED(abort_ccb) 28852cefde5fSJustin T. Gibbs && (abort_ccb->ccb_h.pinfo.index == CAM_DONEQ_INDEX)) { 28862cefde5fSJustin T. Gibbs /* 28872cefde5fSJustin T. Gibbs * It's already completed but waiting 28882cefde5fSJustin T. Gibbs * for our SWI to get to it. 28892cefde5fSJustin T. Gibbs */ 28902cefde5fSJustin T. Gibbs start_ccb->ccb_h.status = CAM_UA_ABORT; 28912cefde5fSJustin T. Gibbs break; 28922cefde5fSJustin T. Gibbs } 28932cefde5fSJustin T. Gibbs /* 28942cefde5fSJustin T. Gibbs * If we weren't able to take care of the abort request 28952cefde5fSJustin T. Gibbs * in the XPT, pass the request down to the SIM for processing. 28962cefde5fSJustin T. Gibbs */ 28972cefde5fSJustin T. Gibbs /* FALLTHROUGH */ 28982cefde5fSJustin T. Gibbs } 28998b8a9b1dSJustin T. Gibbs case XPT_ACCEPT_TARGET_IO: 29008b8a9b1dSJustin T. Gibbs case XPT_EN_LUN: 29018b8a9b1dSJustin T. Gibbs case XPT_IMMED_NOTIFY: 29028b8a9b1dSJustin T. Gibbs case XPT_NOTIFY_ACK: 29038b8a9b1dSJustin T. Gibbs case XPT_GET_TRAN_SETTINGS: 29048b8a9b1dSJustin T. Gibbs case XPT_RESET_BUS: 29058b8a9b1dSJustin T. Gibbs { 29068b8a9b1dSJustin T. Gibbs struct cam_sim *sim; 29078b8a9b1dSJustin T. Gibbs 29088b8a9b1dSJustin T. Gibbs sim = start_ccb->ccb_h.path->bus->sim; 29098b8a9b1dSJustin T. Gibbs (*(sim->sim_action))(sim, start_ccb); 29108b8a9b1dSJustin T. Gibbs break; 29118b8a9b1dSJustin T. Gibbs } 291287cfaf0eSJustin T. Gibbs case XPT_PATH_INQ: 291387cfaf0eSJustin T. Gibbs { 291487cfaf0eSJustin T. Gibbs struct cam_sim *sim; 291587cfaf0eSJustin T. Gibbs 291687cfaf0eSJustin T. Gibbs sim = start_ccb->ccb_h.path->bus->sim; 291787cfaf0eSJustin T. Gibbs (*(sim->sim_action))(sim, start_ccb); 291887cfaf0eSJustin T. Gibbs break; 291987cfaf0eSJustin T. Gibbs } 292087cfaf0eSJustin T. Gibbs case XPT_PATH_STATS: 292187cfaf0eSJustin T. Gibbs start_ccb->cpis.last_reset = 292287cfaf0eSJustin T. Gibbs start_ccb->ccb_h.path->bus->last_reset; 292387cfaf0eSJustin T. Gibbs start_ccb->ccb_h.status = CAM_REQ_CMP; 292487cfaf0eSJustin T. Gibbs break; 29258b8a9b1dSJustin T. Gibbs case XPT_GDEV_TYPE: 2926a5479bc5SJustin T. Gibbs { 292787cfaf0eSJustin T. Gibbs struct cam_ed *dev; 2928a5479bc5SJustin T. Gibbs int s; 2929a5479bc5SJustin T. Gibbs 293087cfaf0eSJustin T. Gibbs dev = start_ccb->ccb_h.path->device; 2931a5479bc5SJustin T. Gibbs s = splcam(); 293287cfaf0eSJustin T. Gibbs if ((dev->flags & CAM_DEV_UNCONFIGURED) != 0) { 29338b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.status = CAM_DEV_NOT_THERE; 29348b8a9b1dSJustin T. Gibbs } else { 29358b8a9b1dSJustin T. Gibbs struct ccb_getdev *cgd; 293687cfaf0eSJustin T. Gibbs struct cam_eb *bus; 29378b8a9b1dSJustin T. Gibbs struct cam_et *tar; 29388b8a9b1dSJustin T. Gibbs 29398b8a9b1dSJustin T. Gibbs cgd = &start_ccb->cgd; 294087cfaf0eSJustin T. Gibbs bus = cgd->ccb_h.path->bus; 29418b8a9b1dSJustin T. Gibbs tar = cgd->ccb_h.path->target; 29428b8a9b1dSJustin T. Gibbs cgd->inq_data = dev->inq_data; 29438b8a9b1dSJustin T. Gibbs cgd->ccb_h.status = CAM_REQ_CMP; 29448b8a9b1dSJustin T. Gibbs cgd->serial_num_len = dev->serial_num_len; 29458b8a9b1dSJustin T. Gibbs if ((dev->serial_num_len > 0) 29468b8a9b1dSJustin T. Gibbs && (dev->serial_num != NULL)) 29478b8a9b1dSJustin T. Gibbs bcopy(dev->serial_num, cgd->serial_num, 29488b8a9b1dSJustin T. Gibbs dev->serial_num_len); 29498b8a9b1dSJustin T. Gibbs } 2950a5479bc5SJustin T. Gibbs splx(s); 29518b8a9b1dSJustin T. Gibbs break; 2952a5479bc5SJustin T. Gibbs } 295387cfaf0eSJustin T. Gibbs case XPT_GDEV_STATS: 295487cfaf0eSJustin T. Gibbs { 295587cfaf0eSJustin T. Gibbs struct cam_ed *dev; 295687cfaf0eSJustin T. Gibbs int s; 295787cfaf0eSJustin T. Gibbs 295887cfaf0eSJustin T. Gibbs dev = start_ccb->ccb_h.path->device; 295987cfaf0eSJustin T. Gibbs s = splcam(); 296087cfaf0eSJustin T. Gibbs if ((dev->flags & CAM_DEV_UNCONFIGURED) != 0) { 296187cfaf0eSJustin T. Gibbs start_ccb->ccb_h.status = CAM_DEV_NOT_THERE; 296287cfaf0eSJustin T. Gibbs } else { 296387cfaf0eSJustin T. Gibbs struct ccb_getdevstats *cgds; 296487cfaf0eSJustin T. Gibbs struct cam_eb *bus; 296587cfaf0eSJustin T. Gibbs struct cam_et *tar; 296687cfaf0eSJustin T. Gibbs 296787cfaf0eSJustin T. Gibbs cgds = &start_ccb->cgds; 296887cfaf0eSJustin T. Gibbs bus = cgds->ccb_h.path->bus; 296987cfaf0eSJustin T. Gibbs tar = cgds->ccb_h.path->target; 297087cfaf0eSJustin T. Gibbs cgds->dev_openings = dev->ccbq.dev_openings; 297187cfaf0eSJustin T. Gibbs cgds->dev_active = dev->ccbq.dev_active; 297287cfaf0eSJustin T. Gibbs cgds->devq_openings = dev->ccbq.devq_openings; 297387cfaf0eSJustin T. Gibbs cgds->devq_queued = dev->ccbq.queue.entries; 297487cfaf0eSJustin T. Gibbs cgds->held = dev->ccbq.held; 297587cfaf0eSJustin T. Gibbs cgds->last_reset = tar->last_reset; 297682815562SJustin T. Gibbs cgds->maxtags = dev->quirk->maxtags; 297782815562SJustin T. Gibbs cgds->mintags = dev->quirk->mintags; 297887cfaf0eSJustin T. Gibbs if (timevalcmp(&tar->last_reset, &bus->last_reset, <)) 297987cfaf0eSJustin T. Gibbs cgds->last_reset = bus->last_reset; 298087cfaf0eSJustin T. Gibbs cgds->ccb_h.status = CAM_REQ_CMP; 298187cfaf0eSJustin T. Gibbs } 298287cfaf0eSJustin T. Gibbs splx(s); 298387cfaf0eSJustin T. Gibbs break; 298487cfaf0eSJustin T. Gibbs } 29858b8a9b1dSJustin T. Gibbs case XPT_GDEVLIST: 29868b8a9b1dSJustin T. Gibbs { 29878b8a9b1dSJustin T. Gibbs struct cam_periph *nperiph; 29888b8a9b1dSJustin T. Gibbs struct periph_list *periph_head; 29898b8a9b1dSJustin T. Gibbs struct ccb_getdevlist *cgdl; 29908b8a9b1dSJustin T. Gibbs int i; 29918b8a9b1dSJustin T. Gibbs int s; 29928b8a9b1dSJustin T. Gibbs struct cam_ed *device; 29938b8a9b1dSJustin T. Gibbs int found; 29948b8a9b1dSJustin T. Gibbs 29958b8a9b1dSJustin T. Gibbs 29968b8a9b1dSJustin T. Gibbs found = 0; 29978b8a9b1dSJustin T. Gibbs 29988b8a9b1dSJustin T. Gibbs /* 29998b8a9b1dSJustin T. Gibbs * Don't want anyone mucking with our data. 30008b8a9b1dSJustin T. Gibbs */ 3001a5479bc5SJustin T. Gibbs s = splcam(); 30028b8a9b1dSJustin T. Gibbs device = start_ccb->ccb_h.path->device; 30038b8a9b1dSJustin T. Gibbs periph_head = &device->periphs; 30048b8a9b1dSJustin T. Gibbs cgdl = &start_ccb->cgdl; 30058b8a9b1dSJustin T. Gibbs 30068b8a9b1dSJustin T. Gibbs /* 30078b8a9b1dSJustin T. Gibbs * Check and see if the list has changed since the user 30088b8a9b1dSJustin T. Gibbs * last requested a list member. If so, tell them that the 30098b8a9b1dSJustin T. Gibbs * list has changed, and therefore they need to start over 30108b8a9b1dSJustin T. Gibbs * from the beginning. 30118b8a9b1dSJustin T. Gibbs */ 30128b8a9b1dSJustin T. Gibbs if ((cgdl->index != 0) && 30138b8a9b1dSJustin T. Gibbs (cgdl->generation != device->generation)) { 30148b8a9b1dSJustin T. Gibbs cgdl->status = CAM_GDEVLIST_LIST_CHANGED; 30158b8a9b1dSJustin T. Gibbs splx(s); 30168b8a9b1dSJustin T. Gibbs break; 30178b8a9b1dSJustin T. Gibbs } 30188b8a9b1dSJustin T. Gibbs 30198b8a9b1dSJustin T. Gibbs /* 30208b8a9b1dSJustin T. Gibbs * Traverse the list of peripherals and attempt to find 30218b8a9b1dSJustin T. Gibbs * the requested peripheral. 30228b8a9b1dSJustin T. Gibbs */ 30238b8a9b1dSJustin T. Gibbs for (nperiph = periph_head->slh_first, i = 0; 30248b8a9b1dSJustin T. Gibbs (nperiph != NULL) && (i <= cgdl->index); 30258b8a9b1dSJustin T. Gibbs nperiph = nperiph->periph_links.sle_next, i++) { 30268b8a9b1dSJustin T. Gibbs if (i == cgdl->index) { 30278b8a9b1dSJustin T. Gibbs strncpy(cgdl->periph_name, 30288b8a9b1dSJustin T. Gibbs nperiph->periph_name, 30298b8a9b1dSJustin T. Gibbs DEV_IDLEN); 30308b8a9b1dSJustin T. Gibbs cgdl->unit_number = nperiph->unit_number; 30318b8a9b1dSJustin T. Gibbs found = 1; 30328b8a9b1dSJustin T. Gibbs } 30338b8a9b1dSJustin T. Gibbs } 30348b8a9b1dSJustin T. Gibbs if (found == 0) { 30358b8a9b1dSJustin T. Gibbs cgdl->status = CAM_GDEVLIST_ERROR; 30368b8a9b1dSJustin T. Gibbs splx(s); 30378b8a9b1dSJustin T. Gibbs break; 30388b8a9b1dSJustin T. Gibbs } 30398b8a9b1dSJustin T. Gibbs 30408b8a9b1dSJustin T. Gibbs if (nperiph == NULL) 30418b8a9b1dSJustin T. Gibbs cgdl->status = CAM_GDEVLIST_LAST_DEVICE; 30428b8a9b1dSJustin T. Gibbs else 30438b8a9b1dSJustin T. Gibbs cgdl->status = CAM_GDEVLIST_MORE_DEVS; 30448b8a9b1dSJustin T. Gibbs 30458b8a9b1dSJustin T. Gibbs cgdl->index++; 30468b8a9b1dSJustin T. Gibbs cgdl->generation = device->generation; 30478b8a9b1dSJustin T. Gibbs 30488b8a9b1dSJustin T. Gibbs splx(s); 30498b8a9b1dSJustin T. Gibbs cgdl->ccb_h.status = CAM_REQ_CMP; 30508b8a9b1dSJustin T. Gibbs break; 30518b8a9b1dSJustin T. Gibbs } 30528b8a9b1dSJustin T. Gibbs case XPT_DEV_MATCH: 30538b8a9b1dSJustin T. Gibbs { 30548b8a9b1dSJustin T. Gibbs int s; 30558b8a9b1dSJustin T. Gibbs dev_pos_type position_type; 30568b8a9b1dSJustin T. Gibbs struct ccb_dev_match *cdm; 30578b8a9b1dSJustin T. Gibbs int ret; 30588b8a9b1dSJustin T. Gibbs 30598b8a9b1dSJustin T. Gibbs cdm = &start_ccb->cdm; 30608b8a9b1dSJustin T. Gibbs 30618b8a9b1dSJustin T. Gibbs /* 30628b8a9b1dSJustin T. Gibbs * Prevent EDT changes while we traverse it. 30638b8a9b1dSJustin T. Gibbs */ 3064a5479bc5SJustin T. Gibbs s = splcam(); 30658b8a9b1dSJustin T. Gibbs /* 30668b8a9b1dSJustin T. Gibbs * There are two ways of getting at information in the EDT. 30678b8a9b1dSJustin T. Gibbs * The first way is via the primary EDT tree. It starts 30688b8a9b1dSJustin T. Gibbs * with a list of busses, then a list of targets on a bus, 30698b8a9b1dSJustin T. Gibbs * then devices/luns on a target, and then peripherals on a 30708b8a9b1dSJustin T. Gibbs * device/lun. The "other" way is by the peripheral driver 30718b8a9b1dSJustin T. Gibbs * lists. The peripheral driver lists are organized by 30728b8a9b1dSJustin T. Gibbs * peripheral driver. (obviously) So it makes sense to 30738b8a9b1dSJustin T. Gibbs * use the peripheral driver list if the user is looking 30748b8a9b1dSJustin T. Gibbs * for something like "da1", or all "da" devices. If the 30758b8a9b1dSJustin T. Gibbs * user is looking for something on a particular bus/target 30768b8a9b1dSJustin T. Gibbs * or lun, it's generally better to go through the EDT tree. 30778b8a9b1dSJustin T. Gibbs */ 30788b8a9b1dSJustin T. Gibbs 30798b8a9b1dSJustin T. Gibbs if (cdm->pos.position_type != CAM_DEV_POS_NONE) 30808b8a9b1dSJustin T. Gibbs position_type = cdm->pos.position_type; 30818b8a9b1dSJustin T. Gibbs else { 30828b8a9b1dSJustin T. Gibbs int i; 30838b8a9b1dSJustin T. Gibbs 30848b8a9b1dSJustin T. Gibbs position_type = CAM_DEV_POS_NONE; 30858b8a9b1dSJustin T. Gibbs 30868b8a9b1dSJustin T. Gibbs for (i = 0; i < cdm->num_patterns; i++) { 30878b8a9b1dSJustin T. Gibbs if ((cdm->patterns[i].type == DEV_MATCH_BUS) 30888b8a9b1dSJustin T. Gibbs ||(cdm->patterns[i].type == DEV_MATCH_DEVICE)){ 30898b8a9b1dSJustin T. Gibbs position_type = CAM_DEV_POS_EDT; 30908b8a9b1dSJustin T. Gibbs break; 30918b8a9b1dSJustin T. Gibbs } 30928b8a9b1dSJustin T. Gibbs } 30938b8a9b1dSJustin T. Gibbs 30948b8a9b1dSJustin T. Gibbs if (cdm->num_patterns == 0) 30958b8a9b1dSJustin T. Gibbs position_type = CAM_DEV_POS_EDT; 30968b8a9b1dSJustin T. Gibbs else if (position_type == CAM_DEV_POS_NONE) 30978b8a9b1dSJustin T. Gibbs position_type = CAM_DEV_POS_PDRV; 30988b8a9b1dSJustin T. Gibbs } 30998b8a9b1dSJustin T. Gibbs 31008b8a9b1dSJustin T. Gibbs switch(position_type & CAM_DEV_POS_TYPEMASK) { 31018b8a9b1dSJustin T. Gibbs case CAM_DEV_POS_EDT: 31028b8a9b1dSJustin T. Gibbs ret = xptedtmatch(cdm); 31038b8a9b1dSJustin T. Gibbs break; 31048b8a9b1dSJustin T. Gibbs case CAM_DEV_POS_PDRV: 31058b8a9b1dSJustin T. Gibbs ret = xptperiphlistmatch(cdm); 31068b8a9b1dSJustin T. Gibbs break; 31078b8a9b1dSJustin T. Gibbs default: 31088b8a9b1dSJustin T. Gibbs cdm->status = CAM_DEV_MATCH_ERROR; 31098b8a9b1dSJustin T. Gibbs break; 31108b8a9b1dSJustin T. Gibbs } 31118b8a9b1dSJustin T. Gibbs 31128b8a9b1dSJustin T. Gibbs splx(s); 31138b8a9b1dSJustin T. Gibbs 31148b8a9b1dSJustin T. Gibbs if (cdm->status == CAM_DEV_MATCH_ERROR) 31158b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.status = CAM_REQ_CMP_ERR; 31168b8a9b1dSJustin T. Gibbs else 31178b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.status = CAM_REQ_CMP; 31188b8a9b1dSJustin T. Gibbs 31198b8a9b1dSJustin T. Gibbs break; 31208b8a9b1dSJustin T. Gibbs } 31218b8a9b1dSJustin T. Gibbs case XPT_SASYNC_CB: 31228b8a9b1dSJustin T. Gibbs { 31238b8a9b1dSJustin T. Gibbs struct ccb_setasync *csa; 31248b8a9b1dSJustin T. Gibbs struct async_node *cur_entry; 31258b8a9b1dSJustin T. Gibbs struct async_list *async_head; 31268b8a9b1dSJustin T. Gibbs u_int32_t added; 31278b8a9b1dSJustin T. Gibbs int s; 31288b8a9b1dSJustin T. Gibbs 31298b8a9b1dSJustin T. Gibbs csa = &start_ccb->csa; 31308b8a9b1dSJustin T. Gibbs added = csa->event_enable; 31318b8a9b1dSJustin T. Gibbs async_head = &csa->ccb_h.path->device->asyncs; 31328b8a9b1dSJustin T. Gibbs 31338b8a9b1dSJustin T. Gibbs /* 31348b8a9b1dSJustin T. Gibbs * If there is already an entry for us, simply 31358b8a9b1dSJustin T. Gibbs * update it. 31368b8a9b1dSJustin T. Gibbs */ 3137a5479bc5SJustin T. Gibbs s = splcam(); 31388b8a9b1dSJustin T. Gibbs cur_entry = SLIST_FIRST(async_head); 31398b8a9b1dSJustin T. Gibbs while (cur_entry != NULL) { 31408b8a9b1dSJustin T. Gibbs if ((cur_entry->callback_arg == csa->callback_arg) 31418b8a9b1dSJustin T. Gibbs && (cur_entry->callback == csa->callback)) 31428b8a9b1dSJustin T. Gibbs break; 31438b8a9b1dSJustin T. Gibbs cur_entry = SLIST_NEXT(cur_entry, links); 31448b8a9b1dSJustin T. Gibbs } 31458b8a9b1dSJustin T. Gibbs 31468b8a9b1dSJustin T. Gibbs if (cur_entry != NULL) { 31478b8a9b1dSJustin T. Gibbs /* 31488b8a9b1dSJustin T. Gibbs * If the request has no flags set, 31498b8a9b1dSJustin T. Gibbs * remove the entry. 31508b8a9b1dSJustin T. Gibbs */ 31518b8a9b1dSJustin T. Gibbs added &= ~cur_entry->event_enable; 31528b8a9b1dSJustin T. Gibbs if (csa->event_enable == 0) { 31538b8a9b1dSJustin T. Gibbs SLIST_REMOVE(async_head, cur_entry, 3154e3975643SJake Burkholder async_node, links); 3155c8bead2aSJustin T. Gibbs csa->ccb_h.path->device->refcount--; 31568b8a9b1dSJustin T. Gibbs free(cur_entry, M_DEVBUF); 31578b8a9b1dSJustin T. Gibbs } else { 31588b8a9b1dSJustin T. Gibbs cur_entry->event_enable = csa->event_enable; 31598b8a9b1dSJustin T. Gibbs } 31608b8a9b1dSJustin T. Gibbs } else { 31618b8a9b1dSJustin T. Gibbs cur_entry = malloc(sizeof(*cur_entry), M_DEVBUF, 31628b8a9b1dSJustin T. Gibbs M_NOWAIT); 31638b8a9b1dSJustin T. Gibbs if (cur_entry == NULL) { 31648b8a9b1dSJustin T. Gibbs splx(s); 31658b8a9b1dSJustin T. Gibbs csa->ccb_h.status = CAM_RESRC_UNAVAIL; 31668b8a9b1dSJustin T. Gibbs break; 31678b8a9b1dSJustin T. Gibbs } 3168434bbf6eSJustin T. Gibbs cur_entry->event_enable = csa->event_enable; 31698b8a9b1dSJustin T. Gibbs cur_entry->callback_arg = csa->callback_arg; 31708b8a9b1dSJustin T. Gibbs cur_entry->callback = csa->callback; 31718b8a9b1dSJustin T. Gibbs SLIST_INSERT_HEAD(async_head, cur_entry, links); 3172c8bead2aSJustin T. Gibbs csa->ccb_h.path->device->refcount++; 31738b8a9b1dSJustin T. Gibbs } 31748b8a9b1dSJustin T. Gibbs 31758b8a9b1dSJustin T. Gibbs if ((added & AC_FOUND_DEVICE) != 0) { 31768b8a9b1dSJustin T. Gibbs /* 31778b8a9b1dSJustin T. Gibbs * Get this peripheral up to date with all 31788b8a9b1dSJustin T. Gibbs * the currently existing devices. 31798b8a9b1dSJustin T. Gibbs */ 31808b8a9b1dSJustin T. Gibbs xpt_for_all_devices(xptsetasyncfunc, cur_entry); 31818b8a9b1dSJustin T. Gibbs } 31828b8a9b1dSJustin T. Gibbs if ((added & AC_PATH_REGISTERED) != 0) { 31838b8a9b1dSJustin T. Gibbs /* 31848b8a9b1dSJustin T. Gibbs * Get this peripheral up to date with all 31858b8a9b1dSJustin T. Gibbs * the currently existing busses. 31868b8a9b1dSJustin T. Gibbs */ 31878b8a9b1dSJustin T. Gibbs xpt_for_all_busses(xptsetasyncbusfunc, cur_entry); 31888b8a9b1dSJustin T. Gibbs } 31898b8a9b1dSJustin T. Gibbs splx(s); 31908b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.status = CAM_REQ_CMP; 31918b8a9b1dSJustin T. Gibbs break; 31928b8a9b1dSJustin T. Gibbs } 31938b8a9b1dSJustin T. Gibbs case XPT_REL_SIMQ: 31948b8a9b1dSJustin T. Gibbs { 31958b8a9b1dSJustin T. Gibbs struct ccb_relsim *crs; 31968b8a9b1dSJustin T. Gibbs struct cam_ed *dev; 31978b8a9b1dSJustin T. Gibbs int s; 31988b8a9b1dSJustin T. Gibbs 31998b8a9b1dSJustin T. Gibbs crs = &start_ccb->crs; 32008b8a9b1dSJustin T. Gibbs dev = crs->ccb_h.path->device; 32018b8a9b1dSJustin T. Gibbs if (dev == NULL) { 32028b8a9b1dSJustin T. Gibbs 32038b8a9b1dSJustin T. Gibbs crs->ccb_h.status = CAM_DEV_NOT_THERE; 32048b8a9b1dSJustin T. Gibbs break; 32058b8a9b1dSJustin T. Gibbs } 32068b8a9b1dSJustin T. Gibbs 32078b8a9b1dSJustin T. Gibbs s = splcam(); 32088b8a9b1dSJustin T. Gibbs 32098b8a9b1dSJustin T. Gibbs if ((crs->release_flags & RELSIM_ADJUST_OPENINGS) != 0) { 32108b8a9b1dSJustin T. Gibbs 32118b8a9b1dSJustin T. Gibbs if ((dev->inq_data.flags & SID_CmdQue) != 0) { 32128b8a9b1dSJustin T. Gibbs 32138b8a9b1dSJustin T. Gibbs /* Don't ever go below one opening */ 32148b8a9b1dSJustin T. Gibbs if (crs->openings > 0) { 32158b8a9b1dSJustin T. Gibbs xpt_dev_ccbq_resize(crs->ccb_h.path, 32168b8a9b1dSJustin T. Gibbs crs->openings); 32178b8a9b1dSJustin T. Gibbs 321879ccc199SJordan K. Hubbard if (bootverbose) { 32198b8a9b1dSJustin T. Gibbs xpt_print_path(crs->ccb_h.path); 32208b8a9b1dSJustin T. Gibbs printf("tagged openings " 32218b8a9b1dSJustin T. Gibbs "now %d\n", 32228b8a9b1dSJustin T. Gibbs crs->openings); 32238b8a9b1dSJustin T. Gibbs } 32248b8a9b1dSJustin T. Gibbs } 32258b8a9b1dSJustin T. Gibbs } 32268b8a9b1dSJustin T. Gibbs } 32278b8a9b1dSJustin T. Gibbs 32288b8a9b1dSJustin T. Gibbs if ((crs->release_flags & RELSIM_RELEASE_AFTER_TIMEOUT) != 0) { 32298b8a9b1dSJustin T. Gibbs 32308b8a9b1dSJustin T. Gibbs if ((dev->flags & CAM_DEV_REL_TIMEOUT_PENDING) != 0) { 32318b8a9b1dSJustin T. Gibbs 32328b8a9b1dSJustin T. Gibbs /* 32338b8a9b1dSJustin T. Gibbs * Just extend the old timeout and decrement 32348b8a9b1dSJustin T. Gibbs * the freeze count so that a single timeout 32358b8a9b1dSJustin T. Gibbs * is sufficient for releasing the queue. 32368b8a9b1dSJustin T. Gibbs */ 32378b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.flags &= ~CAM_DEV_QFREEZE; 32388b8a9b1dSJustin T. Gibbs untimeout(xpt_release_devq_timeout, 32398b8a9b1dSJustin T. Gibbs dev, dev->c_handle); 32408b8a9b1dSJustin T. Gibbs } else { 32418b8a9b1dSJustin T. Gibbs 32428b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.flags |= CAM_DEV_QFREEZE; 32438b8a9b1dSJustin T. Gibbs } 32448b8a9b1dSJustin T. Gibbs 32458b8a9b1dSJustin T. Gibbs dev->c_handle = 32468b8a9b1dSJustin T. Gibbs timeout(xpt_release_devq_timeout, 32478b8a9b1dSJustin T. Gibbs dev, 32488b8a9b1dSJustin T. Gibbs (crs->release_timeout * hz) / 1000); 32498b8a9b1dSJustin T. Gibbs 32508b8a9b1dSJustin T. Gibbs dev->flags |= CAM_DEV_REL_TIMEOUT_PENDING; 32518b8a9b1dSJustin T. Gibbs 32528b8a9b1dSJustin T. Gibbs } 32538b8a9b1dSJustin T. Gibbs 32548b8a9b1dSJustin T. Gibbs if ((crs->release_flags & RELSIM_RELEASE_AFTER_CMDCMPLT) != 0) { 32558b8a9b1dSJustin T. Gibbs 32568b8a9b1dSJustin T. Gibbs if ((dev->flags & CAM_DEV_REL_ON_COMPLETE) != 0) { 32578b8a9b1dSJustin T. Gibbs /* 32588b8a9b1dSJustin T. Gibbs * Decrement the freeze count so that a single 32598b8a9b1dSJustin T. Gibbs * completion is still sufficient to unfreeze 32608b8a9b1dSJustin T. Gibbs * the queue. 32618b8a9b1dSJustin T. Gibbs */ 32628b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.flags &= ~CAM_DEV_QFREEZE; 32638b8a9b1dSJustin T. Gibbs } else { 32648b8a9b1dSJustin T. Gibbs 32658b8a9b1dSJustin T. Gibbs dev->flags |= CAM_DEV_REL_ON_COMPLETE; 32668b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.flags |= CAM_DEV_QFREEZE; 32678b8a9b1dSJustin T. Gibbs } 32688b8a9b1dSJustin T. Gibbs } 32698b8a9b1dSJustin T. Gibbs 32708b8a9b1dSJustin T. Gibbs if ((crs->release_flags & RELSIM_RELEASE_AFTER_QEMPTY) != 0) { 32718b8a9b1dSJustin T. Gibbs 32728b8a9b1dSJustin T. Gibbs if ((dev->flags & CAM_DEV_REL_ON_QUEUE_EMPTY) != 0 32738b8a9b1dSJustin T. Gibbs || (dev->ccbq.dev_active == 0)) { 32748b8a9b1dSJustin T. Gibbs 32758b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.flags &= ~CAM_DEV_QFREEZE; 32768b8a9b1dSJustin T. Gibbs } else { 32778b8a9b1dSJustin T. Gibbs 32788b8a9b1dSJustin T. Gibbs dev->flags |= CAM_DEV_REL_ON_QUEUE_EMPTY; 32798b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.flags |= CAM_DEV_QFREEZE; 32808b8a9b1dSJustin T. Gibbs } 32818b8a9b1dSJustin T. Gibbs } 32828b8a9b1dSJustin T. Gibbs splx(s); 32838b8a9b1dSJustin T. Gibbs 32848b8a9b1dSJustin T. Gibbs if ((start_ccb->ccb_h.flags & CAM_DEV_QFREEZE) == 0) { 32858b8a9b1dSJustin T. Gibbs 32862cefde5fSJustin T. Gibbs xpt_release_devq(crs->ccb_h.path, /*count*/1, 32878b8a9b1dSJustin T. Gibbs /*run_queue*/TRUE); 32888b8a9b1dSJustin T. Gibbs } 32898b8a9b1dSJustin T. Gibbs start_ccb->crs.qfrozen_cnt = dev->qfrozen_cnt; 32908b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.status = CAM_REQ_CMP; 32918b8a9b1dSJustin T. Gibbs break; 32928b8a9b1dSJustin T. Gibbs } 32938b8a9b1dSJustin T. Gibbs case XPT_SCAN_BUS: 32948b8a9b1dSJustin T. Gibbs xpt_scan_bus(start_ccb->ccb_h.path->periph, start_ccb); 32958b8a9b1dSJustin T. Gibbs break; 32968b8a9b1dSJustin T. Gibbs case XPT_SCAN_LUN: 32978b8a9b1dSJustin T. Gibbs xpt_scan_lun(start_ccb->ccb_h.path->periph, 32988b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.path, start_ccb->crcn.flags, 32998b8a9b1dSJustin T. Gibbs start_ccb); 33008b8a9b1dSJustin T. Gibbs break; 33018b8a9b1dSJustin T. Gibbs case XPT_DEBUG: { 33028b8a9b1dSJustin T. Gibbs #ifdef CAMDEBUG 33038b8a9b1dSJustin T. Gibbs int s; 33048b8a9b1dSJustin T. Gibbs 33058b8a9b1dSJustin T. Gibbs s = splcam(); 33062cefde5fSJustin T. Gibbs #ifdef CAM_DEBUG_DELAY 33072cefde5fSJustin T. Gibbs cam_debug_delay = CAM_DEBUG_DELAY; 33082cefde5fSJustin T. Gibbs #endif 33098b8a9b1dSJustin T. Gibbs cam_dflags = start_ccb->cdbg.flags; 33108b8a9b1dSJustin T. Gibbs if (cam_dpath != NULL) { 33118b8a9b1dSJustin T. Gibbs xpt_free_path(cam_dpath); 33128b8a9b1dSJustin T. Gibbs cam_dpath = NULL; 33138b8a9b1dSJustin T. Gibbs } 33148b8a9b1dSJustin T. Gibbs 33158b8a9b1dSJustin T. Gibbs if (cam_dflags != CAM_DEBUG_NONE) { 33168b8a9b1dSJustin T. Gibbs if (xpt_create_path(&cam_dpath, xpt_periph, 33178b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.path_id, 33188b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.target_id, 33198b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.target_lun) != 33208b8a9b1dSJustin T. Gibbs CAM_REQ_CMP) { 33218b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.status = CAM_RESRC_UNAVAIL; 33228b8a9b1dSJustin T. Gibbs cam_dflags = CAM_DEBUG_NONE; 3323aa872be6SMatt Jacob } else { 33248b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.status = CAM_REQ_CMP; 3325aa872be6SMatt Jacob xpt_print_path(cam_dpath); 3326aa872be6SMatt Jacob printf("debugging flags now %x\n", cam_dflags); 3327aa872be6SMatt Jacob } 33288b8a9b1dSJustin T. Gibbs } else { 33298b8a9b1dSJustin T. Gibbs cam_dpath = NULL; 33308b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.status = CAM_REQ_CMP; 33318b8a9b1dSJustin T. Gibbs } 33328b8a9b1dSJustin T. Gibbs splx(s); 33338b8a9b1dSJustin T. Gibbs #else /* !CAMDEBUG */ 33348b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.status = CAM_FUNC_NOTAVAIL; 33358b8a9b1dSJustin T. Gibbs #endif /* CAMDEBUG */ 33368b8a9b1dSJustin T. Gibbs break; 33378b8a9b1dSJustin T. Gibbs } 33388b8a9b1dSJustin T. Gibbs case XPT_NOOP: 333987cfaf0eSJustin T. Gibbs if ((start_ccb->ccb_h.flags & CAM_DEV_QFREEZE) != 0) 334087cfaf0eSJustin T. Gibbs xpt_freeze_devq(start_ccb->ccb_h.path, 1); 33418b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.status = CAM_REQ_CMP; 33428b8a9b1dSJustin T. Gibbs break; 33438b8a9b1dSJustin T. Gibbs default: 33448b8a9b1dSJustin T. Gibbs case XPT_SDEV_TYPE: 33458b8a9b1dSJustin T. Gibbs case XPT_TERM_IO: 33468b8a9b1dSJustin T. Gibbs case XPT_ENG_INQ: 33478b8a9b1dSJustin T. Gibbs /* XXX Implement */ 33488b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.status = CAM_PROVIDE_FAIL; 33498b8a9b1dSJustin T. Gibbs break; 33508b8a9b1dSJustin T. Gibbs } 33519911ecf9SJustin T. Gibbs splx(iopl); 33528b8a9b1dSJustin T. Gibbs } 33538b8a9b1dSJustin T. Gibbs 33548b8a9b1dSJustin T. Gibbs void 33558b8a9b1dSJustin T. Gibbs xpt_polled_action(union ccb *start_ccb) 33568b8a9b1dSJustin T. Gibbs { 33578b8a9b1dSJustin T. Gibbs int s; 33588b8a9b1dSJustin T. Gibbs u_int32_t timeout; 33598b8a9b1dSJustin T. Gibbs struct cam_sim *sim; 33608b8a9b1dSJustin T. Gibbs struct cam_devq *devq; 33618b8a9b1dSJustin T. Gibbs struct cam_ed *dev; 33628b8a9b1dSJustin T. Gibbs 33638b8a9b1dSJustin T. Gibbs timeout = start_ccb->ccb_h.timeout; 33648b8a9b1dSJustin T. Gibbs sim = start_ccb->ccb_h.path->bus->sim; 33658b8a9b1dSJustin T. Gibbs devq = sim->devq; 33668b8a9b1dSJustin T. Gibbs dev = start_ccb->ccb_h.path->device; 33678b8a9b1dSJustin T. Gibbs 33688b8a9b1dSJustin T. Gibbs s = splcam(); 33698b8a9b1dSJustin T. Gibbs 33708b8a9b1dSJustin T. Gibbs /* 33718b8a9b1dSJustin T. Gibbs * Steal an opening so that no other queued requests 33728b8a9b1dSJustin T. Gibbs * can get it before us while we simulate interrupts. 33738b8a9b1dSJustin T. Gibbs */ 33748b8a9b1dSJustin T. Gibbs dev->ccbq.devq_openings--; 33758b8a9b1dSJustin T. Gibbs dev->ccbq.dev_openings--; 33768b8a9b1dSJustin T. Gibbs 33778b8a9b1dSJustin T. Gibbs while((devq->send_openings <= 0 || dev->ccbq.dev_openings < 0) 33788b8a9b1dSJustin T. Gibbs && (--timeout > 0)) { 33798b8a9b1dSJustin T. Gibbs DELAY(1000); 33808b8a9b1dSJustin T. Gibbs (*(sim->sim_poll))(sim); 33818b8a9b1dSJustin T. Gibbs swi_camnet(); 33828b8a9b1dSJustin T. Gibbs swi_cambio(); 33838b8a9b1dSJustin T. Gibbs } 33848b8a9b1dSJustin T. Gibbs 33858b8a9b1dSJustin T. Gibbs dev->ccbq.devq_openings++; 33868b8a9b1dSJustin T. Gibbs dev->ccbq.dev_openings++; 33878b8a9b1dSJustin T. Gibbs 33888b8a9b1dSJustin T. Gibbs if (timeout != 0) { 33898b8a9b1dSJustin T. Gibbs xpt_action(start_ccb); 33908b8a9b1dSJustin T. Gibbs while(--timeout > 0) { 33918b8a9b1dSJustin T. Gibbs (*(sim->sim_poll))(sim); 33928b8a9b1dSJustin T. Gibbs swi_camnet(); 33938b8a9b1dSJustin T. Gibbs swi_cambio(); 33948b8a9b1dSJustin T. Gibbs if ((start_ccb->ccb_h.status & CAM_STATUS_MASK) 33958b8a9b1dSJustin T. Gibbs != CAM_REQ_INPROG) 33968b8a9b1dSJustin T. Gibbs break; 33978b8a9b1dSJustin T. Gibbs DELAY(1000); 33988b8a9b1dSJustin T. Gibbs } 33998b8a9b1dSJustin T. Gibbs if (timeout == 0) { 34008b8a9b1dSJustin T. Gibbs /* 34018b8a9b1dSJustin T. Gibbs * XXX Is it worth adding a sim_timeout entry 34028b8a9b1dSJustin T. Gibbs * point so we can attempt recovery? If 34038b8a9b1dSJustin T. Gibbs * this is only used for dumps, I don't think 34048b8a9b1dSJustin T. Gibbs * it is. 34058b8a9b1dSJustin T. Gibbs */ 34068b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.status = CAM_CMD_TIMEOUT; 34078b8a9b1dSJustin T. Gibbs } 34088b8a9b1dSJustin T. Gibbs } else { 34098b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.status = CAM_RESRC_UNAVAIL; 34108b8a9b1dSJustin T. Gibbs } 34118b8a9b1dSJustin T. Gibbs splx(s); 34128b8a9b1dSJustin T. Gibbs } 34138b8a9b1dSJustin T. Gibbs 34148b8a9b1dSJustin T. Gibbs /* 34158b8a9b1dSJustin T. Gibbs * Schedule a peripheral driver to receive a ccb when it's 34168b8a9b1dSJustin T. Gibbs * target device has space for more transactions. 34178b8a9b1dSJustin T. Gibbs */ 34188b8a9b1dSJustin T. Gibbs void 34198b8a9b1dSJustin T. Gibbs xpt_schedule(struct cam_periph *perph, u_int32_t new_priority) 34208b8a9b1dSJustin T. Gibbs { 34218b8a9b1dSJustin T. Gibbs struct cam_ed *device; 34228b8a9b1dSJustin T. Gibbs int s; 34238b8a9b1dSJustin T. Gibbs int runq; 34248b8a9b1dSJustin T. Gibbs 34258b8a9b1dSJustin T. Gibbs CAM_DEBUG(perph->path, CAM_DEBUG_TRACE, ("xpt_schedule\n")); 34268b8a9b1dSJustin T. Gibbs device = perph->path->device; 34278b8a9b1dSJustin T. Gibbs s = splsoftcam(); 34288b8a9b1dSJustin T. Gibbs if (periph_is_queued(perph)) { 34298b8a9b1dSJustin T. Gibbs /* Simply reorder based on new priority */ 34308b8a9b1dSJustin T. Gibbs CAM_DEBUG(perph->path, CAM_DEBUG_SUBTRACE, 34318b8a9b1dSJustin T. Gibbs (" change priority to %d\n", new_priority)); 34328b8a9b1dSJustin T. Gibbs if (new_priority < perph->pinfo.priority) { 34338b8a9b1dSJustin T. Gibbs camq_change_priority(&device->drvq, 34348b8a9b1dSJustin T. Gibbs perph->pinfo.index, 34358b8a9b1dSJustin T. Gibbs new_priority); 34368b8a9b1dSJustin T. Gibbs } 34378b8a9b1dSJustin T. Gibbs runq = 0; 34388b8a9b1dSJustin T. Gibbs } else { 34398b8a9b1dSJustin T. Gibbs /* New entry on the queue */ 34408b8a9b1dSJustin T. Gibbs CAM_DEBUG(perph->path, CAM_DEBUG_SUBTRACE, 34418b8a9b1dSJustin T. Gibbs (" added periph to queue\n")); 34428b8a9b1dSJustin T. Gibbs perph->pinfo.priority = new_priority; 34438bad620dSJustin T. Gibbs perph->pinfo.generation = ++device->drvq.generation; 34448b8a9b1dSJustin T. Gibbs camq_insert(&device->drvq, &perph->pinfo); 34458b8a9b1dSJustin T. Gibbs runq = xpt_schedule_dev_allocq(perph->path->bus, device); 34468b8a9b1dSJustin T. Gibbs } 34478b8a9b1dSJustin T. Gibbs splx(s); 34488b8a9b1dSJustin T. Gibbs if (runq != 0) { 34498b8a9b1dSJustin T. Gibbs CAM_DEBUG(perph->path, CAM_DEBUG_SUBTRACE, 34508b8a9b1dSJustin T. Gibbs (" calling xpt_run_devq\n")); 34518b8a9b1dSJustin T. Gibbs xpt_run_dev_allocq(perph->path->bus); 34528b8a9b1dSJustin T. Gibbs } 34538b8a9b1dSJustin T. Gibbs } 34548b8a9b1dSJustin T. Gibbs 34558b8a9b1dSJustin T. Gibbs 34568b8a9b1dSJustin T. Gibbs /* 34578b8a9b1dSJustin T. Gibbs * Schedule a device to run on a given queue. 34588b8a9b1dSJustin T. Gibbs * If the device was inserted as a new entry on the queue, 34598b8a9b1dSJustin T. Gibbs * return 1 meaning the device queue should be run. If we 34608b8a9b1dSJustin T. Gibbs * were already queued, implying someone else has already 34618b8a9b1dSJustin T. Gibbs * started the queue, return 0 so the caller doesn't attempt 34628b8a9b1dSJustin T. Gibbs * to run the queue. Must be run at either splsoftcam 34638b8a9b1dSJustin T. Gibbs * (or splcam since that encompases splsoftcam). 34648b8a9b1dSJustin T. Gibbs */ 34658b8a9b1dSJustin T. Gibbs static int 34668b8a9b1dSJustin T. Gibbs xpt_schedule_dev(struct camq *queue, cam_pinfo *pinfo, 34678b8a9b1dSJustin T. Gibbs u_int32_t new_priority) 34688b8a9b1dSJustin T. Gibbs { 34698b8a9b1dSJustin T. Gibbs int retval; 34708b8a9b1dSJustin T. Gibbs u_int32_t old_priority; 34718b8a9b1dSJustin T. Gibbs 3472aa872be6SMatt Jacob CAM_DEBUG_PRINT(CAM_DEBUG_XPT, ("xpt_schedule_dev\n")); 34738b8a9b1dSJustin T. Gibbs 34748b8a9b1dSJustin T. Gibbs old_priority = pinfo->priority; 34758b8a9b1dSJustin T. Gibbs 34768b8a9b1dSJustin T. Gibbs /* 34778b8a9b1dSJustin T. Gibbs * Are we already queued? 34788b8a9b1dSJustin T. Gibbs */ 34798b8a9b1dSJustin T. Gibbs if (pinfo->index != CAM_UNQUEUED_INDEX) { 34808b8a9b1dSJustin T. Gibbs /* Simply reorder based on new priority */ 34818b8a9b1dSJustin T. Gibbs if (new_priority < old_priority) { 34828b8a9b1dSJustin T. Gibbs camq_change_priority(queue, pinfo->index, 34838b8a9b1dSJustin T. Gibbs new_priority); 3484aa872be6SMatt Jacob CAM_DEBUG_PRINT(CAM_DEBUG_XPT, 34858b8a9b1dSJustin T. Gibbs ("changed priority to %d\n", 34868b8a9b1dSJustin T. Gibbs new_priority)); 34878b8a9b1dSJustin T. Gibbs } 34888b8a9b1dSJustin T. Gibbs retval = 0; 34898b8a9b1dSJustin T. Gibbs } else { 34908b8a9b1dSJustin T. Gibbs /* New entry on the queue */ 34918b8a9b1dSJustin T. Gibbs if (new_priority < old_priority) 34928b8a9b1dSJustin T. Gibbs pinfo->priority = new_priority; 34938b8a9b1dSJustin T. Gibbs 3494aa872be6SMatt Jacob CAM_DEBUG_PRINT(CAM_DEBUG_XPT, 34958b8a9b1dSJustin T. Gibbs ("Inserting onto queue\n")); 34968bad620dSJustin T. Gibbs pinfo->generation = ++queue->generation; 34978b8a9b1dSJustin T. Gibbs camq_insert(queue, pinfo); 34988b8a9b1dSJustin T. Gibbs retval = 1; 34998b8a9b1dSJustin T. Gibbs } 35008b8a9b1dSJustin T. Gibbs return (retval); 35018b8a9b1dSJustin T. Gibbs } 35028b8a9b1dSJustin T. Gibbs 35038b8a9b1dSJustin T. Gibbs static void 35048b8a9b1dSJustin T. Gibbs xpt_run_dev_allocq(struct cam_eb *bus) 35058b8a9b1dSJustin T. Gibbs { 35068b8a9b1dSJustin T. Gibbs struct cam_devq *devq; 35078b8a9b1dSJustin T. Gibbs int s; 35088b8a9b1dSJustin T. Gibbs 3509aa872be6SMatt Jacob CAM_DEBUG_PRINT(CAM_DEBUG_XPT, ("xpt_run_dev_allocq\n")); 35108b8a9b1dSJustin T. Gibbs devq = bus->sim->devq; 35118b8a9b1dSJustin T. Gibbs 3512aa872be6SMatt Jacob CAM_DEBUG_PRINT(CAM_DEBUG_XPT, 35138b8a9b1dSJustin T. Gibbs (" qfrozen_cnt == 0x%x, entries == %d, " 35148b8a9b1dSJustin T. Gibbs "openings == %d, active == %d\n", 35158b8a9b1dSJustin T. Gibbs devq->alloc_queue.qfrozen_cnt, 35168b8a9b1dSJustin T. Gibbs devq->alloc_queue.entries, 35178b8a9b1dSJustin T. Gibbs devq->alloc_openings, 35188b8a9b1dSJustin T. Gibbs devq->alloc_active)); 35198b8a9b1dSJustin T. Gibbs 35208b8a9b1dSJustin T. Gibbs s = splsoftcam(); 35218b8a9b1dSJustin T. Gibbs devq->alloc_queue.qfrozen_cnt++; 35228b8a9b1dSJustin T. Gibbs while ((devq->alloc_queue.entries > 0) 35238b8a9b1dSJustin T. Gibbs && (devq->alloc_openings > 0) 35248b8a9b1dSJustin T. Gibbs && (devq->alloc_queue.qfrozen_cnt <= 1)) { 35258b8a9b1dSJustin T. Gibbs struct cam_ed_qinfo *qinfo; 35268b8a9b1dSJustin T. Gibbs struct cam_ed *device; 35278b8a9b1dSJustin T. Gibbs union ccb *work_ccb; 35288b8a9b1dSJustin T. Gibbs struct cam_periph *drv; 35298b8a9b1dSJustin T. Gibbs struct camq *drvq; 35308b8a9b1dSJustin T. Gibbs 35318b8a9b1dSJustin T. Gibbs qinfo = (struct cam_ed_qinfo *)camq_remove(&devq->alloc_queue, 35325a526431SJustin T. Gibbs CAMQ_HEAD); 35338b8a9b1dSJustin T. Gibbs device = qinfo->device; 35348b8a9b1dSJustin T. Gibbs 3535aa872be6SMatt Jacob CAM_DEBUG_PRINT(CAM_DEBUG_XPT, 353650642f18SKenneth D. Merry ("running device %p\n", device)); 35378b8a9b1dSJustin T. Gibbs 35388b8a9b1dSJustin T. Gibbs drvq = &device->drvq; 35398b8a9b1dSJustin T. Gibbs 35408b8a9b1dSJustin T. Gibbs #ifdef CAMDEBUG 35418b8a9b1dSJustin T. Gibbs if (drvq->entries <= 0) { 35428b8a9b1dSJustin T. Gibbs panic("xpt_run_dev_allocq: " 35438b8a9b1dSJustin T. Gibbs "Device on queue without any work to do"); 35448b8a9b1dSJustin T. Gibbs } 35458b8a9b1dSJustin T. Gibbs #endif 35468b8a9b1dSJustin T. Gibbs if ((work_ccb = xpt_get_ccb(device)) != NULL) { 35478b8a9b1dSJustin T. Gibbs devq->alloc_openings--; 35488b8a9b1dSJustin T. Gibbs devq->alloc_active++; 35495a526431SJustin T. Gibbs drv = (struct cam_periph*)camq_remove(drvq, CAMQ_HEAD); 35508b8a9b1dSJustin T. Gibbs splx(s); 35518b8a9b1dSJustin T. Gibbs xpt_setup_ccb(&work_ccb->ccb_h, drv->path, 35528b8a9b1dSJustin T. Gibbs drv->pinfo.priority); 3553aa872be6SMatt Jacob CAM_DEBUG_PRINT(CAM_DEBUG_XPT, 35548b8a9b1dSJustin T. Gibbs ("calling periph start\n")); 35558b8a9b1dSJustin T. Gibbs drv->periph_start(drv, work_ccb); 35568b8a9b1dSJustin T. Gibbs } else { 35578b8a9b1dSJustin T. Gibbs /* 35588b8a9b1dSJustin T. Gibbs * Malloc failure in alloc_ccb 35598b8a9b1dSJustin T. Gibbs */ 35608b8a9b1dSJustin T. Gibbs /* 35618b8a9b1dSJustin T. Gibbs * XXX add us to a list to be run from free_ccb 35628b8a9b1dSJustin T. Gibbs * if we don't have any ccbs active on this 35638b8a9b1dSJustin T. Gibbs * device queue otherwise we may never get run 35648b8a9b1dSJustin T. Gibbs * again. 35658b8a9b1dSJustin T. Gibbs */ 35668b8a9b1dSJustin T. Gibbs break; 35678b8a9b1dSJustin T. Gibbs } 35688b8a9b1dSJustin T. Gibbs 35698b8a9b1dSJustin T. Gibbs /* Raise IPL for possible insertion and test at top of loop */ 35708b8a9b1dSJustin T. Gibbs s = splsoftcam(); 35718b8a9b1dSJustin T. Gibbs 35728b8a9b1dSJustin T. Gibbs if (drvq->entries > 0) { 35738b8a9b1dSJustin T. Gibbs /* We have more work. Attempt to reschedule */ 35748b8a9b1dSJustin T. Gibbs xpt_schedule_dev_allocq(bus, device); 35758b8a9b1dSJustin T. Gibbs } 35768b8a9b1dSJustin T. Gibbs } 35778b8a9b1dSJustin T. Gibbs devq->alloc_queue.qfrozen_cnt--; 35788b8a9b1dSJustin T. Gibbs splx(s); 35798b8a9b1dSJustin T. Gibbs } 35808b8a9b1dSJustin T. Gibbs 35818b8a9b1dSJustin T. Gibbs static void 35828b8a9b1dSJustin T. Gibbs xpt_run_dev_sendq(struct cam_eb *bus) 35838b8a9b1dSJustin T. Gibbs { 35848b8a9b1dSJustin T. Gibbs struct cam_devq *devq; 35858b8a9b1dSJustin T. Gibbs int s; 35868b8a9b1dSJustin T. Gibbs 3587aa872be6SMatt Jacob CAM_DEBUG_PRINT(CAM_DEBUG_XPT, ("xpt_run_dev_sendq\n")); 35888b8a9b1dSJustin T. Gibbs 35898b8a9b1dSJustin T. Gibbs devq = bus->sim->devq; 35908b8a9b1dSJustin T. Gibbs 35918b8a9b1dSJustin T. Gibbs s = splcam(); 35928b8a9b1dSJustin T. Gibbs devq->send_queue.qfrozen_cnt++; 35938b8a9b1dSJustin T. Gibbs splx(s); 35948b8a9b1dSJustin T. Gibbs s = splsoftcam(); 35958b8a9b1dSJustin T. Gibbs while ((devq->send_queue.entries > 0) 35968b8a9b1dSJustin T. Gibbs && (devq->send_openings > 0)) { 35978b8a9b1dSJustin T. Gibbs struct cam_ed_qinfo *qinfo; 35988b8a9b1dSJustin T. Gibbs struct cam_ed *device; 35998b8a9b1dSJustin T. Gibbs union ccb *work_ccb; 36008b8a9b1dSJustin T. Gibbs struct cam_sim *sim; 36018b8a9b1dSJustin T. Gibbs int ospl; 36028b8a9b1dSJustin T. Gibbs 36038b8a9b1dSJustin T. Gibbs ospl = splcam(); 36048b8a9b1dSJustin T. Gibbs if (devq->send_queue.qfrozen_cnt > 1) { 36058b8a9b1dSJustin T. Gibbs splx(ospl); 36068b8a9b1dSJustin T. Gibbs break; 36078b8a9b1dSJustin T. Gibbs } 36088b8a9b1dSJustin T. Gibbs 36098b8a9b1dSJustin T. Gibbs qinfo = (struct cam_ed_qinfo *)camq_remove(&devq->send_queue, 36105a526431SJustin T. Gibbs CAMQ_HEAD); 36118b8a9b1dSJustin T. Gibbs device = qinfo->device; 36128b8a9b1dSJustin T. Gibbs 36138b8a9b1dSJustin T. Gibbs /* 36148b8a9b1dSJustin T. Gibbs * If the device has been "frozen", don't attempt 36158b8a9b1dSJustin T. Gibbs * to run it. 36168b8a9b1dSJustin T. Gibbs */ 36178b8a9b1dSJustin T. Gibbs if (device->qfrozen_cnt > 0) { 36188b8a9b1dSJustin T. Gibbs splx(ospl); 36198b8a9b1dSJustin T. Gibbs continue; 36208b8a9b1dSJustin T. Gibbs } 36218b8a9b1dSJustin T. Gibbs 3622aa872be6SMatt Jacob CAM_DEBUG_PRINT(CAM_DEBUG_XPT, 362350642f18SKenneth D. Merry ("running device %p\n", device)); 36248b8a9b1dSJustin T. Gibbs 36255a526431SJustin T. Gibbs work_ccb = cam_ccbq_peek_ccb(&device->ccbq, CAMQ_HEAD); 36268b8a9b1dSJustin T. Gibbs if (work_ccb == NULL) { 36278b8a9b1dSJustin T. Gibbs printf("device on run queue with no ccbs???"); 36288b8a9b1dSJustin T. Gibbs splx(ospl); 36298b8a9b1dSJustin T. Gibbs continue; 36308b8a9b1dSJustin T. Gibbs } 36318b8a9b1dSJustin T. Gibbs 36328b8a9b1dSJustin T. Gibbs if ((work_ccb->ccb_h.flags & CAM_HIGH_POWER) != 0) { 36338b8a9b1dSJustin T. Gibbs 36348b8a9b1dSJustin T. Gibbs if (num_highpower <= 0) { 36358b8a9b1dSJustin T. Gibbs /* 36368b8a9b1dSJustin T. Gibbs * We got a high power command, but we 36378b8a9b1dSJustin T. Gibbs * don't have any available slots. Freeze 36388b8a9b1dSJustin T. Gibbs * the device queue until we have a slot 36398b8a9b1dSJustin T. Gibbs * available. 36408b8a9b1dSJustin T. Gibbs */ 36418b8a9b1dSJustin T. Gibbs device->qfrozen_cnt++; 36428b8a9b1dSJustin T. Gibbs STAILQ_INSERT_TAIL(&highpowerq, 36438b8a9b1dSJustin T. Gibbs &work_ccb->ccb_h, 36448b8a9b1dSJustin T. Gibbs xpt_links.stqe); 36458b8a9b1dSJustin T. Gibbs 36468b8a9b1dSJustin T. Gibbs splx(ospl); 36478b8a9b1dSJustin T. Gibbs continue; 36488b8a9b1dSJustin T. Gibbs } else { 36498b8a9b1dSJustin T. Gibbs /* 36508b8a9b1dSJustin T. Gibbs * Consume a high power slot while 36518b8a9b1dSJustin T. Gibbs * this ccb runs. 36528b8a9b1dSJustin T. Gibbs */ 36538b8a9b1dSJustin T. Gibbs num_highpower--; 36548b8a9b1dSJustin T. Gibbs } 36558b8a9b1dSJustin T. Gibbs } 36568b8a9b1dSJustin T. Gibbs devq->active_dev = device; 36578b8a9b1dSJustin T. Gibbs cam_ccbq_remove_ccb(&device->ccbq, work_ccb); 36588b8a9b1dSJustin T. Gibbs 36598b8a9b1dSJustin T. Gibbs cam_ccbq_send_ccb(&device->ccbq, work_ccb); 36608b8a9b1dSJustin T. Gibbs splx(ospl); 36618b8a9b1dSJustin T. Gibbs 36628b8a9b1dSJustin T. Gibbs devq->send_openings--; 36638b8a9b1dSJustin T. Gibbs devq->send_active++; 36648b8a9b1dSJustin T. Gibbs 36655a526431SJustin T. Gibbs if (device->ccbq.queue.entries > 0) 36668b8a9b1dSJustin T. Gibbs xpt_schedule_dev_sendq(bus, device); 36678b8a9b1dSJustin T. Gibbs 36688b8a9b1dSJustin T. Gibbs if (work_ccb && (work_ccb->ccb_h.flags & CAM_DEV_QFREEZE) != 0){ 36698b8a9b1dSJustin T. Gibbs /* 36708b8a9b1dSJustin T. Gibbs * The client wants to freeze the queue 36718b8a9b1dSJustin T. Gibbs * after this CCB is sent. 36728b8a9b1dSJustin T. Gibbs */ 36738b8a9b1dSJustin T. Gibbs ospl = splcam(); 36748b8a9b1dSJustin T. Gibbs device->qfrozen_cnt++; 36758b8a9b1dSJustin T. Gibbs splx(ospl); 36768b8a9b1dSJustin T. Gibbs } 36778b8a9b1dSJustin T. Gibbs 36788b8a9b1dSJustin T. Gibbs splx(s); 36798b8a9b1dSJustin T. Gibbs 3680a4eb4f16SMatt Jacob /* In Target mode, the peripheral driver knows best... */ 3681a4eb4f16SMatt Jacob if (work_ccb->ccb_h.func_code == XPT_SCSI_IO) { 3682a4eb4f16SMatt Jacob if ((device->inq_flags & SID_CmdQue) != 0 3683a4eb4f16SMatt Jacob && work_ccb->csio.tag_action != CAM_TAG_ACTION_NONE) 36848b8a9b1dSJustin T. Gibbs work_ccb->ccb_h.flags |= CAM_TAG_ACTION_VALID; 36858b8a9b1dSJustin T. Gibbs else 36868b8a9b1dSJustin T. Gibbs /* 3687a4eb4f16SMatt Jacob * Clear this in case of a retried CCB that 3688a4eb4f16SMatt Jacob * failed due to a rejected tag. 36898b8a9b1dSJustin T. Gibbs */ 36908b8a9b1dSJustin T. Gibbs work_ccb->ccb_h.flags &= ~CAM_TAG_ACTION_VALID; 3691a4eb4f16SMatt Jacob } 36928b8a9b1dSJustin T. Gibbs 36938b8a9b1dSJustin T. Gibbs /* 36948b8a9b1dSJustin T. Gibbs * Device queues can be shared among multiple sim instances 36958b8a9b1dSJustin T. Gibbs * that reside on different busses. Use the SIM in the queue 36968b8a9b1dSJustin T. Gibbs * CCB's path, rather than the one in the bus that was passed 36978b8a9b1dSJustin T. Gibbs * into this function. 36988b8a9b1dSJustin T. Gibbs */ 36998b8a9b1dSJustin T. Gibbs sim = work_ccb->ccb_h.path->bus->sim; 37008b8a9b1dSJustin T. Gibbs (*(sim->sim_action))(sim, work_ccb); 37018b8a9b1dSJustin T. Gibbs 37028b8a9b1dSJustin T. Gibbs ospl = splcam(); 37038b8a9b1dSJustin T. Gibbs devq->active_dev = NULL; 37048b8a9b1dSJustin T. Gibbs splx(ospl); 37058b8a9b1dSJustin T. Gibbs /* Raise IPL for possible insertion and test at top of loop */ 37068b8a9b1dSJustin T. Gibbs s = splsoftcam(); 37078b8a9b1dSJustin T. Gibbs } 37088b8a9b1dSJustin T. Gibbs splx(s); 37098b8a9b1dSJustin T. Gibbs s = splcam(); 37108b8a9b1dSJustin T. Gibbs devq->send_queue.qfrozen_cnt--; 37118b8a9b1dSJustin T. Gibbs splx(s); 37128b8a9b1dSJustin T. Gibbs } 37138b8a9b1dSJustin T. Gibbs 37148b8a9b1dSJustin T. Gibbs /* 37158b8a9b1dSJustin T. Gibbs * This function merges stuff from the slave ccb into the master ccb, while 37168b8a9b1dSJustin T. Gibbs * keeping important fields in the master ccb constant. 37178b8a9b1dSJustin T. Gibbs */ 37188b8a9b1dSJustin T. Gibbs void 37198b8a9b1dSJustin T. Gibbs xpt_merge_ccb(union ccb *master_ccb, union ccb *slave_ccb) 37208b8a9b1dSJustin T. Gibbs { 37218b8a9b1dSJustin T. Gibbs /* 37228b8a9b1dSJustin T. Gibbs * Pull fields that are valid for peripheral drivers to set 37238b8a9b1dSJustin T. Gibbs * into the master CCB along with the CCB "payload". 37248b8a9b1dSJustin T. Gibbs */ 37258b8a9b1dSJustin T. Gibbs master_ccb->ccb_h.retry_count = slave_ccb->ccb_h.retry_count; 37268b8a9b1dSJustin T. Gibbs master_ccb->ccb_h.func_code = slave_ccb->ccb_h.func_code; 37278b8a9b1dSJustin T. Gibbs master_ccb->ccb_h.timeout = slave_ccb->ccb_h.timeout; 37288b8a9b1dSJustin T. Gibbs master_ccb->ccb_h.flags = slave_ccb->ccb_h.flags; 37298b8a9b1dSJustin T. Gibbs bcopy(&(&slave_ccb->ccb_h)[1], &(&master_ccb->ccb_h)[1], 37308b8a9b1dSJustin T. Gibbs sizeof(union ccb) - sizeof(struct ccb_hdr)); 37318b8a9b1dSJustin T. Gibbs } 37328b8a9b1dSJustin T. Gibbs 37338b8a9b1dSJustin T. Gibbs void 37348b8a9b1dSJustin T. Gibbs xpt_setup_ccb(struct ccb_hdr *ccb_h, struct cam_path *path, u_int32_t priority) 37358b8a9b1dSJustin T. Gibbs { 37368b8a9b1dSJustin T. Gibbs CAM_DEBUG(path, CAM_DEBUG_TRACE, ("xpt_setup_ccb\n")); 37378b8a9b1dSJustin T. Gibbs ccb_h->pinfo.priority = priority; 37388b8a9b1dSJustin T. Gibbs ccb_h->path = path; 37398b8a9b1dSJustin T. Gibbs ccb_h->path_id = path->bus->path_id; 37408b8a9b1dSJustin T. Gibbs if (path->target) 37418b8a9b1dSJustin T. Gibbs ccb_h->target_id = path->target->target_id; 37428b8a9b1dSJustin T. Gibbs else 37438b8a9b1dSJustin T. Gibbs ccb_h->target_id = CAM_TARGET_WILDCARD; 37448b8a9b1dSJustin T. Gibbs if (path->device) { 37458b8a9b1dSJustin T. Gibbs ccb_h->target_lun = path->device->lun_id; 37468bad620dSJustin T. Gibbs ccb_h->pinfo.generation = ++path->device->ccbq.queue.generation; 37478b8a9b1dSJustin T. Gibbs } else { 37488b8a9b1dSJustin T. Gibbs ccb_h->target_lun = CAM_TARGET_WILDCARD; 37498b8a9b1dSJustin T. Gibbs } 37508b8a9b1dSJustin T. Gibbs ccb_h->pinfo.index = CAM_UNQUEUED_INDEX; 37518b8a9b1dSJustin T. Gibbs ccb_h->flags = 0; 37528b8a9b1dSJustin T. Gibbs } 37538b8a9b1dSJustin T. Gibbs 37548b8a9b1dSJustin T. Gibbs /* Path manipulation functions */ 37558b8a9b1dSJustin T. Gibbs cam_status 37568b8a9b1dSJustin T. Gibbs xpt_create_path(struct cam_path **new_path_ptr, struct cam_periph *perph, 37578b8a9b1dSJustin T. Gibbs path_id_t path_id, target_id_t target_id, lun_id_t lun_id) 37588b8a9b1dSJustin T. Gibbs { 37598b8a9b1dSJustin T. Gibbs struct cam_path *path; 37608b8a9b1dSJustin T. Gibbs cam_status status; 37618b8a9b1dSJustin T. Gibbs 37628b8a9b1dSJustin T. Gibbs path = (struct cam_path *)malloc(sizeof(*path), M_DEVBUF, M_NOWAIT); 37638b8a9b1dSJustin T. Gibbs 37648b8a9b1dSJustin T. Gibbs if (path == NULL) { 37658b8a9b1dSJustin T. Gibbs status = CAM_RESRC_UNAVAIL; 37668b8a9b1dSJustin T. Gibbs return(status); 37678b8a9b1dSJustin T. Gibbs } 37688b8a9b1dSJustin T. Gibbs status = xpt_compile_path(path, perph, path_id, target_id, lun_id); 37698b8a9b1dSJustin T. Gibbs if (status != CAM_REQ_CMP) { 37708b8a9b1dSJustin T. Gibbs free(path, M_DEVBUF); 37718b8a9b1dSJustin T. Gibbs path = NULL; 37728b8a9b1dSJustin T. Gibbs } 37738b8a9b1dSJustin T. Gibbs *new_path_ptr = path; 37748b8a9b1dSJustin T. Gibbs return (status); 37758b8a9b1dSJustin T. Gibbs } 37768b8a9b1dSJustin T. Gibbs 37778b8a9b1dSJustin T. Gibbs static cam_status 37788b8a9b1dSJustin T. Gibbs xpt_compile_path(struct cam_path *new_path, struct cam_periph *perph, 37798b8a9b1dSJustin T. Gibbs path_id_t path_id, target_id_t target_id, lun_id_t lun_id) 37808b8a9b1dSJustin T. Gibbs { 37818b8a9b1dSJustin T. Gibbs struct cam_eb *bus; 37828b8a9b1dSJustin T. Gibbs struct cam_et *target; 37838b8a9b1dSJustin T. Gibbs struct cam_ed *device; 37848b8a9b1dSJustin T. Gibbs cam_status status; 37858b8a9b1dSJustin T. Gibbs int s; 37868b8a9b1dSJustin T. Gibbs 37878b8a9b1dSJustin T. Gibbs status = CAM_REQ_CMP; /* Completed without error */ 37888b8a9b1dSJustin T. Gibbs target = NULL; /* Wildcarded */ 37898b8a9b1dSJustin T. Gibbs device = NULL; /* Wildcarded */ 3790a5479bc5SJustin T. Gibbs 3791a5479bc5SJustin T. Gibbs /* 3792a5479bc5SJustin T. Gibbs * We will potentially modify the EDT, so block interrupts 3793a5479bc5SJustin T. Gibbs * that may attempt to create cam paths. 3794a5479bc5SJustin T. Gibbs */ 3795a5479bc5SJustin T. Gibbs s = splcam(); 37968b8a9b1dSJustin T. Gibbs bus = xpt_find_bus(path_id); 37978b8a9b1dSJustin T. Gibbs if (bus == NULL) { 37988b8a9b1dSJustin T. Gibbs status = CAM_PATH_INVALID; 3799c8bead2aSJustin T. Gibbs } else { 38008b8a9b1dSJustin T. Gibbs target = xpt_find_target(bus, target_id); 38018b8a9b1dSJustin T. Gibbs if (target == NULL) { 38028b8a9b1dSJustin T. Gibbs /* Create one */ 38038b8a9b1dSJustin T. Gibbs struct cam_et *new_target; 38048b8a9b1dSJustin T. Gibbs 38058b8a9b1dSJustin T. Gibbs new_target = xpt_alloc_target(bus, target_id); 38068b8a9b1dSJustin T. Gibbs if (new_target == NULL) { 38078b8a9b1dSJustin T. Gibbs status = CAM_RESRC_UNAVAIL; 38088b8a9b1dSJustin T. Gibbs } else { 38098b8a9b1dSJustin T. Gibbs target = new_target; 38108b8a9b1dSJustin T. Gibbs } 38118b8a9b1dSJustin T. Gibbs } 3812c8bead2aSJustin T. Gibbs if (target != NULL) { 38138b8a9b1dSJustin T. Gibbs device = xpt_find_device(target, lun_id); 38148b8a9b1dSJustin T. Gibbs if (device == NULL) { 38158b8a9b1dSJustin T. Gibbs /* Create one */ 38168b8a9b1dSJustin T. Gibbs struct cam_ed *new_device; 38178b8a9b1dSJustin T. Gibbs 38188b8a9b1dSJustin T. Gibbs new_device = xpt_alloc_device(bus, 38198b8a9b1dSJustin T. Gibbs target, 38208b8a9b1dSJustin T. Gibbs lun_id); 38218b8a9b1dSJustin T. Gibbs if (new_device == NULL) { 38228b8a9b1dSJustin T. Gibbs status = CAM_RESRC_UNAVAIL; 38238b8a9b1dSJustin T. Gibbs } else { 38248b8a9b1dSJustin T. Gibbs device = new_device; 38258b8a9b1dSJustin T. Gibbs } 38268b8a9b1dSJustin T. Gibbs } 38278b8a9b1dSJustin T. Gibbs } 38288b8a9b1dSJustin T. Gibbs } 3829a5479bc5SJustin T. Gibbs splx(s); 38308b8a9b1dSJustin T. Gibbs 38318b8a9b1dSJustin T. Gibbs /* 38328b8a9b1dSJustin T. Gibbs * Only touch the user's data if we are successful. 38338b8a9b1dSJustin T. Gibbs */ 38348b8a9b1dSJustin T. Gibbs if (status == CAM_REQ_CMP) { 38358b8a9b1dSJustin T. Gibbs new_path->periph = perph; 38368b8a9b1dSJustin T. Gibbs new_path->bus = bus; 38378b8a9b1dSJustin T. Gibbs new_path->target = target; 38388b8a9b1dSJustin T. Gibbs new_path->device = device; 38398b8a9b1dSJustin T. Gibbs CAM_DEBUG(new_path, CAM_DEBUG_TRACE, ("xpt_compile_path\n")); 38408b8a9b1dSJustin T. Gibbs } else { 38418b8a9b1dSJustin T. Gibbs if (device != NULL) 38428b8a9b1dSJustin T. Gibbs xpt_release_device(bus, target, device); 38438b8a9b1dSJustin T. Gibbs if (target != NULL) 38448b8a9b1dSJustin T. Gibbs xpt_release_target(bus, target); 3845a5479bc5SJustin T. Gibbs if (bus != NULL) 3846a5479bc5SJustin T. Gibbs xpt_release_bus(bus); 38478b8a9b1dSJustin T. Gibbs } 38488b8a9b1dSJustin T. Gibbs return (status); 38498b8a9b1dSJustin T. Gibbs } 38508b8a9b1dSJustin T. Gibbs 38518b8a9b1dSJustin T. Gibbs static void 38528b8a9b1dSJustin T. Gibbs xpt_release_path(struct cam_path *path) 38538b8a9b1dSJustin T. Gibbs { 38548b8a9b1dSJustin T. Gibbs CAM_DEBUG(path, CAM_DEBUG_TRACE, ("xpt_release_path\n")); 38559dd03ecfSJustin T. Gibbs if (path->device != NULL) { 38568b8a9b1dSJustin T. Gibbs xpt_release_device(path->bus, path->target, path->device); 38579dd03ecfSJustin T. Gibbs path->device = NULL; 38589dd03ecfSJustin T. Gibbs } 38599dd03ecfSJustin T. Gibbs if (path->target != NULL) { 38608b8a9b1dSJustin T. Gibbs xpt_release_target(path->bus, path->target); 38619dd03ecfSJustin T. Gibbs path->target = NULL; 38629dd03ecfSJustin T. Gibbs } 38639dd03ecfSJustin T. Gibbs if (path->bus != NULL) { 38649dd03ecfSJustin T. Gibbs xpt_release_bus(path->bus); 38659dd03ecfSJustin T. Gibbs path->bus = NULL; 38669dd03ecfSJustin T. Gibbs } 38678b8a9b1dSJustin T. Gibbs } 38688b8a9b1dSJustin T. Gibbs 38698b8a9b1dSJustin T. Gibbs void 38708b8a9b1dSJustin T. Gibbs xpt_free_path(struct cam_path *path) 38718b8a9b1dSJustin T. Gibbs { 38728b8a9b1dSJustin T. Gibbs CAM_DEBUG(path, CAM_DEBUG_TRACE, ("xpt_free_path\n")); 38738b8a9b1dSJustin T. Gibbs xpt_release_path(path); 38748b8a9b1dSJustin T. Gibbs free(path, M_DEVBUF); 38758b8a9b1dSJustin T. Gibbs } 38768b8a9b1dSJustin T. Gibbs 38778b8a9b1dSJustin T. Gibbs 38788b8a9b1dSJustin T. Gibbs /* 38792cefde5fSJustin T. Gibbs * Return -1 for failure, 0 for exact match, 1 for match with wildcards 38802cefde5fSJustin T. Gibbs * in path1, 2 for match with wildcards in path2. 38818b8a9b1dSJustin T. Gibbs */ 38828b8a9b1dSJustin T. Gibbs int 38838b8a9b1dSJustin T. Gibbs xpt_path_comp(struct cam_path *path1, struct cam_path *path2) 38848b8a9b1dSJustin T. Gibbs { 38858b8a9b1dSJustin T. Gibbs int retval = 0; 38868b8a9b1dSJustin T. Gibbs 38878b8a9b1dSJustin T. Gibbs if (path1->bus != path2->bus) { 38882cefde5fSJustin T. Gibbs if (path1->bus->path_id == CAM_BUS_WILDCARD) 38898b8a9b1dSJustin T. Gibbs retval = 1; 38902cefde5fSJustin T. Gibbs else if (path2->bus->path_id == CAM_BUS_WILDCARD) 38912cefde5fSJustin T. Gibbs retval = 2; 38928b8a9b1dSJustin T. Gibbs else 38938b8a9b1dSJustin T. Gibbs return (-1); 38948b8a9b1dSJustin T. Gibbs } 38958b8a9b1dSJustin T. Gibbs if (path1->target != path2->target) { 38962cefde5fSJustin T. Gibbs if (path1->target->target_id == CAM_TARGET_WILDCARD) { 38972cefde5fSJustin T. Gibbs if (retval == 0) 38988b8a9b1dSJustin T. Gibbs retval = 1; 38992cefde5fSJustin T. Gibbs } else if (path2->target->target_id == CAM_TARGET_WILDCARD) 39002cefde5fSJustin T. Gibbs retval = 2; 39018b8a9b1dSJustin T. Gibbs else 39028b8a9b1dSJustin T. Gibbs return (-1); 39038b8a9b1dSJustin T. Gibbs } 39048b8a9b1dSJustin T. Gibbs if (path1->device != path2->device) { 39052cefde5fSJustin T. Gibbs if (path1->device->lun_id == CAM_LUN_WILDCARD) { 39062cefde5fSJustin T. Gibbs if (retval == 0) 39078b8a9b1dSJustin T. Gibbs retval = 1; 39082cefde5fSJustin T. Gibbs } else if (path2->device->lun_id == CAM_LUN_WILDCARD) 39092cefde5fSJustin T. Gibbs retval = 2; 39108b8a9b1dSJustin T. Gibbs else 39118b8a9b1dSJustin T. Gibbs return (-1); 39128b8a9b1dSJustin T. Gibbs } 39138b8a9b1dSJustin T. Gibbs return (retval); 39148b8a9b1dSJustin T. Gibbs } 39158b8a9b1dSJustin T. Gibbs 39168b8a9b1dSJustin T. Gibbs void 39178b8a9b1dSJustin T. Gibbs xpt_print_path(struct cam_path *path) 39188b8a9b1dSJustin T. Gibbs { 39198b8a9b1dSJustin T. Gibbs if (path == NULL) 39208b8a9b1dSJustin T. Gibbs printf("(nopath): "); 39218b8a9b1dSJustin T. Gibbs else { 39228b8a9b1dSJustin T. Gibbs if (path->periph != NULL) 39238b8a9b1dSJustin T. Gibbs printf("(%s%d:", path->periph->periph_name, 39248b8a9b1dSJustin T. Gibbs path->periph->unit_number); 39258b8a9b1dSJustin T. Gibbs else 39268b8a9b1dSJustin T. Gibbs printf("(noperiph:"); 39278b8a9b1dSJustin T. Gibbs 39288b8a9b1dSJustin T. Gibbs if (path->bus != NULL) 39298b8a9b1dSJustin T. Gibbs printf("%s%d:%d:", path->bus->sim->sim_name, 39308b8a9b1dSJustin T. Gibbs path->bus->sim->unit_number, 39318b8a9b1dSJustin T. Gibbs path->bus->sim->bus_id); 39328b8a9b1dSJustin T. Gibbs else 39338b8a9b1dSJustin T. Gibbs printf("nobus:"); 39348b8a9b1dSJustin T. Gibbs 39358b8a9b1dSJustin T. Gibbs if (path->target != NULL) 39368b8a9b1dSJustin T. Gibbs printf("%d:", path->target->target_id); 39378b8a9b1dSJustin T. Gibbs else 39388b8a9b1dSJustin T. Gibbs printf("X:"); 39398b8a9b1dSJustin T. Gibbs 39408b8a9b1dSJustin T. Gibbs if (path->device != NULL) 39418b8a9b1dSJustin T. Gibbs printf("%d): ", path->device->lun_id); 39428b8a9b1dSJustin T. Gibbs else 39438b8a9b1dSJustin T. Gibbs printf("X): "); 39448b8a9b1dSJustin T. Gibbs } 39458b8a9b1dSJustin T. Gibbs } 39468b8a9b1dSJustin T. Gibbs 39478b8a9b1dSJustin T. Gibbs path_id_t 39488b8a9b1dSJustin T. Gibbs xpt_path_path_id(struct cam_path *path) 39498b8a9b1dSJustin T. Gibbs { 39508b8a9b1dSJustin T. Gibbs return(path->bus->path_id); 39518b8a9b1dSJustin T. Gibbs } 39528b8a9b1dSJustin T. Gibbs 39538b8a9b1dSJustin T. Gibbs target_id_t 39548b8a9b1dSJustin T. Gibbs xpt_path_target_id(struct cam_path *path) 39558b8a9b1dSJustin T. Gibbs { 39568b8a9b1dSJustin T. Gibbs if (path->target != NULL) 39578b8a9b1dSJustin T. Gibbs return (path->target->target_id); 39588b8a9b1dSJustin T. Gibbs else 39598b8a9b1dSJustin T. Gibbs return (CAM_TARGET_WILDCARD); 39608b8a9b1dSJustin T. Gibbs } 39618b8a9b1dSJustin T. Gibbs 39628b8a9b1dSJustin T. Gibbs lun_id_t 39638b8a9b1dSJustin T. Gibbs xpt_path_lun_id(struct cam_path *path) 39648b8a9b1dSJustin T. Gibbs { 39658b8a9b1dSJustin T. Gibbs if (path->device != NULL) 39668b8a9b1dSJustin T. Gibbs return (path->device->lun_id); 39678b8a9b1dSJustin T. Gibbs else 39688b8a9b1dSJustin T. Gibbs return (CAM_LUN_WILDCARD); 39698b8a9b1dSJustin T. Gibbs } 39708b8a9b1dSJustin T. Gibbs 39718b8a9b1dSJustin T. Gibbs struct cam_sim * 39728b8a9b1dSJustin T. Gibbs xpt_path_sim(struct cam_path *path) 39738b8a9b1dSJustin T. Gibbs { 39748b8a9b1dSJustin T. Gibbs return (path->bus->sim); 39758b8a9b1dSJustin T. Gibbs } 39768b8a9b1dSJustin T. Gibbs 39778b8a9b1dSJustin T. Gibbs struct cam_periph* 39788b8a9b1dSJustin T. Gibbs xpt_path_periph(struct cam_path *path) 39798b8a9b1dSJustin T. Gibbs { 39808b8a9b1dSJustin T. Gibbs return (path->periph); 39818b8a9b1dSJustin T. Gibbs } 39828b8a9b1dSJustin T. Gibbs 39838b8a9b1dSJustin T. Gibbs /* 39848b8a9b1dSJustin T. Gibbs * Release a CAM control block for the caller. Remit the cost of the structure 39858b8a9b1dSJustin T. Gibbs * to the device referenced by the path. If the this device had no 'credits' 39868b8a9b1dSJustin T. Gibbs * and peripheral drivers have registered async callbacks for this notification 39878b8a9b1dSJustin T. Gibbs * call them now. 39888b8a9b1dSJustin T. Gibbs */ 39898b8a9b1dSJustin T. Gibbs void 39908b8a9b1dSJustin T. Gibbs xpt_release_ccb(union ccb *free_ccb) 39918b8a9b1dSJustin T. Gibbs { 39928b8a9b1dSJustin T. Gibbs int s; 39938b8a9b1dSJustin T. Gibbs struct cam_path *path; 39948b8a9b1dSJustin T. Gibbs struct cam_ed *device; 39958b8a9b1dSJustin T. Gibbs struct cam_eb *bus; 39968b8a9b1dSJustin T. Gibbs 3997aa872be6SMatt Jacob CAM_DEBUG_PRINT(CAM_DEBUG_XPT, ("xpt_release_ccb\n")); 39988b8a9b1dSJustin T. Gibbs path = free_ccb->ccb_h.path; 39998b8a9b1dSJustin T. Gibbs device = path->device; 40008b8a9b1dSJustin T. Gibbs bus = path->bus; 40018b8a9b1dSJustin T. Gibbs s = splsoftcam(); 40028b8a9b1dSJustin T. Gibbs cam_ccbq_release_opening(&device->ccbq); 40038b8a9b1dSJustin T. Gibbs if (xpt_ccb_count > xpt_max_ccbs) { 40048b8a9b1dSJustin T. Gibbs xpt_free_ccb(free_ccb); 40058b8a9b1dSJustin T. Gibbs xpt_ccb_count--; 40068b8a9b1dSJustin T. Gibbs } else { 40078b8a9b1dSJustin T. Gibbs SLIST_INSERT_HEAD(&ccb_freeq, &free_ccb->ccb_h, xpt_links.sle); 40088b8a9b1dSJustin T. Gibbs } 40098b8a9b1dSJustin T. Gibbs bus->sim->devq->alloc_openings++; 40108b8a9b1dSJustin T. Gibbs bus->sim->devq->alloc_active--; 40118b8a9b1dSJustin T. Gibbs /* XXX Turn this into an inline function - xpt_run_device?? */ 40128b8a9b1dSJustin T. Gibbs if ((device_is_alloc_queued(device) == 0) 40138b8a9b1dSJustin T. Gibbs && (device->drvq.entries > 0)) { 40148b8a9b1dSJustin T. Gibbs xpt_schedule_dev_allocq(bus, device); 40158b8a9b1dSJustin T. Gibbs } 40168b8a9b1dSJustin T. Gibbs splx(s); 40178b8a9b1dSJustin T. Gibbs if (dev_allocq_is_runnable(bus->sim->devq)) 40188b8a9b1dSJustin T. Gibbs xpt_run_dev_allocq(bus); 40198b8a9b1dSJustin T. Gibbs } 40208b8a9b1dSJustin T. Gibbs 40218b8a9b1dSJustin T. Gibbs /* Functions accessed by SIM drivers */ 40228b8a9b1dSJustin T. Gibbs 40238b8a9b1dSJustin T. Gibbs /* 40248b8a9b1dSJustin T. Gibbs * A sim structure, listing the SIM entry points and instance 40258b8a9b1dSJustin T. Gibbs * identification info is passed to xpt_bus_register to hook the SIM 40268b8a9b1dSJustin T. Gibbs * into the CAM framework. xpt_bus_register creates a cam_eb entry 40278b8a9b1dSJustin T. Gibbs * for this new bus and places it in the array of busses and assigns 40288b8a9b1dSJustin T. Gibbs * it a path_id. The path_id may be influenced by "hard wiring" 40298b8a9b1dSJustin T. Gibbs * information specified by the user. Once interrupt services are 40308b8a9b1dSJustin T. Gibbs * availible, the bus will be probed. 40318b8a9b1dSJustin T. Gibbs */ 40328b8a9b1dSJustin T. Gibbs int32_t 40338b8a9b1dSJustin T. Gibbs xpt_bus_register(struct cam_sim *sim, u_int32_t bus) 40348b8a9b1dSJustin T. Gibbs { 40358b8a9b1dSJustin T. Gibbs struct cam_eb *new_bus; 4036434bbf6eSJustin T. Gibbs struct cam_eb *old_bus; 40378b8a9b1dSJustin T. Gibbs struct ccb_pathinq cpi; 40388b8a9b1dSJustin T. Gibbs int s; 40398b8a9b1dSJustin T. Gibbs 40408b8a9b1dSJustin T. Gibbs sim->bus_id = bus; 40418b8a9b1dSJustin T. Gibbs new_bus = (struct cam_eb *)malloc(sizeof(*new_bus), 40428b8a9b1dSJustin T. Gibbs M_DEVBUF, M_NOWAIT); 40438b8a9b1dSJustin T. Gibbs if (new_bus == NULL) { 40448b8a9b1dSJustin T. Gibbs /* Couldn't satisfy request */ 40458b8a9b1dSJustin T. Gibbs return (CAM_RESRC_UNAVAIL); 40468b8a9b1dSJustin T. Gibbs } 40478b8a9b1dSJustin T. Gibbs 40488b8a9b1dSJustin T. Gibbs if (strcmp(sim->sim_name, "xpt") != 0) { 40498b8a9b1dSJustin T. Gibbs 4050434bbf6eSJustin T. Gibbs sim->path_id = 4051434bbf6eSJustin T. Gibbs xptpathid(sim->sim_name, sim->unit_number, sim->bus_id); 40528b8a9b1dSJustin T. Gibbs } 40538b8a9b1dSJustin T. Gibbs 4054434bbf6eSJustin T. Gibbs TAILQ_INIT(&new_bus->et_entries); 40558b8a9b1dSJustin T. Gibbs new_bus->path_id = sim->path_id; 40568b8a9b1dSJustin T. Gibbs new_bus->sim = sim; 405787cfaf0eSJustin T. Gibbs timevalclear(&new_bus->last_reset); 4058434bbf6eSJustin T. Gibbs new_bus->flags = 0; 4059a5479bc5SJustin T. Gibbs new_bus->refcount = 1; /* Held until a bus_deregister event */ 4060434bbf6eSJustin T. Gibbs new_bus->generation = 0; 4061a5479bc5SJustin T. Gibbs s = splcam(); 4062434bbf6eSJustin T. Gibbs old_bus = TAILQ_FIRST(&xpt_busses); 4063434bbf6eSJustin T. Gibbs while (old_bus != NULL 4064434bbf6eSJustin T. Gibbs && old_bus->path_id < new_bus->path_id) 4065434bbf6eSJustin T. Gibbs old_bus = TAILQ_NEXT(old_bus, links); 4066434bbf6eSJustin T. Gibbs if (old_bus != NULL) 4067434bbf6eSJustin T. Gibbs TAILQ_INSERT_BEFORE(old_bus, new_bus, links); 4068434bbf6eSJustin T. Gibbs else 40698b8a9b1dSJustin T. Gibbs TAILQ_INSERT_TAIL(&xpt_busses, new_bus, links); 40708b8a9b1dSJustin T. Gibbs bus_generation++; 4071a5479bc5SJustin T. Gibbs splx(s); 40728b8a9b1dSJustin T. Gibbs 40738b8a9b1dSJustin T. Gibbs /* Notify interested parties */ 40748b8a9b1dSJustin T. Gibbs if (sim->path_id != CAM_XPT_PATH_ID) { 40758b8a9b1dSJustin T. Gibbs struct cam_path path; 40768b8a9b1dSJustin T. Gibbs 40778b8a9b1dSJustin T. Gibbs xpt_compile_path(&path, /*periph*/NULL, sim->path_id, 40788b8a9b1dSJustin T. Gibbs CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD); 40798b8a9b1dSJustin T. Gibbs xpt_setup_ccb(&cpi.ccb_h, &path, /*priority*/1); 40808b8a9b1dSJustin T. Gibbs cpi.ccb_h.func_code = XPT_PATH_INQ; 40818b8a9b1dSJustin T. Gibbs xpt_action((union ccb *)&cpi); 40828b8a9b1dSJustin T. Gibbs xpt_async(AC_PATH_REGISTERED, xpt_periph->path, &cpi); 40838b8a9b1dSJustin T. Gibbs xpt_release_path(&path); 40848b8a9b1dSJustin T. Gibbs } 40858b8a9b1dSJustin T. Gibbs return (CAM_SUCCESS); 40868b8a9b1dSJustin T. Gibbs } 40878b8a9b1dSJustin T. Gibbs 4088434bbf6eSJustin T. Gibbs int32_t 4089434bbf6eSJustin T. Gibbs xpt_bus_deregister(path_id_t pathid) 40908b8a9b1dSJustin T. Gibbs { 4091434bbf6eSJustin T. Gibbs struct cam_path bus_path; 4092434bbf6eSJustin T. Gibbs cam_status status; 4093434bbf6eSJustin T. Gibbs 4094434bbf6eSJustin T. Gibbs status = xpt_compile_path(&bus_path, NULL, pathid, 4095434bbf6eSJustin T. Gibbs CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD); 4096434bbf6eSJustin T. Gibbs if (status != CAM_REQ_CMP) 4097434bbf6eSJustin T. Gibbs return (status); 4098434bbf6eSJustin T. Gibbs 4099434bbf6eSJustin T. Gibbs xpt_async(AC_LOST_DEVICE, &bus_path, NULL); 4100434bbf6eSJustin T. Gibbs xpt_async(AC_PATH_DEREGISTERED, &bus_path, NULL); 4101434bbf6eSJustin T. Gibbs 4102434bbf6eSJustin T. Gibbs /* Release the reference count held while registered. */ 4103434bbf6eSJustin T. Gibbs xpt_release_bus(bus_path.bus); 4104434bbf6eSJustin T. Gibbs xpt_release_path(&bus_path); 4105434bbf6eSJustin T. Gibbs 4106434bbf6eSJustin T. Gibbs return (CAM_REQ_CMP); 4107434bbf6eSJustin T. Gibbs } 4108434bbf6eSJustin T. Gibbs 4109434bbf6eSJustin T. Gibbs static path_id_t 4110434bbf6eSJustin T. Gibbs xptnextfreepathid(void) 4111434bbf6eSJustin T. Gibbs { 4112434bbf6eSJustin T. Gibbs struct cam_eb *bus; 4113434bbf6eSJustin T. Gibbs path_id_t pathid; 411475f51904SPeter Wemm char *strval; 41158b8a9b1dSJustin T. Gibbs 4116434bbf6eSJustin T. Gibbs pathid = 0; 4117434bbf6eSJustin T. Gibbs bus = TAILQ_FIRST(&xpt_busses); 4118434bbf6eSJustin T. Gibbs retry: 4119434bbf6eSJustin T. Gibbs /* Find an unoccupied pathid */ 4120434bbf6eSJustin T. Gibbs while (bus != NULL 4121434bbf6eSJustin T. Gibbs && bus->path_id <= pathid) { 4122434bbf6eSJustin T. Gibbs if (bus->path_id == pathid) 4123434bbf6eSJustin T. Gibbs pathid++; 4124434bbf6eSJustin T. Gibbs bus = TAILQ_NEXT(bus, links); 4125434bbf6eSJustin T. Gibbs } 4126434bbf6eSJustin T. Gibbs 4127434bbf6eSJustin T. Gibbs /* 4128434bbf6eSJustin T. Gibbs * Ensure that this pathid is not reserved for 4129434bbf6eSJustin T. Gibbs * a bus that may be registered in the future. 4130434bbf6eSJustin T. Gibbs */ 413175f51904SPeter Wemm if (resource_string_value("scbus", pathid, "at", &strval) == 0) { 4132434bbf6eSJustin T. Gibbs ++pathid; 41338b8a9b1dSJustin T. Gibbs /* Start the search over */ 4134434bbf6eSJustin T. Gibbs goto retry; 41358b8a9b1dSJustin T. Gibbs } 4136434bbf6eSJustin T. Gibbs return (pathid); 41378b8a9b1dSJustin T. Gibbs } 41388b8a9b1dSJustin T. Gibbs 4139434bbf6eSJustin T. Gibbs static path_id_t 4140434bbf6eSJustin T. Gibbs xptpathid(const char *sim_name, int sim_unit, int sim_bus) 41418b8a9b1dSJustin T. Gibbs { 41428b8a9b1dSJustin T. Gibbs path_id_t pathid; 414375f51904SPeter Wemm int i, dunit, val; 414475f51904SPeter Wemm char buf[32], *strval; 41458b8a9b1dSJustin T. Gibbs 41468b8a9b1dSJustin T. Gibbs pathid = CAM_XPT_PATH_ID; 414775f51904SPeter Wemm snprintf(buf, sizeof(buf), "%s%d", sim_name, sim_unit); 414875f51904SPeter Wemm i = -1; 414975f51904SPeter Wemm while ((i = resource_locate(i, "scbus")) != -1) { 415075f51904SPeter Wemm dunit = resource_query_unit(i); 415175f51904SPeter Wemm if (dunit < 0) /* unwired?! */ 41528b8a9b1dSJustin T. Gibbs continue; 415375f51904SPeter Wemm if (resource_string_value("scbus", dunit, "at", &strval) != 0) 415475f51904SPeter Wemm continue; 415575f51904SPeter Wemm if (strcmp(buf, strval) != 0) 415675f51904SPeter Wemm continue; 415775f51904SPeter Wemm if (resource_int_value("scbus", dunit, "bus", &val) == 0) { 415875f51904SPeter Wemm if (sim_bus == val) { 415975f51904SPeter Wemm pathid = dunit; 41608b8a9b1dSJustin T. Gibbs break; 41618b8a9b1dSJustin T. Gibbs } 41628b8a9b1dSJustin T. Gibbs } else if (sim_bus == 0) { 41638b8a9b1dSJustin T. Gibbs /* Unspecified matches bus 0 */ 416475f51904SPeter Wemm pathid = dunit; 41658b8a9b1dSJustin T. Gibbs break; 41668b8a9b1dSJustin T. Gibbs } else { 41678b8a9b1dSJustin T. Gibbs printf("Ambiguous scbus configuration for %s%d " 41688b8a9b1dSJustin T. Gibbs "bus %d, cannot wire down. The kernel " 41698b8a9b1dSJustin T. Gibbs "config entry for scbus%d should " 41708b8a9b1dSJustin T. Gibbs "specify a controller bus.\n" 41718b8a9b1dSJustin T. Gibbs "Scbus will be assigned dynamically.\n", 417275f51904SPeter Wemm sim_name, sim_unit, sim_bus, dunit); 41738b8a9b1dSJustin T. Gibbs break; 41748b8a9b1dSJustin T. Gibbs } 41758b8a9b1dSJustin T. Gibbs } 41768b8a9b1dSJustin T. Gibbs 4177434bbf6eSJustin T. Gibbs if (pathid == CAM_XPT_PATH_ID) 4178434bbf6eSJustin T. Gibbs pathid = xptnextfreepathid(); 41798b8a9b1dSJustin T. Gibbs return (pathid); 41808b8a9b1dSJustin T. Gibbs } 41818b8a9b1dSJustin T. Gibbs 41828b8a9b1dSJustin T. Gibbs void 41838b8a9b1dSJustin T. Gibbs xpt_async(u_int32_t async_code, struct cam_path *path, void *async_arg) 41848b8a9b1dSJustin T. Gibbs { 41858b8a9b1dSJustin T. Gibbs struct cam_eb *bus; 41868b8a9b1dSJustin T. Gibbs struct cam_et *target, *next_target; 41878b8a9b1dSJustin T. Gibbs struct cam_ed *device, *next_device; 41888b8a9b1dSJustin T. Gibbs int s; 41898b8a9b1dSJustin T. Gibbs 41908b8a9b1dSJustin T. Gibbs CAM_DEBUG(path, CAM_DEBUG_TRACE, ("xpt_async\n")); 41918b8a9b1dSJustin T. Gibbs 4192a5479bc5SJustin T. Gibbs /* 4193a5479bc5SJustin T. Gibbs * Most async events come from a CAM interrupt context. In 4194a5479bc5SJustin T. Gibbs * a few cases, the error recovery code at the peripheral layer, 4195a5479bc5SJustin T. Gibbs * which may run from our SWI or a process context, may signal 4196a5479bc5SJustin T. Gibbs * deferred events with a call to xpt_async. Ensure async 4197a5479bc5SJustin T. Gibbs * notifications are serialized by blocking cam interrupts. 4198a5479bc5SJustin T. Gibbs */ 4199a5479bc5SJustin T. Gibbs s = splcam(); 42008b8a9b1dSJustin T. Gibbs 42018b8a9b1dSJustin T. Gibbs bus = path->bus; 42028b8a9b1dSJustin T. Gibbs 42038b8a9b1dSJustin T. Gibbs if (async_code == AC_BUS_RESET) { 420487cfaf0eSJustin T. Gibbs int s; 42058b8a9b1dSJustin T. Gibbs 420687cfaf0eSJustin T. Gibbs s = splclock(); 420787cfaf0eSJustin T. Gibbs /* Update our notion of when the last reset occurred */ 420887cfaf0eSJustin T. Gibbs microtime(&bus->last_reset); 420987cfaf0eSJustin T. Gibbs splx(s); 42108b8a9b1dSJustin T. Gibbs } 42118b8a9b1dSJustin T. Gibbs 42128b8a9b1dSJustin T. Gibbs for (target = TAILQ_FIRST(&bus->et_entries); 42138b8a9b1dSJustin T. Gibbs target != NULL; 42148b8a9b1dSJustin T. Gibbs target = next_target) { 42158b8a9b1dSJustin T. Gibbs 42168b8a9b1dSJustin T. Gibbs next_target = TAILQ_NEXT(target, links); 42178b8a9b1dSJustin T. Gibbs 42188b8a9b1dSJustin T. Gibbs if (path->target != target 421987cfaf0eSJustin T. Gibbs && path->target->target_id != CAM_TARGET_WILDCARD) 42208b8a9b1dSJustin T. Gibbs continue; 42218b8a9b1dSJustin T. Gibbs 422287cfaf0eSJustin T. Gibbs if (async_code == AC_SENT_BDR) { 422387cfaf0eSJustin T. Gibbs int s; 422487cfaf0eSJustin T. Gibbs 422587cfaf0eSJustin T. Gibbs /* Update our notion of when the last reset occurred */ 422687cfaf0eSJustin T. Gibbs s = splclock(); 422787cfaf0eSJustin T. Gibbs microtime(&path->target->last_reset); 422887cfaf0eSJustin T. Gibbs splx(s); 422987cfaf0eSJustin T. Gibbs } 423087cfaf0eSJustin T. Gibbs 42318b8a9b1dSJustin T. Gibbs for (device = TAILQ_FIRST(&target->ed_entries); 42328b8a9b1dSJustin T. Gibbs device != NULL; 42338b8a9b1dSJustin T. Gibbs device = next_device) { 42348b8a9b1dSJustin T. Gibbs cam_status status; 42358b8a9b1dSJustin T. Gibbs struct cam_path newpath; 42368b8a9b1dSJustin T. Gibbs 42378b8a9b1dSJustin T. Gibbs next_device = TAILQ_NEXT(device, links); 42388b8a9b1dSJustin T. Gibbs 42398b8a9b1dSJustin T. Gibbs if (path->device != device 424087cfaf0eSJustin T. Gibbs && path->device->lun_id != CAM_LUN_WILDCARD) 42418b8a9b1dSJustin T. Gibbs continue; 42428b8a9b1dSJustin T. Gibbs 42438b8a9b1dSJustin T. Gibbs /* 4244fd21cc5eSJustin T. Gibbs * We need our own path with wildcards expanded to 4245fd21cc5eSJustin T. Gibbs * handle certain types of events. 42468b8a9b1dSJustin T. Gibbs */ 42478b8a9b1dSJustin T. Gibbs if ((async_code == AC_SENT_BDR) 4248fd21cc5eSJustin T. Gibbs || (async_code == AC_BUS_RESET) 42498b8a9b1dSJustin T. Gibbs || (async_code == AC_INQ_CHANGED)) 42508b8a9b1dSJustin T. Gibbs status = xpt_compile_path(&newpath, NULL, 42518b8a9b1dSJustin T. Gibbs bus->path_id, 42528b8a9b1dSJustin T. Gibbs target->target_id, 42538b8a9b1dSJustin T. Gibbs device->lun_id); 42548b8a9b1dSJustin T. Gibbs else 4255f0adc790SJustin T. Gibbs status = CAM_REQ_CMP_ERR; 42568b8a9b1dSJustin T. Gibbs 4257f0adc790SJustin T. Gibbs if (status == CAM_REQ_CMP) { 4258fd21cc5eSJustin T. Gibbs 4259fd21cc5eSJustin T. Gibbs /* 4260f0adc790SJustin T. Gibbs * Allow transfer negotiation to occur in a 4261f0adc790SJustin T. Gibbs * tag free environment. 4262fd21cc5eSJustin T. Gibbs */ 4263f0adc790SJustin T. Gibbs if (async_code == AC_SENT_BDR 4264f0adc790SJustin T. Gibbs || async_code == AC_BUS_RESET) 4265f0adc790SJustin T. Gibbs xpt_toggle_tags(&newpath); 4266fd21cc5eSJustin T. Gibbs 426787cfaf0eSJustin T. Gibbs if (async_code == AC_INQ_CHANGED) { 42688b8a9b1dSJustin T. Gibbs /* 42698b8a9b1dSJustin T. Gibbs * We've sent a start unit command, or 4270f0adc790SJustin T. Gibbs * something similar to a device that 4271f0adc790SJustin T. Gibbs * may have caused its inquiry data to 4272f0adc790SJustin T. Gibbs * change. So we re-scan the device to 4273f0adc790SJustin T. Gibbs * refresh the inquiry data for it. 42748b8a9b1dSJustin T. Gibbs */ 4275f0adc790SJustin T. Gibbs xpt_scan_lun(newpath.periph, &newpath, 42768b8a9b1dSJustin T. Gibbs CAM_EXPECT_INQ_CHANGE, 42778b8a9b1dSJustin T. Gibbs NULL); 42788b8a9b1dSJustin T. Gibbs } 4279f0adc790SJustin T. Gibbs xpt_release_path(&newpath); 428003e3511bSJustin T. Gibbs } else if (async_code == AC_LOST_DEVICE) { 42818b8a9b1dSJustin T. Gibbs device->flags |= CAM_DEV_UNCONFIGURED; 428203e3511bSJustin T. Gibbs } else if (async_code == AC_TRANSFER_NEG) { 428303e3511bSJustin T. Gibbs struct ccb_trans_settings *settings; 428403e3511bSJustin T. Gibbs 428503e3511bSJustin T. Gibbs settings = 428603e3511bSJustin T. Gibbs (struct ccb_trans_settings *)async_arg; 428703e3511bSJustin T. Gibbs xpt_set_transfer_settings(settings, device, 428803e3511bSJustin T. Gibbs /*async_update*/TRUE); 428903e3511bSJustin T. Gibbs } 429003e3511bSJustin T. Gibbs 42918b8a9b1dSJustin T. Gibbs xpt_async_bcast(&device->asyncs, 42928b8a9b1dSJustin T. Gibbs async_code, 42938b8a9b1dSJustin T. Gibbs path, 42948b8a9b1dSJustin T. Gibbs async_arg); 42958b8a9b1dSJustin T. Gibbs } 42968b8a9b1dSJustin T. Gibbs } 4297c8bead2aSJustin T. Gibbs 4298c8bead2aSJustin T. Gibbs /* 4299c8bead2aSJustin T. Gibbs * If this wasn't a fully wildcarded async, tell all 4300c8bead2aSJustin T. Gibbs * clients that want all async events. 4301c8bead2aSJustin T. Gibbs */ 4302c8bead2aSJustin T. Gibbs if (bus != xpt_periph->path->bus) 4303c8bead2aSJustin T. Gibbs xpt_async_bcast(&xpt_periph->path->device->asyncs, async_code, 43048b8a9b1dSJustin T. Gibbs path, async_arg); 43058b8a9b1dSJustin T. Gibbs splx(s); 43068b8a9b1dSJustin T. Gibbs } 43078b8a9b1dSJustin T. Gibbs 43088b8a9b1dSJustin T. Gibbs static void 43098b8a9b1dSJustin T. Gibbs xpt_async_bcast(struct async_list *async_head, 43108b8a9b1dSJustin T. Gibbs u_int32_t async_code, 43118b8a9b1dSJustin T. Gibbs struct cam_path *path, void *async_arg) 43128b8a9b1dSJustin T. Gibbs { 43138b8a9b1dSJustin T. Gibbs struct async_node *cur_entry; 43148b8a9b1dSJustin T. Gibbs 43158b8a9b1dSJustin T. Gibbs cur_entry = SLIST_FIRST(async_head); 43168b8a9b1dSJustin T. Gibbs while (cur_entry != NULL) { 43178b8a9b1dSJustin T. Gibbs struct async_node *next_entry; 43188b8a9b1dSJustin T. Gibbs /* 43198b8a9b1dSJustin T. Gibbs * Grab the next list entry before we call the current 43208b8a9b1dSJustin T. Gibbs * entry's callback. This is because the callback function 43218b8a9b1dSJustin T. Gibbs * can delete its async callback entry. 43228b8a9b1dSJustin T. Gibbs */ 43238b8a9b1dSJustin T. Gibbs next_entry = SLIST_NEXT(cur_entry, links); 43248b8a9b1dSJustin T. Gibbs if ((cur_entry->event_enable & async_code) != 0) 43258b8a9b1dSJustin T. Gibbs cur_entry->callback(cur_entry->callback_arg, 43268b8a9b1dSJustin T. Gibbs async_code, path, 43278b8a9b1dSJustin T. Gibbs async_arg); 43288b8a9b1dSJustin T. Gibbs cur_entry = next_entry; 43298b8a9b1dSJustin T. Gibbs } 43308b8a9b1dSJustin T. Gibbs } 43318b8a9b1dSJustin T. Gibbs 43328b8a9b1dSJustin T. Gibbs u_int32_t 43338b8a9b1dSJustin T. Gibbs xpt_freeze_devq(struct cam_path *path, u_int count) 43348b8a9b1dSJustin T. Gibbs { 43358b8a9b1dSJustin T. Gibbs int s; 43368b8a9b1dSJustin T. Gibbs struct ccb_hdr *ccbh; 43378b8a9b1dSJustin T. Gibbs 43388b8a9b1dSJustin T. Gibbs s = splcam(); 43398b8a9b1dSJustin T. Gibbs path->device->qfrozen_cnt += count; 43408b8a9b1dSJustin T. Gibbs 43418b8a9b1dSJustin T. Gibbs /* 43428b8a9b1dSJustin T. Gibbs * Mark the last CCB in the queue as needing 43438b8a9b1dSJustin T. Gibbs * to be requeued if the driver hasn't 43448b8a9b1dSJustin T. Gibbs * changed it's state yet. This fixes a race 43458b8a9b1dSJustin T. Gibbs * where a ccb is just about to be queued to 43468b8a9b1dSJustin T. Gibbs * a controller driver when it's interrupt routine 43478b8a9b1dSJustin T. Gibbs * freezes the queue. To completly close the 43488b8a9b1dSJustin T. Gibbs * hole, controller drives must check to see 43498b8a9b1dSJustin T. Gibbs * if a ccb's status is still CAM_REQ_INPROG 43508b8a9b1dSJustin T. Gibbs * under spl protection just before they queue 43518b8a9b1dSJustin T. Gibbs * the CCB. See ahc_action/ahc_freeze_devq for 43528b8a9b1dSJustin T. Gibbs * an example. 43538b8a9b1dSJustin T. Gibbs */ 4354bb6087e5SJustin T. Gibbs ccbh = TAILQ_LAST(&path->device->ccbq.active_ccbs, ccb_hdr_tailq); 43558b8a9b1dSJustin T. Gibbs if (ccbh && ccbh->status == CAM_REQ_INPROG) 43568b8a9b1dSJustin T. Gibbs ccbh->status = CAM_REQUEUE_REQ; 43578b8a9b1dSJustin T. Gibbs splx(s); 43588b8a9b1dSJustin T. Gibbs return (path->device->qfrozen_cnt); 43598b8a9b1dSJustin T. Gibbs } 43608b8a9b1dSJustin T. Gibbs 43618b8a9b1dSJustin T. Gibbs u_int32_t 43628b8a9b1dSJustin T. Gibbs xpt_freeze_simq(struct cam_sim *sim, u_int count) 43638b8a9b1dSJustin T. Gibbs { 43648b8a9b1dSJustin T. Gibbs sim->devq->send_queue.qfrozen_cnt += count; 43658b8a9b1dSJustin T. Gibbs if (sim->devq->active_dev != NULL) { 43668b8a9b1dSJustin T. Gibbs struct ccb_hdr *ccbh; 43678b8a9b1dSJustin T. Gibbs 43688b8a9b1dSJustin T. Gibbs ccbh = TAILQ_LAST(&sim->devq->active_dev->ccbq.active_ccbs, 4369bb6087e5SJustin T. Gibbs ccb_hdr_tailq); 43708b8a9b1dSJustin T. Gibbs if (ccbh && ccbh->status == CAM_REQ_INPROG) 43718b8a9b1dSJustin T. Gibbs ccbh->status = CAM_REQUEUE_REQ; 43728b8a9b1dSJustin T. Gibbs } 43738b8a9b1dSJustin T. Gibbs return (sim->devq->send_queue.qfrozen_cnt); 43748b8a9b1dSJustin T. Gibbs } 43758b8a9b1dSJustin T. Gibbs 43768b8a9b1dSJustin T. Gibbs static void 43778b8a9b1dSJustin T. Gibbs xpt_release_devq_timeout(void *arg) 43788b8a9b1dSJustin T. Gibbs { 43798b8a9b1dSJustin T. Gibbs struct cam_ed *device; 43808b8a9b1dSJustin T. Gibbs 43818b8a9b1dSJustin T. Gibbs device = (struct cam_ed *)arg; 43828b8a9b1dSJustin T. Gibbs 43832cefde5fSJustin T. Gibbs xpt_release_devq_device(device, /*count*/1, /*run_queue*/TRUE); 43848b8a9b1dSJustin T. Gibbs } 43858b8a9b1dSJustin T. Gibbs 43868b8a9b1dSJustin T. Gibbs void 43872cefde5fSJustin T. Gibbs xpt_release_devq(struct cam_path *path, u_int count, int run_queue) 43882cefde5fSJustin T. Gibbs { 43892cefde5fSJustin T. Gibbs xpt_release_devq_device(path->device, count, run_queue); 43902cefde5fSJustin T. Gibbs } 43912cefde5fSJustin T. Gibbs 43922cefde5fSJustin T. Gibbs static void 43932cefde5fSJustin T. Gibbs xpt_release_devq_device(struct cam_ed *dev, u_int count, int run_queue) 43948b8a9b1dSJustin T. Gibbs { 43958b8a9b1dSJustin T. Gibbs int rundevq; 43960642b69aSMatt Jacob int s0, s1; 43978b8a9b1dSJustin T. Gibbs 43988b8a9b1dSJustin T. Gibbs rundevq = 0; 43990642b69aSMatt Jacob s0 = splsoftcam(); 44000642b69aSMatt Jacob s1 = splcam(); 44018b8a9b1dSJustin T. Gibbs if (dev->qfrozen_cnt > 0) { 44028b8a9b1dSJustin T. Gibbs 44032cefde5fSJustin T. Gibbs count = (count > dev->qfrozen_cnt) ? dev->qfrozen_cnt : count; 44042cefde5fSJustin T. Gibbs dev->qfrozen_cnt -= count; 44058b8a9b1dSJustin T. Gibbs if (dev->qfrozen_cnt == 0) { 44068b8a9b1dSJustin T. Gibbs 44078b8a9b1dSJustin T. Gibbs /* 44088b8a9b1dSJustin T. Gibbs * No longer need to wait for a successful 44098b8a9b1dSJustin T. Gibbs * command completion. 44108b8a9b1dSJustin T. Gibbs */ 44118b8a9b1dSJustin T. Gibbs dev->flags &= ~CAM_DEV_REL_ON_COMPLETE; 44128b8a9b1dSJustin T. Gibbs 44138b8a9b1dSJustin T. Gibbs /* 44148b8a9b1dSJustin T. Gibbs * Remove any timeouts that might be scheduled 44158b8a9b1dSJustin T. Gibbs * to release this queue. 44168b8a9b1dSJustin T. Gibbs */ 44178b8a9b1dSJustin T. Gibbs if ((dev->flags & CAM_DEV_REL_TIMEOUT_PENDING) != 0) { 44188b8a9b1dSJustin T. Gibbs untimeout(xpt_release_devq_timeout, dev, 44198b8a9b1dSJustin T. Gibbs dev->c_handle); 44208b8a9b1dSJustin T. Gibbs dev->flags &= ~CAM_DEV_REL_TIMEOUT_PENDING; 44218b8a9b1dSJustin T. Gibbs } 44228b8a9b1dSJustin T. Gibbs 44238b8a9b1dSJustin T. Gibbs /* 44248b8a9b1dSJustin T. Gibbs * Now that we are unfrozen schedule the 44258b8a9b1dSJustin T. Gibbs * device so any pending transactions are 44268b8a9b1dSJustin T. Gibbs * run. 44278b8a9b1dSJustin T. Gibbs */ 44288b8a9b1dSJustin T. Gibbs if ((dev->ccbq.queue.entries > 0) 44298b8a9b1dSJustin T. Gibbs && (xpt_schedule_dev_sendq(dev->target->bus, dev)) 44308b8a9b1dSJustin T. Gibbs && (run_queue != 0)) { 44318b8a9b1dSJustin T. Gibbs rundevq = 1; 44328b8a9b1dSJustin T. Gibbs } 44338b8a9b1dSJustin T. Gibbs } 44348b8a9b1dSJustin T. Gibbs } 44350642b69aSMatt Jacob splx(s1); 44368b8a9b1dSJustin T. Gibbs if (rundevq != 0) 44378b8a9b1dSJustin T. Gibbs xpt_run_dev_sendq(dev->target->bus); 44380642b69aSMatt Jacob splx(s0); 44398b8a9b1dSJustin T. Gibbs } 44408b8a9b1dSJustin T. Gibbs 44418b8a9b1dSJustin T. Gibbs void 44428b8a9b1dSJustin T. Gibbs xpt_release_simq(struct cam_sim *sim, int run_queue) 44438b8a9b1dSJustin T. Gibbs { 44448b8a9b1dSJustin T. Gibbs int s; 44458b8a9b1dSJustin T. Gibbs struct camq *sendq; 44468b8a9b1dSJustin T. Gibbs 44478b8a9b1dSJustin T. Gibbs sendq = &(sim->devq->send_queue); 44488b8a9b1dSJustin T. Gibbs s = splcam(); 44498b8a9b1dSJustin T. Gibbs if (sendq->qfrozen_cnt > 0) { 44508b8a9b1dSJustin T. Gibbs 44518b8a9b1dSJustin T. Gibbs sendq->qfrozen_cnt--; 44528b8a9b1dSJustin T. Gibbs if (sendq->qfrozen_cnt == 0) { 4453a5479bc5SJustin T. Gibbs struct cam_eb *bus; 44548b8a9b1dSJustin T. Gibbs 44558b8a9b1dSJustin T. Gibbs /* 44568b8a9b1dSJustin T. Gibbs * If there is a timeout scheduled to release this 44578b8a9b1dSJustin T. Gibbs * sim queue, remove it. The queue frozen count is 44588b8a9b1dSJustin T. Gibbs * already at 0. 44598b8a9b1dSJustin T. Gibbs */ 44608b8a9b1dSJustin T. Gibbs if ((sim->flags & CAM_SIM_REL_TIMEOUT_PENDING) != 0){ 44618b8a9b1dSJustin T. Gibbs untimeout(xpt_release_simq_timeout, sim, 44628b8a9b1dSJustin T. Gibbs sim->c_handle); 44638b8a9b1dSJustin T. Gibbs sim->flags &= ~CAM_SIM_REL_TIMEOUT_PENDING; 44648b8a9b1dSJustin T. Gibbs } 4465a5479bc5SJustin T. Gibbs bus = xpt_find_bus(sim->path_id); 44668b8a9b1dSJustin T. Gibbs splx(s); 44678b8a9b1dSJustin T. Gibbs 44688b8a9b1dSJustin T. Gibbs if (run_queue) { 44698b8a9b1dSJustin T. Gibbs /* 44708b8a9b1dSJustin T. Gibbs * Now that we are unfrozen run the send queue. 44718b8a9b1dSJustin T. Gibbs */ 4472a5479bc5SJustin T. Gibbs xpt_run_dev_sendq(bus); 44738b8a9b1dSJustin T. Gibbs } 4474a5479bc5SJustin T. Gibbs xpt_release_bus(bus); 44758b8a9b1dSJustin T. Gibbs } else 44768b8a9b1dSJustin T. Gibbs splx(s); 44778b8a9b1dSJustin T. Gibbs } else 44788b8a9b1dSJustin T. Gibbs splx(s); 44798b8a9b1dSJustin T. Gibbs } 44808b8a9b1dSJustin T. Gibbs 44818b8a9b1dSJustin T. Gibbs static void 44828b8a9b1dSJustin T. Gibbs xpt_release_simq_timeout(void *arg) 44838b8a9b1dSJustin T. Gibbs { 44848b8a9b1dSJustin T. Gibbs struct cam_sim *sim; 44858b8a9b1dSJustin T. Gibbs 44868b8a9b1dSJustin T. Gibbs sim = (struct cam_sim *)arg; 44878b8a9b1dSJustin T. Gibbs xpt_release_simq(sim, /* run_queue */ TRUE); 44888b8a9b1dSJustin T. Gibbs } 44898b8a9b1dSJustin T. Gibbs 44908b8a9b1dSJustin T. Gibbs void 4491a5479bc5SJustin T. Gibbs xpt_done(union ccb *done_ccb) 44928b8a9b1dSJustin T. Gibbs { 44938b8a9b1dSJustin T. Gibbs int s; 44948b8a9b1dSJustin T. Gibbs 44958b8a9b1dSJustin T. Gibbs s = splcam(); 44968b8a9b1dSJustin T. Gibbs 44978b8a9b1dSJustin T. Gibbs CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_TRACE, ("xpt_done\n")); 44989deea857SKenneth D. Merry if ((done_ccb->ccb_h.func_code & XPT_FC_QUEUED) != 0) { 44998b8a9b1dSJustin T. Gibbs /* 45008b8a9b1dSJustin T. Gibbs * Queue up the request for handling by our SWI handler 45018b8a9b1dSJustin T. Gibbs * any of the "non-immediate" type of ccbs. 45028b8a9b1dSJustin T. Gibbs */ 45038b8a9b1dSJustin T. Gibbs switch (done_ccb->ccb_h.path->periph->type) { 45048b8a9b1dSJustin T. Gibbs case CAM_PERIPH_BIO: 45058b8a9b1dSJustin T. Gibbs TAILQ_INSERT_TAIL(&cam_bioq, &done_ccb->ccb_h, 45068b8a9b1dSJustin T. Gibbs sim_links.tqe); 45078b8a9b1dSJustin T. Gibbs done_ccb->ccb_h.pinfo.index = CAM_DONEQ_INDEX; 45088b8a9b1dSJustin T. Gibbs setsoftcambio(); 45098b8a9b1dSJustin T. Gibbs break; 45108b8a9b1dSJustin T. Gibbs case CAM_PERIPH_NET: 45118b8a9b1dSJustin T. Gibbs TAILQ_INSERT_TAIL(&cam_netq, &done_ccb->ccb_h, 45128b8a9b1dSJustin T. Gibbs sim_links.tqe); 45138b8a9b1dSJustin T. Gibbs done_ccb->ccb_h.pinfo.index = CAM_DONEQ_INDEX; 45148b8a9b1dSJustin T. Gibbs setsoftcamnet(); 45158b8a9b1dSJustin T. Gibbs break; 45168b8a9b1dSJustin T. Gibbs } 45178b8a9b1dSJustin T. Gibbs } 45188b8a9b1dSJustin T. Gibbs splx(s); 45198b8a9b1dSJustin T. Gibbs } 45208b8a9b1dSJustin T. Gibbs 45218b8a9b1dSJustin T. Gibbs union ccb * 45228b8a9b1dSJustin T. Gibbs xpt_alloc_ccb() 45238b8a9b1dSJustin T. Gibbs { 45248b8a9b1dSJustin T. Gibbs union ccb *new_ccb; 45258b8a9b1dSJustin T. Gibbs 45268b8a9b1dSJustin T. Gibbs new_ccb = malloc(sizeof(*new_ccb), M_DEVBUF, M_WAITOK); 45278b8a9b1dSJustin T. Gibbs return (new_ccb); 45288b8a9b1dSJustin T. Gibbs } 45298b8a9b1dSJustin T. Gibbs 45308b8a9b1dSJustin T. Gibbs void 45318b8a9b1dSJustin T. Gibbs xpt_free_ccb(union ccb *free_ccb) 45328b8a9b1dSJustin T. Gibbs { 45338b8a9b1dSJustin T. Gibbs free(free_ccb, M_DEVBUF); 45348b8a9b1dSJustin T. Gibbs } 45358b8a9b1dSJustin T. Gibbs 45368b8a9b1dSJustin T. Gibbs 45378b8a9b1dSJustin T. Gibbs 45388b8a9b1dSJustin T. Gibbs /* Private XPT functions */ 45398b8a9b1dSJustin T. Gibbs 45408b8a9b1dSJustin T. Gibbs /* 45418b8a9b1dSJustin T. Gibbs * Get a CAM control block for the caller. Charge the structure to the device 45428b8a9b1dSJustin T. Gibbs * referenced by the path. If the this device has no 'credits' then the 45438b8a9b1dSJustin T. Gibbs * device already has the maximum number of outstanding operations under way 45448b8a9b1dSJustin T. Gibbs * and we return NULL. If we don't have sufficient resources to allocate more 45458b8a9b1dSJustin T. Gibbs * ccbs, we also return NULL. 45468b8a9b1dSJustin T. Gibbs */ 45478b8a9b1dSJustin T. Gibbs static union ccb * 45488b8a9b1dSJustin T. Gibbs xpt_get_ccb(struct cam_ed *device) 45498b8a9b1dSJustin T. Gibbs { 45508b8a9b1dSJustin T. Gibbs union ccb *new_ccb; 45518b8a9b1dSJustin T. Gibbs int s; 45528b8a9b1dSJustin T. Gibbs 45538b8a9b1dSJustin T. Gibbs s = splsoftcam(); 45548b8a9b1dSJustin T. Gibbs if ((new_ccb = (union ccb *)ccb_freeq.slh_first) == NULL) { 45558b8a9b1dSJustin T. Gibbs new_ccb = malloc(sizeof(*new_ccb), M_DEVBUF, M_NOWAIT); 45568b8a9b1dSJustin T. Gibbs if (new_ccb == NULL) { 45578b8a9b1dSJustin T. Gibbs splx(s); 45588b8a9b1dSJustin T. Gibbs return (NULL); 45598b8a9b1dSJustin T. Gibbs } 45608b8a9b1dSJustin T. Gibbs callout_handle_init(&new_ccb->ccb_h.timeout_ch); 45618b8a9b1dSJustin T. Gibbs SLIST_INSERT_HEAD(&ccb_freeq, &new_ccb->ccb_h, 45628b8a9b1dSJustin T. Gibbs xpt_links.sle); 45638b8a9b1dSJustin T. Gibbs xpt_ccb_count++; 45648b8a9b1dSJustin T. Gibbs } 45658b8a9b1dSJustin T. Gibbs cam_ccbq_take_opening(&device->ccbq); 45668b8a9b1dSJustin T. Gibbs SLIST_REMOVE_HEAD(&ccb_freeq, xpt_links.sle); 45678b8a9b1dSJustin T. Gibbs splx(s); 45688b8a9b1dSJustin T. Gibbs return (new_ccb); 45698b8a9b1dSJustin T. Gibbs } 45708b8a9b1dSJustin T. Gibbs 4571a5479bc5SJustin T. Gibbs static void 4572a5479bc5SJustin T. Gibbs xpt_release_bus(struct cam_eb *bus) 4573a5479bc5SJustin T. Gibbs { 4574a5479bc5SJustin T. Gibbs int s; 4575a5479bc5SJustin T. Gibbs 4576a5479bc5SJustin T. Gibbs s = splcam(); 4577a5479bc5SJustin T. Gibbs if ((--bus->refcount == 0) 4578a5479bc5SJustin T. Gibbs && (TAILQ_FIRST(&bus->et_entries) == NULL)) { 4579a5479bc5SJustin T. Gibbs TAILQ_REMOVE(&xpt_busses, bus, links); 4580a5479bc5SJustin T. Gibbs bus_generation++; 4581a5479bc5SJustin T. Gibbs splx(s); 4582a5479bc5SJustin T. Gibbs free(bus, M_DEVBUF); 4583a5479bc5SJustin T. Gibbs } else 4584a5479bc5SJustin T. Gibbs splx(s); 4585a5479bc5SJustin T. Gibbs } 45868b8a9b1dSJustin T. Gibbs 45878b8a9b1dSJustin T. Gibbs static struct cam_et * 45888b8a9b1dSJustin T. Gibbs xpt_alloc_target(struct cam_eb *bus, target_id_t target_id) 45898b8a9b1dSJustin T. Gibbs { 45908b8a9b1dSJustin T. Gibbs struct cam_et *target; 45918b8a9b1dSJustin T. Gibbs 45928b8a9b1dSJustin T. Gibbs target = (struct cam_et *)malloc(sizeof(*target), M_DEVBUF, M_NOWAIT); 45938b8a9b1dSJustin T. Gibbs if (target != NULL) { 45948b8a9b1dSJustin T. Gibbs struct cam_et *cur_target; 45958b8a9b1dSJustin T. Gibbs 4596434bbf6eSJustin T. Gibbs TAILQ_INIT(&target->ed_entries); 45978b8a9b1dSJustin T. Gibbs target->bus = bus; 45988b8a9b1dSJustin T. Gibbs target->target_id = target_id; 45998b8a9b1dSJustin T. Gibbs target->refcount = 1; 4600434bbf6eSJustin T. Gibbs target->generation = 0; 4601434bbf6eSJustin T. Gibbs timevalclear(&target->last_reset); 4602a5479bc5SJustin T. Gibbs /* 4603a5479bc5SJustin T. Gibbs * Hold a reference to our parent bus so it 4604a5479bc5SJustin T. Gibbs * will not go away before we do. 4605a5479bc5SJustin T. Gibbs */ 4606a5479bc5SJustin T. Gibbs bus->refcount++; 46078b8a9b1dSJustin T. Gibbs 46088b8a9b1dSJustin T. Gibbs /* Insertion sort into our bus's target list */ 46098b8a9b1dSJustin T. Gibbs cur_target = TAILQ_FIRST(&bus->et_entries); 46108b8a9b1dSJustin T. Gibbs while (cur_target != NULL && cur_target->target_id < target_id) 46118b8a9b1dSJustin T. Gibbs cur_target = TAILQ_NEXT(cur_target, links); 46128b8a9b1dSJustin T. Gibbs 46138b8a9b1dSJustin T. Gibbs if (cur_target != NULL) { 46148b8a9b1dSJustin T. Gibbs TAILQ_INSERT_BEFORE(cur_target, target, links); 46158b8a9b1dSJustin T. Gibbs } else { 46168b8a9b1dSJustin T. Gibbs TAILQ_INSERT_TAIL(&bus->et_entries, target, links); 46178b8a9b1dSJustin T. Gibbs } 4618a5479bc5SJustin T. Gibbs bus->generation++; 46198b8a9b1dSJustin T. Gibbs } 46208b8a9b1dSJustin T. Gibbs return (target); 46218b8a9b1dSJustin T. Gibbs } 46228b8a9b1dSJustin T. Gibbs 4623a5479bc5SJustin T. Gibbs static void 46248b8a9b1dSJustin T. Gibbs xpt_release_target(struct cam_eb *bus, struct cam_et *target) 46258b8a9b1dSJustin T. Gibbs { 4626a5479bc5SJustin T. Gibbs int s; 4627a5479bc5SJustin T. Gibbs 4628a5479bc5SJustin T. Gibbs s = splcam(); 46298b8a9b1dSJustin T. Gibbs if ((--target->refcount == 0) 46308b8a9b1dSJustin T. Gibbs && (TAILQ_FIRST(&target->ed_entries) == NULL)) { 46318b8a9b1dSJustin T. Gibbs TAILQ_REMOVE(&bus->et_entries, target, links); 46328b8a9b1dSJustin T. Gibbs bus->generation++; 4633a5479bc5SJustin T. Gibbs splx(s); 46348b8a9b1dSJustin T. Gibbs free(target, M_DEVBUF); 4635a5479bc5SJustin T. Gibbs xpt_release_bus(bus); 4636a5479bc5SJustin T. Gibbs } else 4637a5479bc5SJustin T. Gibbs splx(s); 46388b8a9b1dSJustin T. Gibbs } 46398b8a9b1dSJustin T. Gibbs 46408b8a9b1dSJustin T. Gibbs static struct cam_ed * 46418b8a9b1dSJustin T. Gibbs xpt_alloc_device(struct cam_eb *bus, struct cam_et *target, lun_id_t lun_id) 46428b8a9b1dSJustin T. Gibbs { 46438b8a9b1dSJustin T. Gibbs struct cam_ed *device; 46448b8a9b1dSJustin T. Gibbs struct cam_devq *devq; 4645a5479bc5SJustin T. Gibbs cam_status status; 46468b8a9b1dSJustin T. Gibbs 46478b8a9b1dSJustin T. Gibbs /* Make space for us in the device queue on our bus */ 46488b8a9b1dSJustin T. Gibbs devq = bus->sim->devq; 46498b8a9b1dSJustin T. Gibbs status = cam_devq_resize(devq, devq->alloc_queue.array_size + 1); 46508b8a9b1dSJustin T. Gibbs 46518b8a9b1dSJustin T. Gibbs if (status != CAM_REQ_CMP) { 46528b8a9b1dSJustin T. Gibbs device = NULL; 46538b8a9b1dSJustin T. Gibbs } else { 46548b8a9b1dSJustin T. Gibbs device = (struct cam_ed *)malloc(sizeof(*device), 46558b8a9b1dSJustin T. Gibbs M_DEVBUF, M_NOWAIT); 46568b8a9b1dSJustin T. Gibbs } 46578b8a9b1dSJustin T. Gibbs 46588b8a9b1dSJustin T. Gibbs if (device != NULL) { 46598b8a9b1dSJustin T. Gibbs struct cam_ed *cur_device; 46608b8a9b1dSJustin T. Gibbs 46618b8a9b1dSJustin T. Gibbs cam_init_pinfo(&device->alloc_ccb_entry.pinfo); 46628b8a9b1dSJustin T. Gibbs device->alloc_ccb_entry.device = device; 46638b8a9b1dSJustin T. Gibbs cam_init_pinfo(&device->send_ccb_entry.pinfo); 46648b8a9b1dSJustin T. Gibbs device->send_ccb_entry.device = device; 46658b8a9b1dSJustin T. Gibbs device->target = target; 46668b8a9b1dSJustin T. Gibbs device->lun_id = lun_id; 46678b8a9b1dSJustin T. Gibbs /* Initialize our queues */ 46688b8a9b1dSJustin T. Gibbs if (camq_init(&device->drvq, 0) != 0) { 46698b8a9b1dSJustin T. Gibbs free(device, M_DEVBUF); 46708b8a9b1dSJustin T. Gibbs return (NULL); 46718b8a9b1dSJustin T. Gibbs } 46728b8a9b1dSJustin T. Gibbs if (cam_ccbq_init(&device->ccbq, 46738b8a9b1dSJustin T. Gibbs bus->sim->max_dev_openings) != 0) { 46748b8a9b1dSJustin T. Gibbs camq_fini(&device->drvq); 46758b8a9b1dSJustin T. Gibbs free(device, M_DEVBUF); 46768b8a9b1dSJustin T. Gibbs return (NULL); 46778b8a9b1dSJustin T. Gibbs } 4678434bbf6eSJustin T. Gibbs SLIST_INIT(&device->asyncs); 4679434bbf6eSJustin T. Gibbs SLIST_INIT(&device->periphs); 4680434bbf6eSJustin T. Gibbs device->generation = 0; 4681434bbf6eSJustin T. Gibbs device->owner = NULL; 4682434bbf6eSJustin T. Gibbs /* 4683434bbf6eSJustin T. Gibbs * Take the default quirk entry until we have inquiry 4684434bbf6eSJustin T. Gibbs * data and can determine a better quirk to use. 4685434bbf6eSJustin T. Gibbs */ 4686434bbf6eSJustin T. Gibbs device->quirk = &xpt_quirk_table[xpt_quirk_table_size - 1]; 4687434bbf6eSJustin T. Gibbs bzero(&device->inq_data, sizeof(device->inq_data)); 4688434bbf6eSJustin T. Gibbs device->inq_flags = 0; 4689434bbf6eSJustin T. Gibbs device->queue_flags = 0; 4690434bbf6eSJustin T. Gibbs device->serial_num = NULL; 4691434bbf6eSJustin T. Gibbs device->serial_num_len = 0; 4692434bbf6eSJustin T. Gibbs device->qfrozen_cnt = 0; 4693434bbf6eSJustin T. Gibbs device->flags = CAM_DEV_UNCONFIGURED; 4694434bbf6eSJustin T. Gibbs device->tag_delay_count = 0; 4695434bbf6eSJustin T. Gibbs device->refcount = 1; 4696434bbf6eSJustin T. Gibbs callout_handle_init(&device->c_handle); 4697434bbf6eSJustin T. Gibbs 4698434bbf6eSJustin T. Gibbs /* 4699434bbf6eSJustin T. Gibbs * Hold a reference to our parent target so it 4700434bbf6eSJustin T. Gibbs * will not go away before we do. 4701434bbf6eSJustin T. Gibbs */ 4702434bbf6eSJustin T. Gibbs target->refcount++; 4703434bbf6eSJustin T. Gibbs 47048b8a9b1dSJustin T. Gibbs /* 47058b8a9b1dSJustin T. Gibbs * XXX should be limited by number of CCBs this bus can 47068b8a9b1dSJustin T. Gibbs * do. 47078b8a9b1dSJustin T. Gibbs */ 47088b8a9b1dSJustin T. Gibbs xpt_max_ccbs += device->ccbq.devq_openings; 47098b8a9b1dSJustin T. Gibbs /* Insertion sort into our target's device list */ 47108b8a9b1dSJustin T. Gibbs cur_device = TAILQ_FIRST(&target->ed_entries); 47118b8a9b1dSJustin T. Gibbs while (cur_device != NULL && cur_device->lun_id < lun_id) 47128b8a9b1dSJustin T. Gibbs cur_device = TAILQ_NEXT(cur_device, links); 47138b8a9b1dSJustin T. Gibbs if (cur_device != NULL) { 47148b8a9b1dSJustin T. Gibbs TAILQ_INSERT_BEFORE(cur_device, device, links); 47158b8a9b1dSJustin T. Gibbs } else { 47168b8a9b1dSJustin T. Gibbs TAILQ_INSERT_TAIL(&target->ed_entries, device, links); 47178b8a9b1dSJustin T. Gibbs } 4718a5479bc5SJustin T. Gibbs target->generation++; 47198b8a9b1dSJustin T. Gibbs } 47208b8a9b1dSJustin T. Gibbs return (device); 47218b8a9b1dSJustin T. Gibbs } 47228b8a9b1dSJustin T. Gibbs 47238b8a9b1dSJustin T. Gibbs static void 47248b8a9b1dSJustin T. Gibbs xpt_release_device(struct cam_eb *bus, struct cam_et *target, 47258b8a9b1dSJustin T. Gibbs struct cam_ed *device) 47268b8a9b1dSJustin T. Gibbs { 47278b8a9b1dSJustin T. Gibbs int s; 47288b8a9b1dSJustin T. Gibbs 4729a5479bc5SJustin T. Gibbs s = splcam(); 47308b8a9b1dSJustin T. Gibbs if ((--device->refcount == 0) 47318b8a9b1dSJustin T. Gibbs && ((device->flags & CAM_DEV_UNCONFIGURED) != 0)) { 47328b8a9b1dSJustin T. Gibbs struct cam_devq *devq; 47338b8a9b1dSJustin T. Gibbs 4734a5479bc5SJustin T. Gibbs if (device->alloc_ccb_entry.pinfo.index != CAM_UNQUEUED_INDEX 4735a5479bc5SJustin T. Gibbs || device->send_ccb_entry.pinfo.index != CAM_UNQUEUED_INDEX) 4736a5479bc5SJustin T. Gibbs panic("Removing device while still queued for ccbs"); 47372cefde5fSJustin T. Gibbs 47382cefde5fSJustin T. Gibbs if ((device->flags & CAM_DEV_REL_TIMEOUT_PENDING) != 0) 47392cefde5fSJustin T. Gibbs untimeout(xpt_release_devq_timeout, device, 47402cefde5fSJustin T. Gibbs device->c_handle); 47412cefde5fSJustin T. Gibbs 47428b8a9b1dSJustin T. Gibbs TAILQ_REMOVE(&target->ed_entries, device,links); 47438b8a9b1dSJustin T. Gibbs target->generation++; 47448b8a9b1dSJustin T. Gibbs xpt_max_ccbs -= device->ccbq.devq_openings; 47458b8a9b1dSJustin T. Gibbs /* Release our slot in the devq */ 47468b8a9b1dSJustin T. Gibbs devq = bus->sim->devq; 47478b8a9b1dSJustin T. Gibbs cam_devq_resize(devq, devq->alloc_queue.array_size - 1); 47488b8a9b1dSJustin T. Gibbs splx(s); 4749a5479bc5SJustin T. Gibbs free(device, M_DEVBUF); 4750434bbf6eSJustin T. Gibbs xpt_release_target(bus, target); 4751a5479bc5SJustin T. Gibbs } else 4752a5479bc5SJustin T. Gibbs splx(s); 47538b8a9b1dSJustin T. Gibbs } 47548b8a9b1dSJustin T. Gibbs 47558b8a9b1dSJustin T. Gibbs static u_int32_t 47568b8a9b1dSJustin T. Gibbs xpt_dev_ccbq_resize(struct cam_path *path, int newopenings) 47578b8a9b1dSJustin T. Gibbs { 47588b8a9b1dSJustin T. Gibbs int s; 47598b8a9b1dSJustin T. Gibbs int diff; 47608b8a9b1dSJustin T. Gibbs int result; 47618b8a9b1dSJustin T. Gibbs struct cam_ed *dev; 47628b8a9b1dSJustin T. Gibbs 47638b8a9b1dSJustin T. Gibbs dev = path->device; 47648b8a9b1dSJustin T. Gibbs s = splsoftcam(); 47658b8a9b1dSJustin T. Gibbs 47668b8a9b1dSJustin T. Gibbs diff = newopenings - (dev->ccbq.dev_active + dev->ccbq.dev_openings); 47678b8a9b1dSJustin T. Gibbs result = cam_ccbq_resize(&dev->ccbq, newopenings); 47688b8a9b1dSJustin T. Gibbs if (result == CAM_REQ_CMP && (diff < 0)) { 47698b8a9b1dSJustin T. Gibbs dev->flags |= CAM_DEV_RESIZE_QUEUE_NEEDED; 47708b8a9b1dSJustin T. Gibbs } 47718b8a9b1dSJustin T. Gibbs /* Adjust the global limit */ 47728b8a9b1dSJustin T. Gibbs xpt_max_ccbs += diff; 47738b8a9b1dSJustin T. Gibbs splx(s); 47748b8a9b1dSJustin T. Gibbs return (result); 47758b8a9b1dSJustin T. Gibbs } 47768b8a9b1dSJustin T. Gibbs 47778b8a9b1dSJustin T. Gibbs static struct cam_eb * 47788b8a9b1dSJustin T. Gibbs xpt_find_bus(path_id_t path_id) 47798b8a9b1dSJustin T. Gibbs { 47808b8a9b1dSJustin T. Gibbs struct cam_eb *bus; 47818b8a9b1dSJustin T. Gibbs 47828b8a9b1dSJustin T. Gibbs for (bus = TAILQ_FIRST(&xpt_busses); 47838b8a9b1dSJustin T. Gibbs bus != NULL; 47848b8a9b1dSJustin T. Gibbs bus = TAILQ_NEXT(bus, links)) { 4785a5479bc5SJustin T. Gibbs if (bus->path_id == path_id) { 4786a5479bc5SJustin T. Gibbs bus->refcount++; 47878b8a9b1dSJustin T. Gibbs break; 47888b8a9b1dSJustin T. Gibbs } 4789a5479bc5SJustin T. Gibbs } 47908b8a9b1dSJustin T. Gibbs return (bus); 47918b8a9b1dSJustin T. Gibbs } 47928b8a9b1dSJustin T. Gibbs 47938b8a9b1dSJustin T. Gibbs static struct cam_et * 47948b8a9b1dSJustin T. Gibbs xpt_find_target(struct cam_eb *bus, target_id_t target_id) 47958b8a9b1dSJustin T. Gibbs { 47968b8a9b1dSJustin T. Gibbs struct cam_et *target; 47978b8a9b1dSJustin T. Gibbs 47988b8a9b1dSJustin T. Gibbs for (target = TAILQ_FIRST(&bus->et_entries); 47998b8a9b1dSJustin T. Gibbs target != NULL; 48008b8a9b1dSJustin T. Gibbs target = TAILQ_NEXT(target, links)) { 48018b8a9b1dSJustin T. Gibbs if (target->target_id == target_id) { 48028b8a9b1dSJustin T. Gibbs target->refcount++; 48038b8a9b1dSJustin T. Gibbs break; 48048b8a9b1dSJustin T. Gibbs } 48058b8a9b1dSJustin T. Gibbs } 48068b8a9b1dSJustin T. Gibbs return (target); 48078b8a9b1dSJustin T. Gibbs } 48088b8a9b1dSJustin T. Gibbs 48098b8a9b1dSJustin T. Gibbs static struct cam_ed * 48108b8a9b1dSJustin T. Gibbs xpt_find_device(struct cam_et *target, lun_id_t lun_id) 48118b8a9b1dSJustin T. Gibbs { 48128b8a9b1dSJustin T. Gibbs struct cam_ed *device; 48138b8a9b1dSJustin T. Gibbs 48148b8a9b1dSJustin T. Gibbs for (device = TAILQ_FIRST(&target->ed_entries); 48158b8a9b1dSJustin T. Gibbs device != NULL; 48168b8a9b1dSJustin T. Gibbs device = TAILQ_NEXT(device, links)) { 48178b8a9b1dSJustin T. Gibbs if (device->lun_id == lun_id) { 48188b8a9b1dSJustin T. Gibbs device->refcount++; 48198b8a9b1dSJustin T. Gibbs break; 48208b8a9b1dSJustin T. Gibbs } 48218b8a9b1dSJustin T. Gibbs } 48228b8a9b1dSJustin T. Gibbs return (device); 48238b8a9b1dSJustin T. Gibbs } 48248b8a9b1dSJustin T. Gibbs 48258b8a9b1dSJustin T. Gibbs typedef struct { 48268b8a9b1dSJustin T. Gibbs union ccb *request_ccb; 48278b8a9b1dSJustin T. Gibbs struct ccb_pathinq *cpi; 48288b8a9b1dSJustin T. Gibbs int pending_count; 48298b8a9b1dSJustin T. Gibbs } xpt_scan_bus_info; 48308b8a9b1dSJustin T. Gibbs 48318b8a9b1dSJustin T. Gibbs /* 48328b8a9b1dSJustin T. Gibbs * To start a scan, request_ccb is an XPT_SCAN_BUS ccb. 48338b8a9b1dSJustin T. Gibbs * As the scan progresses, xpt_scan_bus is used as the 48348b8a9b1dSJustin T. Gibbs * callback on completion function. 48358b8a9b1dSJustin T. Gibbs */ 48368b8a9b1dSJustin T. Gibbs static void 48378b8a9b1dSJustin T. Gibbs xpt_scan_bus(struct cam_periph *periph, union ccb *request_ccb) 48388b8a9b1dSJustin T. Gibbs { 48398b8a9b1dSJustin T. Gibbs CAM_DEBUG(request_ccb->ccb_h.path, CAM_DEBUG_TRACE, 48408b8a9b1dSJustin T. Gibbs ("xpt_scan_bus\n")); 48418b8a9b1dSJustin T. Gibbs switch (request_ccb->ccb_h.func_code) { 48428b8a9b1dSJustin T. Gibbs case XPT_SCAN_BUS: 48438b8a9b1dSJustin T. Gibbs { 48448b8a9b1dSJustin T. Gibbs xpt_scan_bus_info *scan_info; 48458b8a9b1dSJustin T. Gibbs union ccb *work_ccb; 48468b8a9b1dSJustin T. Gibbs struct cam_path *path; 48478b8a9b1dSJustin T. Gibbs u_int i; 48488b8a9b1dSJustin T. Gibbs u_int max_target; 48498b8a9b1dSJustin T. Gibbs u_int initiator_id; 48508b8a9b1dSJustin T. Gibbs 48518b8a9b1dSJustin T. Gibbs /* Find out the characteristics of the bus */ 48528b8a9b1dSJustin T. Gibbs work_ccb = xpt_alloc_ccb(); 48538b8a9b1dSJustin T. Gibbs xpt_setup_ccb(&work_ccb->ccb_h, request_ccb->ccb_h.path, 48548b8a9b1dSJustin T. Gibbs request_ccb->ccb_h.pinfo.priority); 48558b8a9b1dSJustin T. Gibbs work_ccb->ccb_h.func_code = XPT_PATH_INQ; 48568b8a9b1dSJustin T. Gibbs xpt_action(work_ccb); 48578b8a9b1dSJustin T. Gibbs if (work_ccb->ccb_h.status != CAM_REQ_CMP) { 48588b8a9b1dSJustin T. Gibbs request_ccb->ccb_h.status = work_ccb->ccb_h.status; 48598b8a9b1dSJustin T. Gibbs xpt_free_ccb(work_ccb); 48608b8a9b1dSJustin T. Gibbs xpt_done(request_ccb); 48618b8a9b1dSJustin T. Gibbs return; 48628b8a9b1dSJustin T. Gibbs } 48638b8a9b1dSJustin T. Gibbs 486498192658SJustin T. Gibbs if ((work_ccb->cpi.hba_misc & PIM_NOINITIATOR) != 0) { 486598192658SJustin T. Gibbs /* 486698192658SJustin T. Gibbs * Can't scan the bus on an adapter that 486798192658SJustin T. Gibbs * cannot perform the initiator role. 486898192658SJustin T. Gibbs */ 486998192658SJustin T. Gibbs request_ccb->ccb_h.status = CAM_REQ_CMP; 487098192658SJustin T. Gibbs xpt_free_ccb(work_ccb); 487198192658SJustin T. Gibbs xpt_done(request_ccb); 487298192658SJustin T. Gibbs return; 487398192658SJustin T. Gibbs } 487498192658SJustin T. Gibbs 48758b8a9b1dSJustin T. Gibbs /* Save some state for use while we probe for devices */ 48768b8a9b1dSJustin T. Gibbs scan_info = (xpt_scan_bus_info *) 48778b8a9b1dSJustin T. Gibbs malloc(sizeof(xpt_scan_bus_info), M_TEMP, M_WAITOK); 48788b8a9b1dSJustin T. Gibbs scan_info->request_ccb = request_ccb; 48798b8a9b1dSJustin T. Gibbs scan_info->cpi = &work_ccb->cpi; 48808b8a9b1dSJustin T. Gibbs 48818b8a9b1dSJustin T. Gibbs /* Cache on our stack so we can work asynchronously */ 48828b8a9b1dSJustin T. Gibbs max_target = scan_info->cpi->max_target; 48838b8a9b1dSJustin T. Gibbs initiator_id = scan_info->cpi->initiator_id; 48848b8a9b1dSJustin T. Gibbs 48858b8a9b1dSJustin T. Gibbs /* 48868b8a9b1dSJustin T. Gibbs * Don't count the initiator if the 48878b8a9b1dSJustin T. Gibbs * initiator is addressable. 48888b8a9b1dSJustin T. Gibbs */ 48898b8a9b1dSJustin T. Gibbs scan_info->pending_count = max_target + 1; 48908b8a9b1dSJustin T. Gibbs if (initiator_id <= max_target) 48918b8a9b1dSJustin T. Gibbs scan_info->pending_count--; 48928b8a9b1dSJustin T. Gibbs 48938b8a9b1dSJustin T. Gibbs for (i = 0; i <= max_target; i++) { 48948b8a9b1dSJustin T. Gibbs cam_status status; 48958b8a9b1dSJustin T. Gibbs if (i == initiator_id) 48968b8a9b1dSJustin T. Gibbs continue; 48978b8a9b1dSJustin T. Gibbs 48988b8a9b1dSJustin T. Gibbs status = xpt_create_path(&path, xpt_periph, 48998b8a9b1dSJustin T. Gibbs request_ccb->ccb_h.path_id, 49008b8a9b1dSJustin T. Gibbs i, 0); 49018b8a9b1dSJustin T. Gibbs if (status != CAM_REQ_CMP) { 49028b8a9b1dSJustin T. Gibbs printf("xpt_scan_bus: xpt_create_path failed" 49038b8a9b1dSJustin T. Gibbs " with status %#x, bus scan halted\n", 49048b8a9b1dSJustin T. Gibbs status); 49058b8a9b1dSJustin T. Gibbs break; 49068b8a9b1dSJustin T. Gibbs } 49078b8a9b1dSJustin T. Gibbs work_ccb = xpt_alloc_ccb(); 49088b8a9b1dSJustin T. Gibbs xpt_setup_ccb(&work_ccb->ccb_h, path, 49098b8a9b1dSJustin T. Gibbs request_ccb->ccb_h.pinfo.priority); 49108b8a9b1dSJustin T. Gibbs work_ccb->ccb_h.func_code = XPT_SCAN_LUN; 49118b8a9b1dSJustin T. Gibbs work_ccb->ccb_h.cbfcnp = xpt_scan_bus; 49128b8a9b1dSJustin T. Gibbs work_ccb->ccb_h.ppriv_ptr0 = scan_info; 49138b8a9b1dSJustin T. Gibbs work_ccb->crcn.flags = request_ccb->crcn.flags; 49148b8a9b1dSJustin T. Gibbs #if 0 49158b8a9b1dSJustin T. Gibbs printf("xpt_scan_bus: probing %d:%d:%d\n", 49168b8a9b1dSJustin T. Gibbs request_ccb->ccb_h.path_id, i, 0); 49178b8a9b1dSJustin T. Gibbs #endif 49188b8a9b1dSJustin T. Gibbs xpt_action(work_ccb); 49198b8a9b1dSJustin T. Gibbs } 49208b8a9b1dSJustin T. Gibbs break; 49218b8a9b1dSJustin T. Gibbs } 49228b8a9b1dSJustin T. Gibbs case XPT_SCAN_LUN: 49238b8a9b1dSJustin T. Gibbs { 49248b8a9b1dSJustin T. Gibbs xpt_scan_bus_info *scan_info; 49258b8a9b1dSJustin T. Gibbs path_id_t path_id; 49268b8a9b1dSJustin T. Gibbs target_id_t target_id; 49278b8a9b1dSJustin T. Gibbs lun_id_t lun_id; 49288b8a9b1dSJustin T. Gibbs 49298b8a9b1dSJustin T. Gibbs /* Reuse the same CCB to query if a device was really found */ 49308b8a9b1dSJustin T. Gibbs scan_info = (xpt_scan_bus_info *)request_ccb->ccb_h.ppriv_ptr0; 49318b8a9b1dSJustin T. Gibbs xpt_setup_ccb(&request_ccb->ccb_h, request_ccb->ccb_h.path, 49328b8a9b1dSJustin T. Gibbs request_ccb->ccb_h.pinfo.priority); 49338b8a9b1dSJustin T. Gibbs request_ccb->ccb_h.func_code = XPT_GDEV_TYPE; 49348b8a9b1dSJustin T. Gibbs 49358b8a9b1dSJustin T. Gibbs path_id = request_ccb->ccb_h.path_id; 49368b8a9b1dSJustin T. Gibbs target_id = request_ccb->ccb_h.target_id; 49378b8a9b1dSJustin T. Gibbs lun_id = request_ccb->ccb_h.target_lun; 49388b8a9b1dSJustin T. Gibbs xpt_action(request_ccb); 49398b8a9b1dSJustin T. Gibbs 49408b8a9b1dSJustin T. Gibbs #if 0 49418b8a9b1dSJustin T. Gibbs printf("xpt_scan_bus: got back probe from %d:%d:%d\n", 49428b8a9b1dSJustin T. Gibbs path_id, target_id, lun_id); 49438b8a9b1dSJustin T. Gibbs #endif 49448b8a9b1dSJustin T. Gibbs 49458b8a9b1dSJustin T. Gibbs if (request_ccb->ccb_h.status != CAM_REQ_CMP) { 49468b8a9b1dSJustin T. Gibbs struct cam_ed *device; 49478b8a9b1dSJustin T. Gibbs struct cam_et *target; 4948b6a0d1abSMatt Jacob int s, phl; 49498b8a9b1dSJustin T. Gibbs 49508b8a9b1dSJustin T. Gibbs /* 49518b8a9b1dSJustin T. Gibbs * If we already probed lun 0 successfully, or 49528b8a9b1dSJustin T. Gibbs * we have additional configured luns on this 49538b8a9b1dSJustin T. Gibbs * target that might have "gone away", go onto 49548b8a9b1dSJustin T. Gibbs * the next lun. 49558b8a9b1dSJustin T. Gibbs */ 49568b8a9b1dSJustin T. Gibbs target = request_ccb->ccb_h.path->target; 4957b6a0d1abSMatt Jacob /* 4958b6a0d1abSMatt Jacob * We may touch devices that we don't 4959b6a0d1abSMatt Jacob * hold references too, so ensure they 4960b6a0d1abSMatt Jacob * don't disappear out from under us. 4961b6a0d1abSMatt Jacob * The target above is referenced by the 4962b6a0d1abSMatt Jacob * path in the request ccb. 4963b6a0d1abSMatt Jacob */ 4964b6a0d1abSMatt Jacob phl = 0; 4965a5479bc5SJustin T. Gibbs s = splcam(); 49668b8a9b1dSJustin T. Gibbs device = TAILQ_FIRST(&target->ed_entries); 4967b6a0d1abSMatt Jacob if (device != NULL) { 4968b6a0d1abSMatt Jacob phl = device->quirk->quirks & CAM_QUIRK_HILUNS; 4969b6a0d1abSMatt Jacob if (device->lun_id == 0) 49708b8a9b1dSJustin T. Gibbs device = TAILQ_NEXT(device, links); 4971b6a0d1abSMatt Jacob } 4972a5479bc5SJustin T. Gibbs splx(s); 49738b8a9b1dSJustin T. Gibbs if ((lun_id != 0) || (device != NULL)) { 4974b6a0d1abSMatt Jacob if (lun_id < (CAM_SCSI2_MAXLUN-1) || phl) 49758b8a9b1dSJustin T. Gibbs lun_id++; 49768b8a9b1dSJustin T. Gibbs } 49778b8a9b1dSJustin T. Gibbs } else { 49788b8a9b1dSJustin T. Gibbs struct cam_ed *device; 49798b8a9b1dSJustin T. Gibbs 49808b8a9b1dSJustin T. Gibbs device = request_ccb->ccb_h.path->device; 49818b8a9b1dSJustin T. Gibbs 49828b8a9b1dSJustin T. Gibbs if ((device->quirk->quirks & CAM_QUIRK_NOLUNS) == 0) { 49838b8a9b1dSJustin T. Gibbs /* Try the next lun */ 498448f6456dSMatt Jacob if (lun_id < (CAM_SCSI2_MAXLUN-1) || 498548f6456dSMatt Jacob (device->quirk->quirks & CAM_QUIRK_HILUNS)) 49868b8a9b1dSJustin T. Gibbs lun_id++; 49878b8a9b1dSJustin T. Gibbs } 49888b8a9b1dSJustin T. Gibbs } 49898b8a9b1dSJustin T. Gibbs 49908b8a9b1dSJustin T. Gibbs xpt_free_path(request_ccb->ccb_h.path); 49918b8a9b1dSJustin T. Gibbs 49928b8a9b1dSJustin T. Gibbs /* Check Bounds */ 49938b8a9b1dSJustin T. Gibbs if ((lun_id == request_ccb->ccb_h.target_lun) 49948b8a9b1dSJustin T. Gibbs || lun_id > scan_info->cpi->max_lun) { 49958b8a9b1dSJustin T. Gibbs /* We're done */ 49968b8a9b1dSJustin T. Gibbs 49978b8a9b1dSJustin T. Gibbs xpt_free_ccb(request_ccb); 49988b8a9b1dSJustin T. Gibbs scan_info->pending_count--; 49998b8a9b1dSJustin T. Gibbs if (scan_info->pending_count == 0) { 50008b8a9b1dSJustin T. Gibbs xpt_free_ccb((union ccb *)scan_info->cpi); 50018b8a9b1dSJustin T. Gibbs request_ccb = scan_info->request_ccb; 50028b8a9b1dSJustin T. Gibbs free(scan_info, M_TEMP); 50038b8a9b1dSJustin T. Gibbs request_ccb->ccb_h.status = CAM_REQ_CMP; 50048b8a9b1dSJustin T. Gibbs xpt_done(request_ccb); 50058b8a9b1dSJustin T. Gibbs } 50068b8a9b1dSJustin T. Gibbs } else { 50078b8a9b1dSJustin T. Gibbs /* Try the next device */ 50088b8a9b1dSJustin T. Gibbs struct cam_path *path; 50098b8a9b1dSJustin T. Gibbs cam_status status; 50108b8a9b1dSJustin T. Gibbs 50118b8a9b1dSJustin T. Gibbs path = request_ccb->ccb_h.path; 50128b8a9b1dSJustin T. Gibbs status = xpt_create_path(&path, xpt_periph, 50138b8a9b1dSJustin T. Gibbs path_id, target_id, lun_id); 50148b8a9b1dSJustin T. Gibbs if (status != CAM_REQ_CMP) { 50158b8a9b1dSJustin T. Gibbs printf("xpt_scan_bus: xpt_create_path failed " 50168b8a9b1dSJustin T. Gibbs "with status %#x, halting LUN scan\n", 50178b8a9b1dSJustin T. Gibbs status); 50188b8a9b1dSJustin T. Gibbs xpt_free_ccb(request_ccb); 50198b8a9b1dSJustin T. Gibbs scan_info->pending_count--; 50208b8a9b1dSJustin T. Gibbs if (scan_info->pending_count == 0) { 50218b8a9b1dSJustin T. Gibbs xpt_free_ccb( 50228b8a9b1dSJustin T. Gibbs (union ccb *)scan_info->cpi); 50238b8a9b1dSJustin T. Gibbs request_ccb = scan_info->request_ccb; 50248b8a9b1dSJustin T. Gibbs free(scan_info, M_TEMP); 50258b8a9b1dSJustin T. Gibbs request_ccb->ccb_h.status = CAM_REQ_CMP; 50268b8a9b1dSJustin T. Gibbs xpt_done(request_ccb); 50278b8a9b1dSJustin T. Gibbs break; 50288b8a9b1dSJustin T. Gibbs } 50298b8a9b1dSJustin T. Gibbs } 50308b8a9b1dSJustin T. Gibbs xpt_setup_ccb(&request_ccb->ccb_h, path, 50318b8a9b1dSJustin T. Gibbs request_ccb->ccb_h.pinfo.priority); 50328b8a9b1dSJustin T. Gibbs request_ccb->ccb_h.func_code = XPT_SCAN_LUN; 50338b8a9b1dSJustin T. Gibbs request_ccb->ccb_h.cbfcnp = xpt_scan_bus; 50348b8a9b1dSJustin T. Gibbs request_ccb->ccb_h.ppriv_ptr0 = scan_info; 50358b8a9b1dSJustin T. Gibbs request_ccb->crcn.flags = 50368b8a9b1dSJustin T. Gibbs scan_info->request_ccb->crcn.flags; 50378b8a9b1dSJustin T. Gibbs #if 0 50388b8a9b1dSJustin T. Gibbs xpt_print_path(path); 50398b8a9b1dSJustin T. Gibbs printf("xpt_scan bus probing\n"); 50408b8a9b1dSJustin T. Gibbs #endif 50418b8a9b1dSJustin T. Gibbs xpt_action(request_ccb); 50428b8a9b1dSJustin T. Gibbs } 50438b8a9b1dSJustin T. Gibbs break; 50448b8a9b1dSJustin T. Gibbs } 50458b8a9b1dSJustin T. Gibbs default: 50468b8a9b1dSJustin T. Gibbs break; 50478b8a9b1dSJustin T. Gibbs } 50488b8a9b1dSJustin T. Gibbs } 50498b8a9b1dSJustin T. Gibbs 50508b8a9b1dSJustin T. Gibbs typedef enum { 50518b8a9b1dSJustin T. Gibbs PROBE_TUR, 50528b8a9b1dSJustin T. Gibbs PROBE_INQUIRY, 50539ec5d7cdSMatt Jacob PROBE_FULL_INQUIRY, 50548b8a9b1dSJustin T. Gibbs PROBE_MODE_SENSE, 50558b8a9b1dSJustin T. Gibbs PROBE_SERIAL_NUM, 50568b8a9b1dSJustin T. Gibbs PROBE_TUR_FOR_NEGOTIATION 50578b8a9b1dSJustin T. Gibbs } probe_action; 50588b8a9b1dSJustin T. Gibbs 50598b8a9b1dSJustin T. Gibbs typedef enum { 50608b8a9b1dSJustin T. Gibbs PROBE_INQUIRY_CKSUM = 0x01, 50618b8a9b1dSJustin T. Gibbs PROBE_SERIAL_CKSUM = 0x02, 50628b8a9b1dSJustin T. Gibbs PROBE_NO_ANNOUNCE = 0x04 50638b8a9b1dSJustin T. Gibbs } probe_flags; 50648b8a9b1dSJustin T. Gibbs 50658b8a9b1dSJustin T. Gibbs typedef struct { 5066e3975643SJake Burkholder TAILQ_HEAD(, ccb_hdr) request_ccbs; 50678b8a9b1dSJustin T. Gibbs probe_action action; 50688b8a9b1dSJustin T. Gibbs union ccb saved_ccb; 50698b8a9b1dSJustin T. Gibbs probe_flags flags; 50708b8a9b1dSJustin T. Gibbs MD5_CTX context; 50718b8a9b1dSJustin T. Gibbs u_int8_t digest[16]; 50728b8a9b1dSJustin T. Gibbs } probe_softc; 50738b8a9b1dSJustin T. Gibbs 50748b8a9b1dSJustin T. Gibbs static void 50758b8a9b1dSJustin T. Gibbs xpt_scan_lun(struct cam_periph *periph, struct cam_path *path, 50768b8a9b1dSJustin T. Gibbs cam_flags flags, union ccb *request_ccb) 50778b8a9b1dSJustin T. Gibbs { 507898192658SJustin T. Gibbs struct ccb_pathinq cpi; 50798b8a9b1dSJustin T. Gibbs cam_status status; 50808b8a9b1dSJustin T. Gibbs struct cam_path *new_path; 50818b8a9b1dSJustin T. Gibbs struct cam_periph *old_periph; 50828b8a9b1dSJustin T. Gibbs int s; 50838b8a9b1dSJustin T. Gibbs 50848b8a9b1dSJustin T. Gibbs CAM_DEBUG(request_ccb->ccb_h.path, CAM_DEBUG_TRACE, 50858b8a9b1dSJustin T. Gibbs ("xpt_scan_lun\n")); 50868b8a9b1dSJustin T. Gibbs 508798192658SJustin T. Gibbs xpt_setup_ccb(&cpi.ccb_h, path, /*priority*/1); 508898192658SJustin T. Gibbs cpi.ccb_h.func_code = XPT_PATH_INQ; 508998192658SJustin T. Gibbs xpt_action((union ccb *)&cpi); 509098192658SJustin T. Gibbs 509198192658SJustin T. Gibbs if (cpi.ccb_h.status != CAM_REQ_CMP) { 509298192658SJustin T. Gibbs if (request_ccb != NULL) { 509398192658SJustin T. Gibbs request_ccb->ccb_h.status = cpi.ccb_h.status; 509498192658SJustin T. Gibbs xpt_done(request_ccb); 509598192658SJustin T. Gibbs } 509698192658SJustin T. Gibbs return; 509798192658SJustin T. Gibbs } 509898192658SJustin T. Gibbs 509998192658SJustin T. Gibbs if ((cpi.hba_misc & PIM_NOINITIATOR) != 0) { 510098192658SJustin T. Gibbs /* 510198192658SJustin T. Gibbs * Can't scan the bus on an adapter that 510298192658SJustin T. Gibbs * cannot perform the initiator role. 510398192658SJustin T. Gibbs */ 510498192658SJustin T. Gibbs if (request_ccb != NULL) { 510598192658SJustin T. Gibbs request_ccb->ccb_h.status = CAM_REQ_CMP; 510698192658SJustin T. Gibbs xpt_done(request_ccb); 510798192658SJustin T. Gibbs } 510898192658SJustin T. Gibbs return; 510998192658SJustin T. Gibbs } 511098192658SJustin T. Gibbs 51118b8a9b1dSJustin T. Gibbs if (request_ccb == NULL) { 51128b8a9b1dSJustin T. Gibbs request_ccb = malloc(sizeof(union ccb), M_TEMP, M_NOWAIT); 51138b8a9b1dSJustin T. Gibbs if (request_ccb == NULL) { 51148b8a9b1dSJustin T. Gibbs xpt_print_path(path); 51158b8a9b1dSJustin T. Gibbs printf("xpt_scan_lun: can't allocate CCB, can't " 51168b8a9b1dSJustin T. Gibbs "continue\n"); 51178b8a9b1dSJustin T. Gibbs return; 51188b8a9b1dSJustin T. Gibbs } 51198b8a9b1dSJustin T. Gibbs new_path = malloc(sizeof(*new_path), M_TEMP, M_NOWAIT); 51208b8a9b1dSJustin T. Gibbs if (new_path == NULL) { 51218b8a9b1dSJustin T. Gibbs xpt_print_path(path); 51228b8a9b1dSJustin T. Gibbs printf("xpt_scan_lun: can't allocate path, can't " 51238b8a9b1dSJustin T. Gibbs "continue\n"); 51248b8a9b1dSJustin T. Gibbs free(request_ccb, M_TEMP); 51258b8a9b1dSJustin T. Gibbs return; 51268b8a9b1dSJustin T. Gibbs } 5127fce84cb4SKenneth D. Merry status = xpt_compile_path(new_path, xpt_periph, 5128fce84cb4SKenneth D. Merry path->bus->path_id, 51298b8a9b1dSJustin T. Gibbs path->target->target_id, 51308b8a9b1dSJustin T. Gibbs path->device->lun_id); 51318b8a9b1dSJustin T. Gibbs 51328b8a9b1dSJustin T. Gibbs if (status != CAM_REQ_CMP) { 51338b8a9b1dSJustin T. Gibbs xpt_print_path(path); 51348b8a9b1dSJustin T. Gibbs printf("xpt_scan_lun: can't compile path, can't " 51358b8a9b1dSJustin T. Gibbs "continue\n"); 51368b8a9b1dSJustin T. Gibbs free(request_ccb, M_TEMP); 51378b8a9b1dSJustin T. Gibbs free(new_path, M_TEMP); 51388b8a9b1dSJustin T. Gibbs return; 51398b8a9b1dSJustin T. Gibbs } 51408b8a9b1dSJustin T. Gibbs xpt_setup_ccb(&request_ccb->ccb_h, new_path, /*priority*/ 1); 51418b8a9b1dSJustin T. Gibbs request_ccb->ccb_h.cbfcnp = xptscandone; 51428b8a9b1dSJustin T. Gibbs request_ccb->ccb_h.func_code = XPT_SCAN_LUN; 51438b8a9b1dSJustin T. Gibbs request_ccb->crcn.flags = flags; 51448b8a9b1dSJustin T. Gibbs } 51458b8a9b1dSJustin T. Gibbs 51468b8a9b1dSJustin T. Gibbs s = splsoftcam(); 51478b8a9b1dSJustin T. Gibbs if ((old_periph = cam_periph_find(path, "probe")) != NULL) { 51488b8a9b1dSJustin T. Gibbs probe_softc *softc; 51498b8a9b1dSJustin T. Gibbs 51508b8a9b1dSJustin T. Gibbs softc = (probe_softc *)old_periph->softc; 51518b8a9b1dSJustin T. Gibbs TAILQ_INSERT_TAIL(&softc->request_ccbs, &request_ccb->ccb_h, 51528b8a9b1dSJustin T. Gibbs periph_links.tqe); 51538b8a9b1dSJustin T. Gibbs } else { 5154ee9c90c7SKenneth D. Merry status = cam_periph_alloc(proberegister, NULL, probecleanup, 51558b8a9b1dSJustin T. Gibbs probestart, "probe", 51568b8a9b1dSJustin T. Gibbs CAM_PERIPH_BIO, 51578b8a9b1dSJustin T. Gibbs request_ccb->ccb_h.path, NULL, 0, 51588b8a9b1dSJustin T. Gibbs request_ccb); 51598b8a9b1dSJustin T. Gibbs 51608b8a9b1dSJustin T. Gibbs if (status != CAM_REQ_CMP) { 51618b8a9b1dSJustin T. Gibbs xpt_print_path(path); 51628b8a9b1dSJustin T. Gibbs printf("xpt_scan_lun: cam_alloc_periph returned an " 51638b8a9b1dSJustin T. Gibbs "error, can't continue probe\n"); 51648b8a9b1dSJustin T. Gibbs request_ccb->ccb_h.status = status; 51658b8a9b1dSJustin T. Gibbs xpt_done(request_ccb); 51668b8a9b1dSJustin T. Gibbs } 51678b8a9b1dSJustin T. Gibbs } 51688b8a9b1dSJustin T. Gibbs splx(s); 51698b8a9b1dSJustin T. Gibbs } 51708b8a9b1dSJustin T. Gibbs 51718b8a9b1dSJustin T. Gibbs static void 51728b8a9b1dSJustin T. Gibbs xptscandone(struct cam_periph *periph, union ccb *done_ccb) 51738b8a9b1dSJustin T. Gibbs { 51748b8a9b1dSJustin T. Gibbs xpt_release_path(done_ccb->ccb_h.path); 51758b8a9b1dSJustin T. Gibbs free(done_ccb->ccb_h.path, M_TEMP); 51768b8a9b1dSJustin T. Gibbs free(done_ccb, M_TEMP); 51778b8a9b1dSJustin T. Gibbs } 51788b8a9b1dSJustin T. Gibbs 51798b8a9b1dSJustin T. Gibbs static cam_status 51808b8a9b1dSJustin T. Gibbs proberegister(struct cam_periph *periph, void *arg) 51818b8a9b1dSJustin T. Gibbs { 518287cfaf0eSJustin T. Gibbs union ccb *request_ccb; /* CCB representing the probe request */ 51838b8a9b1dSJustin T. Gibbs probe_softc *softc; 51848b8a9b1dSJustin T. Gibbs 518587cfaf0eSJustin T. Gibbs request_ccb = (union ccb *)arg; 51868b8a9b1dSJustin T. Gibbs if (periph == NULL) { 51878b8a9b1dSJustin T. Gibbs printf("proberegister: periph was NULL!!\n"); 51888b8a9b1dSJustin T. Gibbs return(CAM_REQ_CMP_ERR); 51898b8a9b1dSJustin T. Gibbs } 51908b8a9b1dSJustin T. Gibbs 519187cfaf0eSJustin T. Gibbs if (request_ccb == NULL) { 5192434bbf6eSJustin T. Gibbs printf("proberegister: no probe CCB, " 5193434bbf6eSJustin T. Gibbs "can't register device\n"); 51948b8a9b1dSJustin T. Gibbs return(CAM_REQ_CMP_ERR); 51958b8a9b1dSJustin T. Gibbs } 51968b8a9b1dSJustin T. Gibbs 51979bc66b83SJustin T. Gibbs softc = (probe_softc *)malloc(sizeof(*softc), M_TEMP, M_NOWAIT); 51988b8a9b1dSJustin T. Gibbs 51998b8a9b1dSJustin T. Gibbs if (softc == NULL) { 52008b8a9b1dSJustin T. Gibbs printf("proberegister: Unable to probe new device. " 52018b8a9b1dSJustin T. Gibbs "Unable to allocate softc\n"); 52028b8a9b1dSJustin T. Gibbs return(CAM_REQ_CMP_ERR); 52038b8a9b1dSJustin T. Gibbs } 52048b8a9b1dSJustin T. Gibbs TAILQ_INIT(&softc->request_ccbs); 520587cfaf0eSJustin T. Gibbs TAILQ_INSERT_TAIL(&softc->request_ccbs, &request_ccb->ccb_h, 520687cfaf0eSJustin T. Gibbs periph_links.tqe); 52078b8a9b1dSJustin T. Gibbs softc->flags = 0; 52088b8a9b1dSJustin T. Gibbs periph->softc = softc; 52098b8a9b1dSJustin T. Gibbs cam_periph_acquire(periph); 521087cfaf0eSJustin T. Gibbs /* 521187cfaf0eSJustin T. Gibbs * Ensure we've waited at least a bus settle 521287cfaf0eSJustin T. Gibbs * delay before attempting to probe the device. 5213cda9006fSMatt Jacob * For HBAs that don't do bus resets, this won't make a difference. 521487cfaf0eSJustin T. Gibbs */ 521587cfaf0eSJustin T. Gibbs cam_periph_freeze_after_event(periph, &periph->path->bus->last_reset, 521687cfaf0eSJustin T. Gibbs SCSI_DELAY); 52178b8a9b1dSJustin T. Gibbs probeschedule(periph); 52188b8a9b1dSJustin T. Gibbs return(CAM_REQ_CMP); 52198b8a9b1dSJustin T. Gibbs } 52208b8a9b1dSJustin T. Gibbs 52218b8a9b1dSJustin T. Gibbs static void 52228b8a9b1dSJustin T. Gibbs probeschedule(struct cam_periph *periph) 52238b8a9b1dSJustin T. Gibbs { 522487cfaf0eSJustin T. Gibbs struct ccb_pathinq cpi; 52258b8a9b1dSJustin T. Gibbs union ccb *ccb; 52268b8a9b1dSJustin T. Gibbs probe_softc *softc; 52278b8a9b1dSJustin T. Gibbs 52288b8a9b1dSJustin T. Gibbs softc = (probe_softc *)periph->softc; 52298b8a9b1dSJustin T. Gibbs ccb = (union ccb *)TAILQ_FIRST(&softc->request_ccbs); 52308b8a9b1dSJustin T. Gibbs 523187cfaf0eSJustin T. Gibbs xpt_setup_ccb(&cpi.ccb_h, periph->path, /*priority*/1); 523287cfaf0eSJustin T. Gibbs cpi.ccb_h.func_code = XPT_PATH_INQ; 523387cfaf0eSJustin T. Gibbs xpt_action((union ccb *)&cpi); 523487cfaf0eSJustin T. Gibbs 52358b8a9b1dSJustin T. Gibbs /* 52368b8a9b1dSJustin T. Gibbs * If a device has gone away and another device, or the same one, 52378b8a9b1dSJustin T. Gibbs * is back in the same place, it should have a unit attention 52388b8a9b1dSJustin T. Gibbs * condition pending. It will not report the unit attention in 52398b8a9b1dSJustin T. Gibbs * response to an inquiry, which may leave invalid transfer 52408b8a9b1dSJustin T. Gibbs * negotiations in effect. The TUR will reveal the unit attention 52418b8a9b1dSJustin T. Gibbs * condition. Only send the TUR for lun 0, since some devices 52428b8a9b1dSJustin T. Gibbs * will get confused by commands other than inquiry to non-existent 52438b8a9b1dSJustin T. Gibbs * luns. If you think a device has gone away start your scan from 52448b8a9b1dSJustin T. Gibbs * lun 0. This will insure that any bogus transfer settings are 52458b8a9b1dSJustin T. Gibbs * invalidated. 524687cfaf0eSJustin T. Gibbs * 524787cfaf0eSJustin T. Gibbs * If we haven't seen the device before and the controller supports 524887cfaf0eSJustin T. Gibbs * some kind of transfer negotiation, negotiate with the first 524987cfaf0eSJustin T. Gibbs * sent command if no bus reset was performed at startup. This 525087cfaf0eSJustin T. Gibbs * ensures that the device is not confused by transfer negotiation 525187cfaf0eSJustin T. Gibbs * settings left over by loader or BIOS action. 52528b8a9b1dSJustin T. Gibbs */ 52538b8a9b1dSJustin T. Gibbs if (((ccb->ccb_h.path->device->flags & CAM_DEV_UNCONFIGURED) == 0) 525487cfaf0eSJustin T. Gibbs && (ccb->ccb_h.target_lun == 0)) { 52558b8a9b1dSJustin T. Gibbs softc->action = PROBE_TUR; 525687cfaf0eSJustin T. Gibbs } else if ((cpi.hba_inquiry & (PI_WIDE_32|PI_WIDE_16|PI_SDTR_ABLE)) != 0 525787cfaf0eSJustin T. Gibbs && (cpi.hba_misc & PIM_NOBUSRESET) != 0) { 525887cfaf0eSJustin T. Gibbs proberequestdefaultnegotiation(periph); 52598b8a9b1dSJustin T. Gibbs softc->action = PROBE_INQUIRY; 526087cfaf0eSJustin T. Gibbs } else { 526187cfaf0eSJustin T. Gibbs softc->action = PROBE_INQUIRY; 526287cfaf0eSJustin T. Gibbs } 52638b8a9b1dSJustin T. Gibbs 52648b8a9b1dSJustin T. Gibbs if (ccb->crcn.flags & CAM_EXPECT_INQ_CHANGE) 52658b8a9b1dSJustin T. Gibbs softc->flags |= PROBE_NO_ANNOUNCE; 52668b8a9b1dSJustin T. Gibbs else 52678b8a9b1dSJustin T. Gibbs softc->flags &= ~PROBE_NO_ANNOUNCE; 52688b8a9b1dSJustin T. Gibbs 52698b8a9b1dSJustin T. Gibbs xpt_schedule(periph, ccb->ccb_h.pinfo.priority); 52708b8a9b1dSJustin T. Gibbs } 52718b8a9b1dSJustin T. Gibbs 52728b8a9b1dSJustin T. Gibbs static void 52738b8a9b1dSJustin T. Gibbs probestart(struct cam_periph *periph, union ccb *start_ccb) 52748b8a9b1dSJustin T. Gibbs { 52758b8a9b1dSJustin T. Gibbs /* Probe the device that our peripheral driver points to */ 52768b8a9b1dSJustin T. Gibbs struct ccb_scsiio *csio; 52778b8a9b1dSJustin T. Gibbs probe_softc *softc; 52788b8a9b1dSJustin T. Gibbs 52798b8a9b1dSJustin T. Gibbs CAM_DEBUG(start_ccb->ccb_h.path, CAM_DEBUG_TRACE, ("probestart\n")); 52808b8a9b1dSJustin T. Gibbs 52818b8a9b1dSJustin T. Gibbs softc = (probe_softc *)periph->softc; 52828b8a9b1dSJustin T. Gibbs csio = &start_ccb->csio; 52838b8a9b1dSJustin T. Gibbs 52848b8a9b1dSJustin T. Gibbs switch (softc->action) { 52858b8a9b1dSJustin T. Gibbs case PROBE_TUR: 52868b8a9b1dSJustin T. Gibbs case PROBE_TUR_FOR_NEGOTIATION: 52878b8a9b1dSJustin T. Gibbs { 52888b8a9b1dSJustin T. Gibbs scsi_test_unit_ready(csio, 52898b8a9b1dSJustin T. Gibbs /*retries*/4, 52908b8a9b1dSJustin T. Gibbs probedone, 52918b8a9b1dSJustin T. Gibbs MSG_SIMPLE_Q_TAG, 52928b8a9b1dSJustin T. Gibbs SSD_FULL_SIZE, 5293e471e974SJustin T. Gibbs /*timeout*/60000); 52948b8a9b1dSJustin T. Gibbs break; 52958b8a9b1dSJustin T. Gibbs } 52968b8a9b1dSJustin T. Gibbs case PROBE_INQUIRY: 52979ec5d7cdSMatt Jacob case PROBE_FULL_INQUIRY: 52988b8a9b1dSJustin T. Gibbs { 5299c19cf05dSMatt Jacob u_int inquiry_len; 53008b8a9b1dSJustin T. Gibbs struct scsi_inquiry_data *inq_buf; 53018b8a9b1dSJustin T. Gibbs 53028b8a9b1dSJustin T. Gibbs inq_buf = &periph->path->device->inq_data; 53038b8a9b1dSJustin T. Gibbs /* 53048b8a9b1dSJustin T. Gibbs * If the device is currently configured, we calculate an 53058b8a9b1dSJustin T. Gibbs * MD5 checksum of the inquiry data, and if the serial number 53068b8a9b1dSJustin T. Gibbs * length is greater than 0, add the serial number data 53078b8a9b1dSJustin T. Gibbs * into the checksum as well. Once the inquiry and the 53088b8a9b1dSJustin T. Gibbs * serial number check finish, we attempt to figure out 53098b8a9b1dSJustin T. Gibbs * whether we still have the same device. 53108b8a9b1dSJustin T. Gibbs */ 53118b8a9b1dSJustin T. Gibbs if ((periph->path->device->flags & CAM_DEV_UNCONFIGURED) == 0) { 53128b8a9b1dSJustin T. Gibbs 53138b8a9b1dSJustin T. Gibbs MD5Init(&softc->context); 53148b8a9b1dSJustin T. Gibbs MD5Update(&softc->context, (unsigned char *)inq_buf, 53158b8a9b1dSJustin T. Gibbs sizeof(struct scsi_inquiry_data)); 53168b8a9b1dSJustin T. Gibbs softc->flags |= PROBE_INQUIRY_CKSUM; 53178b8a9b1dSJustin T. Gibbs if (periph->path->device->serial_num_len > 0) { 53188b8a9b1dSJustin T. Gibbs MD5Update(&softc->context, 53198b8a9b1dSJustin T. Gibbs periph->path->device->serial_num, 53208b8a9b1dSJustin T. Gibbs periph->path->device->serial_num_len); 53218b8a9b1dSJustin T. Gibbs softc->flags |= PROBE_SERIAL_CKSUM; 53228b8a9b1dSJustin T. Gibbs } 53238b8a9b1dSJustin T. Gibbs MD5Final(softc->digest, &softc->context); 53248b8a9b1dSJustin T. Gibbs } 53258b8a9b1dSJustin T. Gibbs 53269ec5d7cdSMatt Jacob if (softc->action == PROBE_INQUIRY) 5327c19cf05dSMatt Jacob inquiry_len = SHORT_INQUIRY_LENGTH; 5328c19cf05dSMatt Jacob else 5329c19cf05dSMatt Jacob inquiry_len = inq_buf->additional_length + 4; 53309ec5d7cdSMatt Jacob 53318b8a9b1dSJustin T. Gibbs scsi_inquiry(csio, 53328b8a9b1dSJustin T. Gibbs /*retries*/4, 53338b8a9b1dSJustin T. Gibbs probedone, 53348b8a9b1dSJustin T. Gibbs MSG_SIMPLE_Q_TAG, 53358b8a9b1dSJustin T. Gibbs (u_int8_t *)inq_buf, 5336c19cf05dSMatt Jacob inquiry_len, 53378b8a9b1dSJustin T. Gibbs /*evpd*/FALSE, 53388b8a9b1dSJustin T. Gibbs /*page_code*/0, 53398b8a9b1dSJustin T. Gibbs SSD_MIN_SIZE, 5340e471e974SJustin T. Gibbs /*timeout*/60 * 1000); 53418b8a9b1dSJustin T. Gibbs break; 53428b8a9b1dSJustin T. Gibbs } 53438b8a9b1dSJustin T. Gibbs case PROBE_MODE_SENSE: 53448b8a9b1dSJustin T. Gibbs { 53458b8a9b1dSJustin T. Gibbs void *mode_buf; 53468b8a9b1dSJustin T. Gibbs int mode_buf_len; 53478b8a9b1dSJustin T. Gibbs 53488b8a9b1dSJustin T. Gibbs mode_buf_len = sizeof(struct scsi_mode_header_6) 53498b8a9b1dSJustin T. Gibbs + sizeof(struct scsi_mode_blk_desc) 53508b8a9b1dSJustin T. Gibbs + sizeof(struct scsi_control_page); 53518b8a9b1dSJustin T. Gibbs mode_buf = malloc(mode_buf_len, M_TEMP, M_NOWAIT); 53528b8a9b1dSJustin T. Gibbs if (mode_buf != NULL) { 53538b8a9b1dSJustin T. Gibbs scsi_mode_sense(csio, 53548b8a9b1dSJustin T. Gibbs /*retries*/4, 53558b8a9b1dSJustin T. Gibbs probedone, 53568b8a9b1dSJustin T. Gibbs MSG_SIMPLE_Q_TAG, 53578b8a9b1dSJustin T. Gibbs /*dbd*/FALSE, 53588b8a9b1dSJustin T. Gibbs SMS_PAGE_CTRL_CURRENT, 53598b8a9b1dSJustin T. Gibbs SMS_CONTROL_MODE_PAGE, 53608b8a9b1dSJustin T. Gibbs mode_buf, 53618b8a9b1dSJustin T. Gibbs mode_buf_len, 53628b8a9b1dSJustin T. Gibbs SSD_FULL_SIZE, 5363e471e974SJustin T. Gibbs /*timeout*/60000); 53648b8a9b1dSJustin T. Gibbs break; 53658b8a9b1dSJustin T. Gibbs } 53668b8a9b1dSJustin T. Gibbs xpt_print_path(periph->path); 53678b8a9b1dSJustin T. Gibbs printf("Unable to mode sense control page - malloc failure\n"); 53688b8a9b1dSJustin T. Gibbs softc->action = PROBE_SERIAL_NUM; 53698b8a9b1dSJustin T. Gibbs /* FALLTHROUGH */ 53708b8a9b1dSJustin T. Gibbs } 53718b8a9b1dSJustin T. Gibbs case PROBE_SERIAL_NUM: 53728b8a9b1dSJustin T. Gibbs { 53738b8a9b1dSJustin T. Gibbs struct scsi_vpd_unit_serial_number *serial_buf; 53748b8a9b1dSJustin T. Gibbs struct cam_ed* device; 53758b8a9b1dSJustin T. Gibbs 53768b8a9b1dSJustin T. Gibbs serial_buf = NULL; 53778b8a9b1dSJustin T. Gibbs device = periph->path->device; 53788b8a9b1dSJustin T. Gibbs device->serial_num = NULL; 53798b8a9b1dSJustin T. Gibbs device->serial_num_len = 0; 53808b8a9b1dSJustin T. Gibbs 53818b8a9b1dSJustin T. Gibbs if ((device->quirk->quirks & CAM_QUIRK_NOSERIAL) == 0) 53828b8a9b1dSJustin T. Gibbs serial_buf = (struct scsi_vpd_unit_serial_number *) 53838b8a9b1dSJustin T. Gibbs malloc(sizeof(*serial_buf), M_TEMP, M_NOWAIT); 53848b8a9b1dSJustin T. Gibbs 53858b8a9b1dSJustin T. Gibbs if (serial_buf != NULL) { 53868b8a9b1dSJustin T. Gibbs bzero(serial_buf, sizeof(*serial_buf)); 53878b8a9b1dSJustin T. Gibbs scsi_inquiry(csio, 53888b8a9b1dSJustin T. Gibbs /*retries*/4, 53898b8a9b1dSJustin T. Gibbs probedone, 53908b8a9b1dSJustin T. Gibbs MSG_SIMPLE_Q_TAG, 53918b8a9b1dSJustin T. Gibbs (u_int8_t *)serial_buf, 53928b8a9b1dSJustin T. Gibbs sizeof(*serial_buf), 53938b8a9b1dSJustin T. Gibbs /*evpd*/TRUE, 53948b8a9b1dSJustin T. Gibbs SVPD_UNIT_SERIAL_NUMBER, 53958b8a9b1dSJustin T. Gibbs SSD_MIN_SIZE, 5396e471e974SJustin T. Gibbs /*timeout*/60 * 1000); 53978b8a9b1dSJustin T. Gibbs break; 53988b8a9b1dSJustin T. Gibbs } 53998b8a9b1dSJustin T. Gibbs /* 54008b8a9b1dSJustin T. Gibbs * We'll have to do without, let our probedone 54018b8a9b1dSJustin T. Gibbs * routine finish up for us. 54028b8a9b1dSJustin T. Gibbs */ 54038b8a9b1dSJustin T. Gibbs start_ccb->csio.data_ptr = NULL; 54048b8a9b1dSJustin T. Gibbs probedone(periph, start_ccb); 54058b8a9b1dSJustin T. Gibbs return; 54068b8a9b1dSJustin T. Gibbs } 54078b8a9b1dSJustin T. Gibbs } 54088b8a9b1dSJustin T. Gibbs xpt_action(start_ccb); 54098b8a9b1dSJustin T. Gibbs } 54108b8a9b1dSJustin T. Gibbs 54118b8a9b1dSJustin T. Gibbs static void 541287cfaf0eSJustin T. Gibbs proberequestdefaultnegotiation(struct cam_periph *periph) 541387cfaf0eSJustin T. Gibbs { 541487cfaf0eSJustin T. Gibbs struct ccb_trans_settings cts; 541587cfaf0eSJustin T. Gibbs 541687cfaf0eSJustin T. Gibbs xpt_setup_ccb(&cts.ccb_h, periph->path, /*priority*/1); 541787cfaf0eSJustin T. Gibbs cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS; 541887cfaf0eSJustin T. Gibbs cts.flags = CCB_TRANS_USER_SETTINGS; 541987cfaf0eSJustin T. Gibbs xpt_action((union ccb *)&cts); 542087cfaf0eSJustin T. Gibbs cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS; 542187cfaf0eSJustin T. Gibbs cts.flags &= ~CCB_TRANS_USER_SETTINGS; 542287cfaf0eSJustin T. Gibbs cts.flags |= CCB_TRANS_CURRENT_SETTINGS; 542387cfaf0eSJustin T. Gibbs xpt_action((union ccb *)&cts); 542487cfaf0eSJustin T. Gibbs } 542587cfaf0eSJustin T. Gibbs 542687cfaf0eSJustin T. Gibbs static void 54278b8a9b1dSJustin T. Gibbs probedone(struct cam_periph *periph, union ccb *done_ccb) 54288b8a9b1dSJustin T. Gibbs { 54298b8a9b1dSJustin T. Gibbs probe_softc *softc; 54308b8a9b1dSJustin T. Gibbs struct cam_path *path; 54318b8a9b1dSJustin T. Gibbs u_int32_t priority; 54328b8a9b1dSJustin T. Gibbs 54338b8a9b1dSJustin T. Gibbs CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_TRACE, ("probedone\n")); 54348b8a9b1dSJustin T. Gibbs 54358b8a9b1dSJustin T. Gibbs softc = (probe_softc *)periph->softc; 54368b8a9b1dSJustin T. Gibbs path = done_ccb->ccb_h.path; 54378b8a9b1dSJustin T. Gibbs priority = done_ccb->ccb_h.pinfo.priority; 54388b8a9b1dSJustin T. Gibbs 54398b8a9b1dSJustin T. Gibbs switch (softc->action) { 54408b8a9b1dSJustin T. Gibbs case PROBE_TUR: 54418b8a9b1dSJustin T. Gibbs { 54428b8a9b1dSJustin T. Gibbs if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 54438b8a9b1dSJustin T. Gibbs 54448b8a9b1dSJustin T. Gibbs if (cam_periph_error(done_ccb, 0, 54458b8a9b1dSJustin T. Gibbs SF_NO_PRINT, NULL) == ERESTART) 54468b8a9b1dSJustin T. Gibbs return; 54478b8a9b1dSJustin T. Gibbs else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) 54488b8a9b1dSJustin T. Gibbs /* Don't wedge the queue */ 54492cefde5fSJustin T. Gibbs xpt_release_devq(done_ccb->ccb_h.path, 54502cefde5fSJustin T. Gibbs /*count*/1, 54518b8a9b1dSJustin T. Gibbs /*run_queue*/TRUE); 54528b8a9b1dSJustin T. Gibbs } 54538b8a9b1dSJustin T. Gibbs softc->action = PROBE_INQUIRY; 54548b8a9b1dSJustin T. Gibbs xpt_release_ccb(done_ccb); 54558b8a9b1dSJustin T. Gibbs xpt_schedule(periph, priority); 54568b8a9b1dSJustin T. Gibbs return; 54578b8a9b1dSJustin T. Gibbs } 54588b8a9b1dSJustin T. Gibbs case PROBE_INQUIRY: 54599ec5d7cdSMatt Jacob case PROBE_FULL_INQUIRY: 54608b8a9b1dSJustin T. Gibbs { 54618b8a9b1dSJustin T. Gibbs if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) { 54628b8a9b1dSJustin T. Gibbs struct scsi_inquiry_data *inq_buf; 54638b8a9b1dSJustin T. Gibbs u_int8_t periph_qual; 54648b8a9b1dSJustin T. Gibbs u_int8_t periph_dtype; 54658b8a9b1dSJustin T. Gibbs 546687cfaf0eSJustin T. Gibbs path->device->flags |= CAM_DEV_INQUIRY_DATA_VALID; 54678b8a9b1dSJustin T. Gibbs inq_buf = &path->device->inq_data; 54688b8a9b1dSJustin T. Gibbs 54698b8a9b1dSJustin T. Gibbs periph_qual = SID_QUAL(inq_buf); 54708b8a9b1dSJustin T. Gibbs periph_dtype = SID_TYPE(inq_buf); 54719ec5d7cdSMatt Jacob 5472c19cf05dSMatt Jacob if (periph_dtype != T_NODEVICE) { 5473c19cf05dSMatt Jacob switch(periph_qual) { 5474c19cf05dSMatt Jacob case SID_QUAL_LU_CONNECTED: 5475c19cf05dSMatt Jacob { 5476c19cf05dSMatt Jacob u_int8_t alen; 5477c19cf05dSMatt Jacob 54789ec5d7cdSMatt Jacob /* 5479c19cf05dSMatt Jacob * We conservatively request only 5480c19cf05dSMatt Jacob * SHORT_INQUIRY_LEN bytes of inquiry 5481c19cf05dSMatt Jacob * information during our first try 5482c19cf05dSMatt Jacob * at sending an INQUIRY. If the device 5483c19cf05dSMatt Jacob * has more information to give, 5484c19cf05dSMatt Jacob * perform a second request specifying 5485c19cf05dSMatt Jacob * the amount of information the device 5486c19cf05dSMatt Jacob * is willing to give. 54879ec5d7cdSMatt Jacob */ 54889ec5d7cdSMatt Jacob alen = inq_buf->additional_length; 5489c19cf05dSMatt Jacob if (softc->action == PROBE_INQUIRY 5490c19cf05dSMatt Jacob && alen > (SHORT_INQUIRY_LENGTH - 4)) { 5491c19cf05dSMatt Jacob softc->action = 5492c19cf05dSMatt Jacob PROBE_FULL_INQUIRY; 54939ec5d7cdSMatt Jacob xpt_release_ccb(done_ccb); 54949ec5d7cdSMatt Jacob xpt_schedule(periph, priority); 54959ec5d7cdSMatt Jacob return; 54969ec5d7cdSMatt Jacob } 54979ec5d7cdSMatt Jacob 54988b8a9b1dSJustin T. Gibbs xpt_find_quirk(path->device); 54998b8a9b1dSJustin T. Gibbs 55008b8a9b1dSJustin T. Gibbs if ((inq_buf->flags & SID_CmdQue) != 0) 55018b8a9b1dSJustin T. Gibbs softc->action = 55028b8a9b1dSJustin T. Gibbs PROBE_MODE_SENSE; 55038b8a9b1dSJustin T. Gibbs else 55048b8a9b1dSJustin T. Gibbs softc->action = 55058b8a9b1dSJustin T. Gibbs PROBE_SERIAL_NUM; 55068b8a9b1dSJustin T. Gibbs 55078b8a9b1dSJustin T. Gibbs path->device->flags &= 55088b8a9b1dSJustin T. Gibbs ~CAM_DEV_UNCONFIGURED; 55098b8a9b1dSJustin T. Gibbs 55108b8a9b1dSJustin T. Gibbs xpt_release_ccb(done_ccb); 55118b8a9b1dSJustin T. Gibbs xpt_schedule(periph, priority); 55128b8a9b1dSJustin T. Gibbs return; 55138b8a9b1dSJustin T. Gibbs } 55148b8a9b1dSJustin T. Gibbs default: 55158b8a9b1dSJustin T. Gibbs break; 55168b8a9b1dSJustin T. Gibbs } 55178b8a9b1dSJustin T. Gibbs } 55188b8a9b1dSJustin T. Gibbs } else if (cam_periph_error(done_ccb, 0, 55198b8a9b1dSJustin T. Gibbs done_ccb->ccb_h.target_lun > 0 55208b8a9b1dSJustin T. Gibbs ? SF_RETRY_UA|SF_QUIET_IR 55218b8a9b1dSJustin T. Gibbs : SF_RETRY_UA, 55228b8a9b1dSJustin T. Gibbs &softc->saved_ccb) == ERESTART) { 55238b8a9b1dSJustin T. Gibbs return; 55248b8a9b1dSJustin T. Gibbs } else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) { 55258b8a9b1dSJustin T. Gibbs /* Don't wedge the queue */ 55262cefde5fSJustin T. Gibbs xpt_release_devq(done_ccb->ccb_h.path, /*count*/1, 55278b8a9b1dSJustin T. Gibbs /*run_queue*/TRUE); 55288b8a9b1dSJustin T. Gibbs } 55298b8a9b1dSJustin T. Gibbs /* 55308b8a9b1dSJustin T. Gibbs * If we get to this point, we got an error status back 55318b8a9b1dSJustin T. Gibbs * from the inquiry and the error status doesn't require 55328b8a9b1dSJustin T. Gibbs * automatically retrying the command. Therefore, the 55338b8a9b1dSJustin T. Gibbs * inquiry failed. If we had inquiry information before 55348b8a9b1dSJustin T. Gibbs * for this device, but this latest inquiry command failed, 55358b8a9b1dSJustin T. Gibbs * the device has probably gone away. If this device isn't 55368b8a9b1dSJustin T. Gibbs * already marked unconfigured, notify the peripheral 55378b8a9b1dSJustin T. Gibbs * drivers that this device is no more. 55388b8a9b1dSJustin T. Gibbs */ 55398b8a9b1dSJustin T. Gibbs if ((path->device->flags & CAM_DEV_UNCONFIGURED) == 0) 55408b8a9b1dSJustin T. Gibbs /* Send the async notification. */ 55418b8a9b1dSJustin T. Gibbs xpt_async(AC_LOST_DEVICE, path, NULL); 55428b8a9b1dSJustin T. Gibbs 55438b8a9b1dSJustin T. Gibbs xpt_release_ccb(done_ccb); 55448b8a9b1dSJustin T. Gibbs break; 55458b8a9b1dSJustin T. Gibbs } 55468b8a9b1dSJustin T. Gibbs case PROBE_MODE_SENSE: 55478b8a9b1dSJustin T. Gibbs { 55488b8a9b1dSJustin T. Gibbs struct ccb_scsiio *csio; 55498b8a9b1dSJustin T. Gibbs struct scsi_mode_header_6 *mode_hdr; 55508b8a9b1dSJustin T. Gibbs 55518b8a9b1dSJustin T. Gibbs csio = &done_ccb->csio; 55528b8a9b1dSJustin T. Gibbs mode_hdr = (struct scsi_mode_header_6 *)csio->data_ptr; 55538b8a9b1dSJustin T. Gibbs if ((csio->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) { 55548b8a9b1dSJustin T. Gibbs struct scsi_control_page *page; 55558b8a9b1dSJustin T. Gibbs u_int8_t *offset; 55568b8a9b1dSJustin T. Gibbs 55578b8a9b1dSJustin T. Gibbs offset = ((u_int8_t *)&mode_hdr[1]) 55588b8a9b1dSJustin T. Gibbs + mode_hdr->blk_desc_len; 55598b8a9b1dSJustin T. Gibbs page = (struct scsi_control_page *)offset; 55608b8a9b1dSJustin T. Gibbs path->device->queue_flags = page->queue_flags; 55618b8a9b1dSJustin T. Gibbs } else if (cam_periph_error(done_ccb, 0, 55628b8a9b1dSJustin T. Gibbs SF_RETRY_UA|SF_NO_PRINT, 55638b8a9b1dSJustin T. Gibbs &softc->saved_ccb) == ERESTART) { 55648b8a9b1dSJustin T. Gibbs return; 55658b8a9b1dSJustin T. Gibbs } else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) { 55668b8a9b1dSJustin T. Gibbs /* Don't wedge the queue */ 55672cefde5fSJustin T. Gibbs xpt_release_devq(done_ccb->ccb_h.path, 55682cefde5fSJustin T. Gibbs /*count*/1, /*run_queue*/TRUE); 55698b8a9b1dSJustin T. Gibbs } 55708b8a9b1dSJustin T. Gibbs xpt_release_ccb(done_ccb); 55718b8a9b1dSJustin T. Gibbs free(mode_hdr, M_TEMP); 55728b8a9b1dSJustin T. Gibbs softc->action = PROBE_SERIAL_NUM; 55738b8a9b1dSJustin T. Gibbs xpt_schedule(periph, priority); 55748b8a9b1dSJustin T. Gibbs return; 55758b8a9b1dSJustin T. Gibbs } 55768b8a9b1dSJustin T. Gibbs case PROBE_SERIAL_NUM: 55778b8a9b1dSJustin T. Gibbs { 55788b8a9b1dSJustin T. Gibbs struct ccb_scsiio *csio; 55798b8a9b1dSJustin T. Gibbs struct scsi_vpd_unit_serial_number *serial_buf; 55808b8a9b1dSJustin T. Gibbs u_int32_t priority; 55818b8a9b1dSJustin T. Gibbs int changed; 55828b8a9b1dSJustin T. Gibbs int have_serialnum; 55838b8a9b1dSJustin T. Gibbs 55848b8a9b1dSJustin T. Gibbs changed = 1; 55858b8a9b1dSJustin T. Gibbs have_serialnum = 0; 55868b8a9b1dSJustin T. Gibbs csio = &done_ccb->csio; 55878b8a9b1dSJustin T. Gibbs priority = done_ccb->ccb_h.pinfo.priority; 55888b8a9b1dSJustin T. Gibbs serial_buf = 55898b8a9b1dSJustin T. Gibbs (struct scsi_vpd_unit_serial_number *)csio->data_ptr; 55908b8a9b1dSJustin T. Gibbs 55918b8a9b1dSJustin T. Gibbs /* Clean up from previous instance of this device */ 55928b8a9b1dSJustin T. Gibbs if (path->device->serial_num != NULL) { 55938b8a9b1dSJustin T. Gibbs free(path->device->serial_num, M_DEVBUF); 55948b8a9b1dSJustin T. Gibbs path->device->serial_num = NULL; 55958b8a9b1dSJustin T. Gibbs path->device->serial_num_len = 0; 55968b8a9b1dSJustin T. Gibbs } 55978b8a9b1dSJustin T. Gibbs 55988b8a9b1dSJustin T. Gibbs if (serial_buf == NULL) { 55998b8a9b1dSJustin T. Gibbs /* 56008b8a9b1dSJustin T. Gibbs * Don't process the command as it was never sent 56018b8a9b1dSJustin T. Gibbs */ 56028b8a9b1dSJustin T. Gibbs } else if ((csio->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP 56038b8a9b1dSJustin T. Gibbs && (serial_buf->length > 0)) { 56048b8a9b1dSJustin T. Gibbs 56058b8a9b1dSJustin T. Gibbs have_serialnum = 1; 56068b8a9b1dSJustin T. Gibbs path->device->serial_num = 56078b8a9b1dSJustin T. Gibbs (u_int8_t *)malloc((serial_buf->length + 1), 56088b8a9b1dSJustin T. Gibbs M_DEVBUF, M_NOWAIT); 56098b8a9b1dSJustin T. Gibbs if (path->device->serial_num != NULL) { 56108b8a9b1dSJustin T. Gibbs bcopy(serial_buf->serial_num, 56118b8a9b1dSJustin T. Gibbs path->device->serial_num, 56128b8a9b1dSJustin T. Gibbs serial_buf->length); 56138b8a9b1dSJustin T. Gibbs path->device->serial_num_len = 56148b8a9b1dSJustin T. Gibbs serial_buf->length; 56158b8a9b1dSJustin T. Gibbs path->device->serial_num[serial_buf->length] 56168b8a9b1dSJustin T. Gibbs = '\0'; 56178b8a9b1dSJustin T. Gibbs } 56188b8a9b1dSJustin T. Gibbs } else if (cam_periph_error(done_ccb, 0, 56198b8a9b1dSJustin T. Gibbs SF_RETRY_UA|SF_NO_PRINT, 56208b8a9b1dSJustin T. Gibbs &softc->saved_ccb) == ERESTART) { 56218b8a9b1dSJustin T. Gibbs return; 56228b8a9b1dSJustin T. Gibbs } else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) { 56238b8a9b1dSJustin T. Gibbs /* Don't wedge the queue */ 56242cefde5fSJustin T. Gibbs xpt_release_devq(done_ccb->ccb_h.path, /*count*/1, 56258b8a9b1dSJustin T. Gibbs /*run_queue*/TRUE); 56268b8a9b1dSJustin T. Gibbs } 56278b8a9b1dSJustin T. Gibbs 56288b8a9b1dSJustin T. Gibbs /* 56298b8a9b1dSJustin T. Gibbs * Let's see if we have seen this device before. 56308b8a9b1dSJustin T. Gibbs */ 56318b8a9b1dSJustin T. Gibbs if ((softc->flags & PROBE_INQUIRY_CKSUM) != 0) { 56328b8a9b1dSJustin T. Gibbs MD5_CTX context; 56338b8a9b1dSJustin T. Gibbs u_int8_t digest[16]; 56348b8a9b1dSJustin T. Gibbs 56358b8a9b1dSJustin T. Gibbs MD5Init(&context); 56368b8a9b1dSJustin T. Gibbs 56378b8a9b1dSJustin T. Gibbs MD5Update(&context, 56388b8a9b1dSJustin T. Gibbs (unsigned char *)&path->device->inq_data, 56398b8a9b1dSJustin T. Gibbs sizeof(struct scsi_inquiry_data)); 56408b8a9b1dSJustin T. Gibbs 56418b8a9b1dSJustin T. Gibbs if (have_serialnum) 56428b8a9b1dSJustin T. Gibbs MD5Update(&context, serial_buf->serial_num, 56438b8a9b1dSJustin T. Gibbs serial_buf->length); 56448b8a9b1dSJustin T. Gibbs 56458b8a9b1dSJustin T. Gibbs MD5Final(digest, &context); 56468b8a9b1dSJustin T. Gibbs if (bcmp(softc->digest, digest, 16) == 0) 56478b8a9b1dSJustin T. Gibbs changed = 0; 56488b8a9b1dSJustin T. Gibbs 56498b8a9b1dSJustin T. Gibbs /* 56508b8a9b1dSJustin T. Gibbs * XXX Do we need to do a TUR in order to ensure 56518b8a9b1dSJustin T. Gibbs * that the device really hasn't changed??? 56528b8a9b1dSJustin T. Gibbs */ 56538b8a9b1dSJustin T. Gibbs if ((changed != 0) 56548b8a9b1dSJustin T. Gibbs && ((softc->flags & PROBE_NO_ANNOUNCE) == 0)) 56558b8a9b1dSJustin T. Gibbs xpt_async(AC_LOST_DEVICE, path, NULL); 56568b8a9b1dSJustin T. Gibbs } 56578b8a9b1dSJustin T. Gibbs if (serial_buf != NULL) 56588b8a9b1dSJustin T. Gibbs free(serial_buf, M_TEMP); 56598b8a9b1dSJustin T. Gibbs 56608b8a9b1dSJustin T. Gibbs if (changed != 0) { 56618b8a9b1dSJustin T. Gibbs /* 56628b8a9b1dSJustin T. Gibbs * Now that we have all the necessary 56638b8a9b1dSJustin T. Gibbs * information to safely perform transfer 56648b8a9b1dSJustin T. Gibbs * negotiations... Controllers don't perform 56658b8a9b1dSJustin T. Gibbs * any negotiation or tagged queuing until 56668b8a9b1dSJustin T. Gibbs * after the first XPT_SET_TRAN_SETTINGS ccb is 56678b8a9b1dSJustin T. Gibbs * received. So, on a new device, just retreive 56688b8a9b1dSJustin T. Gibbs * the user settings, and set them as the current 56698b8a9b1dSJustin T. Gibbs * settings to set the device up. 56708b8a9b1dSJustin T. Gibbs */ 567187cfaf0eSJustin T. Gibbs proberequestdefaultnegotiation(periph); 56728b8a9b1dSJustin T. Gibbs xpt_release_ccb(done_ccb); 56738b8a9b1dSJustin T. Gibbs 56748b8a9b1dSJustin T. Gibbs /* 56758b8a9b1dSJustin T. Gibbs * Perform a TUR to allow the controller to 56768b8a9b1dSJustin T. Gibbs * perform any necessary transfer negotiation. 56778b8a9b1dSJustin T. Gibbs */ 56788b8a9b1dSJustin T. Gibbs softc->action = PROBE_TUR_FOR_NEGOTIATION; 56798b8a9b1dSJustin T. Gibbs xpt_schedule(periph, priority); 56808b8a9b1dSJustin T. Gibbs return; 56818b8a9b1dSJustin T. Gibbs } 56828b8a9b1dSJustin T. Gibbs xpt_release_ccb(done_ccb); 56838b8a9b1dSJustin T. Gibbs break; 56848b8a9b1dSJustin T. Gibbs } 56858b8a9b1dSJustin T. Gibbs case PROBE_TUR_FOR_NEGOTIATION: 56868b8a9b1dSJustin T. Gibbs if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) { 56878b8a9b1dSJustin T. Gibbs /* Don't wedge the queue */ 56882cefde5fSJustin T. Gibbs xpt_release_devq(done_ccb->ccb_h.path, /*count*/1, 56898b8a9b1dSJustin T. Gibbs /*run_queue*/TRUE); 56908b8a9b1dSJustin T. Gibbs } 56918b8a9b1dSJustin T. Gibbs 56928b8a9b1dSJustin T. Gibbs path->device->flags &= ~CAM_DEV_UNCONFIGURED; 56938b8a9b1dSJustin T. Gibbs 56948b8a9b1dSJustin T. Gibbs if ((softc->flags & PROBE_NO_ANNOUNCE) == 0) { 56958b8a9b1dSJustin T. Gibbs /* Inform the XPT that a new device has been found */ 56968b8a9b1dSJustin T. Gibbs done_ccb->ccb_h.func_code = XPT_GDEV_TYPE; 56978b8a9b1dSJustin T. Gibbs xpt_action(done_ccb); 56988b8a9b1dSJustin T. Gibbs 56998b8a9b1dSJustin T. Gibbs xpt_async(AC_FOUND_DEVICE, xpt_periph->path, done_ccb); 57008b8a9b1dSJustin T. Gibbs } 57018b8a9b1dSJustin T. Gibbs xpt_release_ccb(done_ccb); 57028b8a9b1dSJustin T. Gibbs break; 57038b8a9b1dSJustin T. Gibbs } 57048b8a9b1dSJustin T. Gibbs done_ccb = (union ccb *)TAILQ_FIRST(&softc->request_ccbs); 57058b8a9b1dSJustin T. Gibbs TAILQ_REMOVE(&softc->request_ccbs, &done_ccb->ccb_h, periph_links.tqe); 57068b8a9b1dSJustin T. Gibbs done_ccb->ccb_h.status = CAM_REQ_CMP; 57078b8a9b1dSJustin T. Gibbs xpt_done(done_ccb); 57088b8a9b1dSJustin T. Gibbs if (TAILQ_FIRST(&softc->request_ccbs) == NULL) { 57098b8a9b1dSJustin T. Gibbs cam_periph_invalidate(periph); 57108b8a9b1dSJustin T. Gibbs cam_periph_release(periph); 57118b8a9b1dSJustin T. Gibbs } else { 57128b8a9b1dSJustin T. Gibbs probeschedule(periph); 57138b8a9b1dSJustin T. Gibbs } 57148b8a9b1dSJustin T. Gibbs } 57158b8a9b1dSJustin T. Gibbs 57168b8a9b1dSJustin T. Gibbs static void 57178b8a9b1dSJustin T. Gibbs probecleanup(struct cam_periph *periph) 57188b8a9b1dSJustin T. Gibbs { 57198b8a9b1dSJustin T. Gibbs free(periph->softc, M_TEMP); 57208b8a9b1dSJustin T. Gibbs } 57218b8a9b1dSJustin T. Gibbs 57228b8a9b1dSJustin T. Gibbs static void 57238b8a9b1dSJustin T. Gibbs xpt_find_quirk(struct cam_ed *device) 57248b8a9b1dSJustin T. Gibbs { 57258b8a9b1dSJustin T. Gibbs caddr_t match; 57268b8a9b1dSJustin T. Gibbs 57278b8a9b1dSJustin T. Gibbs match = cam_quirkmatch((caddr_t)&device->inq_data, 57288b8a9b1dSJustin T. Gibbs (caddr_t)xpt_quirk_table, 57298b8a9b1dSJustin T. Gibbs sizeof(xpt_quirk_table)/sizeof(*xpt_quirk_table), 57308b8a9b1dSJustin T. Gibbs sizeof(*xpt_quirk_table), scsi_inquiry_match); 57318b8a9b1dSJustin T. Gibbs 57328b8a9b1dSJustin T. Gibbs if (match == NULL) 57338b8a9b1dSJustin T. Gibbs panic("xpt_find_quirk: device didn't match wildcard entry!!"); 57348b8a9b1dSJustin T. Gibbs 57358b8a9b1dSJustin T. Gibbs device->quirk = (struct xpt_quirk_entry *)match; 57368b8a9b1dSJustin T. Gibbs } 57378b8a9b1dSJustin T. Gibbs 57388b8a9b1dSJustin T. Gibbs static void 573903e3511bSJustin T. Gibbs xpt_set_transfer_settings(struct ccb_trans_settings *cts, struct cam_ed *device, 574003e3511bSJustin T. Gibbs int async_update) 57418b8a9b1dSJustin T. Gibbs { 57428b8a9b1dSJustin T. Gibbs struct cam_sim *sim; 57438b8a9b1dSJustin T. Gibbs int qfrozen; 57448b8a9b1dSJustin T. Gibbs 57458b8a9b1dSJustin T. Gibbs sim = cts->ccb_h.path->bus->sim; 57468b8a9b1dSJustin T. Gibbs if (async_update == FALSE) { 57478b8a9b1dSJustin T. Gibbs struct scsi_inquiry_data *inq_data; 57488b8a9b1dSJustin T. Gibbs struct ccb_pathinq cpi; 57499deea857SKenneth D. Merry struct ccb_trans_settings cur_cts; 57508b8a9b1dSJustin T. Gibbs 575103e3511bSJustin T. Gibbs if (device == NULL) { 575203e3511bSJustin T. Gibbs cts->ccb_h.status = CAM_PATH_INVALID; 575303e3511bSJustin T. Gibbs xpt_done((union ccb *)cts); 575403e3511bSJustin T. Gibbs return; 575503e3511bSJustin T. Gibbs } 575603e3511bSJustin T. Gibbs 57578b8a9b1dSJustin T. Gibbs /* 57588b8a9b1dSJustin T. Gibbs * Perform sanity checking against what the 57598b8a9b1dSJustin T. Gibbs * controller and device can do. 57608b8a9b1dSJustin T. Gibbs */ 57618b8a9b1dSJustin T. Gibbs xpt_setup_ccb(&cpi.ccb_h, cts->ccb_h.path, /*priority*/1); 57628b8a9b1dSJustin T. Gibbs cpi.ccb_h.func_code = XPT_PATH_INQ; 57638b8a9b1dSJustin T. Gibbs xpt_action((union ccb *)&cpi); 57649deea857SKenneth D. Merry xpt_setup_ccb(&cur_cts.ccb_h, cts->ccb_h.path, /*priority*/1); 57659deea857SKenneth D. Merry cur_cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS; 57669deea857SKenneth D. Merry cur_cts.flags = CCB_TRANS_CURRENT_SETTINGS; 57679deea857SKenneth D. Merry xpt_action((union ccb *)&cur_cts); 57688b8a9b1dSJustin T. Gibbs inq_data = &device->inq_data; 57699deea857SKenneth D. Merry 57709deea857SKenneth D. Merry /* Fill in any gaps in what the user gave us */ 57719deea857SKenneth D. Merry if ((cts->valid & CCB_TRANS_SYNC_RATE_VALID) == 0) 57729deea857SKenneth D. Merry cts->sync_period = cur_cts.sync_period; 57739deea857SKenneth D. Merry if ((cts->valid & CCB_TRANS_SYNC_OFFSET_VALID) == 0) 57749deea857SKenneth D. Merry cts->sync_offset = cur_cts.sync_offset; 57759deea857SKenneth D. Merry if ((cts->valid & CCB_TRANS_BUS_WIDTH_VALID) == 0) 57769deea857SKenneth D. Merry cts->bus_width = cur_cts.bus_width; 57779deea857SKenneth D. Merry if ((cts->valid & CCB_TRANS_DISC_VALID) == 0) { 57789deea857SKenneth D. Merry cts->flags &= ~CCB_TRANS_DISC_ENB; 57799deea857SKenneth D. Merry cts->flags |= cur_cts.flags & CCB_TRANS_DISC_ENB; 57809deea857SKenneth D. Merry } 57819deea857SKenneth D. Merry if ((cts->valid & CCB_TRANS_TQ_VALID) == 0) { 57829deea857SKenneth D. Merry cts->flags &= ~CCB_TRANS_TAG_ENB; 57839deea857SKenneth D. Merry cts->flags |= cur_cts.flags & CCB_TRANS_TAG_ENB; 57849deea857SKenneth D. Merry } 578587cfaf0eSJustin T. Gibbs if (((device->flags & CAM_DEV_INQUIRY_DATA_VALID) != 0 578687cfaf0eSJustin T. Gibbs && (inq_data->flags & SID_Sync) == 0) 57878b8a9b1dSJustin T. Gibbs || (cpi.hba_inquiry & PI_SDTR_ABLE) == 0) { 57888b8a9b1dSJustin T. Gibbs /* Force async */ 57898b8a9b1dSJustin T. Gibbs cts->sync_period = 0; 57908b8a9b1dSJustin T. Gibbs cts->sync_offset = 0; 57918b8a9b1dSJustin T. Gibbs } 57928b8a9b1dSJustin T. Gibbs 5793dd5bac9dSJustin T. Gibbs /* 5794dd5bac9dSJustin T. Gibbs * Don't allow DT transmission rates if the 5795dd5bac9dSJustin T. Gibbs * device does not support it. 5796dd5bac9dSJustin T. Gibbs */ 5797dd5bac9dSJustin T. Gibbs if ((device->flags & CAM_DEV_INQUIRY_DATA_VALID) != 0 5798dd5bac9dSJustin T. Gibbs && (inq_data->spi3data & SID_SPI_CLOCK_DT) == 0 5799dd5bac9dSJustin T. Gibbs && cts->sync_period <= 0x9) 5800dd5bac9dSJustin T. Gibbs cts->sync_period = 0xa; 5801dd5bac9dSJustin T. Gibbs 58028b8a9b1dSJustin T. Gibbs switch (cts->bus_width) { 58038b8a9b1dSJustin T. Gibbs case MSG_EXT_WDTR_BUS_32_BIT: 580487cfaf0eSJustin T. Gibbs if (((device->flags & CAM_DEV_INQUIRY_DATA_VALID) == 0 580587cfaf0eSJustin T. Gibbs || (inq_data->flags & SID_WBus32) != 0) 58068b8a9b1dSJustin T. Gibbs && (cpi.hba_inquiry & PI_WIDE_32) != 0) 58078b8a9b1dSJustin T. Gibbs break; 58088b8a9b1dSJustin T. Gibbs /* Fall Through to 16-bit */ 58098b8a9b1dSJustin T. Gibbs case MSG_EXT_WDTR_BUS_16_BIT: 581087cfaf0eSJustin T. Gibbs if (((device->flags & CAM_DEV_INQUIRY_DATA_VALID) == 0 581187cfaf0eSJustin T. Gibbs || (inq_data->flags & SID_WBus16) != 0) 58128b8a9b1dSJustin T. Gibbs && (cpi.hba_inquiry & PI_WIDE_16) != 0) { 58138b8a9b1dSJustin T. Gibbs cts->bus_width = MSG_EXT_WDTR_BUS_16_BIT; 58148b8a9b1dSJustin T. Gibbs break; 58158b8a9b1dSJustin T. Gibbs } 58168b8a9b1dSJustin T. Gibbs /* Fall Through to 8-bit */ 58178b8a9b1dSJustin T. Gibbs default: /* New bus width?? */ 58188b8a9b1dSJustin T. Gibbs case MSG_EXT_WDTR_BUS_8_BIT: 58198b8a9b1dSJustin T. Gibbs /* All targets can do this */ 58208b8a9b1dSJustin T. Gibbs cts->bus_width = MSG_EXT_WDTR_BUS_8_BIT; 58218b8a9b1dSJustin T. Gibbs break; 58228b8a9b1dSJustin T. Gibbs } 58238b8a9b1dSJustin T. Gibbs 58248b8a9b1dSJustin T. Gibbs if ((cts->flags & CCB_TRANS_DISC_ENB) == 0) { 58258b8a9b1dSJustin T. Gibbs /* 58268b8a9b1dSJustin T. Gibbs * Can't tag queue without disconnection. 58278b8a9b1dSJustin T. Gibbs */ 58288b8a9b1dSJustin T. Gibbs cts->flags &= ~CCB_TRANS_TAG_ENB; 58292ba01e6fSJustin T. Gibbs cts->valid |= CCB_TRANS_TQ_VALID; 58308b8a9b1dSJustin T. Gibbs } 58318b8a9b1dSJustin T. Gibbs 58328b8a9b1dSJustin T. Gibbs if ((cpi.hba_inquiry & PI_TAG_ABLE) == 0 58338b8a9b1dSJustin T. Gibbs || (inq_data->flags & SID_CmdQue) == 0 58348b8a9b1dSJustin T. Gibbs || (device->queue_flags & SCP_QUEUE_DQUE) != 0 58358b8a9b1dSJustin T. Gibbs || (device->quirk->mintags == 0)) { 58368b8a9b1dSJustin T. Gibbs /* 58378b8a9b1dSJustin T. Gibbs * Can't tag on hardware that doesn't support, 58388b8a9b1dSJustin T. Gibbs * doesn't have it enabled, or has broken tag support. 58398b8a9b1dSJustin T. Gibbs */ 58408b8a9b1dSJustin T. Gibbs cts->flags &= ~CCB_TRANS_TAG_ENB; 58418b8a9b1dSJustin T. Gibbs } 58428b8a9b1dSJustin T. Gibbs } 58438b8a9b1dSJustin T. Gibbs 584403e3511bSJustin T. Gibbs qfrozen = FALSE; 58458bad620dSJustin T. Gibbs if ((cts->valid & CCB_TRANS_TQ_VALID) != 0 58468bad620dSJustin T. Gibbs && (async_update == FALSE)) { 584703e3511bSJustin T. Gibbs int device_tagenb; 584803e3511bSJustin T. Gibbs 58498b8a9b1dSJustin T. Gibbs /* 58508b8a9b1dSJustin T. Gibbs * If we are transitioning from tags to no-tags or 58518b8a9b1dSJustin T. Gibbs * vice-versa, we need to carefully freeze and restart 58528b8a9b1dSJustin T. Gibbs * the queue so that we don't overlap tagged and non-tagged 5853f0adc790SJustin T. Gibbs * commands. We also temporarily stop tags if there is 5854f0adc790SJustin T. Gibbs * a change in transfer negotiation settings to allow 5855f0adc790SJustin T. Gibbs * "tag-less" negotiation. 58568b8a9b1dSJustin T. Gibbs */ 5857f0adc790SJustin T. Gibbs if ((device->flags & CAM_DEV_TAG_AFTER_COUNT) != 0 5858f0adc790SJustin T. Gibbs || (device->inq_flags & SID_CmdQue) != 0) 5859f0adc790SJustin T. Gibbs device_tagenb = TRUE; 5860f0adc790SJustin T. Gibbs else 5861f0adc790SJustin T. Gibbs device_tagenb = FALSE; 5862f0adc790SJustin T. Gibbs 586303e3511bSJustin T. Gibbs if (((cts->flags & CCB_TRANS_TAG_ENB) != 0 5864f0adc790SJustin T. Gibbs && device_tagenb == FALSE) 58658b8a9b1dSJustin T. Gibbs || ((cts->flags & CCB_TRANS_TAG_ENB) == 0 586603e3511bSJustin T. Gibbs && device_tagenb == TRUE)) { 58678b8a9b1dSJustin T. Gibbs 58688b8a9b1dSJustin T. Gibbs if ((cts->flags & CCB_TRANS_TAG_ENB) != 0) { 5869fd21cc5eSJustin T. Gibbs /* 5870fd21cc5eSJustin T. Gibbs * Delay change to use tags until after a 5871fd21cc5eSJustin T. Gibbs * few commands have gone to this device so 5872fd21cc5eSJustin T. Gibbs * the controller has time to perform transfer 5873fd21cc5eSJustin T. Gibbs * negotiations without tagged messages getting 5874fd21cc5eSJustin T. Gibbs * in the way. 5875fd21cc5eSJustin T. Gibbs */ 5876fd21cc5eSJustin T. Gibbs device->tag_delay_count = CAM_TAG_DELAY_COUNT; 5877fd21cc5eSJustin T. Gibbs device->flags |= CAM_DEV_TAG_AFTER_COUNT; 58788b8a9b1dSJustin T. Gibbs } else { 5879fd21cc5eSJustin T. Gibbs xpt_freeze_devq(cts->ccb_h.path, /*count*/1); 5880fd21cc5eSJustin T. Gibbs qfrozen = TRUE; 58818b8a9b1dSJustin T. Gibbs device->inq_flags &= ~SID_CmdQue; 5882fd21cc5eSJustin T. Gibbs xpt_dev_ccbq_resize(cts->ccb_h.path, 5883fd21cc5eSJustin T. Gibbs sim->max_dev_openings); 5884fd21cc5eSJustin T. Gibbs device->flags &= ~CAM_DEV_TAG_AFTER_COUNT; 5885fd21cc5eSJustin T. Gibbs device->tag_delay_count = 0; 58868b8a9b1dSJustin T. Gibbs } 58878b8a9b1dSJustin T. Gibbs } 588803e3511bSJustin T. Gibbs } 58898b8a9b1dSJustin T. Gibbs 58908bad620dSJustin T. Gibbs if (async_update == FALSE) { 58918bad620dSJustin T. Gibbs /* 58928bad620dSJustin T. Gibbs * If we are currently performing tagged transactions to 58938bad620dSJustin T. Gibbs * this device and want to change its negotiation parameters, 58948bad620dSJustin T. Gibbs * go non-tagged for a bit to give the controller a chance to 58958bad620dSJustin T. Gibbs * negotiate unhampered by tag messages. 58968bad620dSJustin T. Gibbs */ 58978bad620dSJustin T. Gibbs if ((device->inq_flags & SID_CmdQue) != 0 58988bad620dSJustin T. Gibbs && (cts->flags & (CCB_TRANS_SYNC_RATE_VALID| 58998bad620dSJustin T. Gibbs CCB_TRANS_SYNC_OFFSET_VALID| 59008bad620dSJustin T. Gibbs CCB_TRANS_BUS_WIDTH_VALID)) != 0) 59018bad620dSJustin T. Gibbs xpt_toggle_tags(cts->ccb_h.path); 59028bad620dSJustin T. Gibbs 59038b8a9b1dSJustin T. Gibbs (*(sim->sim_action))(sim, (union ccb *)cts); 59048bad620dSJustin T. Gibbs } 59058b8a9b1dSJustin T. Gibbs 59068b8a9b1dSJustin T. Gibbs if (qfrozen) { 59078b8a9b1dSJustin T. Gibbs struct ccb_relsim crs; 59088b8a9b1dSJustin T. Gibbs 59098b8a9b1dSJustin T. Gibbs xpt_setup_ccb(&crs.ccb_h, cts->ccb_h.path, 59108b8a9b1dSJustin T. Gibbs /*priority*/1); 59118b8a9b1dSJustin T. Gibbs crs.ccb_h.func_code = XPT_REL_SIMQ; 59128b8a9b1dSJustin T. Gibbs crs.release_flags = RELSIM_RELEASE_AFTER_QEMPTY; 59138b8a9b1dSJustin T. Gibbs crs.openings 59148b8a9b1dSJustin T. Gibbs = crs.release_timeout 59158b8a9b1dSJustin T. Gibbs = crs.qfrozen_cnt 59168b8a9b1dSJustin T. Gibbs = 0; 59178b8a9b1dSJustin T. Gibbs xpt_action((union ccb *)&crs); 59188b8a9b1dSJustin T. Gibbs } 59198b8a9b1dSJustin T. Gibbs } 59208b8a9b1dSJustin T. Gibbs 5921fd21cc5eSJustin T. Gibbs static void 5922f0adc790SJustin T. Gibbs xpt_toggle_tags(struct cam_path *path) 5923f0adc790SJustin T. Gibbs { 592487cfaf0eSJustin T. Gibbs struct cam_ed *dev; 592587cfaf0eSJustin T. Gibbs 5926f0adc790SJustin T. Gibbs /* 5927f0adc790SJustin T. Gibbs * Give controllers a chance to renegotiate 5928f0adc790SJustin T. Gibbs * before starting tag operations. We 5929f0adc790SJustin T. Gibbs * "toggle" tagged queuing off then on 5930f0adc790SJustin T. Gibbs * which causes the tag enable command delay 5931f0adc790SJustin T. Gibbs * counter to come into effect. 5932f0adc790SJustin T. Gibbs */ 593387cfaf0eSJustin T. Gibbs dev = path->device; 593487cfaf0eSJustin T. Gibbs if ((dev->flags & CAM_DEV_TAG_AFTER_COUNT) != 0 593587cfaf0eSJustin T. Gibbs || ((dev->inq_flags & SID_CmdQue) != 0 593687cfaf0eSJustin T. Gibbs && (dev->inq_flags & (SID_Sync|SID_WBus16|SID_WBus32)) != 0)) { 5937f0adc790SJustin T. Gibbs struct ccb_trans_settings cts; 5938f0adc790SJustin T. Gibbs 5939f0adc790SJustin T. Gibbs xpt_setup_ccb(&cts.ccb_h, path, 1); 5940f0adc790SJustin T. Gibbs cts.flags = 0; 5941f0adc790SJustin T. Gibbs cts.valid = CCB_TRANS_TQ_VALID; 594203e3511bSJustin T. Gibbs xpt_set_transfer_settings(&cts, path->device, 594303e3511bSJustin T. Gibbs /*async_update*/TRUE); 5944f0adc790SJustin T. Gibbs cts.flags = CCB_TRANS_TAG_ENB; 594503e3511bSJustin T. Gibbs xpt_set_transfer_settings(&cts, path->device, 594603e3511bSJustin T. Gibbs /*async_update*/TRUE); 5947f0adc790SJustin T. Gibbs } 5948f0adc790SJustin T. Gibbs } 5949f0adc790SJustin T. Gibbs 5950f0adc790SJustin T. Gibbs static void 5951f0adc790SJustin T. Gibbs xpt_start_tags(struct cam_path *path) 5952f0adc790SJustin T. Gibbs { 5953fd21cc5eSJustin T. Gibbs struct ccb_relsim crs; 5954fd21cc5eSJustin T. Gibbs struct cam_ed *device; 5955fd21cc5eSJustin T. Gibbs struct cam_sim *sim; 5956fd21cc5eSJustin T. Gibbs int newopenings; 5957fd21cc5eSJustin T. Gibbs 5958fd21cc5eSJustin T. Gibbs device = path->device; 5959fd21cc5eSJustin T. Gibbs sim = path->bus->sim; 5960fd21cc5eSJustin T. Gibbs device->flags &= ~CAM_DEV_TAG_AFTER_COUNT; 5961fd21cc5eSJustin T. Gibbs xpt_freeze_devq(path, /*count*/1); 5962fd21cc5eSJustin T. Gibbs device->inq_flags |= SID_CmdQue; 5963fd21cc5eSJustin T. Gibbs newopenings = min(device->quirk->maxtags, sim->max_tagged_dev_openings); 5964f0adc790SJustin T. Gibbs xpt_dev_ccbq_resize(path, newopenings); 5965fd21cc5eSJustin T. Gibbs xpt_setup_ccb(&crs.ccb_h, path, /*priority*/1); 5966fd21cc5eSJustin T. Gibbs crs.ccb_h.func_code = XPT_REL_SIMQ; 5967fd21cc5eSJustin T. Gibbs crs.release_flags = RELSIM_RELEASE_AFTER_QEMPTY; 5968fd21cc5eSJustin T. Gibbs crs.openings 5969fd21cc5eSJustin T. Gibbs = crs.release_timeout 5970fd21cc5eSJustin T. Gibbs = crs.qfrozen_cnt 5971fd21cc5eSJustin T. Gibbs = 0; 5972fd21cc5eSJustin T. Gibbs xpt_action((union ccb *)&crs); 5973fd21cc5eSJustin T. Gibbs } 5974fd21cc5eSJustin T. Gibbs 59758b8a9b1dSJustin T. Gibbs static int busses_to_config; 597687cfaf0eSJustin T. Gibbs static int busses_to_reset; 59778b8a9b1dSJustin T. Gibbs 59788b8a9b1dSJustin T. Gibbs static int 59798b8a9b1dSJustin T. Gibbs xptconfigbuscountfunc(struct cam_eb *bus, void *arg) 59808b8a9b1dSJustin T. Gibbs { 598187cfaf0eSJustin T. Gibbs if (bus->path_id != CAM_XPT_PATH_ID) { 598287cfaf0eSJustin T. Gibbs struct cam_path path; 598387cfaf0eSJustin T. Gibbs struct ccb_pathinq cpi; 598487cfaf0eSJustin T. Gibbs int can_negotiate; 598587cfaf0eSJustin T. Gibbs 59868b8a9b1dSJustin T. Gibbs busses_to_config++; 598787cfaf0eSJustin T. Gibbs xpt_compile_path(&path, NULL, bus->path_id, 598887cfaf0eSJustin T. Gibbs CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD); 598987cfaf0eSJustin T. Gibbs xpt_setup_ccb(&cpi.ccb_h, &path, /*priority*/1); 599087cfaf0eSJustin T. Gibbs cpi.ccb_h.func_code = XPT_PATH_INQ; 599187cfaf0eSJustin T. Gibbs xpt_action((union ccb *)&cpi); 599287cfaf0eSJustin T. Gibbs can_negotiate = cpi.hba_inquiry; 599387cfaf0eSJustin T. Gibbs can_negotiate &= (PI_WIDE_32|PI_WIDE_16|PI_SDTR_ABLE); 599487cfaf0eSJustin T. Gibbs if ((cpi.hba_misc & PIM_NOBUSRESET) == 0 599587cfaf0eSJustin T. Gibbs && can_negotiate) 599687cfaf0eSJustin T. Gibbs busses_to_reset++; 599787cfaf0eSJustin T. Gibbs xpt_release_path(&path); 599887cfaf0eSJustin T. Gibbs } 59998b8a9b1dSJustin T. Gibbs 60008b8a9b1dSJustin T. Gibbs return(1); 60018b8a9b1dSJustin T. Gibbs } 60028b8a9b1dSJustin T. Gibbs 60038b8a9b1dSJustin T. Gibbs static int 60048b8a9b1dSJustin T. Gibbs xptconfigfunc(struct cam_eb *bus, void *arg) 60058b8a9b1dSJustin T. Gibbs { 60068b8a9b1dSJustin T. Gibbs struct cam_path *path; 60078b8a9b1dSJustin T. Gibbs union ccb *work_ccb; 60088b8a9b1dSJustin T. Gibbs 60098b8a9b1dSJustin T. Gibbs if (bus->path_id != CAM_XPT_PATH_ID) { 60108b8a9b1dSJustin T. Gibbs cam_status status; 601187cfaf0eSJustin T. Gibbs int can_negotiate; 60128b8a9b1dSJustin T. Gibbs 60138b8a9b1dSJustin T. Gibbs work_ccb = xpt_alloc_ccb(); 60148b8a9b1dSJustin T. Gibbs if ((status = xpt_create_path(&path, xpt_periph, bus->path_id, 60158b8a9b1dSJustin T. Gibbs CAM_TARGET_WILDCARD, 60168b8a9b1dSJustin T. Gibbs CAM_LUN_WILDCARD)) !=CAM_REQ_CMP){ 60178b8a9b1dSJustin T. Gibbs printf("xptconfigfunc: xpt_create_path failed with " 60188b8a9b1dSJustin T. Gibbs "status %#x for bus %d\n", status, bus->path_id); 60198b8a9b1dSJustin T. Gibbs printf("xptconfigfunc: halting bus configuration\n"); 60208b8a9b1dSJustin T. Gibbs xpt_free_ccb(work_ccb); 602198192658SJustin T. Gibbs busses_to_config--; 602298192658SJustin T. Gibbs xpt_finishconfig(xpt_periph, NULL); 60238b8a9b1dSJustin T. Gibbs return(0); 60248b8a9b1dSJustin T. Gibbs } 60258b8a9b1dSJustin T. Gibbs xpt_setup_ccb(&work_ccb->ccb_h, path, /*priority*/1); 602698192658SJustin T. Gibbs work_ccb->ccb_h.func_code = XPT_PATH_INQ; 602798192658SJustin T. Gibbs xpt_action(work_ccb); 602898192658SJustin T. Gibbs if (work_ccb->ccb_h.status != CAM_REQ_CMP) { 602998192658SJustin T. Gibbs printf("xptconfigfunc: CPI failed on bus %d " 603098192658SJustin T. Gibbs "with status %d\n", bus->path_id, 603198192658SJustin T. Gibbs work_ccb->ccb_h.status); 603298192658SJustin T. Gibbs xpt_finishconfig(xpt_periph, work_ccb); 603398192658SJustin T. Gibbs return(1); 603498192658SJustin T. Gibbs } 603598192658SJustin T. Gibbs 603687cfaf0eSJustin T. Gibbs can_negotiate = work_ccb->cpi.hba_inquiry; 603787cfaf0eSJustin T. Gibbs can_negotiate &= (PI_WIDE_32|PI_WIDE_16|PI_SDTR_ABLE); 603887cfaf0eSJustin T. Gibbs if ((work_ccb->cpi.hba_misc & PIM_NOBUSRESET) == 0 603987cfaf0eSJustin T. Gibbs && (can_negotiate != 0)) { 604098192658SJustin T. Gibbs xpt_setup_ccb(&work_ccb->ccb_h, path, /*priority*/1); 60418b8a9b1dSJustin T. Gibbs work_ccb->ccb_h.func_code = XPT_RESET_BUS; 60428b8a9b1dSJustin T. Gibbs work_ccb->ccb_h.cbfcnp = NULL; 60438b8a9b1dSJustin T. Gibbs CAM_DEBUG(path, CAM_DEBUG_SUBTRACE, 60448b8a9b1dSJustin T. Gibbs ("Resetting Bus\n")); 60458b8a9b1dSJustin T. Gibbs xpt_action(work_ccb); 60468b8a9b1dSJustin T. Gibbs xpt_finishconfig(xpt_periph, work_ccb); 604798192658SJustin T. Gibbs } else { 604898192658SJustin T. Gibbs /* Act as though we performed a successful BUS RESET */ 604998192658SJustin T. Gibbs work_ccb->ccb_h.func_code = XPT_RESET_BUS; 605098192658SJustin T. Gibbs xpt_finishconfig(xpt_periph, work_ccb); 605198192658SJustin T. Gibbs } 60528b8a9b1dSJustin T. Gibbs } 60538b8a9b1dSJustin T. Gibbs 60548b8a9b1dSJustin T. Gibbs return(1); 60558b8a9b1dSJustin T. Gibbs } 60568b8a9b1dSJustin T. Gibbs 60578b8a9b1dSJustin T. Gibbs static void 60588b8a9b1dSJustin T. Gibbs xpt_config(void *arg) 60598b8a9b1dSJustin T. Gibbs { 60608b8a9b1dSJustin T. Gibbs /* Now that interrupts are enabled, go find our devices */ 60618b8a9b1dSJustin T. Gibbs 60628b8a9b1dSJustin T. Gibbs #ifdef CAMDEBUG 60638b8a9b1dSJustin T. Gibbs /* Setup debugging flags and path */ 60648b8a9b1dSJustin T. Gibbs #ifdef CAM_DEBUG_FLAGS 60658b8a9b1dSJustin T. Gibbs cam_dflags = CAM_DEBUG_FLAGS; 60668b8a9b1dSJustin T. Gibbs #else /* !CAM_DEBUG_FLAGS */ 60678b8a9b1dSJustin T. Gibbs cam_dflags = CAM_DEBUG_NONE; 60688b8a9b1dSJustin T. Gibbs #endif /* CAM_DEBUG_FLAGS */ 60698b8a9b1dSJustin T. Gibbs #ifdef CAM_DEBUG_BUS 60708b8a9b1dSJustin T. Gibbs if (cam_dflags != CAM_DEBUG_NONE) { 60718b8a9b1dSJustin T. Gibbs if (xpt_create_path(&cam_dpath, xpt_periph, 60728b8a9b1dSJustin T. Gibbs CAM_DEBUG_BUS, CAM_DEBUG_TARGET, 60738b8a9b1dSJustin T. Gibbs CAM_DEBUG_LUN) != CAM_REQ_CMP) { 60748b8a9b1dSJustin T. Gibbs printf("xpt_config: xpt_create_path() failed for debug" 60758b8a9b1dSJustin T. Gibbs " target %d:%d:%d, debugging disabled\n", 60768b8a9b1dSJustin T. Gibbs CAM_DEBUG_BUS, CAM_DEBUG_TARGET, CAM_DEBUG_LUN); 60778b8a9b1dSJustin T. Gibbs cam_dflags = CAM_DEBUG_NONE; 60788b8a9b1dSJustin T. Gibbs } 60798b8a9b1dSJustin T. Gibbs } else 60808b8a9b1dSJustin T. Gibbs cam_dpath = NULL; 60818b8a9b1dSJustin T. Gibbs #else /* !CAM_DEBUG_BUS */ 60828b8a9b1dSJustin T. Gibbs cam_dpath = NULL; 60838b8a9b1dSJustin T. Gibbs #endif /* CAM_DEBUG_BUS */ 60848b8a9b1dSJustin T. Gibbs #endif /* CAMDEBUG */ 60858b8a9b1dSJustin T. Gibbs 6086a5479bc5SJustin T. Gibbs /* 6087a5479bc5SJustin T. Gibbs * Scan all installed busses. 6088a5479bc5SJustin T. Gibbs */ 60898b8a9b1dSJustin T. Gibbs xpt_for_all_busses(xptconfigbuscountfunc, NULL); 60908b8a9b1dSJustin T. Gibbs 6091ecdf1113SJustin T. Gibbs if (busses_to_config == 0) { 6092ecdf1113SJustin T. Gibbs /* Call manually because we don't have any busses */ 60938b8a9b1dSJustin T. Gibbs xpt_finishconfig(xpt_periph, NULL); 60942863f7b1SJustin T. Gibbs } else { 609587cfaf0eSJustin T. Gibbs if (busses_to_reset > 0 && SCSI_DELAY >= 2000) { 60962863f7b1SJustin T. Gibbs printf("Waiting %d seconds for SCSI " 60972863f7b1SJustin T. Gibbs "devices to settle\n", SCSI_DELAY/1000); 60982863f7b1SJustin T. Gibbs } 6099ecdf1113SJustin T. Gibbs xpt_for_all_busses(xptconfigfunc, NULL); 61008b8a9b1dSJustin T. Gibbs } 61012863f7b1SJustin T. Gibbs } 61028b8a9b1dSJustin T. Gibbs 61038b8a9b1dSJustin T. Gibbs /* 61048b8a9b1dSJustin T. Gibbs * If the given device only has one peripheral attached to it, and if that 61058b8a9b1dSJustin T. Gibbs * peripheral is the passthrough driver, announce it. This insures that the 61068b8a9b1dSJustin T. Gibbs * user sees some sort of announcement for every peripheral in their system. 61078b8a9b1dSJustin T. Gibbs */ 61088b8a9b1dSJustin T. Gibbs static int 61098b8a9b1dSJustin T. Gibbs xptpassannouncefunc(struct cam_ed *device, void *arg) 61108b8a9b1dSJustin T. Gibbs { 61118b8a9b1dSJustin T. Gibbs struct cam_periph *periph; 61128b8a9b1dSJustin T. Gibbs int i; 61138b8a9b1dSJustin T. Gibbs 61148b8a9b1dSJustin T. Gibbs for (periph = SLIST_FIRST(&device->periphs), i = 0; periph != NULL; 61158b8a9b1dSJustin T. Gibbs periph = SLIST_NEXT(periph, periph_links), i++); 61168b8a9b1dSJustin T. Gibbs 61178b8a9b1dSJustin T. Gibbs periph = SLIST_FIRST(&device->periphs); 61188b8a9b1dSJustin T. Gibbs if ((i == 1) 61198b8a9b1dSJustin T. Gibbs && (strncmp(periph->periph_name, "pass", 4) == 0)) 61208b8a9b1dSJustin T. Gibbs xpt_announce_periph(periph, NULL); 61218b8a9b1dSJustin T. Gibbs 61228b8a9b1dSJustin T. Gibbs return(1); 61238b8a9b1dSJustin T. Gibbs } 61248b8a9b1dSJustin T. Gibbs 61258b8a9b1dSJustin T. Gibbs static void 61268b8a9b1dSJustin T. Gibbs xpt_finishconfig(struct cam_periph *periph, union ccb *done_ccb) 61278b8a9b1dSJustin T. Gibbs { 61288b8a9b1dSJustin T. Gibbs struct periph_driver **p_drv; 61298b8a9b1dSJustin T. Gibbs int i; 61308b8a9b1dSJustin T. Gibbs 61318b8a9b1dSJustin T. Gibbs if (done_ccb != NULL) { 61328b8a9b1dSJustin T. Gibbs CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_TRACE, 61338b8a9b1dSJustin T. Gibbs ("xpt_finishconfig\n")); 61348b8a9b1dSJustin T. Gibbs switch(done_ccb->ccb_h.func_code) { 61358b8a9b1dSJustin T. Gibbs case XPT_RESET_BUS: 61368b8a9b1dSJustin T. Gibbs if (done_ccb->ccb_h.status == CAM_REQ_CMP) { 61378b8a9b1dSJustin T. Gibbs done_ccb->ccb_h.func_code = XPT_SCAN_BUS; 61388b8a9b1dSJustin T. Gibbs done_ccb->ccb_h.cbfcnp = xpt_finishconfig; 61398b8a9b1dSJustin T. Gibbs xpt_action(done_ccb); 61408b8a9b1dSJustin T. Gibbs return; 61418b8a9b1dSJustin T. Gibbs } 61428b8a9b1dSJustin T. Gibbs /* FALLTHROUGH */ 61438b8a9b1dSJustin T. Gibbs case XPT_SCAN_BUS: 614498192658SJustin T. Gibbs default: 61458b8a9b1dSJustin T. Gibbs xpt_free_path(done_ccb->ccb_h.path); 61468b8a9b1dSJustin T. Gibbs busses_to_config--; 61478b8a9b1dSJustin T. Gibbs break; 61488b8a9b1dSJustin T. Gibbs } 61498b8a9b1dSJustin T. Gibbs } 61508b8a9b1dSJustin T. Gibbs 61518b8a9b1dSJustin T. Gibbs if (busses_to_config == 0) { 61528b8a9b1dSJustin T. Gibbs /* Register all the peripheral drivers */ 6153e9189611SPeter Wemm /* XXX This will have to change when we have loadable modules */ 61548b8a9b1dSJustin T. Gibbs p_drv = (struct periph_driver **)periphdriver_set.ls_items; 61558b8a9b1dSJustin T. Gibbs for (i = 0; p_drv[i] != NULL; i++) { 61568b8a9b1dSJustin T. Gibbs (*p_drv[i]->init)(); 61578b8a9b1dSJustin T. Gibbs } 61588b8a9b1dSJustin T. Gibbs 61598b8a9b1dSJustin T. Gibbs /* 61608b8a9b1dSJustin T. Gibbs * Check for devices with no "standard" peripheral driver 61618b8a9b1dSJustin T. Gibbs * attached. For any devices like that, announce the 61628b8a9b1dSJustin T. Gibbs * passthrough driver so the user will see something. 61638b8a9b1dSJustin T. Gibbs */ 61648b8a9b1dSJustin T. Gibbs xpt_for_all_devices(xptpassannouncefunc, NULL); 61658b8a9b1dSJustin T. Gibbs 61668b8a9b1dSJustin T. Gibbs /* Release our hook so that the boot can continue. */ 61678b8a9b1dSJustin T. Gibbs config_intrhook_disestablish(xpt_config_hook); 61689dd03ecfSJustin T. Gibbs free(xpt_config_hook, M_TEMP); 61699dd03ecfSJustin T. Gibbs xpt_config_hook = NULL; 61708b8a9b1dSJustin T. Gibbs } 61718b8a9b1dSJustin T. Gibbs if (done_ccb != NULL) 61728b8a9b1dSJustin T. Gibbs xpt_free_ccb(done_ccb); 61738b8a9b1dSJustin T. Gibbs } 61748b8a9b1dSJustin T. Gibbs 61758b8a9b1dSJustin T. Gibbs static void 61768b8a9b1dSJustin T. Gibbs xptaction(struct cam_sim *sim, union ccb *work_ccb) 61778b8a9b1dSJustin T. Gibbs { 61788b8a9b1dSJustin T. Gibbs CAM_DEBUG(work_ccb->ccb_h.path, CAM_DEBUG_TRACE, ("xptaction\n")); 61798b8a9b1dSJustin T. Gibbs 61808b8a9b1dSJustin T. Gibbs switch (work_ccb->ccb_h.func_code) { 61818b8a9b1dSJustin T. Gibbs /* Common cases first */ 61828b8a9b1dSJustin T. Gibbs case XPT_PATH_INQ: /* Path routing inquiry */ 61838b8a9b1dSJustin T. Gibbs { 61848b8a9b1dSJustin T. Gibbs struct ccb_pathinq *cpi; 61858b8a9b1dSJustin T. Gibbs 61868b8a9b1dSJustin T. Gibbs cpi = &work_ccb->cpi; 61878b8a9b1dSJustin T. Gibbs cpi->version_num = 1; /* XXX??? */ 61888b8a9b1dSJustin T. Gibbs cpi->hba_inquiry = 0; 61898b8a9b1dSJustin T. Gibbs cpi->target_sprt = 0; 61908b8a9b1dSJustin T. Gibbs cpi->hba_misc = 0; 61918b8a9b1dSJustin T. Gibbs cpi->hba_eng_cnt = 0; 61928b8a9b1dSJustin T. Gibbs cpi->max_target = 0; 61938b8a9b1dSJustin T. Gibbs cpi->max_lun = 0; 61948b8a9b1dSJustin T. Gibbs cpi->initiator_id = 0; 61958b8a9b1dSJustin T. Gibbs strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN); 61968b8a9b1dSJustin T. Gibbs strncpy(cpi->hba_vid, "", HBA_IDLEN); 61978b8a9b1dSJustin T. Gibbs strncpy(cpi->dev_name, sim->sim_name, DEV_IDLEN); 61988b8a9b1dSJustin T. Gibbs cpi->unit_number = sim->unit_number; 61998b8a9b1dSJustin T. Gibbs cpi->bus_id = sim->bus_id; 62009deea857SKenneth D. Merry cpi->base_transfer_speed = 0; 62018b8a9b1dSJustin T. Gibbs cpi->ccb_h.status = CAM_REQ_CMP; 62028b8a9b1dSJustin T. Gibbs xpt_done(work_ccb); 62038b8a9b1dSJustin T. Gibbs break; 62048b8a9b1dSJustin T. Gibbs } 62058b8a9b1dSJustin T. Gibbs default: 62068b8a9b1dSJustin T. Gibbs work_ccb->ccb_h.status = CAM_REQ_INVALID; 62078b8a9b1dSJustin T. Gibbs xpt_done(work_ccb); 62088b8a9b1dSJustin T. Gibbs break; 62098b8a9b1dSJustin T. Gibbs } 62108b8a9b1dSJustin T. Gibbs } 62118b8a9b1dSJustin T. Gibbs 62128b8a9b1dSJustin T. Gibbs /* 6213434bbf6eSJustin T. Gibbs * The xpt as a "controller" has no interrupt sources, so polling 6214434bbf6eSJustin T. Gibbs * is a no-op. 6215434bbf6eSJustin T. Gibbs */ 6216434bbf6eSJustin T. Gibbs static void 6217434bbf6eSJustin T. Gibbs xptpoll(struct cam_sim *sim) 6218434bbf6eSJustin T. Gibbs { 6219434bbf6eSJustin T. Gibbs } 6220434bbf6eSJustin T. Gibbs 6221434bbf6eSJustin T. Gibbs /* 62228b8a9b1dSJustin T. Gibbs * Should only be called by the machine interrupt dispatch routines, 62238b8a9b1dSJustin T. Gibbs * so put these prototypes here instead of in the header. 62248b8a9b1dSJustin T. Gibbs */ 62258b8a9b1dSJustin T. Gibbs 62265d754af7SMatt Jacob static void 62275d754af7SMatt Jacob swi_camnet(void) 62288b8a9b1dSJustin T. Gibbs { 62298b8a9b1dSJustin T. Gibbs camisr(&cam_netq); 62308b8a9b1dSJustin T. Gibbs } 62318b8a9b1dSJustin T. Gibbs 62325d754af7SMatt Jacob static void 62335d754af7SMatt Jacob swi_cambio(void) 62348b8a9b1dSJustin T. Gibbs { 62358b8a9b1dSJustin T. Gibbs camisr(&cam_bioq); 62368b8a9b1dSJustin T. Gibbs } 62378b8a9b1dSJustin T. Gibbs 62388b8a9b1dSJustin T. Gibbs static void 62398b8a9b1dSJustin T. Gibbs camisr(cam_isrq_t *queue) 62408b8a9b1dSJustin T. Gibbs { 62418b8a9b1dSJustin T. Gibbs int s; 62428b8a9b1dSJustin T. Gibbs struct ccb_hdr *ccb_h; 62438b8a9b1dSJustin T. Gibbs 62448b8a9b1dSJustin T. Gibbs s = splcam(); 62458b8a9b1dSJustin T. Gibbs while ((ccb_h = TAILQ_FIRST(queue)) != NULL) { 62468b8a9b1dSJustin T. Gibbs int runq; 62478b8a9b1dSJustin T. Gibbs 62488b8a9b1dSJustin T. Gibbs TAILQ_REMOVE(queue, ccb_h, sim_links.tqe); 62498b8a9b1dSJustin T. Gibbs ccb_h->pinfo.index = CAM_UNQUEUED_INDEX; 62508b8a9b1dSJustin T. Gibbs splx(s); 62518b8a9b1dSJustin T. Gibbs 62528b8a9b1dSJustin T. Gibbs CAM_DEBUG(ccb_h->path, CAM_DEBUG_TRACE, 62538b8a9b1dSJustin T. Gibbs ("camisr")); 62548b8a9b1dSJustin T. Gibbs 62558b8a9b1dSJustin T. Gibbs runq = FALSE; 62568b8a9b1dSJustin T. Gibbs 62578b8a9b1dSJustin T. Gibbs if (ccb_h->flags & CAM_HIGH_POWER) { 62588b8a9b1dSJustin T. Gibbs struct highpowerlist *hphead; 62598b8a9b1dSJustin T. Gibbs struct cam_ed *device; 62608b8a9b1dSJustin T. Gibbs union ccb *send_ccb; 62618b8a9b1dSJustin T. Gibbs 62628b8a9b1dSJustin T. Gibbs hphead = &highpowerq; 62638b8a9b1dSJustin T. Gibbs 62648b8a9b1dSJustin T. Gibbs send_ccb = (union ccb *)STAILQ_FIRST(hphead); 62658b8a9b1dSJustin T. Gibbs 62668b8a9b1dSJustin T. Gibbs /* 62678b8a9b1dSJustin T. Gibbs * Increment the count since this command is done. 62688b8a9b1dSJustin T. Gibbs */ 62698b8a9b1dSJustin T. Gibbs num_highpower++; 62708b8a9b1dSJustin T. Gibbs 62718b8a9b1dSJustin T. Gibbs /* 62728b8a9b1dSJustin T. Gibbs * Any high powered commands queued up? 62738b8a9b1dSJustin T. Gibbs */ 62748b8a9b1dSJustin T. Gibbs if (send_ccb != NULL) { 62758b8a9b1dSJustin T. Gibbs device = send_ccb->ccb_h.path->device; 62768b8a9b1dSJustin T. Gibbs 62778b8a9b1dSJustin T. Gibbs STAILQ_REMOVE_HEAD(hphead, xpt_links.stqe); 62788b8a9b1dSJustin T. Gibbs 62792cefde5fSJustin T. Gibbs xpt_release_devq(send_ccb->ccb_h.path, 62802cefde5fSJustin T. Gibbs /*count*/1, /*runqueue*/TRUE); 62818b8a9b1dSJustin T. Gibbs } 62828b8a9b1dSJustin T. Gibbs } 62839deea857SKenneth D. Merry if ((ccb_h->func_code & XPT_FC_USER_CCB) == 0) { 62848b8a9b1dSJustin T. Gibbs struct cam_ed *dev; 62858b8a9b1dSJustin T. Gibbs 62868b8a9b1dSJustin T. Gibbs dev = ccb_h->path->device; 62878b8a9b1dSJustin T. Gibbs 62888b8a9b1dSJustin T. Gibbs s = splcam(); 62898b8a9b1dSJustin T. Gibbs cam_ccbq_ccb_done(&dev->ccbq, (union ccb *)ccb_h); 62908b8a9b1dSJustin T. Gibbs 62918b8a9b1dSJustin T. Gibbs ccb_h->path->bus->sim->devq->send_active--; 62928b8a9b1dSJustin T. Gibbs ccb_h->path->bus->sim->devq->send_openings++; 62938b8a9b1dSJustin T. Gibbs splx(s); 62948b8a9b1dSJustin T. Gibbs 62958b8a9b1dSJustin T. Gibbs if ((dev->flags & CAM_DEV_REL_ON_COMPLETE) != 0 62968b8a9b1dSJustin T. Gibbs || ((dev->flags & CAM_DEV_REL_ON_QUEUE_EMPTY) != 0 62978b8a9b1dSJustin T. Gibbs && (dev->ccbq.dev_active == 0))) { 62988b8a9b1dSJustin T. Gibbs 62992cefde5fSJustin T. Gibbs xpt_release_devq(ccb_h->path, /*count*/1, 63008b8a9b1dSJustin T. Gibbs /*run_queue*/TRUE); 63018b8a9b1dSJustin T. Gibbs } 63028b8a9b1dSJustin T. Gibbs 6303fd21cc5eSJustin T. Gibbs if ((dev->flags & CAM_DEV_TAG_AFTER_COUNT) != 0 6304fd21cc5eSJustin T. Gibbs && (--dev->tag_delay_count == 0)) 6305fd21cc5eSJustin T. Gibbs xpt_start_tags(ccb_h->path); 6306fd21cc5eSJustin T. Gibbs 63078b8a9b1dSJustin T. Gibbs if ((dev->ccbq.queue.entries > 0) 63088b8a9b1dSJustin T. Gibbs && (dev->qfrozen_cnt == 0) 63098b8a9b1dSJustin T. Gibbs && (device_is_send_queued(dev) == 0)) { 63108b8a9b1dSJustin T. Gibbs runq = xpt_schedule_dev_sendq(ccb_h->path->bus, 63118b8a9b1dSJustin T. Gibbs dev); 63128b8a9b1dSJustin T. Gibbs } 63138b8a9b1dSJustin T. Gibbs } 63148b8a9b1dSJustin T. Gibbs 63158b8a9b1dSJustin T. Gibbs if (ccb_h->status & CAM_RELEASE_SIMQ) { 63168b8a9b1dSJustin T. Gibbs xpt_release_simq(ccb_h->path->bus->sim, 63178b8a9b1dSJustin T. Gibbs /*run_queue*/TRUE); 6318434bbf6eSJustin T. Gibbs ccb_h->status &= ~CAM_RELEASE_SIMQ; 6319434bbf6eSJustin T. Gibbs runq = FALSE; 6320434bbf6eSJustin T. Gibbs } 6321434bbf6eSJustin T. Gibbs 6322434bbf6eSJustin T. Gibbs if ((ccb_h->flags & CAM_DEV_QFRZDIS) 63238b8a9b1dSJustin T. Gibbs && (ccb_h->status & CAM_DEV_QFRZN)) { 63242cefde5fSJustin T. Gibbs xpt_release_devq(ccb_h->path, /*count*/1, 63258b8a9b1dSJustin T. Gibbs /*run_queue*/TRUE); 63268b8a9b1dSJustin T. Gibbs ccb_h->status &= ~CAM_DEV_QFRZN; 63278b8a9b1dSJustin T. Gibbs } else if (runq) { 63288b8a9b1dSJustin T. Gibbs xpt_run_dev_sendq(ccb_h->path->bus); 63298b8a9b1dSJustin T. Gibbs } 63308b8a9b1dSJustin T. Gibbs 63318b8a9b1dSJustin T. Gibbs /* Call the peripheral driver's callback */ 6332434bbf6eSJustin T. Gibbs (*ccb_h->cbfcnp)(ccb_h->path->periph, (union ccb *)ccb_h); 63338b8a9b1dSJustin T. Gibbs 63348b8a9b1dSJustin T. Gibbs /* Raise IPL for while test */ 63358b8a9b1dSJustin T. Gibbs s = splcam(); 63368b8a9b1dSJustin T. Gibbs } 63378b8a9b1dSJustin T. Gibbs splx(s); 63388b8a9b1dSJustin T. Gibbs } 6339