1898b0535SWarner Losh /*- 28b8a9b1dSJustin T. Gibbs * Implementation of the Common Access Method Transport (XPT) layer. 38b8a9b1dSJustin T. Gibbs * 4c8bead2aSJustin T. Gibbs * Copyright (c) 1997, 1998, 1999 Justin T. Gibbs. 559190eaaSKenneth D. Merry * Copyright (c) 1997, 1998, 1999 Kenneth D. Merry. 68b8a9b1dSJustin T. Gibbs * All rights reserved. 78b8a9b1dSJustin T. Gibbs * 88b8a9b1dSJustin T. Gibbs * Redistribution and use in source and binary forms, with or without 98b8a9b1dSJustin T. Gibbs * modification, are permitted provided that the following conditions 108b8a9b1dSJustin T. Gibbs * are met: 118b8a9b1dSJustin T. Gibbs * 1. Redistributions of source code must retain the above copyright 128b8a9b1dSJustin T. Gibbs * notice, this list of conditions, and the following disclaimer, 138b8a9b1dSJustin T. Gibbs * without modification, immediately at the beginning of the file. 148b8a9b1dSJustin T. Gibbs * 2. The name of the author may not be used to endorse or promote products 158b8a9b1dSJustin T. Gibbs * derived from this software without specific prior written permission. 168b8a9b1dSJustin T. Gibbs * 178b8a9b1dSJustin T. Gibbs * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 188b8a9b1dSJustin T. Gibbs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 198b8a9b1dSJustin T. Gibbs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 208b8a9b1dSJustin T. Gibbs * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 218b8a9b1dSJustin T. Gibbs * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 228b8a9b1dSJustin T. Gibbs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 238b8a9b1dSJustin T. Gibbs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 248b8a9b1dSJustin T. Gibbs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 258b8a9b1dSJustin T. Gibbs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 268b8a9b1dSJustin T. Gibbs * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 278b8a9b1dSJustin T. Gibbs * SUCH DAMAGE. 288b8a9b1dSJustin T. Gibbs */ 299c963d87SDavid E. O'Brien 309c963d87SDavid E. O'Brien #include <sys/cdefs.h> 319c963d87SDavid E. O'Brien __FBSDID("$FreeBSD$"); 329c963d87SDavid E. O'Brien 338b8a9b1dSJustin T. Gibbs #include <sys/param.h> 349a94c9c5SJohn Baldwin #include <sys/bus.h> 358b8a9b1dSJustin T. Gibbs #include <sys/systm.h> 368b8a9b1dSJustin T. Gibbs #include <sys/types.h> 378b8a9b1dSJustin T. Gibbs #include <sys/malloc.h> 388b8a9b1dSJustin T. Gibbs #include <sys/kernel.h> 3987cfaf0eSJustin T. Gibbs #include <sys/time.h> 408b8a9b1dSJustin T. Gibbs #include <sys/conf.h> 418b8a9b1dSJustin T. Gibbs #include <sys/fcntl.h> 428b8a9b1dSJustin T. Gibbs #include <sys/md5.h> 435d754af7SMatt Jacob #include <sys/interrupt.h> 443393f8daSKenneth D. Merry #include <sys/sbuf.h> 458b8a9b1dSJustin T. Gibbs 46ef3cf714SScott Long #include <sys/lock.h> 47ef3cf714SScott Long #include <sys/mutex.h> 48ef3cf714SScott Long 498b8a9b1dSJustin T. Gibbs #ifdef PC98 508b8a9b1dSJustin T. Gibbs #include <pc98/pc98/pc98_machdep.h> /* geometry translation */ 518b8a9b1dSJustin T. Gibbs #endif 528b8a9b1dSJustin T. Gibbs 538b8a9b1dSJustin T. Gibbs #include <cam/cam.h> 548b8a9b1dSJustin T. Gibbs #include <cam/cam_ccb.h> 558b8a9b1dSJustin T. Gibbs #include <cam/cam_periph.h> 568b8a9b1dSJustin T. Gibbs #include <cam/cam_sim.h> 578b8a9b1dSJustin T. Gibbs #include <cam/cam_xpt.h> 588b8a9b1dSJustin T. Gibbs #include <cam/cam_xpt_sim.h> 598b8a9b1dSJustin T. Gibbs #include <cam/cam_xpt_periph.h> 608b8a9b1dSJustin T. Gibbs #include <cam/cam_debug.h> 618b8a9b1dSJustin T. Gibbs 628b8a9b1dSJustin T. Gibbs #include <cam/scsi/scsi_all.h> 638b8a9b1dSJustin T. Gibbs #include <cam/scsi/scsi_message.h> 648b8a9b1dSJustin T. Gibbs #include <cam/scsi/scsi_pass.h> 658b8a9b1dSJustin T. Gibbs #include "opt_cam.h" 668b8a9b1dSJustin T. Gibbs 678b8a9b1dSJustin T. Gibbs /* Datastructures internal to the xpt layer */ 688b8a9b1dSJustin T. Gibbs 698b8a9b1dSJustin T. Gibbs /* 708b8a9b1dSJustin T. Gibbs * Definition of an async handler callback block. These are used to add 718b8a9b1dSJustin T. Gibbs * SIMs and peripherals to the async callback lists. 728b8a9b1dSJustin T. Gibbs */ 738b8a9b1dSJustin T. Gibbs struct async_node { 74e3975643SJake Burkholder SLIST_ENTRY(async_node) links; 758b8a9b1dSJustin T. Gibbs u_int32_t event_enable; /* Async Event enables */ 768b8a9b1dSJustin T. Gibbs void (*callback)(void *arg, u_int32_t code, 778b8a9b1dSJustin T. Gibbs struct cam_path *path, void *args); 788b8a9b1dSJustin T. Gibbs void *callback_arg; 798b8a9b1dSJustin T. Gibbs }; 808b8a9b1dSJustin T. Gibbs 81e3975643SJake Burkholder SLIST_HEAD(async_list, async_node); 82e3975643SJake Burkholder SLIST_HEAD(periph_list, cam_periph); 83e3975643SJake Burkholder static STAILQ_HEAD(highpowerlist, ccb_hdr) highpowerq; 848b8a9b1dSJustin T. Gibbs 858b8a9b1dSJustin T. Gibbs /* 868b8a9b1dSJustin T. Gibbs * This is the maximum number of high powered commands (e.g. start unit) 878b8a9b1dSJustin T. Gibbs * that can be outstanding at a particular time. 888b8a9b1dSJustin T. Gibbs */ 898b8a9b1dSJustin T. Gibbs #ifndef CAM_MAX_HIGHPOWER 908b8a9b1dSJustin T. Gibbs #define CAM_MAX_HIGHPOWER 4 918b8a9b1dSJustin T. Gibbs #endif 928b8a9b1dSJustin T. Gibbs 938b8a9b1dSJustin T. Gibbs /* number of high powered commands that can go through right now */ 948b8a9b1dSJustin T. Gibbs static int num_highpower = CAM_MAX_HIGHPOWER; 958b8a9b1dSJustin T. Gibbs 968b8a9b1dSJustin T. Gibbs /* 978b8a9b1dSJustin T. Gibbs * Structure for queueing a device in a run queue. 988b8a9b1dSJustin T. Gibbs * There is one run queue for allocating new ccbs, 998b8a9b1dSJustin T. Gibbs * and another for sending ccbs to the controller. 1008b8a9b1dSJustin T. Gibbs */ 1018b8a9b1dSJustin T. Gibbs struct cam_ed_qinfo { 1028b8a9b1dSJustin T. Gibbs cam_pinfo pinfo; 1038b8a9b1dSJustin T. Gibbs struct cam_ed *device; 1048b8a9b1dSJustin T. Gibbs }; 1058b8a9b1dSJustin T. Gibbs 1068b8a9b1dSJustin T. Gibbs /* 1078b8a9b1dSJustin T. Gibbs * The CAM EDT (Existing Device Table) contains the device information for 1088b8a9b1dSJustin T. Gibbs * all devices for all busses in the system. The table contains a 1098b8a9b1dSJustin T. Gibbs * cam_ed structure for each device on the bus. 1108b8a9b1dSJustin T. Gibbs */ 1118b8a9b1dSJustin T. Gibbs struct cam_ed { 112e3975643SJake Burkholder TAILQ_ENTRY(cam_ed) links; 1138b8a9b1dSJustin T. Gibbs struct cam_ed_qinfo alloc_ccb_entry; 1148b8a9b1dSJustin T. Gibbs struct cam_ed_qinfo send_ccb_entry; 1158b8a9b1dSJustin T. Gibbs struct cam_et *target; 1168b8a9b1dSJustin T. Gibbs lun_id_t lun_id; 1178b8a9b1dSJustin T. Gibbs struct camq drvq; /* 1188b8a9b1dSJustin T. Gibbs * Queue of type drivers wanting to do 1198b8a9b1dSJustin T. Gibbs * work on this device. 1208b8a9b1dSJustin T. Gibbs */ 1218b8a9b1dSJustin T. Gibbs struct cam_ccbq ccbq; /* Queue of pending ccbs */ 1228b8a9b1dSJustin T. Gibbs struct async_list asyncs; /* Async callback info for this B/T/L */ 1238b8a9b1dSJustin T. Gibbs struct periph_list periphs; /* All attached devices */ 1248b8a9b1dSJustin T. Gibbs u_int generation; /* Generation number */ 1258b8a9b1dSJustin T. Gibbs struct cam_periph *owner; /* Peripheral driver's ownership tag */ 1268b8a9b1dSJustin T. Gibbs struct xpt_quirk_entry *quirk; /* Oddities about this device */ 1278b8a9b1dSJustin T. Gibbs /* Storage for the inquiry data */ 1283393f8daSKenneth D. Merry #ifdef CAM_NEW_TRAN_CODE 1293393f8daSKenneth D. Merry cam_proto protocol; 1303393f8daSKenneth D. Merry u_int protocol_version; 1313393f8daSKenneth D. Merry cam_xport transport; 1323393f8daSKenneth D. Merry u_int transport_version; 1333393f8daSKenneth D. Merry #endif /* CAM_NEW_TRAN_CODE */ 1348b8a9b1dSJustin T. Gibbs struct scsi_inquiry_data inq_data; 1358b8a9b1dSJustin T. Gibbs u_int8_t inq_flags; /* 1368b8a9b1dSJustin T. Gibbs * Current settings for inquiry flags. 1378b8a9b1dSJustin T. Gibbs * This allows us to override settings 1388b8a9b1dSJustin T. Gibbs * like disconnection and tagged 1398b8a9b1dSJustin T. Gibbs * queuing for a device. 1408b8a9b1dSJustin T. Gibbs */ 1418b8a9b1dSJustin T. Gibbs u_int8_t queue_flags; /* Queue flags from the control page */ 1428b8a9b1dSJustin T. Gibbs u_int8_t serial_num_len; 1439ec5d7cdSMatt Jacob u_int8_t *serial_num; 1448b8a9b1dSJustin T. Gibbs u_int32_t qfrozen_cnt; 1458b8a9b1dSJustin T. Gibbs u_int32_t flags; 1468b8a9b1dSJustin T. Gibbs #define CAM_DEV_UNCONFIGURED 0x01 1478b8a9b1dSJustin T. Gibbs #define CAM_DEV_REL_TIMEOUT_PENDING 0x02 1488b8a9b1dSJustin T. Gibbs #define CAM_DEV_REL_ON_COMPLETE 0x04 1498b8a9b1dSJustin T. Gibbs #define CAM_DEV_REL_ON_QUEUE_EMPTY 0x08 1508b8a9b1dSJustin T. Gibbs #define CAM_DEV_RESIZE_QUEUE_NEEDED 0x10 151fd21cc5eSJustin T. Gibbs #define CAM_DEV_TAG_AFTER_COUNT 0x20 15287cfaf0eSJustin T. Gibbs #define CAM_DEV_INQUIRY_DATA_VALID 0x40 153fd21cc5eSJustin T. Gibbs u_int32_t tag_delay_count; 154fd21cc5eSJustin T. Gibbs #define CAM_TAG_DELAY_COUNT 5 155df8f9080SJustin T. Gibbs u_int32_t tag_saved_openings; 1568b8a9b1dSJustin T. Gibbs u_int32_t refcount; 1578b8a9b1dSJustin T. Gibbs struct callout_handle c_handle; 1588b8a9b1dSJustin T. Gibbs }; 1598b8a9b1dSJustin T. Gibbs 1608b8a9b1dSJustin T. Gibbs /* 1618b8a9b1dSJustin T. Gibbs * Each target is represented by an ET (Existing Target). These 1628b8a9b1dSJustin T. Gibbs * entries are created when a target is successfully probed with an 1638b8a9b1dSJustin T. Gibbs * identify, and removed when a device fails to respond after a number 1648b8a9b1dSJustin T. Gibbs * of retries, or a bus rescan finds the device missing. 1658b8a9b1dSJustin T. Gibbs */ 1668b8a9b1dSJustin T. Gibbs struct cam_et { 167e3975643SJake Burkholder TAILQ_HEAD(, cam_ed) ed_entries; 168e3975643SJake Burkholder TAILQ_ENTRY(cam_et) links; 1698b8a9b1dSJustin T. Gibbs struct cam_eb *bus; 1708b8a9b1dSJustin T. Gibbs target_id_t target_id; 1718b8a9b1dSJustin T. Gibbs u_int32_t refcount; 1728b8a9b1dSJustin T. Gibbs u_int generation; 17387cfaf0eSJustin T. Gibbs struct timeval last_reset; 1748b8a9b1dSJustin T. Gibbs }; 1758b8a9b1dSJustin T. Gibbs 1768b8a9b1dSJustin T. Gibbs /* 1778b8a9b1dSJustin T. Gibbs * Each bus is represented by an EB (Existing Bus). These entries 1788b8a9b1dSJustin T. Gibbs * are created by calls to xpt_bus_register and deleted by calls to 1798b8a9b1dSJustin T. Gibbs * xpt_bus_deregister. 1808b8a9b1dSJustin T. Gibbs */ 1818b8a9b1dSJustin T. Gibbs struct cam_eb { 182e3975643SJake Burkholder TAILQ_HEAD(, cam_et) et_entries; 183e3975643SJake Burkholder TAILQ_ENTRY(cam_eb) links; 1848b8a9b1dSJustin T. Gibbs path_id_t path_id; 1858b8a9b1dSJustin T. Gibbs struct cam_sim *sim; 18687cfaf0eSJustin T. Gibbs struct timeval last_reset; 1878b8a9b1dSJustin T. Gibbs u_int32_t flags; 1888b8a9b1dSJustin T. Gibbs #define CAM_EB_RUNQ_SCHEDULED 0x01 189a5479bc5SJustin T. Gibbs u_int32_t refcount; 1908b8a9b1dSJustin T. Gibbs u_int generation; 1918b8a9b1dSJustin T. Gibbs }; 1928b8a9b1dSJustin T. Gibbs 1938b8a9b1dSJustin T. Gibbs struct cam_path { 1948b8a9b1dSJustin T. Gibbs struct cam_periph *periph; 1958b8a9b1dSJustin T. Gibbs struct cam_eb *bus; 1968b8a9b1dSJustin T. Gibbs struct cam_et *target; 1978b8a9b1dSJustin T. Gibbs struct cam_ed *device; 1988b8a9b1dSJustin T. Gibbs }; 1998b8a9b1dSJustin T. Gibbs 2008b8a9b1dSJustin T. Gibbs struct xpt_quirk_entry { 2018b8a9b1dSJustin T. Gibbs struct scsi_inquiry_pattern inq_pat; 2028b8a9b1dSJustin T. Gibbs u_int8_t quirks; 2038b8a9b1dSJustin T. Gibbs #define CAM_QUIRK_NOLUNS 0x01 2048b8a9b1dSJustin T. Gibbs #define CAM_QUIRK_NOSERIAL 0x02 20548f6456dSMatt Jacob #define CAM_QUIRK_HILUNS 0x04 206f4322bc8SMatt Jacob #define CAM_QUIRK_NOHILUNS 0x08 2079deea857SKenneth D. Merry u_int mintags; 2089deea857SKenneth D. Merry u_int maxtags; 2098b8a9b1dSJustin T. Gibbs }; 21048f6456dSMatt Jacob #define CAM_SCSI2_MAXLUN 8 211f4322bc8SMatt Jacob /* 212f4322bc8SMatt Jacob * If we're not quirked to search <= the first 8 luns 213f4322bc8SMatt Jacob * and we are either quirked to search above lun 8, 214f4322bc8SMatt Jacob * or we're > SCSI-2, we can look for luns above lun 8. 215f4322bc8SMatt Jacob */ 216f4322bc8SMatt Jacob #define CAN_SRCH_HI(dv) \ 217f4322bc8SMatt Jacob (((dv->quirk->quirks & CAM_QUIRK_NOHILUNS) == 0) \ 218f4322bc8SMatt Jacob && ((dv->quirk->quirks & CAM_QUIRK_HILUNS) \ 219f4322bc8SMatt Jacob || SID_ANSI_REV(&dv->inq_data) > SCSI_REV_2)) 2208b8a9b1dSJustin T. Gibbs 2218b8a9b1dSJustin T. Gibbs typedef enum { 2228b8a9b1dSJustin T. Gibbs XPT_FLAG_OPEN = 0x01 2238b8a9b1dSJustin T. Gibbs } xpt_flags; 2248b8a9b1dSJustin T. Gibbs 2258b8a9b1dSJustin T. Gibbs struct xpt_softc { 2268b8a9b1dSJustin T. Gibbs xpt_flags flags; 2278b8a9b1dSJustin T. Gibbs u_int32_t generation; 2288b8a9b1dSJustin T. Gibbs }; 2298b8a9b1dSJustin T. Gibbs 2308b8a9b1dSJustin T. Gibbs static const char quantum[] = "QUANTUM"; 231f24c39c7SKenneth D. Merry static const char sony[] = "SONY"; 232f24c39c7SKenneth D. Merry static const char west_digital[] = "WDIGTL"; 2331f04f5abSKenneth D. Merry static const char samsung[] = "SAMSUNG"; 234560d629fSKenneth D. Merry static const char seagate[] = "SEAGATE"; 2355acba6ecSJohn-Mark Gurney static const char microp[] = "MICROP"; 2368b8a9b1dSJustin T. Gibbs 2378b8a9b1dSJustin T. Gibbs static struct xpt_quirk_entry xpt_quirk_table[] = 2388b8a9b1dSJustin T. Gibbs { 2398b8a9b1dSJustin T. Gibbs { 2408b8a9b1dSJustin T. Gibbs /* Reports QUEUE FULL for temporary resource shortages */ 2416747168dSKenneth D. Merry { T_DIRECT, SIP_MEDIA_FIXED, quantum, "XP39100*", "*" }, 2428b8a9b1dSJustin T. Gibbs /*quirks*/0, /*mintags*/24, /*maxtags*/32 2438b8a9b1dSJustin T. Gibbs }, 2448b8a9b1dSJustin T. Gibbs { 2458b8a9b1dSJustin T. Gibbs /* Reports QUEUE FULL for temporary resource shortages */ 2466747168dSKenneth D. Merry { T_DIRECT, SIP_MEDIA_FIXED, quantum, "XP34550*", "*" }, 2476747168dSKenneth D. Merry /*quirks*/0, /*mintags*/24, /*maxtags*/32 2486747168dSKenneth D. Merry }, 2496747168dSKenneth D. Merry { 2506747168dSKenneth D. Merry /* Reports QUEUE FULL for temporary resource shortages */ 2516747168dSKenneth D. Merry { T_DIRECT, SIP_MEDIA_FIXED, quantum, "XP32275*", "*" }, 2528b8a9b1dSJustin T. Gibbs /*quirks*/0, /*mintags*/24, /*maxtags*/32 2538b8a9b1dSJustin T. Gibbs }, 2548b8a9b1dSJustin T. Gibbs { 2558b8a9b1dSJustin T. Gibbs /* Broken tagged queuing drive */ 2565acba6ecSJohn-Mark Gurney { T_DIRECT, SIP_MEDIA_FIXED, microp, "4421-07*", "*" }, 2575acba6ecSJohn-Mark Gurney /*quirks*/0, /*mintags*/0, /*maxtags*/0 2585acba6ecSJohn-Mark Gurney }, 2595acba6ecSJohn-Mark Gurney { 2605acba6ecSJohn-Mark Gurney /* Broken tagged queuing drive */ 2618b8a9b1dSJustin T. Gibbs { T_DIRECT, SIP_MEDIA_FIXED, "HP", "C372*", "*" }, 2628b8a9b1dSJustin T. Gibbs /*quirks*/0, /*mintags*/0, /*maxtags*/0 2638b8a9b1dSJustin T. Gibbs }, 2648b8a9b1dSJustin T. Gibbs { 2658b8a9b1dSJustin T. Gibbs /* Broken tagged queuing drive */ 2665acba6ecSJohn-Mark Gurney { T_DIRECT, SIP_MEDIA_FIXED, microp, "3391*", "x43h" }, 2678b8a9b1dSJustin T. Gibbs /*quirks*/0, /*mintags*/0, /*maxtags*/0 2688b8a9b1dSJustin T. Gibbs }, 2698b8a9b1dSJustin T. Gibbs { 2708597eafeSKenneth D. Merry /* 2714cdd0221SKenneth D. Merry * Unfortunately, the Quantum Atlas III has the same 2724cdd0221SKenneth D. Merry * problem as the Atlas II drives above. 2734cdd0221SKenneth D. Merry * Reported by: "Johan Granlund" <johan@granlund.nu> 2744cdd0221SKenneth D. Merry * 2754cdd0221SKenneth D. Merry * For future reference, the drive with the problem was: 2764cdd0221SKenneth D. Merry * QUANTUM QM39100TD-SW N1B0 2774cdd0221SKenneth D. Merry * 2784cdd0221SKenneth D. Merry * It's possible that Quantum will fix the problem in later 2794cdd0221SKenneth D. Merry * firmware revisions. If that happens, the quirk entry 2804cdd0221SKenneth D. Merry * will need to be made specific to the firmware revisions 2814cdd0221SKenneth D. Merry * with the problem. 2824cdd0221SKenneth D. Merry * 2834cdd0221SKenneth D. Merry */ 2844cdd0221SKenneth D. Merry /* Reports QUEUE FULL for temporary resource shortages */ 2854cdd0221SKenneth D. Merry { T_DIRECT, SIP_MEDIA_FIXED, quantum, "QM39100*", "*" }, 2864cdd0221SKenneth D. Merry /*quirks*/0, /*mintags*/24, /*maxtags*/32 2874cdd0221SKenneth D. Merry }, 2884cdd0221SKenneth D. Merry { 2894cdd0221SKenneth D. Merry /* 290588b47e5SKenneth D. Merry * 18 Gig Atlas III, same problem as the 9G version. 291588b47e5SKenneth D. Merry * Reported by: Andre Albsmeier 292588b47e5SKenneth D. Merry * <andre.albsmeier@mchp.siemens.de> 293588b47e5SKenneth D. Merry * 294588b47e5SKenneth D. Merry * For future reference, the drive with the problem was: 295588b47e5SKenneth D. Merry * QUANTUM QM318000TD-S N491 296588b47e5SKenneth D. Merry */ 297588b47e5SKenneth D. Merry /* Reports QUEUE FULL for temporary resource shortages */ 298588b47e5SKenneth D. Merry { T_DIRECT, SIP_MEDIA_FIXED, quantum, "QM318000*", "*" }, 299588b47e5SKenneth D. Merry /*quirks*/0, /*mintags*/24, /*maxtags*/32 300588b47e5SKenneth D. Merry }, 301588b47e5SKenneth D. Merry { 302588b47e5SKenneth D. Merry /* 3038597eafeSKenneth D. Merry * Broken tagged queuing drive 3048597eafeSKenneth D. Merry * Reported by: Bret Ford <bford@uop.cs.uop.edu> 3058597eafeSKenneth D. Merry * and: Martin Renters <martin@tdc.on.ca> 3068597eafeSKenneth D. Merry */ 307560d629fSKenneth D. Merry { T_DIRECT, SIP_MEDIA_FIXED, seagate, "ST410800*", "71*" }, 3088597eafeSKenneth D. Merry /*quirks*/0, /*mintags*/0, /*maxtags*/0 3098597eafeSKenneth D. Merry }, 310560d629fSKenneth D. Merry /* 311c816e025SKenneth D. Merry * The Seagate Medalist Pro drives have very poor write 312c816e025SKenneth D. Merry * performance with anything more than 2 tags. 313560d629fSKenneth D. Merry * 314560d629fSKenneth D. Merry * Reported by: Paul van der Zwan <paulz@trantor.xs4all.nl> 315560d629fSKenneth D. Merry * Drive: <SEAGATE ST36530N 1444> 316c816e025SKenneth D. Merry * 317c816e025SKenneth D. Merry * Reported by: Jeremy Lea <reg@shale.csir.co.za> 318c816e025SKenneth D. Merry * Drive: <SEAGATE ST34520W 1281> 319c816e025SKenneth D. Merry * 320c816e025SKenneth D. Merry * No one has actually reported that the 9G version 321c816e025SKenneth D. Merry * (ST39140*) of the Medalist Pro has the same problem, but 322c816e025SKenneth D. Merry * we're assuming that it does because the 4G and 6.5G 323c816e025SKenneth D. Merry * versions of the drive are broken. 324560d629fSKenneth D. Merry */ 325c816e025SKenneth D. Merry { 326c816e025SKenneth D. Merry { T_DIRECT, SIP_MEDIA_FIXED, seagate, "ST34520*", "*"}, 327c816e025SKenneth D. Merry /*quirks*/0, /*mintags*/2, /*maxtags*/2 328c816e025SKenneth D. Merry }, 329c816e025SKenneth D. Merry { 330560d629fSKenneth D. Merry { T_DIRECT, SIP_MEDIA_FIXED, seagate, "ST36530*", "*"}, 331560d629fSKenneth D. Merry /*quirks*/0, /*mintags*/2, /*maxtags*/2 332560d629fSKenneth D. Merry }, 333560d629fSKenneth D. Merry { 334c816e025SKenneth D. Merry { T_DIRECT, SIP_MEDIA_FIXED, seagate, "ST39140*", "*"}, 335c816e025SKenneth D. Merry /*quirks*/0, /*mintags*/2, /*maxtags*/2 336c816e025SKenneth D. Merry }, 337c816e025SKenneth D. Merry { 338ca3b51e9SKenneth D. Merry /* 339ca3b51e9SKenneth D. Merry * Slow when tagged queueing is enabled. Write performance 340ca3b51e9SKenneth D. Merry * steadily drops off with more and more concurrent 341ca3b51e9SKenneth D. Merry * transactions. Best sequential write performance with 342ca3b51e9SKenneth D. Merry * tagged queueing turned off and write caching turned on. 343ca3b51e9SKenneth D. Merry * 344ca3b51e9SKenneth D. Merry * PR: kern/10398 345ca3b51e9SKenneth D. Merry * Submitted by: Hideaki Okada <hokada@isl.melco.co.jp> 346ca3b51e9SKenneth D. Merry * Drive: DCAS-34330 w/ "S65A" firmware. 347ca3b51e9SKenneth D. Merry * 348ca3b51e9SKenneth D. Merry * The drive with the problem had the "S65A" firmware 349ca3b51e9SKenneth D. Merry * revision, and has also been reported (by Stephen J. 350ca3b51e9SKenneth D. Merry * Roznowski <sjr@home.net>) for a drive with the "S61A" 351ca3b51e9SKenneth D. Merry * firmware revision. 352ca3b51e9SKenneth D. Merry * 353ca3b51e9SKenneth D. Merry * Although no one has reported problems with the 2 gig 354ca3b51e9SKenneth D. Merry * version of the DCAS drive, the assumption is that it 355ca3b51e9SKenneth D. Merry * has the same problems as the 4 gig version. Therefore 356ca3b51e9SKenneth D. Merry * this quirk entries disables tagged queueing for all 357ca3b51e9SKenneth D. Merry * DCAS drives. 358ca3b51e9SKenneth D. Merry */ 359ca3b51e9SKenneth D. Merry { T_DIRECT, SIP_MEDIA_FIXED, "IBM", "DCAS*", "*" }, 360ca3b51e9SKenneth D. Merry /*quirks*/0, /*mintags*/0, /*maxtags*/0 361ca3b51e9SKenneth D. Merry }, 362ca3b51e9SKenneth D. Merry { 3638b8a9b1dSJustin T. Gibbs /* Broken tagged queuing drive */ 3648b8a9b1dSJustin T. Gibbs { T_DIRECT, SIP_MEDIA_REMOVABLE, "iomega", "jaz*", "*" }, 3658b8a9b1dSJustin T. Gibbs /*quirks*/0, /*mintags*/0, /*maxtags*/0 3668b8a9b1dSJustin T. Gibbs }, 3678b8a9b1dSJustin T. Gibbs { 3682ba01e6fSJustin T. Gibbs /* Broken tagged queuing drive */ 3696dd76100SKenneth D. Merry { T_DIRECT, SIP_MEDIA_FIXED, "CONNER", "CFP2107*", "*" }, 3702ba01e6fSJustin T. Gibbs /*quirks*/0, /*mintags*/0, /*maxtags*/0 3712ba01e6fSJustin T. Gibbs }, 3722ba01e6fSJustin T. Gibbs { 373e471e974SJustin T. Gibbs /* 3741f04f5abSKenneth D. Merry * Broken tagged queuing drive. 3751f04f5abSKenneth D. Merry * Submitted by: 3761f04f5abSKenneth D. Merry * NAKAJI Hiroyuki <nakaji@zeisei.dpri.kyoto-u.ac.jp> 3771f04f5abSKenneth D. Merry * in PR kern/9535 3781f04f5abSKenneth D. Merry */ 3791f04f5abSKenneth D. Merry { T_DIRECT, SIP_MEDIA_FIXED, samsung, "WN34324U*", "*" }, 3801f04f5abSKenneth D. Merry /*quirks*/0, /*mintags*/0, /*maxtags*/0 3811f04f5abSKenneth D. Merry }, 3821f04f5abSKenneth D. Merry { 3831f04f5abSKenneth D. Merry /* 384f24c39c7SKenneth D. Merry * Slow when tagged queueing is enabled. (1.5MB/sec versus 385f24c39c7SKenneth D. Merry * 8MB/sec.) 386f24c39c7SKenneth D. Merry * Submitted by: Andrew Gallatin <gallatin@cs.duke.edu> 387ca3b51e9SKenneth D. Merry * Best performance with these drives is achieved with 388ca3b51e9SKenneth D. Merry * tagged queueing turned off, and write caching turned on. 389f24c39c7SKenneth D. Merry */ 390f24c39c7SKenneth D. Merry { T_DIRECT, SIP_MEDIA_FIXED, west_digital, "WDE*", "*" }, 391f24c39c7SKenneth D. Merry /*quirks*/0, /*mintags*/0, /*maxtags*/0 392f24c39c7SKenneth D. Merry }, 393f24c39c7SKenneth D. Merry { 394f24c39c7SKenneth D. Merry /* 395f24c39c7SKenneth D. Merry * Slow when tagged queueing is enabled. (1.5MB/sec versus 396f24c39c7SKenneth D. Merry * 8MB/sec.) 397f24c39c7SKenneth D. Merry * Submitted by: Andrew Gallatin <gallatin@cs.duke.edu> 398ca3b51e9SKenneth D. Merry * Best performance with these drives is achieved with 399ca3b51e9SKenneth D. Merry * tagged queueing turned off, and write caching turned on. 400f24c39c7SKenneth D. Merry */ 401f24c39c7SKenneth D. Merry { T_DIRECT, SIP_MEDIA_FIXED, west_digital, "ENTERPRISE", "*" }, 402f24c39c7SKenneth D. Merry /*quirks*/0, /*mintags*/0, /*maxtags*/0 403f24c39c7SKenneth D. Merry }, 404f24c39c7SKenneth D. Merry { 405f24c39c7SKenneth D. Merry /* 406e471e974SJustin T. Gibbs * Doesn't handle queue full condition correctly, 407e471e974SJustin T. Gibbs * so we need to limit maxtags to what the device 408e471e974SJustin T. Gibbs * can handle instead of determining this automatically. 409e471e974SJustin T. Gibbs */ 4101f04f5abSKenneth D. Merry { T_DIRECT, SIP_MEDIA_FIXED, samsung, "WN321010S*", "*" }, 411fd21cc5eSJustin T. Gibbs /*quirks*/0, /*mintags*/2, /*maxtags*/32 412e471e974SJustin T. Gibbs }, 413e471e974SJustin T. Gibbs { 4148b8a9b1dSJustin T. Gibbs /* Really only one LUN */ 415f2538844SMatt Jacob { T_ENCLOSURE, SIP_MEDIA_FIXED, "SUN", "SENA", "*" }, 4168b8a9b1dSJustin T. Gibbs CAM_QUIRK_NOLUNS, /*mintags*/0, /*maxtags*/0 4178b8a9b1dSJustin T. Gibbs }, 4188b8a9b1dSJustin T. Gibbs { 419fd21cc5eSJustin T. Gibbs /* I can't believe we need a quirk for DPT volumes. */ 4204b4c702bSMatt Jacob { T_ANY, SIP_MEDIA_FIXED|SIP_MEDIA_REMOVABLE, "DPT", "*", "*" }, 421fd21cc5eSJustin T. Gibbs CAM_QUIRK_NOSERIAL|CAM_QUIRK_NOLUNS, 422fd21cc5eSJustin T. Gibbs /*mintags*/0, /*maxtags*/255 423fd21cc5eSJustin T. Gibbs }, 424fd21cc5eSJustin T. Gibbs { 425f24c39c7SKenneth D. Merry /* 42625e5ca27SKenneth D. Merry * Many Sony CDROM drives don't like multi-LUN probing. 427f24c39c7SKenneth D. Merry */ 4284b4c702bSMatt Jacob { T_CDROM, SIP_MEDIA_REMOVABLE, sony, "CD-ROM CDU*", "*" }, 429f24c39c7SKenneth D. Merry CAM_QUIRK_NOLUNS, /*mintags*/0, /*maxtags*/0 430f24c39c7SKenneth D. Merry }, 431f24c39c7SKenneth D. Merry { 432f24c39c7SKenneth D. Merry /* 433f24c39c7SKenneth D. Merry * This drive doesn't like multiple LUN probing. 434f24c39c7SKenneth D. Merry * Submitted by: Parag Patel <parag@cgt.com> 435f24c39c7SKenneth D. Merry */ 4364b4c702bSMatt Jacob { T_WORM, SIP_MEDIA_REMOVABLE, sony, "CD-R CDU9*", "*" }, 437f24c39c7SKenneth D. Merry CAM_QUIRK_NOLUNS, /*mintags*/0, /*maxtags*/0 438f24c39c7SKenneth D. Merry }, 439f24c39c7SKenneth D. Merry { 440ca2b07adSKenneth D. Merry { T_WORM, SIP_MEDIA_REMOVABLE, "YAMAHA", "CDR100*", "*" }, 441ca2b07adSKenneth D. Merry CAM_QUIRK_NOLUNS, /*mintags*/0, /*maxtags*/0 442ca2b07adSKenneth D. Merry }, 443ca2b07adSKenneth D. Merry { 444b1d26455SKenneth D. Merry /* 445b1d26455SKenneth D. Merry * The 8200 doesn't like multi-lun probing, and probably 446b1d26455SKenneth D. Merry * don't like serial number requests either. 447b1d26455SKenneth D. Merry */ 448b1d26455SKenneth D. Merry { 449b1d26455SKenneth D. Merry T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "EXABYTE", 450b1d26455SKenneth D. Merry "EXB-8200*", "*" 451b1d26455SKenneth D. Merry }, 452b1d26455SKenneth D. Merry CAM_QUIRK_NOSERIAL|CAM_QUIRK_NOLUNS, /*mintags*/0, /*maxtags*/0 453b1d26455SKenneth D. Merry }, 454b1d26455SKenneth D. Merry { 45536230d67SJoerg Wunsch /* 456f2538844SMatt Jacob * Let's try the same as above, but for a drive that says 457f2538844SMatt Jacob * it's an IPL-6860 but is actually an EXB 8200. 458f2538844SMatt Jacob */ 459f2538844SMatt Jacob { 460f2538844SMatt Jacob T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "EXABYTE", 461f2538844SMatt Jacob "IPL-6860*", "*" 462f2538844SMatt Jacob }, 463f2538844SMatt Jacob CAM_QUIRK_NOSERIAL|CAM_QUIRK_NOLUNS, /*mintags*/0, /*maxtags*/0 464f2538844SMatt Jacob }, 465f2538844SMatt Jacob { 466f2538844SMatt Jacob /* 467a6cb9949SKenneth D. Merry * These Hitachi drives don't like multi-lun probing. 468a6cb9949SKenneth D. Merry * The PR submitter has a DK319H, but says that the Linux 469a6cb9949SKenneth D. Merry * kernel has a similar work-around for the DK312 and DK314, 470a6cb9949SKenneth D. Merry * so all DK31* drives are quirked here. 471a6cb9949SKenneth D. Merry * PR: misc/18793 472a6cb9949SKenneth D. Merry * Submitted by: Paul Haddad <paul@pth.com> 473a6cb9949SKenneth D. Merry */ 474a6cb9949SKenneth D. Merry { T_DIRECT, SIP_MEDIA_FIXED, "HITACHI", "DK31*", "*" }, 475a6cb9949SKenneth D. Merry CAM_QUIRK_NOLUNS, /*mintags*/2, /*maxtags*/255 476a6cb9949SKenneth D. Merry }, 477a6cb9949SKenneth D. Merry { 478a6cb9949SKenneth D. Merry /* 479136b546aSDavid Greenman * The Hitachi CJ series with J8A8 firmware apparantly has 480136b546aSDavid Greenman * problems with tagged commands. 481136b546aSDavid Greenman * PR: 23536 482136b546aSDavid Greenman * Reported by: amagai@nue.org 483136b546aSDavid Greenman */ 484136b546aSDavid Greenman { T_DIRECT, SIP_MEDIA_FIXED, "HITACHI", "DK32CJ*", "J8A8" }, 485136b546aSDavid Greenman CAM_QUIRK_NOLUNS, /*mintags*/0, /*maxtags*/0 486136b546aSDavid Greenman }, 487136b546aSDavid Greenman { 488136b546aSDavid Greenman /* 48978900a83SMatt Jacob * These are the large storage arrays. 49078900a83SMatt Jacob * Submitted by: William Carrel <william.carrel@infospace.com> 49178900a83SMatt Jacob */ 49278900a83SMatt Jacob { T_DIRECT, SIP_MEDIA_FIXED, "HITACHI", "OPEN*", "*" }, 49378900a83SMatt Jacob CAM_QUIRK_HILUNS, 2, 1024 49478900a83SMatt Jacob }, 49578900a83SMatt Jacob { 49678900a83SMatt Jacob /* 49736230d67SJoerg Wunsch * This old revision of the TDC3600 is also SCSI-1, and 49836230d67SJoerg Wunsch * hangs upon serial number probing. 49936230d67SJoerg Wunsch */ 50036230d67SJoerg Wunsch { 50136230d67SJoerg Wunsch T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "TANDBERG", 50236230d67SJoerg Wunsch " TDC 3600", "U07:" 50336230d67SJoerg Wunsch }, 50436230d67SJoerg Wunsch CAM_QUIRK_NOSERIAL, /*mintags*/0, /*maxtags*/0 50536230d67SJoerg Wunsch }, 50636230d67SJoerg Wunsch { 5072c3cca96SMatt Jacob /* 5087afa4afbSHidetoshi Shimokawa * Maxtor Personal Storage 3000XT (Firewire) 5097afa4afbSHidetoshi Shimokawa * hangs upon serial number probing. 5107afa4afbSHidetoshi Shimokawa */ 5117afa4afbSHidetoshi Shimokawa { 5127afa4afbSHidetoshi Shimokawa T_DIRECT, SIP_MEDIA_FIXED, "Maxtor", 5137afa4afbSHidetoshi Shimokawa "1394 storage", "*" 5147afa4afbSHidetoshi Shimokawa }, 5157afa4afbSHidetoshi Shimokawa CAM_QUIRK_NOSERIAL, /*mintags*/0, /*maxtags*/0 5167afa4afbSHidetoshi Shimokawa }, 5177afa4afbSHidetoshi Shimokawa { 5187afa4afbSHidetoshi Shimokawa /* 5192c3cca96SMatt Jacob * Would repond to all LUNs if asked for. 5202c3cca96SMatt Jacob */ 5212c3cca96SMatt Jacob { 5222c3cca96SMatt Jacob T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "CALIPER", 5232c3cca96SMatt Jacob "CP150", "*" 5242c3cca96SMatt Jacob }, 5252c3cca96SMatt Jacob CAM_QUIRK_NOLUNS, /*mintags*/0, /*maxtags*/0 5262c3cca96SMatt Jacob }, 5272c3cca96SMatt Jacob { 528040816ecSMatt Jacob /* 529040816ecSMatt Jacob * Would repond to all LUNs if asked for. 530040816ecSMatt Jacob */ 531040816ecSMatt Jacob { 532040816ecSMatt Jacob T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "KENNEDY", 533040816ecSMatt Jacob "96X2*", "*" 534040816ecSMatt Jacob }, 535040816ecSMatt Jacob CAM_QUIRK_NOLUNS, /*mintags*/0, /*maxtags*/0 536040816ecSMatt Jacob }, 537040816ecSMatt Jacob { 5384b4c702bSMatt Jacob /* Submitted by: Matthew Dodd <winter@jurai.net> */ 5394b4c702bSMatt Jacob { T_PROCESSOR, SIP_MEDIA_FIXED, "Cabletrn", "EA41*", "*" }, 5404b4c702bSMatt Jacob CAM_QUIRK_NOLUNS, /*mintags*/0, /*maxtags*/0 5414b4c702bSMatt Jacob }, 5424b4c702bSMatt Jacob { 5434b4c702bSMatt Jacob /* Submitted by: Matthew Dodd <winter@jurai.net> */ 5444b4c702bSMatt Jacob { T_PROCESSOR, SIP_MEDIA_FIXED, "CABLETRN", "EA41*", "*" }, 5454b4c702bSMatt Jacob CAM_QUIRK_NOLUNS, /*mintags*/0, /*maxtags*/0 5464b4c702bSMatt Jacob }, 5474b4c702bSMatt Jacob { 548da6efda6SDavid Greenman /* TeraSolutions special settings for TRC-22 RAID */ 549da6efda6SDavid Greenman { T_DIRECT, SIP_MEDIA_FIXED, "TERASOLU", "TRC-22", "*" }, 550da6efda6SDavid Greenman /*quirks*/0, /*mintags*/55, /*maxtags*/255 551da6efda6SDavid Greenman }, 552da6efda6SDavid Greenman { 553c7948a94SMatt Jacob /* Veritas Storage Appliance */ 554c7948a94SMatt Jacob { T_DIRECT, SIP_MEDIA_FIXED, "VERITAS", "*", "*" }, 555c7948a94SMatt Jacob CAM_QUIRK_HILUNS, /*mintags*/2, /*maxtags*/1024 556c7948a94SMatt Jacob }, 557c7948a94SMatt Jacob { 5583b9d81dcSJoerg Wunsch /* 5593b9d81dcSJoerg Wunsch * Would respond to all LUNs. Device type and removable 5603b9d81dcSJoerg Wunsch * flag are jumper-selectable. 5613b9d81dcSJoerg Wunsch */ 5623b9d81dcSJoerg Wunsch { T_ANY, SIP_MEDIA_REMOVABLE|SIP_MEDIA_FIXED, "MaxOptix", 5633b9d81dcSJoerg Wunsch "Tahiti 1", "*" 5643b9d81dcSJoerg Wunsch }, 5653b9d81dcSJoerg Wunsch CAM_QUIRK_NOLUNS, /*mintags*/0, /*maxtags*/0 5663b9d81dcSJoerg Wunsch }, 5673b9d81dcSJoerg Wunsch { 5688924340fSMichael Reifenberger /* EasyRAID E5A aka. areca ARC-6010 */ 5698924340fSMichael Reifenberger { T_DIRECT, SIP_MEDIA_FIXED, "easyRAID", "*", "*" }, 5708924340fSMichael Reifenberger CAM_QUIRK_NOHILUNS, /*mintags*/2, /*maxtags*/255 5718924340fSMichael Reifenberger }, 5728924340fSMichael Reifenberger { 5738b8a9b1dSJustin T. Gibbs /* Default tagged queuing parameters for all devices */ 5748b8a9b1dSJustin T. Gibbs { 5758b8a9b1dSJustin T. Gibbs T_ANY, SIP_MEDIA_REMOVABLE|SIP_MEDIA_FIXED, 5768b8a9b1dSJustin T. Gibbs /*vendor*/"*", /*product*/"*", /*revision*/"*" 5778b8a9b1dSJustin T. Gibbs }, 578fd21cc5eSJustin T. Gibbs /*quirks*/0, /*mintags*/2, /*maxtags*/255 5798b8a9b1dSJustin T. Gibbs }, 5808b8a9b1dSJustin T. Gibbs }; 581fd21cc5eSJustin T. Gibbs 58287cfaf0eSJustin T. Gibbs static const int xpt_quirk_table_size = 58387cfaf0eSJustin T. Gibbs sizeof(xpt_quirk_table) / sizeof(*xpt_quirk_table); 58487cfaf0eSJustin T. Gibbs 5858b8a9b1dSJustin T. Gibbs typedef enum { 5868b8a9b1dSJustin T. Gibbs DM_RET_COPY = 0x01, 5878b8a9b1dSJustin T. Gibbs DM_RET_FLAG_MASK = 0x0f, 5888b8a9b1dSJustin T. Gibbs DM_RET_NONE = 0x00, 5898b8a9b1dSJustin T. Gibbs DM_RET_STOP = 0x10, 5908b8a9b1dSJustin T. Gibbs DM_RET_DESCEND = 0x20, 5918b8a9b1dSJustin T. Gibbs DM_RET_ERROR = 0x30, 5928b8a9b1dSJustin T. Gibbs DM_RET_ACTION_MASK = 0xf0 5938b8a9b1dSJustin T. Gibbs } dev_match_ret; 5948b8a9b1dSJustin T. Gibbs 5958b8a9b1dSJustin T. Gibbs typedef enum { 5968b8a9b1dSJustin T. Gibbs XPT_DEPTH_BUS, 5978b8a9b1dSJustin T. Gibbs XPT_DEPTH_TARGET, 5988b8a9b1dSJustin T. Gibbs XPT_DEPTH_DEVICE, 5998b8a9b1dSJustin T. Gibbs XPT_DEPTH_PERIPH 6008b8a9b1dSJustin T. Gibbs } xpt_traverse_depth; 6018b8a9b1dSJustin T. Gibbs 6028b8a9b1dSJustin T. Gibbs struct xpt_traverse_config { 6038b8a9b1dSJustin T. Gibbs xpt_traverse_depth depth; 6048b8a9b1dSJustin T. Gibbs void *tr_func; 6058b8a9b1dSJustin T. Gibbs void *tr_arg; 6068b8a9b1dSJustin T. Gibbs }; 6078b8a9b1dSJustin T. Gibbs 6088b8a9b1dSJustin T. Gibbs typedef int xpt_busfunc_t (struct cam_eb *bus, void *arg); 6098b8a9b1dSJustin T. Gibbs typedef int xpt_targetfunc_t (struct cam_et *target, void *arg); 6108b8a9b1dSJustin T. Gibbs typedef int xpt_devicefunc_t (struct cam_ed *device, void *arg); 6118b8a9b1dSJustin T. Gibbs typedef int xpt_periphfunc_t (struct cam_periph *periph, void *arg); 6128b8a9b1dSJustin T. Gibbs typedef int xpt_pdrvfunc_t (struct periph_driver **pdrv, void *arg); 6138b8a9b1dSJustin T. Gibbs 6148b8a9b1dSJustin T. Gibbs /* Transport layer configuration information */ 6158b8a9b1dSJustin T. Gibbs static struct xpt_softc xsoftc; 6168b8a9b1dSJustin T. Gibbs 6178b8a9b1dSJustin T. Gibbs /* Queues for our software interrupt handler */ 618e3975643SJake Burkholder typedef TAILQ_HEAD(cam_isrq, ccb_hdr) cam_isrq_t; 6198b8a9b1dSJustin T. Gibbs static cam_isrq_t cam_bioq; 620ef3cf714SScott Long static struct mtx cam_bioq_lock; 6218b8a9b1dSJustin T. Gibbs 6228b8a9b1dSJustin T. Gibbs /* "Pool" of inactive ccbs managed by xpt_alloc_ccb and xpt_free_ccb */ 623e3975643SJake Burkholder static SLIST_HEAD(,ccb_hdr) ccb_freeq; 6248b8a9b1dSJustin T. Gibbs static u_int xpt_max_ccbs; /* 6258b8a9b1dSJustin T. Gibbs * Maximum size of ccb pool. Modified as 6268b8a9b1dSJustin T. Gibbs * devices are added/removed or have their 6278b8a9b1dSJustin T. Gibbs * opening counts changed. 6288b8a9b1dSJustin T. Gibbs */ 6298b8a9b1dSJustin T. Gibbs static u_int xpt_ccb_count; /* Current count of allocated ccbs */ 6308b8a9b1dSJustin T. Gibbs 6319a1c8571SNick Hibma struct cam_periph *xpt_periph; 6329a1c8571SNick Hibma 6338b8a9b1dSJustin T. Gibbs static periph_init_t xpt_periph_init; 6348b8a9b1dSJustin T. Gibbs 6358b8a9b1dSJustin T. Gibbs static periph_init_t probe_periph_init; 6368b8a9b1dSJustin T. Gibbs 6378b8a9b1dSJustin T. Gibbs static struct periph_driver xpt_driver = 6388b8a9b1dSJustin T. Gibbs { 6398b8a9b1dSJustin T. Gibbs xpt_periph_init, "xpt", 6408b8a9b1dSJustin T. Gibbs TAILQ_HEAD_INITIALIZER(xpt_driver.units) 6418b8a9b1dSJustin T. Gibbs }; 6428b8a9b1dSJustin T. Gibbs 6438b8a9b1dSJustin T. Gibbs static struct periph_driver probe_driver = 6448b8a9b1dSJustin T. Gibbs { 6458b8a9b1dSJustin T. Gibbs probe_periph_init, "probe", 6468b8a9b1dSJustin T. Gibbs TAILQ_HEAD_INITIALIZER(probe_driver.units) 6478b8a9b1dSJustin T. Gibbs }; 6488b8a9b1dSJustin T. Gibbs 6490b7c27b9SPeter Wemm PERIPHDRIVER_DECLARE(xpt, xpt_driver); 6500b7c27b9SPeter Wemm PERIPHDRIVER_DECLARE(probe, probe_driver); 6518b8a9b1dSJustin T. Gibbs 6528b8a9b1dSJustin T. Gibbs 6538b8a9b1dSJustin T. Gibbs static d_open_t xptopen; 6548b8a9b1dSJustin T. Gibbs static d_close_t xptclose; 6558b8a9b1dSJustin T. Gibbs static d_ioctl_t xptioctl; 6568b8a9b1dSJustin T. Gibbs 6574e2f199eSPoul-Henning Kamp static struct cdevsw xpt_cdevsw = { 658dc08ffecSPoul-Henning Kamp .d_version = D_VERSION, 659dc08ffecSPoul-Henning Kamp .d_flags = D_NEEDGIANT, 6607ac40f5fSPoul-Henning Kamp .d_open = xptopen, 6617ac40f5fSPoul-Henning Kamp .d_close = xptclose, 6627ac40f5fSPoul-Henning Kamp .d_ioctl = xptioctl, 6637ac40f5fSPoul-Henning Kamp .d_name = "xpt", 6648b8a9b1dSJustin T. Gibbs }; 6658b8a9b1dSJustin T. Gibbs 6668b8a9b1dSJustin T. Gibbs static struct intr_config_hook *xpt_config_hook; 6678b8a9b1dSJustin T. Gibbs 6688b8a9b1dSJustin T. Gibbs /* Registered busses */ 669e3975643SJake Burkholder static TAILQ_HEAD(,cam_eb) xpt_busses; 6708b8a9b1dSJustin T. Gibbs static u_int bus_generation; 6718b8a9b1dSJustin T. Gibbs 6728b8a9b1dSJustin T. Gibbs /* Storage for debugging datastructures */ 6738b8a9b1dSJustin T. Gibbs #ifdef CAMDEBUG 6748b8a9b1dSJustin T. Gibbs struct cam_path *cam_dpath; 6758b8a9b1dSJustin T. Gibbs u_int32_t cam_dflags; 6762cefde5fSJustin T. Gibbs u_int32_t cam_debug_delay; 6778b8a9b1dSJustin T. Gibbs #endif 6788b8a9b1dSJustin T. Gibbs 6798088699fSJohn Baldwin /* Pointers to software interrupt handlers */ 68065c38256SMike Smith static void *cambio_ih; 6818088699fSJohn Baldwin 6828b8a9b1dSJustin T. Gibbs #if defined(CAM_DEBUG_FLAGS) && !defined(CAMDEBUG) 6838b8a9b1dSJustin T. Gibbs #error "You must have options CAMDEBUG to use options CAM_DEBUG_FLAGS" 6848b8a9b1dSJustin T. Gibbs #endif 6858b8a9b1dSJustin T. Gibbs 6868b8a9b1dSJustin T. Gibbs /* 6878b8a9b1dSJustin T. Gibbs * In order to enable the CAM_DEBUG_* options, the user must have CAMDEBUG 6888b8a9b1dSJustin T. Gibbs * enabled. Also, the user must have either none, or all of CAM_DEBUG_BUS, 6898b8a9b1dSJustin T. Gibbs * CAM_DEBUG_TARGET, and CAM_DEBUG_LUN specified. 6908b8a9b1dSJustin T. Gibbs */ 6918b8a9b1dSJustin T. Gibbs #if defined(CAM_DEBUG_BUS) || defined(CAM_DEBUG_TARGET) \ 6928b8a9b1dSJustin T. Gibbs || defined(CAM_DEBUG_LUN) 6938b8a9b1dSJustin T. Gibbs #ifdef CAMDEBUG 6948b8a9b1dSJustin T. Gibbs #if !defined(CAM_DEBUG_BUS) || !defined(CAM_DEBUG_TARGET) \ 6958b8a9b1dSJustin T. Gibbs || !defined(CAM_DEBUG_LUN) 6968b8a9b1dSJustin T. Gibbs #error "You must define all or none of CAM_DEBUG_BUS, CAM_DEBUG_TARGET \ 6978b8a9b1dSJustin T. Gibbs and CAM_DEBUG_LUN" 6988b8a9b1dSJustin T. Gibbs #endif /* !CAM_DEBUG_BUS || !CAM_DEBUG_TARGET || !CAM_DEBUG_LUN */ 6998b8a9b1dSJustin T. Gibbs #else /* !CAMDEBUG */ 7008b8a9b1dSJustin T. Gibbs #error "You must use options CAMDEBUG if you use the CAM_DEBUG_* options" 7018b8a9b1dSJustin T. Gibbs #endif /* CAMDEBUG */ 7028b8a9b1dSJustin T. Gibbs #endif /* CAM_DEBUG_BUS || CAM_DEBUG_TARGET || CAM_DEBUG_LUN */ 7038b8a9b1dSJustin T. Gibbs 7046d2a8f1cSPeter Wemm /* Our boot-time initialization hook */ 70574bd1c10SNick Hibma static int cam_module_event_handler(module_t, int /*modeventtype_t*/, void *); 70674bd1c10SNick Hibma 70774bd1c10SNick Hibma static moduledata_t cam_moduledata = { 70874bd1c10SNick Hibma "cam", 70974bd1c10SNick Hibma cam_module_event_handler, 71074bd1c10SNick Hibma NULL 71174bd1c10SNick Hibma }; 71274bd1c10SNick Hibma 7136d2a8f1cSPeter Wemm static void xpt_init(void *); 71474bd1c10SNick Hibma 71574bd1c10SNick Hibma DECLARE_MODULE(cam, cam_moduledata, SI_SUB_CONFIGURE, SI_ORDER_SECOND); 71674bd1c10SNick Hibma MODULE_VERSION(cam, 1); 71774bd1c10SNick Hibma 7188b8a9b1dSJustin T. Gibbs 7198b8a9b1dSJustin T. Gibbs static cam_status xpt_compile_path(struct cam_path *new_path, 7208b8a9b1dSJustin T. Gibbs struct cam_periph *perph, 7218b8a9b1dSJustin T. Gibbs path_id_t path_id, 7228b8a9b1dSJustin T. Gibbs target_id_t target_id, 7238b8a9b1dSJustin T. Gibbs lun_id_t lun_id); 7248b8a9b1dSJustin T. Gibbs 7258b8a9b1dSJustin T. Gibbs static void xpt_release_path(struct cam_path *path); 7268b8a9b1dSJustin T. Gibbs 7278b8a9b1dSJustin T. Gibbs static void xpt_async_bcast(struct async_list *async_head, 7288b8a9b1dSJustin T. Gibbs u_int32_t async_code, 7298b8a9b1dSJustin T. Gibbs struct cam_path *path, 7308b8a9b1dSJustin T. Gibbs void *async_arg); 7312f22d08dSJustin T. Gibbs static void xpt_dev_async(u_int32_t async_code, 7322f22d08dSJustin T. Gibbs struct cam_eb *bus, 7332f22d08dSJustin T. Gibbs struct cam_et *target, 7342f22d08dSJustin T. Gibbs struct cam_ed *device, 7352f22d08dSJustin T. Gibbs void *async_arg); 736434bbf6eSJustin T. Gibbs static path_id_t xptnextfreepathid(void); 737434bbf6eSJustin T. Gibbs static path_id_t xptpathid(const char *sim_name, int sim_unit, int sim_bus); 7388b8a9b1dSJustin T. Gibbs static union ccb *xpt_get_ccb(struct cam_ed *device); 7398b8a9b1dSJustin T. Gibbs static int xpt_schedule_dev(struct camq *queue, cam_pinfo *dev_pinfo, 7408b8a9b1dSJustin T. Gibbs u_int32_t new_priority); 7418b8a9b1dSJustin T. Gibbs static void xpt_run_dev_allocq(struct cam_eb *bus); 7428b8a9b1dSJustin T. Gibbs static void xpt_run_dev_sendq(struct cam_eb *bus); 7438b8a9b1dSJustin T. Gibbs static timeout_t xpt_release_devq_timeout; 7448b8a9b1dSJustin T. Gibbs static timeout_t xpt_release_simq_timeout; 745a5479bc5SJustin T. Gibbs static void xpt_release_bus(struct cam_eb *bus); 7462cefde5fSJustin T. Gibbs static void xpt_release_devq_device(struct cam_ed *dev, u_int count, 7472cefde5fSJustin T. Gibbs int run_queue); 7488b8a9b1dSJustin T. Gibbs static struct cam_et* 7498b8a9b1dSJustin T. Gibbs xpt_alloc_target(struct cam_eb *bus, target_id_t target_id); 7508b8a9b1dSJustin T. Gibbs static void xpt_release_target(struct cam_eb *bus, struct cam_et *target); 7518b8a9b1dSJustin T. Gibbs static struct cam_ed* 7528b8a9b1dSJustin T. Gibbs xpt_alloc_device(struct cam_eb *bus, struct cam_et *target, 7538b8a9b1dSJustin T. Gibbs lun_id_t lun_id); 7548b8a9b1dSJustin T. Gibbs static void xpt_release_device(struct cam_eb *bus, struct cam_et *target, 7558b8a9b1dSJustin T. Gibbs struct cam_ed *device); 7568b8a9b1dSJustin T. Gibbs static u_int32_t xpt_dev_ccbq_resize(struct cam_path *path, int newopenings); 7578b8a9b1dSJustin T. Gibbs static struct cam_eb* 7588b8a9b1dSJustin T. Gibbs xpt_find_bus(path_id_t path_id); 7598b8a9b1dSJustin T. Gibbs static struct cam_et* 7608b8a9b1dSJustin T. Gibbs xpt_find_target(struct cam_eb *bus, target_id_t target_id); 7618b8a9b1dSJustin T. Gibbs static struct cam_ed* 7628b8a9b1dSJustin T. Gibbs xpt_find_device(struct cam_et *target, lun_id_t lun_id); 7638b8a9b1dSJustin T. Gibbs static void xpt_scan_bus(struct cam_periph *periph, union ccb *ccb); 7648b8a9b1dSJustin T. Gibbs static void xpt_scan_lun(struct cam_periph *periph, 7658b8a9b1dSJustin T. Gibbs struct cam_path *path, cam_flags flags, 7668b8a9b1dSJustin T. Gibbs union ccb *ccb); 7678b8a9b1dSJustin T. Gibbs static void xptscandone(struct cam_periph *periph, union ccb *done_ccb); 7688b8a9b1dSJustin T. Gibbs static xpt_busfunc_t xptconfigbuscountfunc; 7698b8a9b1dSJustin T. Gibbs static xpt_busfunc_t xptconfigfunc; 7708b8a9b1dSJustin T. Gibbs static void xpt_config(void *arg); 7718b8a9b1dSJustin T. Gibbs static xpt_devicefunc_t xptpassannouncefunc; 7728b8a9b1dSJustin T. Gibbs static void xpt_finishconfig(struct cam_periph *periph, union ccb *ccb); 7738b8a9b1dSJustin T. Gibbs static void xptaction(struct cam_sim *sim, union ccb *work_ccb); 774434bbf6eSJustin T. Gibbs static void xptpoll(struct cam_sim *sim); 7758088699fSJohn Baldwin static void camisr(void *); 7768b8a9b1dSJustin T. Gibbs #if 0 7778b8a9b1dSJustin T. Gibbs static void xptstart(struct cam_periph *periph, union ccb *work_ccb); 7788b8a9b1dSJustin T. Gibbs static void xptasync(struct cam_periph *periph, 7798b8a9b1dSJustin T. Gibbs u_int32_t code, cam_path *path); 7808b8a9b1dSJustin T. Gibbs #endif 7818b8a9b1dSJustin T. Gibbs static dev_match_ret xptbusmatch(struct dev_match_pattern *patterns, 7823393f8daSKenneth D. Merry u_int num_patterns, struct cam_eb *bus); 7838b8a9b1dSJustin T. Gibbs static dev_match_ret xptdevicematch(struct dev_match_pattern *patterns, 7843393f8daSKenneth D. Merry u_int num_patterns, 7853393f8daSKenneth D. Merry struct cam_ed *device); 7868b8a9b1dSJustin T. Gibbs static dev_match_ret xptperiphmatch(struct dev_match_pattern *patterns, 7873393f8daSKenneth D. Merry u_int num_patterns, 7888b8a9b1dSJustin T. Gibbs struct cam_periph *periph); 7898b8a9b1dSJustin T. Gibbs static xpt_busfunc_t xptedtbusfunc; 7908b8a9b1dSJustin T. Gibbs static xpt_targetfunc_t xptedttargetfunc; 7918b8a9b1dSJustin T. Gibbs static xpt_devicefunc_t xptedtdevicefunc; 7928b8a9b1dSJustin T. Gibbs static xpt_periphfunc_t xptedtperiphfunc; 7938b8a9b1dSJustin T. Gibbs static xpt_pdrvfunc_t xptplistpdrvfunc; 7948b8a9b1dSJustin T. Gibbs static xpt_periphfunc_t xptplistperiphfunc; 7958b8a9b1dSJustin T. Gibbs static int xptedtmatch(struct ccb_dev_match *cdm); 7968b8a9b1dSJustin T. Gibbs static int xptperiphlistmatch(struct ccb_dev_match *cdm); 7978b8a9b1dSJustin T. Gibbs static int xptbustraverse(struct cam_eb *start_bus, 7988b8a9b1dSJustin T. Gibbs xpt_busfunc_t *tr_func, void *arg); 7998b8a9b1dSJustin T. Gibbs static int xpttargettraverse(struct cam_eb *bus, 8008b8a9b1dSJustin T. Gibbs struct cam_et *start_target, 8018b8a9b1dSJustin T. Gibbs xpt_targetfunc_t *tr_func, void *arg); 8028b8a9b1dSJustin T. Gibbs static int xptdevicetraverse(struct cam_et *target, 8038b8a9b1dSJustin T. Gibbs struct cam_ed *start_device, 8048b8a9b1dSJustin T. Gibbs xpt_devicefunc_t *tr_func, void *arg); 8058b8a9b1dSJustin T. Gibbs static int xptperiphtraverse(struct cam_ed *device, 8068b8a9b1dSJustin T. Gibbs struct cam_periph *start_periph, 8078b8a9b1dSJustin T. Gibbs xpt_periphfunc_t *tr_func, void *arg); 8088b8a9b1dSJustin T. Gibbs static int xptpdrvtraverse(struct periph_driver **start_pdrv, 8098b8a9b1dSJustin T. Gibbs xpt_pdrvfunc_t *tr_func, void *arg); 8108b8a9b1dSJustin T. Gibbs static int xptpdperiphtraverse(struct periph_driver **pdrv, 8118b8a9b1dSJustin T. Gibbs struct cam_periph *start_periph, 8128b8a9b1dSJustin T. Gibbs xpt_periphfunc_t *tr_func, 8138b8a9b1dSJustin T. Gibbs void *arg); 8148b8a9b1dSJustin T. Gibbs static xpt_busfunc_t xptdefbusfunc; 8158b8a9b1dSJustin T. Gibbs static xpt_targetfunc_t xptdeftargetfunc; 8168b8a9b1dSJustin T. Gibbs static xpt_devicefunc_t xptdefdevicefunc; 8178b8a9b1dSJustin T. Gibbs static xpt_periphfunc_t xptdefperiphfunc; 8188b8a9b1dSJustin T. Gibbs static int xpt_for_all_busses(xpt_busfunc_t *tr_func, void *arg); 819bfc0eb0fSKenneth D. Merry #ifdef notusedyet 8208b8a9b1dSJustin T. Gibbs static int xpt_for_all_targets(xpt_targetfunc_t *tr_func, 8218b8a9b1dSJustin T. Gibbs void *arg); 822bfc0eb0fSKenneth D. Merry #endif 8238b8a9b1dSJustin T. Gibbs static int xpt_for_all_devices(xpt_devicefunc_t *tr_func, 8248b8a9b1dSJustin T. Gibbs void *arg); 825bfc0eb0fSKenneth D. Merry #ifdef notusedyet 8268b8a9b1dSJustin T. Gibbs static int xpt_for_all_periphs(xpt_periphfunc_t *tr_func, 8278b8a9b1dSJustin T. Gibbs void *arg); 828bfc0eb0fSKenneth D. Merry #endif 8298b8a9b1dSJustin T. Gibbs static xpt_devicefunc_t xptsetasyncfunc; 8308b8a9b1dSJustin T. Gibbs static xpt_busfunc_t xptsetasyncbusfunc; 8318b8a9b1dSJustin T. Gibbs static cam_status xptregister(struct cam_periph *periph, 8328b8a9b1dSJustin T. Gibbs void *arg); 8338b8a9b1dSJustin T. Gibbs static cam_status proberegister(struct cam_periph *periph, 8348b8a9b1dSJustin T. Gibbs void *arg); 8358b8a9b1dSJustin T. Gibbs static void probeschedule(struct cam_periph *probe_periph); 8368b8a9b1dSJustin T. Gibbs static void probestart(struct cam_periph *periph, union ccb *start_ccb); 83787cfaf0eSJustin T. Gibbs static void proberequestdefaultnegotiation(struct cam_periph *periph); 8388b8a9b1dSJustin T. Gibbs static void probedone(struct cam_periph *periph, union ccb *done_ccb); 8398b8a9b1dSJustin T. Gibbs static void probecleanup(struct cam_periph *periph); 8408b8a9b1dSJustin T. Gibbs static void xpt_find_quirk(struct cam_ed *device); 8413393f8daSKenneth D. Merry #ifdef CAM_NEW_TRAN_CODE 8423393f8daSKenneth D. Merry static void xpt_devise_transport(struct cam_path *path); 8433393f8daSKenneth D. Merry #endif /* CAM_NEW_TRAN_CODE */ 8448b8a9b1dSJustin T. Gibbs static void xpt_set_transfer_settings(struct ccb_trans_settings *cts, 84503e3511bSJustin T. Gibbs struct cam_ed *device, 8468b8a9b1dSJustin T. Gibbs int async_update); 847f0adc790SJustin T. Gibbs static void xpt_toggle_tags(struct cam_path *path); 848fd21cc5eSJustin T. Gibbs static void xpt_start_tags(struct cam_path *path); 8498b8a9b1dSJustin T. Gibbs static __inline int xpt_schedule_dev_allocq(struct cam_eb *bus, 8508b8a9b1dSJustin T. Gibbs struct cam_ed *dev); 8518b8a9b1dSJustin T. Gibbs static __inline int xpt_schedule_dev_sendq(struct cam_eb *bus, 8528b8a9b1dSJustin T. Gibbs struct cam_ed *dev); 8538b8a9b1dSJustin T. Gibbs static __inline int periph_is_queued(struct cam_periph *periph); 8548b8a9b1dSJustin T. Gibbs static __inline int device_is_alloc_queued(struct cam_ed *device); 8558b8a9b1dSJustin T. Gibbs static __inline int device_is_send_queued(struct cam_ed *device); 8568b8a9b1dSJustin T. Gibbs static __inline int dev_allocq_is_runnable(struct cam_devq *devq); 8578b8a9b1dSJustin T. Gibbs 8588b8a9b1dSJustin T. Gibbs static __inline int 8598b8a9b1dSJustin T. Gibbs xpt_schedule_dev_allocq(struct cam_eb *bus, struct cam_ed *dev) 8608b8a9b1dSJustin T. Gibbs { 8618b8a9b1dSJustin T. Gibbs int retval; 8628b8a9b1dSJustin T. Gibbs 8638b8a9b1dSJustin T. Gibbs if (dev->ccbq.devq_openings > 0) { 8648b8a9b1dSJustin T. Gibbs if ((dev->flags & CAM_DEV_RESIZE_QUEUE_NEEDED) != 0) { 8658b8a9b1dSJustin T. Gibbs cam_ccbq_resize(&dev->ccbq, 8668b8a9b1dSJustin T. Gibbs dev->ccbq.dev_openings 8678b8a9b1dSJustin T. Gibbs + dev->ccbq.dev_active); 8688b8a9b1dSJustin T. Gibbs dev->flags &= ~CAM_DEV_RESIZE_QUEUE_NEEDED; 8698b8a9b1dSJustin T. Gibbs } 8705a526431SJustin T. Gibbs /* 8715a526431SJustin T. Gibbs * The priority of a device waiting for CCB resources 8725a526431SJustin T. Gibbs * is that of the the highest priority peripheral driver 8735a526431SJustin T. Gibbs * enqueued. 8745a526431SJustin T. Gibbs */ 8758b8a9b1dSJustin T. Gibbs retval = xpt_schedule_dev(&bus->sim->devq->alloc_queue, 8768b8a9b1dSJustin T. Gibbs &dev->alloc_ccb_entry.pinfo, 8775a526431SJustin T. Gibbs CAMQ_GET_HEAD(&dev->drvq)->priority); 8788b8a9b1dSJustin T. Gibbs } else { 8798b8a9b1dSJustin T. Gibbs retval = 0; 8808b8a9b1dSJustin T. Gibbs } 8818b8a9b1dSJustin T. Gibbs 8828b8a9b1dSJustin T. Gibbs return (retval); 8838b8a9b1dSJustin T. Gibbs } 8848b8a9b1dSJustin T. Gibbs 8858b8a9b1dSJustin T. Gibbs static __inline int 8868b8a9b1dSJustin T. Gibbs xpt_schedule_dev_sendq(struct cam_eb *bus, struct cam_ed *dev) 8878b8a9b1dSJustin T. Gibbs { 8888b8a9b1dSJustin T. Gibbs int retval; 8898b8a9b1dSJustin T. Gibbs 8908b8a9b1dSJustin T. Gibbs if (dev->ccbq.dev_openings > 0) { 8915a526431SJustin T. Gibbs /* 8925a526431SJustin T. Gibbs * The priority of a device waiting for controller 8935a526431SJustin T. Gibbs * resources is that of the the highest priority CCB 8945a526431SJustin T. Gibbs * enqueued. 8955a526431SJustin T. Gibbs */ 8965a526431SJustin T. Gibbs retval = 8975a526431SJustin T. Gibbs xpt_schedule_dev(&bus->sim->devq->send_queue, 8988b8a9b1dSJustin T. Gibbs &dev->send_ccb_entry.pinfo, 8995a526431SJustin T. Gibbs CAMQ_GET_HEAD(&dev->ccbq.queue)->priority); 9008b8a9b1dSJustin T. Gibbs } else { 9018b8a9b1dSJustin T. Gibbs retval = 0; 9028b8a9b1dSJustin T. Gibbs } 9038b8a9b1dSJustin T. Gibbs return (retval); 9048b8a9b1dSJustin T. Gibbs } 9058b8a9b1dSJustin T. Gibbs 9068b8a9b1dSJustin T. Gibbs static __inline int 9078b8a9b1dSJustin T. Gibbs periph_is_queued(struct cam_periph *periph) 9088b8a9b1dSJustin T. Gibbs { 9098b8a9b1dSJustin T. Gibbs return (periph->pinfo.index != CAM_UNQUEUED_INDEX); 9108b8a9b1dSJustin T. Gibbs } 9118b8a9b1dSJustin T. Gibbs 9128b8a9b1dSJustin T. Gibbs static __inline int 9138b8a9b1dSJustin T. Gibbs device_is_alloc_queued(struct cam_ed *device) 9148b8a9b1dSJustin T. Gibbs { 9158b8a9b1dSJustin T. Gibbs return (device->alloc_ccb_entry.pinfo.index != CAM_UNQUEUED_INDEX); 9168b8a9b1dSJustin T. Gibbs } 9178b8a9b1dSJustin T. Gibbs 9188b8a9b1dSJustin T. Gibbs static __inline int 9198b8a9b1dSJustin T. Gibbs device_is_send_queued(struct cam_ed *device) 9208b8a9b1dSJustin T. Gibbs { 9218b8a9b1dSJustin T. Gibbs return (device->send_ccb_entry.pinfo.index != CAM_UNQUEUED_INDEX); 9228b8a9b1dSJustin T. Gibbs } 9238b8a9b1dSJustin T. Gibbs 9248b8a9b1dSJustin T. Gibbs static __inline int 9258b8a9b1dSJustin T. Gibbs dev_allocq_is_runnable(struct cam_devq *devq) 9268b8a9b1dSJustin T. Gibbs { 9278b8a9b1dSJustin T. Gibbs /* 9288b8a9b1dSJustin T. Gibbs * Have work to do. 9298b8a9b1dSJustin T. Gibbs * Have space to do more work. 9308b8a9b1dSJustin T. Gibbs * Allowed to do work. 9318b8a9b1dSJustin T. Gibbs */ 9328b8a9b1dSJustin T. Gibbs return ((devq->alloc_queue.qfrozen_cnt == 0) 9338b8a9b1dSJustin T. Gibbs && (devq->alloc_queue.entries > 0) 9348b8a9b1dSJustin T. Gibbs && (devq->alloc_openings > 0)); 9358b8a9b1dSJustin T. Gibbs } 9368b8a9b1dSJustin T. Gibbs 9378b8a9b1dSJustin T. Gibbs static void 9388b8a9b1dSJustin T. Gibbs xpt_periph_init() 9398b8a9b1dSJustin T. Gibbs { 94073d26919SKenneth D. Merry make_dev(&xpt_cdevsw, 0, UID_ROOT, GID_OPERATOR, 0600, "xpt0"); 9418b8a9b1dSJustin T. Gibbs } 9428b8a9b1dSJustin T. Gibbs 9438b8a9b1dSJustin T. Gibbs static void 9448b8a9b1dSJustin T. Gibbs probe_periph_init() 9458b8a9b1dSJustin T. Gibbs { 9468b8a9b1dSJustin T. Gibbs } 9478b8a9b1dSJustin T. Gibbs 9488b8a9b1dSJustin T. Gibbs 9498b8a9b1dSJustin T. Gibbs static void 9508b8a9b1dSJustin T. Gibbs xptdone(struct cam_periph *periph, union ccb *done_ccb) 9518b8a9b1dSJustin T. Gibbs { 9528b8a9b1dSJustin T. Gibbs /* Caller will release the CCB */ 9538b8a9b1dSJustin T. Gibbs wakeup(&done_ccb->ccb_h.cbfcnp); 9548b8a9b1dSJustin T. Gibbs } 9558b8a9b1dSJustin T. Gibbs 9568b8a9b1dSJustin T. Gibbs static int 95789c9c53dSPoul-Henning Kamp xptopen(struct cdev *dev, int flags, int fmt, struct thread *td) 9588b8a9b1dSJustin T. Gibbs { 9598b8a9b1dSJustin T. Gibbs int unit; 9608b8a9b1dSJustin T. Gibbs 9618b8a9b1dSJustin T. Gibbs unit = minor(dev) & 0xff; 9628b8a9b1dSJustin T. Gibbs 9638b8a9b1dSJustin T. Gibbs /* 96466a0780eSKenneth D. Merry * Only allow read-write access. 96566a0780eSKenneth D. Merry */ 96666a0780eSKenneth D. Merry if (((flags & FWRITE) == 0) || ((flags & FREAD) == 0)) 96766a0780eSKenneth D. Merry return(EPERM); 96866a0780eSKenneth D. Merry 96966a0780eSKenneth D. Merry /* 9708b8a9b1dSJustin T. Gibbs * We don't allow nonblocking access. 9718b8a9b1dSJustin T. Gibbs */ 9728b8a9b1dSJustin T. Gibbs if ((flags & O_NONBLOCK) != 0) { 97357b89bbcSNate Lawson printf("xpt%d: can't do nonblocking access\n", unit); 9748b8a9b1dSJustin T. Gibbs return(ENODEV); 9758b8a9b1dSJustin T. Gibbs } 9768b8a9b1dSJustin T. Gibbs 9778b8a9b1dSJustin T. Gibbs /* 9788b8a9b1dSJustin T. Gibbs * We only have one transport layer right now. If someone accesses 9798b8a9b1dSJustin T. Gibbs * us via something other than minor number 1, point out their 9808b8a9b1dSJustin T. Gibbs * mistake. 9818b8a9b1dSJustin T. Gibbs */ 9828b8a9b1dSJustin T. Gibbs if (unit != 0) { 9838b8a9b1dSJustin T. Gibbs printf("xptopen: got invalid xpt unit %d\n", unit); 9848b8a9b1dSJustin T. Gibbs return(ENXIO); 9858b8a9b1dSJustin T. Gibbs } 9868b8a9b1dSJustin T. Gibbs 9878b8a9b1dSJustin T. Gibbs /* Mark ourselves open */ 9888b8a9b1dSJustin T. Gibbs xsoftc.flags |= XPT_FLAG_OPEN; 9898b8a9b1dSJustin T. Gibbs 9908b8a9b1dSJustin T. Gibbs return(0); 9918b8a9b1dSJustin T. Gibbs } 9928b8a9b1dSJustin T. Gibbs 9938b8a9b1dSJustin T. Gibbs static int 99489c9c53dSPoul-Henning Kamp xptclose(struct cdev *dev, int flag, int fmt, struct thread *td) 9958b8a9b1dSJustin T. Gibbs { 9968b8a9b1dSJustin T. Gibbs int unit; 9978b8a9b1dSJustin T. Gibbs 9988b8a9b1dSJustin T. Gibbs unit = minor(dev) & 0xff; 9998b8a9b1dSJustin T. Gibbs 10008b8a9b1dSJustin T. Gibbs /* 10018b8a9b1dSJustin T. Gibbs * We only have one transport layer right now. If someone accesses 10028b8a9b1dSJustin T. Gibbs * us via something other than minor number 1, point out their 10038b8a9b1dSJustin T. Gibbs * mistake. 10048b8a9b1dSJustin T. Gibbs */ 10058b8a9b1dSJustin T. Gibbs if (unit != 0) { 10068b8a9b1dSJustin T. Gibbs printf("xptclose: got invalid xpt unit %d\n", unit); 10078b8a9b1dSJustin T. Gibbs return(ENXIO); 10088b8a9b1dSJustin T. Gibbs } 10098b8a9b1dSJustin T. Gibbs 10108b8a9b1dSJustin T. Gibbs /* Mark ourselves closed */ 10118b8a9b1dSJustin T. Gibbs xsoftc.flags &= ~XPT_FLAG_OPEN; 10128b8a9b1dSJustin T. Gibbs 10138b8a9b1dSJustin T. Gibbs return(0); 10148b8a9b1dSJustin T. Gibbs } 10158b8a9b1dSJustin T. Gibbs 10168b8a9b1dSJustin T. Gibbs static int 101789c9c53dSPoul-Henning Kamp xptioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, struct thread *td) 10188b8a9b1dSJustin T. Gibbs { 10198b8a9b1dSJustin T. Gibbs int unit, error; 10208b8a9b1dSJustin T. Gibbs 10218b8a9b1dSJustin T. Gibbs error = 0; 10228b8a9b1dSJustin T. Gibbs unit = minor(dev) & 0xff; 10238b8a9b1dSJustin T. Gibbs 10248b8a9b1dSJustin T. Gibbs /* 10258b8a9b1dSJustin T. Gibbs * We only have one transport layer right now. If someone accesses 10268b8a9b1dSJustin T. Gibbs * us via something other than minor number 1, point out their 10278b8a9b1dSJustin T. Gibbs * mistake. 10288b8a9b1dSJustin T. Gibbs */ 10298b8a9b1dSJustin T. Gibbs if (unit != 0) { 10308b8a9b1dSJustin T. Gibbs printf("xptioctl: got invalid xpt unit %d\n", unit); 10318b8a9b1dSJustin T. Gibbs return(ENXIO); 10328b8a9b1dSJustin T. Gibbs } 10338b8a9b1dSJustin T. Gibbs 10348b8a9b1dSJustin T. Gibbs switch(cmd) { 10358b8a9b1dSJustin T. Gibbs /* 10368b8a9b1dSJustin T. Gibbs * For the transport layer CAMIOCOMMAND ioctl, we really only want 10378b8a9b1dSJustin T. Gibbs * to accept CCB types that don't quite make sense to send through a 10388c7a96c5SScott Long * passthrough driver. XPT_PATH_INQ is an exception to this, as stated 10398c7a96c5SScott Long * in the CAM spec. 10408b8a9b1dSJustin T. Gibbs */ 10418b8a9b1dSJustin T. Gibbs case CAMIOCOMMAND: { 10428b8a9b1dSJustin T. Gibbs union ccb *ccb; 10438b8a9b1dSJustin T. Gibbs union ccb *inccb; 10448b8a9b1dSJustin T. Gibbs 10458b8a9b1dSJustin T. Gibbs inccb = (union ccb *)addr; 10468b8a9b1dSJustin T. Gibbs 10478b8a9b1dSJustin T. Gibbs switch(inccb->ccb_h.func_code) { 10488b8a9b1dSJustin T. Gibbs case XPT_SCAN_BUS: 10498b8a9b1dSJustin T. Gibbs case XPT_RESET_BUS: 10508b8a9b1dSJustin T. Gibbs if ((inccb->ccb_h.target_id != CAM_TARGET_WILDCARD) 10518b8a9b1dSJustin T. Gibbs || (inccb->ccb_h.target_lun != CAM_LUN_WILDCARD)) { 10528b8a9b1dSJustin T. Gibbs error = EINVAL; 10538b8a9b1dSJustin T. Gibbs break; 10548b8a9b1dSJustin T. Gibbs } 10558b8a9b1dSJustin T. Gibbs /* FALLTHROUGH */ 10568c7a96c5SScott Long case XPT_PATH_INQ: 10578fcf57f5SJustin T. Gibbs case XPT_ENG_INQ: 10588b8a9b1dSJustin T. Gibbs case XPT_SCAN_LUN: 10598b8a9b1dSJustin T. Gibbs 10608b8a9b1dSJustin T. Gibbs ccb = xpt_alloc_ccb(); 10618b8a9b1dSJustin T. Gibbs 10628b8a9b1dSJustin T. Gibbs /* 10638b8a9b1dSJustin T. Gibbs * Create a path using the bus, target, and lun the 10648b8a9b1dSJustin T. Gibbs * user passed in. 10658b8a9b1dSJustin T. Gibbs */ 10668b8a9b1dSJustin T. Gibbs if (xpt_create_path(&ccb->ccb_h.path, xpt_periph, 10678b8a9b1dSJustin T. Gibbs inccb->ccb_h.path_id, 10688b8a9b1dSJustin T. Gibbs inccb->ccb_h.target_id, 10698b8a9b1dSJustin T. Gibbs inccb->ccb_h.target_lun) != 10708b8a9b1dSJustin T. Gibbs CAM_REQ_CMP){ 10718b8a9b1dSJustin T. Gibbs error = EINVAL; 10728b8a9b1dSJustin T. Gibbs xpt_free_ccb(ccb); 10738b8a9b1dSJustin T. Gibbs break; 10748b8a9b1dSJustin T. Gibbs } 10758b8a9b1dSJustin T. Gibbs /* Ensure all of our fields are correct */ 10768b8a9b1dSJustin T. Gibbs xpt_setup_ccb(&ccb->ccb_h, ccb->ccb_h.path, 10778b8a9b1dSJustin T. Gibbs inccb->ccb_h.pinfo.priority); 10788b8a9b1dSJustin T. Gibbs xpt_merge_ccb(ccb, inccb); 10798b8a9b1dSJustin T. Gibbs ccb->ccb_h.cbfcnp = xptdone; 10808b8a9b1dSJustin T. Gibbs cam_periph_runccb(ccb, NULL, 0, 0, NULL); 10818b8a9b1dSJustin T. Gibbs bcopy(ccb, inccb, sizeof(union ccb)); 10828b8a9b1dSJustin T. Gibbs xpt_free_path(ccb->ccb_h.path); 10838b8a9b1dSJustin T. Gibbs xpt_free_ccb(ccb); 10848b8a9b1dSJustin T. Gibbs break; 10858b8a9b1dSJustin T. Gibbs 10868b8a9b1dSJustin T. Gibbs case XPT_DEBUG: { 10878b8a9b1dSJustin T. Gibbs union ccb ccb; 10888b8a9b1dSJustin T. Gibbs 10898b8a9b1dSJustin T. Gibbs /* 1090aa872be6SMatt Jacob * This is an immediate CCB, so it's okay to 10918b8a9b1dSJustin T. Gibbs * allocate it on the stack. 10928b8a9b1dSJustin T. Gibbs */ 10938b8a9b1dSJustin T. Gibbs 10948b8a9b1dSJustin T. Gibbs /* 10958b8a9b1dSJustin T. Gibbs * Create a path using the bus, target, and lun the 10968b8a9b1dSJustin T. Gibbs * user passed in. 10978b8a9b1dSJustin T. Gibbs */ 10988b8a9b1dSJustin T. Gibbs if (xpt_create_path(&ccb.ccb_h.path, xpt_periph, 10998b8a9b1dSJustin T. Gibbs inccb->ccb_h.path_id, 11008b8a9b1dSJustin T. Gibbs inccb->ccb_h.target_id, 11018b8a9b1dSJustin T. Gibbs inccb->ccb_h.target_lun) != 11028b8a9b1dSJustin T. Gibbs CAM_REQ_CMP){ 11038b8a9b1dSJustin T. Gibbs error = EINVAL; 11048b8a9b1dSJustin T. Gibbs break; 11058b8a9b1dSJustin T. Gibbs } 11068b8a9b1dSJustin T. Gibbs /* Ensure all of our fields are correct */ 11078b8a9b1dSJustin T. Gibbs xpt_setup_ccb(&ccb.ccb_h, ccb.ccb_h.path, 11088b8a9b1dSJustin T. Gibbs inccb->ccb_h.pinfo.priority); 11098b8a9b1dSJustin T. Gibbs xpt_merge_ccb(&ccb, inccb); 11108b8a9b1dSJustin T. Gibbs ccb.ccb_h.cbfcnp = xptdone; 11118b8a9b1dSJustin T. Gibbs xpt_action(&ccb); 11128b8a9b1dSJustin T. Gibbs bcopy(&ccb, inccb, sizeof(union ccb)); 11138b8a9b1dSJustin T. Gibbs xpt_free_path(ccb.ccb_h.path); 11148b8a9b1dSJustin T. Gibbs break; 11158b8a9b1dSJustin T. Gibbs 11168b8a9b1dSJustin T. Gibbs } 11178b8a9b1dSJustin T. Gibbs case XPT_DEV_MATCH: { 11188b8a9b1dSJustin T. Gibbs struct cam_periph_map_info mapinfo; 111959190eaaSKenneth D. Merry struct cam_path *old_path; 11208b8a9b1dSJustin T. Gibbs 11218b8a9b1dSJustin T. Gibbs /* 11228b8a9b1dSJustin T. Gibbs * We can't deal with physical addresses for this 11238b8a9b1dSJustin T. Gibbs * type of transaction. 11248b8a9b1dSJustin T. Gibbs */ 11258b8a9b1dSJustin T. Gibbs if (inccb->ccb_h.flags & CAM_DATA_PHYS) { 11268b8a9b1dSJustin T. Gibbs error = EINVAL; 11278b8a9b1dSJustin T. Gibbs break; 11288b8a9b1dSJustin T. Gibbs } 112959190eaaSKenneth D. Merry 113059190eaaSKenneth D. Merry /* 113159190eaaSKenneth D. Merry * Save this in case the caller had it set to 113259190eaaSKenneth D. Merry * something in particular. 113359190eaaSKenneth D. Merry */ 113459190eaaSKenneth D. Merry old_path = inccb->ccb_h.path; 113559190eaaSKenneth D. Merry 113659190eaaSKenneth D. Merry /* 113759190eaaSKenneth D. Merry * We really don't need a path for the matching 113859190eaaSKenneth D. Merry * code. The path is needed because of the 113959190eaaSKenneth D. Merry * debugging statements in xpt_action(). They 114059190eaaSKenneth D. Merry * assume that the CCB has a valid path. 114159190eaaSKenneth D. Merry */ 114259190eaaSKenneth D. Merry inccb->ccb_h.path = xpt_periph->path; 114359190eaaSKenneth D. Merry 11448b8a9b1dSJustin T. Gibbs bzero(&mapinfo, sizeof(mapinfo)); 11458b8a9b1dSJustin T. Gibbs 11468b8a9b1dSJustin T. Gibbs /* 11478b8a9b1dSJustin T. Gibbs * Map the pattern and match buffers into kernel 11488b8a9b1dSJustin T. Gibbs * virtual address space. 11498b8a9b1dSJustin T. Gibbs */ 11508b8a9b1dSJustin T. Gibbs error = cam_periph_mapmem(inccb, &mapinfo); 11518b8a9b1dSJustin T. Gibbs 115259190eaaSKenneth D. Merry if (error) { 115359190eaaSKenneth D. Merry inccb->ccb_h.path = old_path; 11548b8a9b1dSJustin T. Gibbs break; 115559190eaaSKenneth D. Merry } 11568b8a9b1dSJustin T. Gibbs 11578b8a9b1dSJustin T. Gibbs /* 11588b8a9b1dSJustin T. Gibbs * This is an immediate CCB, we can send it on directly. 11598b8a9b1dSJustin T. Gibbs */ 11608b8a9b1dSJustin T. Gibbs xpt_action(inccb); 11618b8a9b1dSJustin T. Gibbs 11628b8a9b1dSJustin T. Gibbs /* 11638b8a9b1dSJustin T. Gibbs * Map the buffers back into user space. 11648b8a9b1dSJustin T. Gibbs */ 11658b8a9b1dSJustin T. Gibbs cam_periph_unmapmem(inccb, &mapinfo); 11668b8a9b1dSJustin T. Gibbs 116759190eaaSKenneth D. Merry inccb->ccb_h.path = old_path; 116859190eaaSKenneth D. Merry 11698b8a9b1dSJustin T. Gibbs error = 0; 11708b8a9b1dSJustin T. Gibbs break; 11718b8a9b1dSJustin T. Gibbs } 11728b8a9b1dSJustin T. Gibbs default: 11738fcf57f5SJustin T. Gibbs error = ENOTSUP; 11748b8a9b1dSJustin T. Gibbs break; 11758b8a9b1dSJustin T. Gibbs } 11768b8a9b1dSJustin T. Gibbs break; 11778b8a9b1dSJustin T. Gibbs } 11788b8a9b1dSJustin T. Gibbs /* 11798b8a9b1dSJustin T. Gibbs * This is the getpassthru ioctl. It takes a XPT_GDEVLIST ccb as input, 11808b8a9b1dSJustin T. Gibbs * with the periphal driver name and unit name filled in. The other 11818b8a9b1dSJustin T. Gibbs * fields don't really matter as input. The passthrough driver name 11828b8a9b1dSJustin T. Gibbs * ("pass"), and unit number are passed back in the ccb. The current 11838b8a9b1dSJustin T. Gibbs * device generation number, and the index into the device peripheral 11848b8a9b1dSJustin T. Gibbs * driver list, and the status are also passed back. Note that 11858b8a9b1dSJustin T. Gibbs * since we do everything in one pass, unlike the XPT_GDEVLIST ccb, 11868b8a9b1dSJustin T. Gibbs * we never return a status of CAM_GDEVLIST_LIST_CHANGED. It is 11878b8a9b1dSJustin T. Gibbs * (or rather should be) impossible for the device peripheral driver 11888b8a9b1dSJustin T. Gibbs * list to change since we look at the whole thing in one pass, and 1189a5479bc5SJustin T. Gibbs * we do it with splcam protection. 11908b8a9b1dSJustin T. Gibbs * 11918b8a9b1dSJustin T. Gibbs */ 11928b8a9b1dSJustin T. Gibbs case CAMGETPASSTHRU: { 11938b8a9b1dSJustin T. Gibbs union ccb *ccb; 11948b8a9b1dSJustin T. Gibbs struct cam_periph *periph; 11958b8a9b1dSJustin T. Gibbs struct periph_driver **p_drv; 11968b8a9b1dSJustin T. Gibbs char *name; 11973393f8daSKenneth D. Merry u_int unit; 11983393f8daSKenneth D. Merry u_int cur_generation; 1199621a60d4SKenneth D. Merry int base_periph_found; 12008b8a9b1dSJustin T. Gibbs int splbreaknum; 12018b8a9b1dSJustin T. Gibbs int s; 12028b8a9b1dSJustin T. Gibbs 12038b8a9b1dSJustin T. Gibbs ccb = (union ccb *)addr; 12048b8a9b1dSJustin T. Gibbs unit = ccb->cgdl.unit_number; 12058b8a9b1dSJustin T. Gibbs name = ccb->cgdl.periph_name; 12068b8a9b1dSJustin T. Gibbs /* 12078b8a9b1dSJustin T. Gibbs * Every 100 devices, we want to drop our spl protection to 12088b8a9b1dSJustin T. Gibbs * give the software interrupt handler a chance to run. 12098b8a9b1dSJustin T. Gibbs * Most systems won't run into this check, but this should 12108b8a9b1dSJustin T. Gibbs * avoid starvation in the software interrupt handler in 12118b8a9b1dSJustin T. Gibbs * large systems. 12128b8a9b1dSJustin T. Gibbs */ 12138b8a9b1dSJustin T. Gibbs splbreaknum = 100; 12148b8a9b1dSJustin T. Gibbs 12158b8a9b1dSJustin T. Gibbs ccb = (union ccb *)addr; 12168b8a9b1dSJustin T. Gibbs 1217621a60d4SKenneth D. Merry base_periph_found = 0; 1218621a60d4SKenneth D. Merry 12198b8a9b1dSJustin T. Gibbs /* 12208b8a9b1dSJustin T. Gibbs * Sanity check -- make sure we don't get a null peripheral 12218b8a9b1dSJustin T. Gibbs * driver name. 12228b8a9b1dSJustin T. Gibbs */ 12238b8a9b1dSJustin T. Gibbs if (*ccb->cgdl.periph_name == '\0') { 12248b8a9b1dSJustin T. Gibbs error = EINVAL; 12258b8a9b1dSJustin T. Gibbs break; 12268b8a9b1dSJustin T. Gibbs } 12278b8a9b1dSJustin T. Gibbs 12288b8a9b1dSJustin T. Gibbs /* Keep the list from changing while we traverse it */ 1229a5479bc5SJustin T. Gibbs s = splcam(); 12308b8a9b1dSJustin T. Gibbs ptstartover: 12318b8a9b1dSJustin T. Gibbs cur_generation = xsoftc.generation; 12328b8a9b1dSJustin T. Gibbs 12338b8a9b1dSJustin T. Gibbs /* first find our driver in the list of drivers */ 12340b7c27b9SPeter Wemm for (p_drv = periph_drivers; *p_drv != NULL; p_drv++) 12358b8a9b1dSJustin T. Gibbs if (strcmp((*p_drv)->driver_name, name) == 0) 12368b8a9b1dSJustin T. Gibbs break; 12378b8a9b1dSJustin T. Gibbs 12388b8a9b1dSJustin T. Gibbs if (*p_drv == NULL) { 12398b8a9b1dSJustin T. Gibbs splx(s); 12408b8a9b1dSJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_CMP_ERR; 12418b8a9b1dSJustin T. Gibbs ccb->cgdl.status = CAM_GDEVLIST_ERROR; 12428b8a9b1dSJustin T. Gibbs *ccb->cgdl.periph_name = '\0'; 12438b8a9b1dSJustin T. Gibbs ccb->cgdl.unit_number = 0; 12448b8a9b1dSJustin T. Gibbs error = ENOENT; 12458b8a9b1dSJustin T. Gibbs break; 12468b8a9b1dSJustin T. Gibbs } 12478b8a9b1dSJustin T. Gibbs 12488b8a9b1dSJustin T. Gibbs /* 12498b8a9b1dSJustin T. Gibbs * Run through every peripheral instance of this driver 12508b8a9b1dSJustin T. Gibbs * and check to see whether it matches the unit passed 12518b8a9b1dSJustin T. Gibbs * in by the user. If it does, get out of the loops and 12528b8a9b1dSJustin T. Gibbs * find the passthrough driver associated with that 12538b8a9b1dSJustin T. Gibbs * peripheral driver. 12548b8a9b1dSJustin T. Gibbs */ 12558b8a9b1dSJustin T. Gibbs for (periph = TAILQ_FIRST(&(*p_drv)->units); periph != NULL; 12568b8a9b1dSJustin T. Gibbs periph = TAILQ_NEXT(periph, unit_links)) { 12578b8a9b1dSJustin T. Gibbs 12588b8a9b1dSJustin T. Gibbs if (periph->unit_number == unit) { 12598b8a9b1dSJustin T. Gibbs break; 12608b8a9b1dSJustin T. Gibbs } else if (--splbreaknum == 0) { 12618b8a9b1dSJustin T. Gibbs splx(s); 1262a5479bc5SJustin T. Gibbs s = splcam(); 12638b8a9b1dSJustin T. Gibbs splbreaknum = 100; 12648b8a9b1dSJustin T. Gibbs if (cur_generation != xsoftc.generation) 12658b8a9b1dSJustin T. Gibbs goto ptstartover; 12668b8a9b1dSJustin T. Gibbs } 12678b8a9b1dSJustin T. Gibbs } 12688b8a9b1dSJustin T. Gibbs /* 12698b8a9b1dSJustin T. Gibbs * If we found the peripheral driver that the user passed 12708b8a9b1dSJustin T. Gibbs * in, go through all of the peripheral drivers for that 12718b8a9b1dSJustin T. Gibbs * particular device and look for a passthrough driver. 12728b8a9b1dSJustin T. Gibbs */ 12738b8a9b1dSJustin T. Gibbs if (periph != NULL) { 12748b8a9b1dSJustin T. Gibbs struct cam_ed *device; 12758b8a9b1dSJustin T. Gibbs int i; 12768b8a9b1dSJustin T. Gibbs 1277621a60d4SKenneth D. Merry base_periph_found = 1; 12788b8a9b1dSJustin T. Gibbs device = periph->path->device; 1279fc2ffbe6SPoul-Henning Kamp for (i = 0, periph = SLIST_FIRST(&device->periphs); 12808b8a9b1dSJustin T. Gibbs periph != NULL; 1281fc2ffbe6SPoul-Henning Kamp periph = SLIST_NEXT(periph, periph_links), i++) { 12828b8a9b1dSJustin T. Gibbs /* 12838b8a9b1dSJustin T. Gibbs * Check to see whether we have a 12848b8a9b1dSJustin T. Gibbs * passthrough device or not. 12858b8a9b1dSJustin T. Gibbs */ 12868b8a9b1dSJustin T. Gibbs if (strcmp(periph->periph_name, "pass") == 0) { 12878b8a9b1dSJustin T. Gibbs /* 12888b8a9b1dSJustin T. Gibbs * Fill in the getdevlist fields. 12898b8a9b1dSJustin T. Gibbs */ 12908b8a9b1dSJustin T. Gibbs strcpy(ccb->cgdl.periph_name, 12918b8a9b1dSJustin T. Gibbs periph->periph_name); 12928b8a9b1dSJustin T. Gibbs ccb->cgdl.unit_number = 12938b8a9b1dSJustin T. Gibbs periph->unit_number; 1294fc2ffbe6SPoul-Henning Kamp if (SLIST_NEXT(periph, periph_links)) 12958b8a9b1dSJustin T. Gibbs ccb->cgdl.status = 12968b8a9b1dSJustin T. Gibbs CAM_GDEVLIST_MORE_DEVS; 12978b8a9b1dSJustin T. Gibbs else 12988b8a9b1dSJustin T. Gibbs ccb->cgdl.status = 12998b8a9b1dSJustin T. Gibbs CAM_GDEVLIST_LAST_DEVICE; 13008b8a9b1dSJustin T. Gibbs ccb->cgdl.generation = 13018b8a9b1dSJustin T. Gibbs device->generation; 13028b8a9b1dSJustin T. Gibbs ccb->cgdl.index = i; 13038b8a9b1dSJustin T. Gibbs /* 13048b8a9b1dSJustin T. Gibbs * Fill in some CCB header fields 13058b8a9b1dSJustin T. Gibbs * that the user may want. 13068b8a9b1dSJustin T. Gibbs */ 13078b8a9b1dSJustin T. Gibbs ccb->ccb_h.path_id = 13088b8a9b1dSJustin T. Gibbs periph->path->bus->path_id; 13098b8a9b1dSJustin T. Gibbs ccb->ccb_h.target_id = 13108b8a9b1dSJustin T. Gibbs periph->path->target->target_id; 13118b8a9b1dSJustin T. Gibbs ccb->ccb_h.target_lun = 13128b8a9b1dSJustin T. Gibbs periph->path->device->lun_id; 13138b8a9b1dSJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_CMP; 13148b8a9b1dSJustin T. Gibbs break; 13158b8a9b1dSJustin T. Gibbs } 13168b8a9b1dSJustin T. Gibbs } 13178b8a9b1dSJustin T. Gibbs } 13188b8a9b1dSJustin T. Gibbs 13198b8a9b1dSJustin T. Gibbs /* 13208b8a9b1dSJustin T. Gibbs * If the periph is null here, one of two things has 13218b8a9b1dSJustin T. Gibbs * happened. The first possibility is that we couldn't 13228b8a9b1dSJustin T. Gibbs * find the unit number of the particular peripheral driver 13238b8a9b1dSJustin T. Gibbs * that the user is asking about. e.g. the user asks for 13248b8a9b1dSJustin T. Gibbs * the passthrough driver for "da11". We find the list of 13258b8a9b1dSJustin T. Gibbs * "da" peripherals all right, but there is no unit 11. 13268b8a9b1dSJustin T. Gibbs * The other possibility is that we went through the list 13278b8a9b1dSJustin T. Gibbs * of peripheral drivers attached to the device structure, 13288b8a9b1dSJustin T. Gibbs * but didn't find one with the name "pass". Either way, 13298b8a9b1dSJustin T. Gibbs * we return ENOENT, since we couldn't find something. 13308b8a9b1dSJustin T. Gibbs */ 13318b8a9b1dSJustin T. Gibbs if (periph == NULL) { 13328b8a9b1dSJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_CMP_ERR; 13338b8a9b1dSJustin T. Gibbs ccb->cgdl.status = CAM_GDEVLIST_ERROR; 13348b8a9b1dSJustin T. Gibbs *ccb->cgdl.periph_name = '\0'; 13358b8a9b1dSJustin T. Gibbs ccb->cgdl.unit_number = 0; 13368b8a9b1dSJustin T. Gibbs error = ENOENT; 1337621a60d4SKenneth D. Merry /* 1338621a60d4SKenneth D. Merry * It is unfortunate that this is even necessary, 1339621a60d4SKenneth D. Merry * but there are many, many clueless users out there. 1340621a60d4SKenneth D. Merry * If this is true, the user is looking for the 1341621a60d4SKenneth D. Merry * passthrough driver, but doesn't have one in his 1342621a60d4SKenneth D. Merry * kernel. 1343621a60d4SKenneth D. Merry */ 1344621a60d4SKenneth D. Merry if (base_periph_found == 1) { 1345621a60d4SKenneth D. Merry printf("xptioctl: pass driver is not in the " 1346621a60d4SKenneth D. Merry "kernel\n"); 1347621a60d4SKenneth D. Merry printf("xptioctl: put \"device pass0\" in " 1348621a60d4SKenneth D. Merry "your kernel config file\n"); 1349621a60d4SKenneth D. Merry } 13508b8a9b1dSJustin T. Gibbs } 13518b8a9b1dSJustin T. Gibbs splx(s); 13528b8a9b1dSJustin T. Gibbs break; 13538b8a9b1dSJustin T. Gibbs } 13548b8a9b1dSJustin T. Gibbs default: 13558b8a9b1dSJustin T. Gibbs error = ENOTTY; 13568b8a9b1dSJustin T. Gibbs break; 13578b8a9b1dSJustin T. Gibbs } 13588b8a9b1dSJustin T. Gibbs 13598b8a9b1dSJustin T. Gibbs return(error); 13608b8a9b1dSJustin T. Gibbs } 13618b8a9b1dSJustin T. Gibbs 136274bd1c10SNick Hibma static int 136374bd1c10SNick Hibma cam_module_event_handler(module_t mod, int what, void *arg) 136474bd1c10SNick Hibma { 136574bd1c10SNick Hibma if (what == MOD_LOAD) { 136674bd1c10SNick Hibma xpt_init(NULL); 136774bd1c10SNick Hibma } else if (what == MOD_UNLOAD) { 136874bd1c10SNick Hibma return EBUSY; 13693e019deaSPoul-Henning Kamp } else { 13703e019deaSPoul-Henning Kamp return EOPNOTSUPP; 137174bd1c10SNick Hibma } 137274bd1c10SNick Hibma 137374bd1c10SNick Hibma return 0; 137474bd1c10SNick Hibma } 137574bd1c10SNick Hibma 13768b8a9b1dSJustin T. Gibbs /* Functions accessed by the peripheral drivers */ 1377667d00a7SMatt Jacob static void 13786d2a8f1cSPeter Wemm xpt_init(dummy) 13796d2a8f1cSPeter Wemm void *dummy; 13808b8a9b1dSJustin T. Gibbs { 13818b8a9b1dSJustin T. Gibbs struct cam_sim *xpt_sim; 13828b8a9b1dSJustin T. Gibbs struct cam_path *path; 1383434bbf6eSJustin T. Gibbs struct cam_devq *devq; 13848b8a9b1dSJustin T. Gibbs cam_status status; 13858b8a9b1dSJustin T. Gibbs 13868b8a9b1dSJustin T. Gibbs TAILQ_INIT(&xpt_busses); 13878b8a9b1dSJustin T. Gibbs TAILQ_INIT(&cam_bioq); 13888b8a9b1dSJustin T. Gibbs SLIST_INIT(&ccb_freeq); 13898b8a9b1dSJustin T. Gibbs STAILQ_INIT(&highpowerq); 13908b8a9b1dSJustin T. Gibbs 1391ef3cf714SScott Long mtx_init(&cam_bioq_lock, "CAM BIOQ lock", NULL, MTX_DEF); 1392ef3cf714SScott Long 13938b8a9b1dSJustin T. Gibbs /* 13948b8a9b1dSJustin T. Gibbs * The xpt layer is, itself, the equivelent of a SIM. 13958b8a9b1dSJustin T. Gibbs * Allow 16 ccbs in the ccb pool for it. This should 13968b8a9b1dSJustin T. Gibbs * give decent parallelism when we probe busses and 13978b8a9b1dSJustin T. Gibbs * perform other XPT functions. 13988b8a9b1dSJustin T. Gibbs */ 1399434bbf6eSJustin T. Gibbs devq = cam_simq_alloc(16); 1400434bbf6eSJustin T. Gibbs xpt_sim = cam_sim_alloc(xptaction, 1401434bbf6eSJustin T. Gibbs xptpoll, 1402434bbf6eSJustin T. Gibbs "xpt", 1403434bbf6eSJustin T. Gibbs /*softc*/NULL, 1404434bbf6eSJustin T. Gibbs /*unit*/0, 1405434bbf6eSJustin T. Gibbs /*max_dev_transactions*/0, 1406434bbf6eSJustin T. Gibbs /*max_tagged_dev_transactions*/0, 1407434bbf6eSJustin T. Gibbs devq); 14088b8a9b1dSJustin T. Gibbs xpt_max_ccbs = 16; 14098b8a9b1dSJustin T. Gibbs 1410434bbf6eSJustin T. Gibbs xpt_bus_register(xpt_sim, /*bus #*/0); 14118b8a9b1dSJustin T. Gibbs 14128b8a9b1dSJustin T. Gibbs /* 14138b8a9b1dSJustin T. Gibbs * Looking at the XPT from the SIM layer, the XPT is 14148b8a9b1dSJustin T. Gibbs * the equivelent of a peripheral driver. Allocate 14158b8a9b1dSJustin T. Gibbs * a peripheral driver entry for us. 14168b8a9b1dSJustin T. Gibbs */ 14178b8a9b1dSJustin T. Gibbs if ((status = xpt_create_path(&path, NULL, CAM_XPT_PATH_ID, 14188b8a9b1dSJustin T. Gibbs CAM_TARGET_WILDCARD, 14198b8a9b1dSJustin T. Gibbs CAM_LUN_WILDCARD)) != CAM_REQ_CMP) { 14208b8a9b1dSJustin T. Gibbs printf("xpt_init: xpt_create_path failed with status %#x," 14218b8a9b1dSJustin T. Gibbs " failing attach\n", status); 14228b8a9b1dSJustin T. Gibbs return; 14238b8a9b1dSJustin T. Gibbs } 14248b8a9b1dSJustin T. Gibbs 1425ee9c90c7SKenneth D. Merry cam_periph_alloc(xptregister, NULL, NULL, NULL, "xpt", CAM_PERIPH_BIO, 14268b8a9b1dSJustin T. Gibbs path, NULL, 0, NULL); 14278b8a9b1dSJustin T. Gibbs xpt_free_path(path); 14288b8a9b1dSJustin T. Gibbs 14298b8a9b1dSJustin T. Gibbs xpt_sim->softc = xpt_periph; 14308b8a9b1dSJustin T. Gibbs 14318b8a9b1dSJustin T. Gibbs /* 14328b8a9b1dSJustin T. Gibbs * Register a callback for when interrupts are enabled. 14338b8a9b1dSJustin T. Gibbs */ 14348b8a9b1dSJustin T. Gibbs xpt_config_hook = 14358b8a9b1dSJustin T. Gibbs (struct intr_config_hook *)malloc(sizeof(struct intr_config_hook), 14365417ec4dSDavid Malone M_TEMP, M_NOWAIT | M_ZERO); 14378b8a9b1dSJustin T. Gibbs if (xpt_config_hook == NULL) { 14388b8a9b1dSJustin T. Gibbs printf("xpt_init: Cannot malloc config hook " 14398b8a9b1dSJustin T. Gibbs "- failing attach\n"); 14408b8a9b1dSJustin T. Gibbs return; 14418b8a9b1dSJustin T. Gibbs } 14428b8a9b1dSJustin T. Gibbs 14438b8a9b1dSJustin T. Gibbs xpt_config_hook->ich_func = xpt_config; 14448b8a9b1dSJustin T. Gibbs if (config_intrhook_establish(xpt_config_hook) != 0) { 14458b8a9b1dSJustin T. Gibbs free (xpt_config_hook, M_TEMP); 14468b8a9b1dSJustin T. Gibbs printf("xpt_init: config_intrhook_establish failed " 14478b8a9b1dSJustin T. Gibbs "- failing attach\n"); 14488b8a9b1dSJustin T. Gibbs } 14498b8a9b1dSJustin T. Gibbs 14508b8a9b1dSJustin T. Gibbs /* Install our software interrupt handlers */ 1451062d8ff5SJohn Baldwin swi_add(NULL, "cambio", camisr, &cam_bioq, SWI_CAMBIO, 0, &cambio_ih); 14528b8a9b1dSJustin T. Gibbs } 14538b8a9b1dSJustin T. Gibbs 14548b8a9b1dSJustin T. Gibbs static cam_status 14558b8a9b1dSJustin T. Gibbs xptregister(struct cam_periph *periph, void *arg) 14568b8a9b1dSJustin T. Gibbs { 14578b8a9b1dSJustin T. Gibbs if (periph == NULL) { 14588b8a9b1dSJustin T. Gibbs printf("xptregister: periph was NULL!!\n"); 14598b8a9b1dSJustin T. Gibbs return(CAM_REQ_CMP_ERR); 14608b8a9b1dSJustin T. Gibbs } 14618b8a9b1dSJustin T. Gibbs 14628b8a9b1dSJustin T. Gibbs periph->softc = NULL; 14638b8a9b1dSJustin T. Gibbs 14648b8a9b1dSJustin T. Gibbs xpt_periph = periph; 14658b8a9b1dSJustin T. Gibbs 14668b8a9b1dSJustin T. Gibbs return(CAM_REQ_CMP); 14678b8a9b1dSJustin T. Gibbs } 14688b8a9b1dSJustin T. Gibbs 14698b8a9b1dSJustin T. Gibbs int32_t 14708b8a9b1dSJustin T. Gibbs xpt_add_periph(struct cam_periph *periph) 14718b8a9b1dSJustin T. Gibbs { 14728b8a9b1dSJustin T. Gibbs struct cam_ed *device; 14738b8a9b1dSJustin T. Gibbs int32_t status; 14748b8a9b1dSJustin T. Gibbs struct periph_list *periph_head; 14758b8a9b1dSJustin T. Gibbs 147668153f43SScott Long GIANT_REQUIRED; 147768153f43SScott Long 14788b8a9b1dSJustin T. Gibbs device = periph->path->device; 14798b8a9b1dSJustin T. Gibbs 14808b8a9b1dSJustin T. Gibbs periph_head = &device->periphs; 14818b8a9b1dSJustin T. Gibbs 14828b8a9b1dSJustin T. Gibbs status = CAM_REQ_CMP; 14838b8a9b1dSJustin T. Gibbs 14848b8a9b1dSJustin T. Gibbs if (device != NULL) { 14858b8a9b1dSJustin T. Gibbs int s; 14868b8a9b1dSJustin T. Gibbs 14878b8a9b1dSJustin T. Gibbs /* 14888b8a9b1dSJustin T. Gibbs * Make room for this peripheral 14898b8a9b1dSJustin T. Gibbs * so it will fit in the queue 14908b8a9b1dSJustin T. Gibbs * when it's scheduled to run 14918b8a9b1dSJustin T. Gibbs */ 14928b8a9b1dSJustin T. Gibbs s = splsoftcam(); 14938b8a9b1dSJustin T. Gibbs status = camq_resize(&device->drvq, 14948b8a9b1dSJustin T. Gibbs device->drvq.array_size + 1); 14958b8a9b1dSJustin T. Gibbs 14968b8a9b1dSJustin T. Gibbs device->generation++; 14978b8a9b1dSJustin T. Gibbs 14988b8a9b1dSJustin T. Gibbs SLIST_INSERT_HEAD(periph_head, periph, periph_links); 14998b8a9b1dSJustin T. Gibbs 15008b8a9b1dSJustin T. Gibbs splx(s); 15018b8a9b1dSJustin T. Gibbs } 15028b8a9b1dSJustin T. Gibbs 15038b8a9b1dSJustin T. Gibbs xsoftc.generation++; 15048b8a9b1dSJustin T. Gibbs 15058b8a9b1dSJustin T. Gibbs return (status); 15068b8a9b1dSJustin T. Gibbs } 15078b8a9b1dSJustin T. Gibbs 15088b8a9b1dSJustin T. Gibbs void 15098b8a9b1dSJustin T. Gibbs xpt_remove_periph(struct cam_periph *periph) 15108b8a9b1dSJustin T. Gibbs { 15118b8a9b1dSJustin T. Gibbs struct cam_ed *device; 15128b8a9b1dSJustin T. Gibbs 151368153f43SScott Long GIANT_REQUIRED; 151468153f43SScott Long 15158b8a9b1dSJustin T. Gibbs device = periph->path->device; 15168b8a9b1dSJustin T. Gibbs 15178b8a9b1dSJustin T. Gibbs if (device != NULL) { 15188b8a9b1dSJustin T. Gibbs int s; 15198b8a9b1dSJustin T. Gibbs struct periph_list *periph_head; 15208b8a9b1dSJustin T. Gibbs 15218b8a9b1dSJustin T. Gibbs periph_head = &device->periphs; 15228b8a9b1dSJustin T. Gibbs 15238b8a9b1dSJustin T. Gibbs /* Release the slot for this peripheral */ 15248b8a9b1dSJustin T. Gibbs s = splsoftcam(); 15258b8a9b1dSJustin T. Gibbs camq_resize(&device->drvq, device->drvq.array_size - 1); 15268b8a9b1dSJustin T. Gibbs 15278b8a9b1dSJustin T. Gibbs device->generation++; 15288b8a9b1dSJustin T. Gibbs 1529e3975643SJake Burkholder SLIST_REMOVE(periph_head, periph, cam_periph, periph_links); 15308b8a9b1dSJustin T. Gibbs 15318b8a9b1dSJustin T. Gibbs splx(s); 15328b8a9b1dSJustin T. Gibbs } 15338b8a9b1dSJustin T. Gibbs 15348b8a9b1dSJustin T. Gibbs xsoftc.generation++; 15358b8a9b1dSJustin T. Gibbs 15368b8a9b1dSJustin T. Gibbs } 15378b8a9b1dSJustin T. Gibbs 15383393f8daSKenneth D. Merry #ifdef CAM_NEW_TRAN_CODE 15393393f8daSKenneth D. Merry 15403393f8daSKenneth D. Merry void 15413393f8daSKenneth D. Merry xpt_announce_periph(struct cam_periph *periph, char *announce_string) 15423393f8daSKenneth D. Merry { 15433393f8daSKenneth D. Merry struct ccb_pathinq cpi; 15443393f8daSKenneth D. Merry struct ccb_trans_settings cts; 15453393f8daSKenneth D. Merry struct cam_path *path; 15463393f8daSKenneth D. Merry u_int speed; 15473393f8daSKenneth D. Merry u_int freq; 15483393f8daSKenneth D. Merry u_int mb; 15493393f8daSKenneth D. Merry int s; 15503393f8daSKenneth D. Merry 155168153f43SScott Long GIANT_REQUIRED; 155268153f43SScott Long 15533393f8daSKenneth D. Merry path = periph->path; 15543393f8daSKenneth D. Merry /* 15553393f8daSKenneth D. Merry * To ensure that this is printed in one piece, 15563393f8daSKenneth D. Merry * mask out CAM interrupts. 15573393f8daSKenneth D. Merry */ 15583393f8daSKenneth D. Merry s = splsoftcam(); 15593393f8daSKenneth D. Merry printf("%s%d at %s%d bus %d target %d lun %d\n", 15603393f8daSKenneth D. Merry periph->periph_name, periph->unit_number, 15613393f8daSKenneth D. Merry path->bus->sim->sim_name, 15623393f8daSKenneth D. Merry path->bus->sim->unit_number, 15633393f8daSKenneth D. Merry path->bus->sim->bus_id, 15643393f8daSKenneth D. Merry path->target->target_id, 15653393f8daSKenneth D. Merry path->device->lun_id); 15663393f8daSKenneth D. Merry printf("%s%d: ", periph->periph_name, periph->unit_number); 15673393f8daSKenneth D. Merry scsi_print_inquiry(&path->device->inq_data); 1568f053d777SMatt Jacob if (bootverbose && path->device->serial_num_len > 0) { 15693393f8daSKenneth D. Merry /* Don't wrap the screen - print only the first 60 chars */ 15703393f8daSKenneth D. Merry printf("%s%d: Serial Number %.60s\n", periph->periph_name, 15713393f8daSKenneth D. Merry periph->unit_number, path->device->serial_num); 15723393f8daSKenneth D. Merry } 15733393f8daSKenneth D. Merry xpt_setup_ccb(&cts.ccb_h, path, /*priority*/1); 15743393f8daSKenneth D. Merry cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS; 15753393f8daSKenneth D. Merry cts.type = CTS_TYPE_CURRENT_SETTINGS; 15763393f8daSKenneth D. Merry xpt_action((union ccb*)&cts); 15773393f8daSKenneth D. Merry 15783393f8daSKenneth D. Merry /* Ask the SIM for its base transfer speed */ 15793393f8daSKenneth D. Merry xpt_setup_ccb(&cpi.ccb_h, path, /*priority*/1); 15803393f8daSKenneth D. Merry cpi.ccb_h.func_code = XPT_PATH_INQ; 15813393f8daSKenneth D. Merry xpt_action((union ccb *)&cpi); 15823393f8daSKenneth D. Merry 15833393f8daSKenneth D. Merry speed = cpi.base_transfer_speed; 15843393f8daSKenneth D. Merry freq = 0; 1585f053d777SMatt Jacob if (cts.ccb_h.status == CAM_REQ_CMP && cts.transport == XPORT_SPI) { 15863393f8daSKenneth D. Merry struct ccb_trans_settings_spi *spi; 15873393f8daSKenneth D. Merry 15883393f8daSKenneth D. Merry spi = &cts.xport_specific.spi; 15893393f8daSKenneth D. Merry if ((spi->valid & CTS_SPI_VALID_SYNC_OFFSET) != 0 15903393f8daSKenneth D. Merry && spi->sync_offset != 0) { 15913393f8daSKenneth D. Merry freq = scsi_calc_syncsrate(spi->sync_period); 15923393f8daSKenneth D. Merry speed = freq; 15933393f8daSKenneth D. Merry } 15943393f8daSKenneth D. Merry 15953393f8daSKenneth D. Merry if ((spi->valid & CTS_SPI_VALID_BUS_WIDTH) != 0) 15963393f8daSKenneth D. Merry speed *= (0x01 << spi->bus_width); 15973393f8daSKenneth D. Merry } 15982c7d0b8dSMatt Jacob 1599f053d777SMatt Jacob if (cts.ccb_h.status == CAM_REQ_CMP && cts.transport == XPORT_FC) { 1600f053d777SMatt Jacob struct ccb_trans_settings_fc *fc = &cts.xport_specific.fc; 1601f053d777SMatt Jacob if (fc->valid & CTS_FC_VALID_SPEED) { 16022c7d0b8dSMatt Jacob speed = fc->bitrate; 16032c7d0b8dSMatt Jacob } 1604f053d777SMatt Jacob } 16053393f8daSKenneth D. Merry 16063393f8daSKenneth D. Merry mb = speed / 1000; 16073393f8daSKenneth D. Merry if (mb > 0) 16083393f8daSKenneth D. Merry printf("%s%d: %d.%03dMB/s transfers", 16093393f8daSKenneth D. Merry periph->periph_name, periph->unit_number, 16103393f8daSKenneth D. Merry mb, speed % 1000); 16113393f8daSKenneth D. Merry else 16123393f8daSKenneth D. Merry printf("%s%d: %dKB/s transfers", periph->periph_name, 16133393f8daSKenneth D. Merry periph->unit_number, speed); 16143393f8daSKenneth D. Merry /* Report additional information about SPI connections */ 1615f053d777SMatt Jacob if (cts.ccb_h.status == CAM_REQ_CMP && cts.transport == XPORT_SPI) { 16163393f8daSKenneth D. Merry struct ccb_trans_settings_spi *spi; 16173393f8daSKenneth D. Merry 16183393f8daSKenneth D. Merry spi = &cts.xport_specific.spi; 16193393f8daSKenneth D. Merry if (freq != 0) { 16203393f8daSKenneth D. Merry printf(" (%d.%03dMHz%s, offset %d", freq / 1000, 16213393f8daSKenneth D. Merry freq % 1000, 16223393f8daSKenneth D. Merry (spi->ppr_options & MSG_EXT_PPR_DT_REQ) != 0 16233393f8daSKenneth D. Merry ? " DT" : "", 16243393f8daSKenneth D. Merry spi->sync_offset); 16253393f8daSKenneth D. Merry } 16263393f8daSKenneth D. Merry if ((spi->valid & CTS_SPI_VALID_BUS_WIDTH) != 0 16273393f8daSKenneth D. Merry && spi->bus_width > 0) { 16283393f8daSKenneth D. Merry if (freq != 0) { 16293393f8daSKenneth D. Merry printf(", "); 16303393f8daSKenneth D. Merry } else { 16313393f8daSKenneth D. Merry printf(" ("); 16323393f8daSKenneth D. Merry } 16333393f8daSKenneth D. Merry printf("%dbit)", 8 * (0x01 << spi->bus_width)); 16343393f8daSKenneth D. Merry } else if (freq != 0) { 16353393f8daSKenneth D. Merry printf(")"); 16363393f8daSKenneth D. Merry } 16373393f8daSKenneth D. Merry } 1638f053d777SMatt Jacob if (cts.ccb_h.status == CAM_REQ_CMP && cts.transport == XPORT_FC) { 16392c7d0b8dSMatt Jacob struct ccb_trans_settings_fc *fc; 16402c7d0b8dSMatt Jacob 16412c7d0b8dSMatt Jacob fc = &cts.xport_specific.fc; 1642f053d777SMatt Jacob if (fc->valid & CTS_FC_VALID_WWNN) 1643f053d777SMatt Jacob printf(" WWNN 0x%llx", (long long) fc->wwnn); 1644f053d777SMatt Jacob if (fc->valid & CTS_FC_VALID_WWPN) 1645f053d777SMatt Jacob printf(" WWPN 0x%llx", (long long) fc->wwpn); 1646f053d777SMatt Jacob if (fc->valid & CTS_FC_VALID_PORT) 1647f053d777SMatt Jacob printf(" PortID 0x%x", fc->port); 16482c7d0b8dSMatt Jacob } 16493393f8daSKenneth D. Merry 16503393f8daSKenneth D. Merry if (path->device->inq_flags & SID_CmdQue 16513393f8daSKenneth D. Merry || path->device->flags & CAM_DEV_TAG_AFTER_COUNT) { 16523393f8daSKenneth D. Merry printf("\n%s%d: Tagged Queueing Enabled", 16533393f8daSKenneth D. Merry periph->periph_name, periph->unit_number); 16543393f8daSKenneth D. Merry } 16553393f8daSKenneth D. Merry printf("\n"); 16563393f8daSKenneth D. Merry 16573393f8daSKenneth D. Merry /* 16583393f8daSKenneth D. Merry * We only want to print the caller's announce string if they've 16593393f8daSKenneth D. Merry * passed one in.. 16603393f8daSKenneth D. Merry */ 16613393f8daSKenneth D. Merry if (announce_string != NULL) 16623393f8daSKenneth D. Merry printf("%s%d: %s\n", periph->periph_name, 16633393f8daSKenneth D. Merry periph->unit_number, announce_string); 16643393f8daSKenneth D. Merry splx(s); 16653393f8daSKenneth D. Merry } 16663393f8daSKenneth D. Merry #else /* CAM_NEW_TRAN_CODE */ 16678b8a9b1dSJustin T. Gibbs void 16688b8a9b1dSJustin T. Gibbs xpt_announce_periph(struct cam_periph *periph, char *announce_string) 16698b8a9b1dSJustin T. Gibbs { 16708b8a9b1dSJustin T. Gibbs int s; 16718b8a9b1dSJustin T. Gibbs u_int mb; 16728b8a9b1dSJustin T. Gibbs struct cam_path *path; 16738b8a9b1dSJustin T. Gibbs struct ccb_trans_settings cts; 16748b8a9b1dSJustin T. Gibbs 167568153f43SScott Long GIANT_REQUIRED; 167668153f43SScott Long 16778b8a9b1dSJustin T. Gibbs path = periph->path; 16788b8a9b1dSJustin T. Gibbs /* 16798b8a9b1dSJustin T. Gibbs * To ensure that this is printed in one piece, 16808b8a9b1dSJustin T. Gibbs * mask out CAM interrupts. 16818b8a9b1dSJustin T. Gibbs */ 16828b8a9b1dSJustin T. Gibbs s = splsoftcam(); 16838b8a9b1dSJustin T. Gibbs printf("%s%d at %s%d bus %d target %d lun %d\n", 16848b8a9b1dSJustin T. Gibbs periph->periph_name, periph->unit_number, 16858b8a9b1dSJustin T. Gibbs path->bus->sim->sim_name, 16868b8a9b1dSJustin T. Gibbs path->bus->sim->unit_number, 16878b8a9b1dSJustin T. Gibbs path->bus->sim->bus_id, 16888b8a9b1dSJustin T. Gibbs path->target->target_id, 16898b8a9b1dSJustin T. Gibbs path->device->lun_id); 16908b8a9b1dSJustin T. Gibbs printf("%s%d: ", periph->periph_name, periph->unit_number); 16918b8a9b1dSJustin T. Gibbs scsi_print_inquiry(&path->device->inq_data); 16928b8a9b1dSJustin T. Gibbs if ((bootverbose) 16938b8a9b1dSJustin T. Gibbs && (path->device->serial_num_len > 0)) { 16948b8a9b1dSJustin T. Gibbs /* Don't wrap the screen - print only the first 60 chars */ 16958b8a9b1dSJustin T. Gibbs printf("%s%d: Serial Number %.60s\n", periph->periph_name, 16968b8a9b1dSJustin T. Gibbs periph->unit_number, path->device->serial_num); 16978b8a9b1dSJustin T. Gibbs } 16988b8a9b1dSJustin T. Gibbs xpt_setup_ccb(&cts.ccb_h, path, /*priority*/1); 16998b8a9b1dSJustin T. Gibbs cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS; 17008b8a9b1dSJustin T. Gibbs cts.flags = CCB_TRANS_CURRENT_SETTINGS; 17018b8a9b1dSJustin T. Gibbs xpt_action((union ccb*)&cts); 17028b8a9b1dSJustin T. Gibbs if (cts.ccb_h.status == CAM_REQ_CMP) { 17038b8a9b1dSJustin T. Gibbs u_int speed; 17048b8a9b1dSJustin T. Gibbs u_int freq; 17058b8a9b1dSJustin T. Gibbs 17068b8a9b1dSJustin T. Gibbs if ((cts.valid & CCB_TRANS_SYNC_OFFSET_VALID) != 0 17078b8a9b1dSJustin T. Gibbs && cts.sync_offset != 0) { 17088b8a9b1dSJustin T. Gibbs freq = scsi_calc_syncsrate(cts.sync_period); 17098b8a9b1dSJustin T. Gibbs speed = freq; 17108b8a9b1dSJustin T. Gibbs } else { 17119deea857SKenneth D. Merry struct ccb_pathinq cpi; 17129deea857SKenneth D. Merry 17139deea857SKenneth D. Merry /* Ask the SIM for its base transfer speed */ 17149deea857SKenneth D. Merry xpt_setup_ccb(&cpi.ccb_h, path, /*priority*/1); 17159deea857SKenneth D. Merry cpi.ccb_h.func_code = XPT_PATH_INQ; 17169deea857SKenneth D. Merry xpt_action((union ccb *)&cpi); 17179deea857SKenneth D. Merry 17189deea857SKenneth D. Merry speed = cpi.base_transfer_speed; 17198b8a9b1dSJustin T. Gibbs freq = 0; 17208b8a9b1dSJustin T. Gibbs } 17218b8a9b1dSJustin T. Gibbs if ((cts.valid & CCB_TRANS_BUS_WIDTH_VALID) != 0) 17228b8a9b1dSJustin T. Gibbs speed *= (0x01 << cts.bus_width); 17238b8a9b1dSJustin T. Gibbs mb = speed / 1000; 17248b8a9b1dSJustin T. Gibbs if (mb > 0) 1725588b47e5SKenneth D. Merry printf("%s%d: %d.%03dMB/s transfers", 1726588b47e5SKenneth D. Merry periph->periph_name, periph->unit_number, 1727588b47e5SKenneth D. Merry mb, speed % 1000); 17288b8a9b1dSJustin T. Gibbs else 17298b8a9b1dSJustin T. Gibbs printf("%s%d: %dKB/s transfers", periph->periph_name, 17300cdabce0SNick Hibma periph->unit_number, speed); 17318b8a9b1dSJustin T. Gibbs if ((cts.valid & CCB_TRANS_SYNC_OFFSET_VALID) != 0 17328b8a9b1dSJustin T. Gibbs && cts.sync_offset != 0) { 1733588b47e5SKenneth D. Merry printf(" (%d.%03dMHz, offset %d", freq / 1000, 17348b8a9b1dSJustin T. Gibbs freq % 1000, cts.sync_offset); 17358b8a9b1dSJustin T. Gibbs } 17368b8a9b1dSJustin T. Gibbs if ((cts.valid & CCB_TRANS_BUS_WIDTH_VALID) != 0 17378b8a9b1dSJustin T. Gibbs && cts.bus_width > 0) { 17388b8a9b1dSJustin T. Gibbs if ((cts.valid & CCB_TRANS_SYNC_OFFSET_VALID) != 0 17398b8a9b1dSJustin T. Gibbs && cts.sync_offset != 0) { 17408b8a9b1dSJustin T. Gibbs printf(", "); 17418b8a9b1dSJustin T. Gibbs } else { 17428b8a9b1dSJustin T. Gibbs printf(" ("); 17438b8a9b1dSJustin T. Gibbs } 17448b8a9b1dSJustin T. Gibbs printf("%dbit)", 8 * (0x01 << cts.bus_width)); 17458b8a9b1dSJustin T. Gibbs } else if ((cts.valid & CCB_TRANS_SYNC_OFFSET_VALID) != 0 17468b8a9b1dSJustin T. Gibbs && cts.sync_offset != 0) { 17478b8a9b1dSJustin T. Gibbs printf(")"); 17488b8a9b1dSJustin T. Gibbs } 1749fd21cc5eSJustin T. Gibbs 1750fd21cc5eSJustin T. Gibbs if (path->device->inq_flags & SID_CmdQue 1751fd21cc5eSJustin T. Gibbs || path->device->flags & CAM_DEV_TAG_AFTER_COUNT) { 17528b8a9b1dSJustin T. Gibbs printf(", Tagged Queueing Enabled"); 17538b8a9b1dSJustin T. Gibbs } 17548b8a9b1dSJustin T. Gibbs 17558b8a9b1dSJustin T. Gibbs printf("\n"); 17562ba01e6fSJustin T. Gibbs } else if (path->device->inq_flags & SID_CmdQue 17572ba01e6fSJustin T. Gibbs || path->device->flags & CAM_DEV_TAG_AFTER_COUNT) { 17588b8a9b1dSJustin T. Gibbs printf("%s%d: Tagged Queueing Enabled\n", 17598b8a9b1dSJustin T. Gibbs periph->periph_name, periph->unit_number); 17608b8a9b1dSJustin T. Gibbs } 17618b8a9b1dSJustin T. Gibbs 17628b8a9b1dSJustin T. Gibbs /* 17638b8a9b1dSJustin T. Gibbs * We only want to print the caller's announce string if they've 17648b8a9b1dSJustin T. Gibbs * passed one in.. 17658b8a9b1dSJustin T. Gibbs */ 17668b8a9b1dSJustin T. Gibbs if (announce_string != NULL) 17678b8a9b1dSJustin T. Gibbs printf("%s%d: %s\n", periph->periph_name, 17688b8a9b1dSJustin T. Gibbs periph->unit_number, announce_string); 17698b8a9b1dSJustin T. Gibbs splx(s); 17708b8a9b1dSJustin T. Gibbs } 17718b8a9b1dSJustin T. Gibbs 17723393f8daSKenneth D. Merry #endif /* CAM_NEW_TRAN_CODE */ 17738b8a9b1dSJustin T. Gibbs 17748b8a9b1dSJustin T. Gibbs static dev_match_ret 17753393f8daSKenneth D. Merry xptbusmatch(struct dev_match_pattern *patterns, u_int num_patterns, 17768b8a9b1dSJustin T. Gibbs struct cam_eb *bus) 17778b8a9b1dSJustin T. Gibbs { 17788b8a9b1dSJustin T. Gibbs dev_match_ret retval; 17798b8a9b1dSJustin T. Gibbs int i; 17808b8a9b1dSJustin T. Gibbs 17818b8a9b1dSJustin T. Gibbs retval = DM_RET_NONE; 17828b8a9b1dSJustin T. Gibbs 17838b8a9b1dSJustin T. Gibbs /* 17848b8a9b1dSJustin T. Gibbs * If we aren't given something to match against, that's an error. 17858b8a9b1dSJustin T. Gibbs */ 17868b8a9b1dSJustin T. Gibbs if (bus == NULL) 17878b8a9b1dSJustin T. Gibbs return(DM_RET_ERROR); 17888b8a9b1dSJustin T. Gibbs 17898b8a9b1dSJustin T. Gibbs /* 17908b8a9b1dSJustin T. Gibbs * If there are no match entries, then this bus matches no 17918b8a9b1dSJustin T. Gibbs * matter what. 17928b8a9b1dSJustin T. Gibbs */ 17938b8a9b1dSJustin T. Gibbs if ((patterns == NULL) || (num_patterns == 0)) 17948b8a9b1dSJustin T. Gibbs return(DM_RET_DESCEND | DM_RET_COPY); 17958b8a9b1dSJustin T. Gibbs 17968b8a9b1dSJustin T. Gibbs for (i = 0; i < num_patterns; i++) { 17978b8a9b1dSJustin T. Gibbs struct bus_match_pattern *cur_pattern; 17988b8a9b1dSJustin T. Gibbs 17998b8a9b1dSJustin T. Gibbs /* 18008b8a9b1dSJustin T. Gibbs * If the pattern in question isn't for a bus node, we 18018b8a9b1dSJustin T. Gibbs * aren't interested. However, we do indicate to the 18028b8a9b1dSJustin T. Gibbs * calling routine that we should continue descending the 18038b8a9b1dSJustin T. Gibbs * tree, since the user wants to match against lower-level 18048b8a9b1dSJustin T. Gibbs * EDT elements. 18058b8a9b1dSJustin T. Gibbs */ 18068b8a9b1dSJustin T. Gibbs if (patterns[i].type != DEV_MATCH_BUS) { 18078b8a9b1dSJustin T. Gibbs if ((retval & DM_RET_ACTION_MASK) == DM_RET_NONE) 18088b8a9b1dSJustin T. Gibbs retval |= DM_RET_DESCEND; 18098b8a9b1dSJustin T. Gibbs continue; 18108b8a9b1dSJustin T. Gibbs } 18118b8a9b1dSJustin T. Gibbs 18128b8a9b1dSJustin T. Gibbs cur_pattern = &patterns[i].pattern.bus_pattern; 18138b8a9b1dSJustin T. Gibbs 18148b8a9b1dSJustin T. Gibbs /* 18158b8a9b1dSJustin T. Gibbs * If they want to match any bus node, we give them any 18168b8a9b1dSJustin T. Gibbs * device node. 18178b8a9b1dSJustin T. Gibbs */ 18188b8a9b1dSJustin T. Gibbs if (cur_pattern->flags == BUS_MATCH_ANY) { 18198b8a9b1dSJustin T. Gibbs /* set the copy flag */ 18208b8a9b1dSJustin T. Gibbs retval |= DM_RET_COPY; 18218b8a9b1dSJustin T. Gibbs 18228b8a9b1dSJustin T. Gibbs /* 18238b8a9b1dSJustin T. Gibbs * If we've already decided on an action, go ahead 18248b8a9b1dSJustin T. Gibbs * and return. 18258b8a9b1dSJustin T. Gibbs */ 18268b8a9b1dSJustin T. Gibbs if ((retval & DM_RET_ACTION_MASK) != DM_RET_NONE) 18278b8a9b1dSJustin T. Gibbs return(retval); 18288b8a9b1dSJustin T. Gibbs } 18298b8a9b1dSJustin T. Gibbs 18308b8a9b1dSJustin T. Gibbs /* 18318b8a9b1dSJustin T. Gibbs * Not sure why someone would do this... 18328b8a9b1dSJustin T. Gibbs */ 18338b8a9b1dSJustin T. Gibbs if (cur_pattern->flags == BUS_MATCH_NONE) 18348b8a9b1dSJustin T. Gibbs continue; 18358b8a9b1dSJustin T. Gibbs 18368b8a9b1dSJustin T. Gibbs if (((cur_pattern->flags & BUS_MATCH_PATH) != 0) 18378b8a9b1dSJustin T. Gibbs && (cur_pattern->path_id != bus->path_id)) 18388b8a9b1dSJustin T. Gibbs continue; 18398b8a9b1dSJustin T. Gibbs 18408b8a9b1dSJustin T. Gibbs if (((cur_pattern->flags & BUS_MATCH_BUS_ID) != 0) 18418b8a9b1dSJustin T. Gibbs && (cur_pattern->bus_id != bus->sim->bus_id)) 18428b8a9b1dSJustin T. Gibbs continue; 18438b8a9b1dSJustin T. Gibbs 18448b8a9b1dSJustin T. Gibbs if (((cur_pattern->flags & BUS_MATCH_UNIT) != 0) 18458b8a9b1dSJustin T. Gibbs && (cur_pattern->unit_number != bus->sim->unit_number)) 18468b8a9b1dSJustin T. Gibbs continue; 18478b8a9b1dSJustin T. Gibbs 18488b8a9b1dSJustin T. Gibbs if (((cur_pattern->flags & BUS_MATCH_NAME) != 0) 18498b8a9b1dSJustin T. Gibbs && (strncmp(cur_pattern->dev_name, bus->sim->sim_name, 18508b8a9b1dSJustin T. Gibbs DEV_IDLEN) != 0)) 18518b8a9b1dSJustin T. Gibbs continue; 18528b8a9b1dSJustin T. Gibbs 18538b8a9b1dSJustin T. Gibbs /* 18548b8a9b1dSJustin T. Gibbs * If we get to this point, the user definitely wants 18558b8a9b1dSJustin T. Gibbs * information on this bus. So tell the caller to copy the 18568b8a9b1dSJustin T. Gibbs * data out. 18578b8a9b1dSJustin T. Gibbs */ 18588b8a9b1dSJustin T. Gibbs retval |= DM_RET_COPY; 18598b8a9b1dSJustin T. Gibbs 18608b8a9b1dSJustin T. Gibbs /* 18618b8a9b1dSJustin T. Gibbs * If the return action has been set to descend, then we 18628b8a9b1dSJustin T. Gibbs * know that we've already seen a non-bus matching 18638b8a9b1dSJustin T. Gibbs * expression, therefore we need to further descend the tree. 18648b8a9b1dSJustin T. Gibbs * This won't change by continuing around the loop, so we 18658b8a9b1dSJustin T. Gibbs * go ahead and return. If we haven't seen a non-bus 18668b8a9b1dSJustin T. Gibbs * matching expression, we keep going around the loop until 18678b8a9b1dSJustin T. Gibbs * we exhaust the matching expressions. We'll set the stop 18688b8a9b1dSJustin T. Gibbs * flag once we fall out of the loop. 18698b8a9b1dSJustin T. Gibbs */ 18708b8a9b1dSJustin T. Gibbs if ((retval & DM_RET_ACTION_MASK) == DM_RET_DESCEND) 18718b8a9b1dSJustin T. Gibbs return(retval); 18728b8a9b1dSJustin T. Gibbs } 18738b8a9b1dSJustin T. Gibbs 18748b8a9b1dSJustin T. Gibbs /* 18758b8a9b1dSJustin T. Gibbs * If the return action hasn't been set to descend yet, that means 18768b8a9b1dSJustin T. Gibbs * we haven't seen anything other than bus matching patterns. So 18778b8a9b1dSJustin T. Gibbs * tell the caller to stop descending the tree -- the user doesn't 18788b8a9b1dSJustin T. Gibbs * want to match against lower level tree elements. 18798b8a9b1dSJustin T. Gibbs */ 18808b8a9b1dSJustin T. Gibbs if ((retval & DM_RET_ACTION_MASK) == DM_RET_NONE) 18818b8a9b1dSJustin T. Gibbs retval |= DM_RET_STOP; 18828b8a9b1dSJustin T. Gibbs 18838b8a9b1dSJustin T. Gibbs return(retval); 18848b8a9b1dSJustin T. Gibbs } 18858b8a9b1dSJustin T. Gibbs 18868b8a9b1dSJustin T. Gibbs static dev_match_ret 18873393f8daSKenneth D. Merry xptdevicematch(struct dev_match_pattern *patterns, u_int num_patterns, 18888b8a9b1dSJustin T. Gibbs struct cam_ed *device) 18898b8a9b1dSJustin T. Gibbs { 18908b8a9b1dSJustin T. Gibbs dev_match_ret retval; 18918b8a9b1dSJustin T. Gibbs int i; 18928b8a9b1dSJustin T. Gibbs 18938b8a9b1dSJustin T. Gibbs retval = DM_RET_NONE; 18948b8a9b1dSJustin T. Gibbs 18958b8a9b1dSJustin T. Gibbs /* 18968b8a9b1dSJustin T. Gibbs * If we aren't given something to match against, that's an error. 18978b8a9b1dSJustin T. Gibbs */ 18988b8a9b1dSJustin T. Gibbs if (device == NULL) 18998b8a9b1dSJustin T. Gibbs return(DM_RET_ERROR); 19008b8a9b1dSJustin T. Gibbs 19018b8a9b1dSJustin T. Gibbs /* 19028b8a9b1dSJustin T. Gibbs * If there are no match entries, then this device matches no 19038b8a9b1dSJustin T. Gibbs * matter what. 19048b8a9b1dSJustin T. Gibbs */ 190559e75884SColin Percival if ((patterns == NULL) || (num_patterns == 0)) 19068b8a9b1dSJustin T. Gibbs return(DM_RET_DESCEND | DM_RET_COPY); 19078b8a9b1dSJustin T. Gibbs 19088b8a9b1dSJustin T. Gibbs for (i = 0; i < num_patterns; i++) { 19098b8a9b1dSJustin T. Gibbs struct device_match_pattern *cur_pattern; 19108b8a9b1dSJustin T. Gibbs 19118b8a9b1dSJustin T. Gibbs /* 19128b8a9b1dSJustin T. Gibbs * If the pattern in question isn't for a device node, we 19138b8a9b1dSJustin T. Gibbs * aren't interested. 19148b8a9b1dSJustin T. Gibbs */ 19158b8a9b1dSJustin T. Gibbs if (patterns[i].type != DEV_MATCH_DEVICE) { 19168b8a9b1dSJustin T. Gibbs if ((patterns[i].type == DEV_MATCH_PERIPH) 19178b8a9b1dSJustin T. Gibbs && ((retval & DM_RET_ACTION_MASK) == DM_RET_NONE)) 19188b8a9b1dSJustin T. Gibbs retval |= DM_RET_DESCEND; 19198b8a9b1dSJustin T. Gibbs continue; 19208b8a9b1dSJustin T. Gibbs } 19218b8a9b1dSJustin T. Gibbs 19228b8a9b1dSJustin T. Gibbs cur_pattern = &patterns[i].pattern.device_pattern; 19238b8a9b1dSJustin T. Gibbs 19248b8a9b1dSJustin T. Gibbs /* 19258b8a9b1dSJustin T. Gibbs * If they want to match any device node, we give them any 19268b8a9b1dSJustin T. Gibbs * device node. 19278b8a9b1dSJustin T. Gibbs */ 19288b8a9b1dSJustin T. Gibbs if (cur_pattern->flags == DEV_MATCH_ANY) { 19298b8a9b1dSJustin T. Gibbs /* set the copy flag */ 19308b8a9b1dSJustin T. Gibbs retval |= DM_RET_COPY; 19318b8a9b1dSJustin T. Gibbs 19328b8a9b1dSJustin T. Gibbs 19338b8a9b1dSJustin T. Gibbs /* 19348b8a9b1dSJustin T. Gibbs * If we've already decided on an action, go ahead 19358b8a9b1dSJustin T. Gibbs * and return. 19368b8a9b1dSJustin T. Gibbs */ 19378b8a9b1dSJustin T. Gibbs if ((retval & DM_RET_ACTION_MASK) != DM_RET_NONE) 19388b8a9b1dSJustin T. Gibbs return(retval); 19398b8a9b1dSJustin T. Gibbs } 19408b8a9b1dSJustin T. Gibbs 19418b8a9b1dSJustin T. Gibbs /* 19428b8a9b1dSJustin T. Gibbs * Not sure why someone would do this... 19438b8a9b1dSJustin T. Gibbs */ 19448b8a9b1dSJustin T. Gibbs if (cur_pattern->flags == DEV_MATCH_NONE) 19458b8a9b1dSJustin T. Gibbs continue; 19468b8a9b1dSJustin T. Gibbs 19478b8a9b1dSJustin T. Gibbs if (((cur_pattern->flags & DEV_MATCH_PATH) != 0) 19488b8a9b1dSJustin T. Gibbs && (cur_pattern->path_id != device->target->bus->path_id)) 19498b8a9b1dSJustin T. Gibbs continue; 19508b8a9b1dSJustin T. Gibbs 19518b8a9b1dSJustin T. Gibbs if (((cur_pattern->flags & DEV_MATCH_TARGET) != 0) 19528b8a9b1dSJustin T. Gibbs && (cur_pattern->target_id != device->target->target_id)) 19538b8a9b1dSJustin T. Gibbs continue; 19548b8a9b1dSJustin T. Gibbs 19558b8a9b1dSJustin T. Gibbs if (((cur_pattern->flags & DEV_MATCH_LUN) != 0) 19568b8a9b1dSJustin T. Gibbs && (cur_pattern->target_lun != device->lun_id)) 19578b8a9b1dSJustin T. Gibbs continue; 19588b8a9b1dSJustin T. Gibbs 19598b8a9b1dSJustin T. Gibbs if (((cur_pattern->flags & DEV_MATCH_INQUIRY) != 0) 19608b8a9b1dSJustin T. Gibbs && (cam_quirkmatch((caddr_t)&device->inq_data, 19618b8a9b1dSJustin T. Gibbs (caddr_t)&cur_pattern->inq_pat, 19628b8a9b1dSJustin T. Gibbs 1, sizeof(cur_pattern->inq_pat), 19638b8a9b1dSJustin T. Gibbs scsi_static_inquiry_match) == NULL)) 19648b8a9b1dSJustin T. Gibbs continue; 19658b8a9b1dSJustin T. Gibbs 19668b8a9b1dSJustin T. Gibbs /* 19678b8a9b1dSJustin T. Gibbs * If we get to this point, the user definitely wants 19688b8a9b1dSJustin T. Gibbs * information on this device. So tell the caller to copy 19698b8a9b1dSJustin T. Gibbs * the data out. 19708b8a9b1dSJustin T. Gibbs */ 19718b8a9b1dSJustin T. Gibbs retval |= DM_RET_COPY; 19728b8a9b1dSJustin T. Gibbs 19738b8a9b1dSJustin T. Gibbs /* 19748b8a9b1dSJustin T. Gibbs * If the return action has been set to descend, then we 19758b8a9b1dSJustin T. Gibbs * know that we've already seen a peripheral matching 19768b8a9b1dSJustin T. Gibbs * expression, therefore we need to further descend the tree. 19778b8a9b1dSJustin T. Gibbs * This won't change by continuing around the loop, so we 19788b8a9b1dSJustin T. Gibbs * go ahead and return. If we haven't seen a peripheral 19798b8a9b1dSJustin T. Gibbs * matching expression, we keep going around the loop until 19808b8a9b1dSJustin T. Gibbs * we exhaust the matching expressions. We'll set the stop 19818b8a9b1dSJustin T. Gibbs * flag once we fall out of the loop. 19828b8a9b1dSJustin T. Gibbs */ 19838b8a9b1dSJustin T. Gibbs if ((retval & DM_RET_ACTION_MASK) == DM_RET_DESCEND) 19848b8a9b1dSJustin T. Gibbs return(retval); 19858b8a9b1dSJustin T. Gibbs } 19868b8a9b1dSJustin T. Gibbs 19878b8a9b1dSJustin T. Gibbs /* 19888b8a9b1dSJustin T. Gibbs * If the return action hasn't been set to descend yet, that means 19898b8a9b1dSJustin T. Gibbs * we haven't seen any peripheral matching patterns. So tell the 19908b8a9b1dSJustin T. Gibbs * caller to stop descending the tree -- the user doesn't want to 19918b8a9b1dSJustin T. Gibbs * match against lower level tree elements. 19928b8a9b1dSJustin T. Gibbs */ 19938b8a9b1dSJustin T. Gibbs if ((retval & DM_RET_ACTION_MASK) == DM_RET_NONE) 19948b8a9b1dSJustin T. Gibbs retval |= DM_RET_STOP; 19958b8a9b1dSJustin T. Gibbs 19968b8a9b1dSJustin T. Gibbs return(retval); 19978b8a9b1dSJustin T. Gibbs } 19988b8a9b1dSJustin T. Gibbs 19998b8a9b1dSJustin T. Gibbs /* 20008b8a9b1dSJustin T. Gibbs * Match a single peripheral against any number of match patterns. 20018b8a9b1dSJustin T. Gibbs */ 20028b8a9b1dSJustin T. Gibbs static dev_match_ret 20033393f8daSKenneth D. Merry xptperiphmatch(struct dev_match_pattern *patterns, u_int num_patterns, 20048b8a9b1dSJustin T. Gibbs struct cam_periph *periph) 20058b8a9b1dSJustin T. Gibbs { 20068b8a9b1dSJustin T. Gibbs dev_match_ret retval; 20078b8a9b1dSJustin T. Gibbs int i; 20088b8a9b1dSJustin T. Gibbs 20098b8a9b1dSJustin T. Gibbs /* 20108b8a9b1dSJustin T. Gibbs * If we aren't given something to match against, that's an error. 20118b8a9b1dSJustin T. Gibbs */ 20128b8a9b1dSJustin T. Gibbs if (periph == NULL) 20138b8a9b1dSJustin T. Gibbs return(DM_RET_ERROR); 20148b8a9b1dSJustin T. Gibbs 20158b8a9b1dSJustin T. Gibbs /* 20168b8a9b1dSJustin T. Gibbs * If there are no match entries, then this peripheral matches no 20178b8a9b1dSJustin T. Gibbs * matter what. 20188b8a9b1dSJustin T. Gibbs */ 20198b8a9b1dSJustin T. Gibbs if ((patterns == NULL) || (num_patterns == 0)) 20208b8a9b1dSJustin T. Gibbs return(DM_RET_STOP | DM_RET_COPY); 20218b8a9b1dSJustin T. Gibbs 20228b8a9b1dSJustin T. Gibbs /* 20238b8a9b1dSJustin T. Gibbs * There aren't any nodes below a peripheral node, so there's no 20248b8a9b1dSJustin T. Gibbs * reason to descend the tree any further. 20258b8a9b1dSJustin T. Gibbs */ 20268b8a9b1dSJustin T. Gibbs retval = DM_RET_STOP; 20278b8a9b1dSJustin T. Gibbs 20288b8a9b1dSJustin T. Gibbs for (i = 0; i < num_patterns; i++) { 20298b8a9b1dSJustin T. Gibbs struct periph_match_pattern *cur_pattern; 20308b8a9b1dSJustin T. Gibbs 20318b8a9b1dSJustin T. Gibbs /* 20328b8a9b1dSJustin T. Gibbs * If the pattern in question isn't for a peripheral, we 20338b8a9b1dSJustin T. Gibbs * aren't interested. 20348b8a9b1dSJustin T. Gibbs */ 20358b8a9b1dSJustin T. Gibbs if (patterns[i].type != DEV_MATCH_PERIPH) 20368b8a9b1dSJustin T. Gibbs continue; 20378b8a9b1dSJustin T. Gibbs 20388b8a9b1dSJustin T. Gibbs cur_pattern = &patterns[i].pattern.periph_pattern; 20398b8a9b1dSJustin T. Gibbs 20408b8a9b1dSJustin T. Gibbs /* 20418b8a9b1dSJustin T. Gibbs * If they want to match on anything, then we will do so. 20428b8a9b1dSJustin T. Gibbs */ 20438b8a9b1dSJustin T. Gibbs if (cur_pattern->flags == PERIPH_MATCH_ANY) { 20448b8a9b1dSJustin T. Gibbs /* set the copy flag */ 20458b8a9b1dSJustin T. Gibbs retval |= DM_RET_COPY; 20468b8a9b1dSJustin T. Gibbs 20478b8a9b1dSJustin T. Gibbs /* 20488b8a9b1dSJustin T. Gibbs * We've already set the return action to stop, 20498b8a9b1dSJustin T. Gibbs * since there are no nodes below peripherals in 20508b8a9b1dSJustin T. Gibbs * the tree. 20518b8a9b1dSJustin T. Gibbs */ 20528b8a9b1dSJustin T. Gibbs return(retval); 20538b8a9b1dSJustin T. Gibbs } 20548b8a9b1dSJustin T. Gibbs 20558b8a9b1dSJustin T. Gibbs /* 20568b8a9b1dSJustin T. Gibbs * Not sure why someone would do this... 20578b8a9b1dSJustin T. Gibbs */ 20588b8a9b1dSJustin T. Gibbs if (cur_pattern->flags == PERIPH_MATCH_NONE) 20598b8a9b1dSJustin T. Gibbs continue; 20608b8a9b1dSJustin T. Gibbs 20618b8a9b1dSJustin T. Gibbs if (((cur_pattern->flags & PERIPH_MATCH_PATH) != 0) 20628b8a9b1dSJustin T. Gibbs && (cur_pattern->path_id != periph->path->bus->path_id)) 20638b8a9b1dSJustin T. Gibbs continue; 20648b8a9b1dSJustin T. Gibbs 20658b8a9b1dSJustin T. Gibbs /* 20668b8a9b1dSJustin T. Gibbs * For the target and lun id's, we have to make sure the 20678b8a9b1dSJustin T. Gibbs * target and lun pointers aren't NULL. The xpt peripheral 20688b8a9b1dSJustin T. Gibbs * has a wildcard target and device. 20698b8a9b1dSJustin T. Gibbs */ 20708b8a9b1dSJustin T. Gibbs if (((cur_pattern->flags & PERIPH_MATCH_TARGET) != 0) 20718b8a9b1dSJustin T. Gibbs && ((periph->path->target == NULL) 20728b8a9b1dSJustin T. Gibbs ||(cur_pattern->target_id != periph->path->target->target_id))) 20738b8a9b1dSJustin T. Gibbs continue; 20748b8a9b1dSJustin T. Gibbs 20758b8a9b1dSJustin T. Gibbs if (((cur_pattern->flags & PERIPH_MATCH_LUN) != 0) 20768b8a9b1dSJustin T. Gibbs && ((periph->path->device == NULL) 20778b8a9b1dSJustin T. Gibbs || (cur_pattern->target_lun != periph->path->device->lun_id))) 20788b8a9b1dSJustin T. Gibbs continue; 20798b8a9b1dSJustin T. Gibbs 20808b8a9b1dSJustin T. Gibbs if (((cur_pattern->flags & PERIPH_MATCH_UNIT) != 0) 20818b8a9b1dSJustin T. Gibbs && (cur_pattern->unit_number != periph->unit_number)) 20828b8a9b1dSJustin T. Gibbs continue; 20838b8a9b1dSJustin T. Gibbs 20848b8a9b1dSJustin T. Gibbs if (((cur_pattern->flags & PERIPH_MATCH_NAME) != 0) 20858b8a9b1dSJustin T. Gibbs && (strncmp(cur_pattern->periph_name, periph->periph_name, 20868b8a9b1dSJustin T. Gibbs DEV_IDLEN) != 0)) 20878b8a9b1dSJustin T. Gibbs continue; 20888b8a9b1dSJustin T. Gibbs 20898b8a9b1dSJustin T. Gibbs /* 20908b8a9b1dSJustin T. Gibbs * If we get to this point, the user definitely wants 20918b8a9b1dSJustin T. Gibbs * information on this peripheral. So tell the caller to 20928b8a9b1dSJustin T. Gibbs * copy the data out. 20938b8a9b1dSJustin T. Gibbs */ 20948b8a9b1dSJustin T. Gibbs retval |= DM_RET_COPY; 20958b8a9b1dSJustin T. Gibbs 20968b8a9b1dSJustin T. Gibbs /* 20978b8a9b1dSJustin T. Gibbs * The return action has already been set to stop, since 20988b8a9b1dSJustin T. Gibbs * peripherals don't have any nodes below them in the EDT. 20998b8a9b1dSJustin T. Gibbs */ 21008b8a9b1dSJustin T. Gibbs return(retval); 21018b8a9b1dSJustin T. Gibbs } 21028b8a9b1dSJustin T. Gibbs 21038b8a9b1dSJustin T. Gibbs /* 21048b8a9b1dSJustin T. Gibbs * If we get to this point, the peripheral that was passed in 21058b8a9b1dSJustin T. Gibbs * doesn't match any of the patterns. 21068b8a9b1dSJustin T. Gibbs */ 21078b8a9b1dSJustin T. Gibbs return(retval); 21088b8a9b1dSJustin T. Gibbs } 21098b8a9b1dSJustin T. Gibbs 21108b8a9b1dSJustin T. Gibbs static int 21118b8a9b1dSJustin T. Gibbs xptedtbusfunc(struct cam_eb *bus, void *arg) 21128b8a9b1dSJustin T. Gibbs { 21138b8a9b1dSJustin T. Gibbs struct ccb_dev_match *cdm; 21148b8a9b1dSJustin T. Gibbs dev_match_ret retval; 21158b8a9b1dSJustin T. Gibbs 21168b8a9b1dSJustin T. Gibbs cdm = (struct ccb_dev_match *)arg; 21178b8a9b1dSJustin T. Gibbs 21188b8a9b1dSJustin T. Gibbs /* 21198b8a9b1dSJustin T. Gibbs * If our position is for something deeper in the tree, that means 21208b8a9b1dSJustin T. Gibbs * that we've already seen this node. So, we keep going down. 21218b8a9b1dSJustin T. Gibbs */ 21228b8a9b1dSJustin T. Gibbs if ((cdm->pos.position_type & CAM_DEV_POS_BUS) 21238b8a9b1dSJustin T. Gibbs && (cdm->pos.cookie.bus == bus) 21248b8a9b1dSJustin T. Gibbs && (cdm->pos.position_type & CAM_DEV_POS_TARGET) 21258b8a9b1dSJustin T. Gibbs && (cdm->pos.cookie.target != NULL)) 21268b8a9b1dSJustin T. Gibbs retval = DM_RET_DESCEND; 21278b8a9b1dSJustin T. Gibbs else 21288b8a9b1dSJustin T. Gibbs retval = xptbusmatch(cdm->patterns, cdm->num_patterns, bus); 21298b8a9b1dSJustin T. Gibbs 21308b8a9b1dSJustin T. Gibbs /* 21318b8a9b1dSJustin T. Gibbs * If we got an error, bail out of the search. 21328b8a9b1dSJustin T. Gibbs */ 21338b8a9b1dSJustin T. Gibbs if ((retval & DM_RET_ACTION_MASK) == DM_RET_ERROR) { 21348b8a9b1dSJustin T. Gibbs cdm->status = CAM_DEV_MATCH_ERROR; 21358b8a9b1dSJustin T. Gibbs return(0); 21368b8a9b1dSJustin T. Gibbs } 21378b8a9b1dSJustin T. Gibbs 21388b8a9b1dSJustin T. Gibbs /* 21398b8a9b1dSJustin T. Gibbs * If the copy flag is set, copy this bus out. 21408b8a9b1dSJustin T. Gibbs */ 21418b8a9b1dSJustin T. Gibbs if (retval & DM_RET_COPY) { 21428b8a9b1dSJustin T. Gibbs int spaceleft, j; 21438b8a9b1dSJustin T. Gibbs 21448b8a9b1dSJustin T. Gibbs spaceleft = cdm->match_buf_len - (cdm->num_matches * 21458b8a9b1dSJustin T. Gibbs sizeof(struct dev_match_result)); 21468b8a9b1dSJustin T. Gibbs 21478b8a9b1dSJustin T. Gibbs /* 21488b8a9b1dSJustin T. Gibbs * If we don't have enough space to put in another 21498b8a9b1dSJustin T. Gibbs * match result, save our position and tell the 21508b8a9b1dSJustin T. Gibbs * user there are more devices to check. 21518b8a9b1dSJustin T. Gibbs */ 21528b8a9b1dSJustin T. Gibbs if (spaceleft < sizeof(struct dev_match_result)) { 21538b8a9b1dSJustin T. Gibbs bzero(&cdm->pos, sizeof(cdm->pos)); 21548b8a9b1dSJustin T. Gibbs cdm->pos.position_type = 21558b8a9b1dSJustin T. Gibbs CAM_DEV_POS_EDT | CAM_DEV_POS_BUS; 21568b8a9b1dSJustin T. Gibbs 21578b8a9b1dSJustin T. Gibbs cdm->pos.cookie.bus = bus; 21588b8a9b1dSJustin T. Gibbs cdm->pos.generations[CAM_BUS_GENERATION]= 21598b8a9b1dSJustin T. Gibbs bus_generation; 21608b8a9b1dSJustin T. Gibbs cdm->status = CAM_DEV_MATCH_MORE; 21618b8a9b1dSJustin T. Gibbs return(0); 21628b8a9b1dSJustin T. Gibbs } 21638b8a9b1dSJustin T. Gibbs j = cdm->num_matches; 21648b8a9b1dSJustin T. Gibbs cdm->num_matches++; 21658b8a9b1dSJustin T. Gibbs cdm->matches[j].type = DEV_MATCH_BUS; 21668b8a9b1dSJustin T. Gibbs cdm->matches[j].result.bus_result.path_id = bus->path_id; 21678b8a9b1dSJustin T. Gibbs cdm->matches[j].result.bus_result.bus_id = bus->sim->bus_id; 21688b8a9b1dSJustin T. Gibbs cdm->matches[j].result.bus_result.unit_number = 21698b8a9b1dSJustin T. Gibbs bus->sim->unit_number; 21708b8a9b1dSJustin T. Gibbs strncpy(cdm->matches[j].result.bus_result.dev_name, 21718b8a9b1dSJustin T. Gibbs bus->sim->sim_name, DEV_IDLEN); 21728b8a9b1dSJustin T. Gibbs } 21738b8a9b1dSJustin T. Gibbs 21748b8a9b1dSJustin T. Gibbs /* 21758b8a9b1dSJustin T. Gibbs * If the user is only interested in busses, there's no 21768b8a9b1dSJustin T. Gibbs * reason to descend to the next level in the tree. 21778b8a9b1dSJustin T. Gibbs */ 21788b8a9b1dSJustin T. Gibbs if ((retval & DM_RET_ACTION_MASK) == DM_RET_STOP) 21798b8a9b1dSJustin T. Gibbs return(1); 21808b8a9b1dSJustin T. Gibbs 21818b8a9b1dSJustin T. Gibbs /* 21828b8a9b1dSJustin T. Gibbs * If there is a target generation recorded, check it to 21838b8a9b1dSJustin T. Gibbs * make sure the target list hasn't changed. 21848b8a9b1dSJustin T. Gibbs */ 21858b8a9b1dSJustin T. Gibbs if ((cdm->pos.position_type & CAM_DEV_POS_BUS) 21868b8a9b1dSJustin T. Gibbs && (bus == cdm->pos.cookie.bus) 21878b8a9b1dSJustin T. Gibbs && (cdm->pos.position_type & CAM_DEV_POS_TARGET) 21888b8a9b1dSJustin T. Gibbs && (cdm->pos.generations[CAM_TARGET_GENERATION] != 0) 21898b8a9b1dSJustin T. Gibbs && (cdm->pos.generations[CAM_TARGET_GENERATION] != 21908b8a9b1dSJustin T. Gibbs bus->generation)) { 21918b8a9b1dSJustin T. Gibbs cdm->status = CAM_DEV_MATCH_LIST_CHANGED; 21928b8a9b1dSJustin T. Gibbs return(0); 21938b8a9b1dSJustin T. Gibbs } 21948b8a9b1dSJustin T. Gibbs 21958b8a9b1dSJustin T. Gibbs if ((cdm->pos.position_type & CAM_DEV_POS_BUS) 21968b8a9b1dSJustin T. Gibbs && (cdm->pos.cookie.bus == bus) 21978b8a9b1dSJustin T. Gibbs && (cdm->pos.position_type & CAM_DEV_POS_TARGET) 21988b8a9b1dSJustin T. Gibbs && (cdm->pos.cookie.target != NULL)) 21998b8a9b1dSJustin T. Gibbs return(xpttargettraverse(bus, 22008b8a9b1dSJustin T. Gibbs (struct cam_et *)cdm->pos.cookie.target, 22018b8a9b1dSJustin T. Gibbs xptedttargetfunc, arg)); 22028b8a9b1dSJustin T. Gibbs else 22038b8a9b1dSJustin T. Gibbs return(xpttargettraverse(bus, NULL, xptedttargetfunc, arg)); 22048b8a9b1dSJustin T. Gibbs } 22058b8a9b1dSJustin T. Gibbs 22068b8a9b1dSJustin T. Gibbs static int 22078b8a9b1dSJustin T. Gibbs xptedttargetfunc(struct cam_et *target, void *arg) 22088b8a9b1dSJustin T. Gibbs { 22098b8a9b1dSJustin T. Gibbs struct ccb_dev_match *cdm; 22108b8a9b1dSJustin T. Gibbs 22118b8a9b1dSJustin T. Gibbs cdm = (struct ccb_dev_match *)arg; 22128b8a9b1dSJustin T. Gibbs 22138b8a9b1dSJustin T. Gibbs /* 22148b8a9b1dSJustin T. Gibbs * If there is a device list generation recorded, check it to 22158b8a9b1dSJustin T. Gibbs * make sure the device list hasn't changed. 22168b8a9b1dSJustin T. Gibbs */ 22178b8a9b1dSJustin T. Gibbs if ((cdm->pos.position_type & CAM_DEV_POS_BUS) 22188b8a9b1dSJustin T. Gibbs && (cdm->pos.cookie.bus == target->bus) 22198b8a9b1dSJustin T. Gibbs && (cdm->pos.position_type & CAM_DEV_POS_TARGET) 22208b8a9b1dSJustin T. Gibbs && (cdm->pos.cookie.target == target) 22218b8a9b1dSJustin T. Gibbs && (cdm->pos.position_type & CAM_DEV_POS_DEVICE) 22228b8a9b1dSJustin T. Gibbs && (cdm->pos.generations[CAM_DEV_GENERATION] != 0) 22238b8a9b1dSJustin T. Gibbs && (cdm->pos.generations[CAM_DEV_GENERATION] != 22248b8a9b1dSJustin T. Gibbs target->generation)) { 22258b8a9b1dSJustin T. Gibbs cdm->status = CAM_DEV_MATCH_LIST_CHANGED; 22268b8a9b1dSJustin T. Gibbs return(0); 22278b8a9b1dSJustin T. Gibbs } 22288b8a9b1dSJustin T. Gibbs 22298b8a9b1dSJustin T. Gibbs if ((cdm->pos.position_type & CAM_DEV_POS_BUS) 22308b8a9b1dSJustin T. Gibbs && (cdm->pos.cookie.bus == target->bus) 22318b8a9b1dSJustin T. Gibbs && (cdm->pos.position_type & CAM_DEV_POS_TARGET) 22328b8a9b1dSJustin T. Gibbs && (cdm->pos.cookie.target == target) 22338b8a9b1dSJustin T. Gibbs && (cdm->pos.position_type & CAM_DEV_POS_DEVICE) 22348b8a9b1dSJustin T. Gibbs && (cdm->pos.cookie.device != NULL)) 22358b8a9b1dSJustin T. Gibbs return(xptdevicetraverse(target, 22368b8a9b1dSJustin T. Gibbs (struct cam_ed *)cdm->pos.cookie.device, 22378b8a9b1dSJustin T. Gibbs xptedtdevicefunc, arg)); 22388b8a9b1dSJustin T. Gibbs else 22398b8a9b1dSJustin T. Gibbs return(xptdevicetraverse(target, NULL, xptedtdevicefunc, arg)); 22408b8a9b1dSJustin T. Gibbs } 22418b8a9b1dSJustin T. Gibbs 22428b8a9b1dSJustin T. Gibbs static int 22438b8a9b1dSJustin T. Gibbs xptedtdevicefunc(struct cam_ed *device, void *arg) 22448b8a9b1dSJustin T. Gibbs { 22458b8a9b1dSJustin T. Gibbs 22468b8a9b1dSJustin T. Gibbs struct ccb_dev_match *cdm; 22478b8a9b1dSJustin T. Gibbs dev_match_ret retval; 22488b8a9b1dSJustin T. Gibbs 22498b8a9b1dSJustin T. Gibbs cdm = (struct ccb_dev_match *)arg; 22508b8a9b1dSJustin T. Gibbs 22518b8a9b1dSJustin T. Gibbs /* 22528b8a9b1dSJustin T. Gibbs * If our position is for something deeper in the tree, that means 22538b8a9b1dSJustin T. Gibbs * that we've already seen this node. So, we keep going down. 22548b8a9b1dSJustin T. Gibbs */ 22558b8a9b1dSJustin T. Gibbs if ((cdm->pos.position_type & CAM_DEV_POS_DEVICE) 22568b8a9b1dSJustin T. Gibbs && (cdm->pos.cookie.device == device) 22578b8a9b1dSJustin T. Gibbs && (cdm->pos.position_type & CAM_DEV_POS_PERIPH) 22588b8a9b1dSJustin T. Gibbs && (cdm->pos.cookie.periph != NULL)) 22598b8a9b1dSJustin T. Gibbs retval = DM_RET_DESCEND; 22608b8a9b1dSJustin T. Gibbs else 22618b8a9b1dSJustin T. Gibbs retval = xptdevicematch(cdm->patterns, cdm->num_patterns, 22628b8a9b1dSJustin T. Gibbs device); 22638b8a9b1dSJustin T. Gibbs 22648b8a9b1dSJustin T. Gibbs if ((retval & DM_RET_ACTION_MASK) == DM_RET_ERROR) { 22658b8a9b1dSJustin T. Gibbs cdm->status = CAM_DEV_MATCH_ERROR; 22668b8a9b1dSJustin T. Gibbs return(0); 22678b8a9b1dSJustin T. Gibbs } 22688b8a9b1dSJustin T. Gibbs 22698b8a9b1dSJustin T. Gibbs /* 22708b8a9b1dSJustin T. Gibbs * If the copy flag is set, copy this device out. 22718b8a9b1dSJustin T. Gibbs */ 22728b8a9b1dSJustin T. Gibbs if (retval & DM_RET_COPY) { 22738b8a9b1dSJustin T. Gibbs int spaceleft, j; 22748b8a9b1dSJustin T. Gibbs 22758b8a9b1dSJustin T. Gibbs spaceleft = cdm->match_buf_len - (cdm->num_matches * 22768b8a9b1dSJustin T. Gibbs sizeof(struct dev_match_result)); 22778b8a9b1dSJustin T. Gibbs 22788b8a9b1dSJustin T. Gibbs /* 22798b8a9b1dSJustin T. Gibbs * If we don't have enough space to put in another 22808b8a9b1dSJustin T. Gibbs * match result, save our position and tell the 22818b8a9b1dSJustin T. Gibbs * user there are more devices to check. 22828b8a9b1dSJustin T. Gibbs */ 22838b8a9b1dSJustin T. Gibbs if (spaceleft < sizeof(struct dev_match_result)) { 22848b8a9b1dSJustin T. Gibbs bzero(&cdm->pos, sizeof(cdm->pos)); 22858b8a9b1dSJustin T. Gibbs cdm->pos.position_type = 22868b8a9b1dSJustin T. Gibbs CAM_DEV_POS_EDT | CAM_DEV_POS_BUS | 22878b8a9b1dSJustin T. Gibbs CAM_DEV_POS_TARGET | CAM_DEV_POS_DEVICE; 22888b8a9b1dSJustin T. Gibbs 22898b8a9b1dSJustin T. Gibbs cdm->pos.cookie.bus = device->target->bus; 22908b8a9b1dSJustin T. Gibbs cdm->pos.generations[CAM_BUS_GENERATION]= 22918b8a9b1dSJustin T. Gibbs bus_generation; 22928b8a9b1dSJustin T. Gibbs cdm->pos.cookie.target = device->target; 22938b8a9b1dSJustin T. Gibbs cdm->pos.generations[CAM_TARGET_GENERATION] = 22948b8a9b1dSJustin T. Gibbs device->target->bus->generation; 22958b8a9b1dSJustin T. Gibbs cdm->pos.cookie.device = device; 22968b8a9b1dSJustin T. Gibbs cdm->pos.generations[CAM_DEV_GENERATION] = 22978b8a9b1dSJustin T. Gibbs device->target->generation; 22988b8a9b1dSJustin T. Gibbs cdm->status = CAM_DEV_MATCH_MORE; 22998b8a9b1dSJustin T. Gibbs return(0); 23008b8a9b1dSJustin T. Gibbs } 23018b8a9b1dSJustin T. Gibbs j = cdm->num_matches; 23028b8a9b1dSJustin T. Gibbs cdm->num_matches++; 23038b8a9b1dSJustin T. Gibbs cdm->matches[j].type = DEV_MATCH_DEVICE; 23048b8a9b1dSJustin T. Gibbs cdm->matches[j].result.device_result.path_id = 23058b8a9b1dSJustin T. Gibbs device->target->bus->path_id; 23068b8a9b1dSJustin T. Gibbs cdm->matches[j].result.device_result.target_id = 23078b8a9b1dSJustin T. Gibbs device->target->target_id; 23088b8a9b1dSJustin T. Gibbs cdm->matches[j].result.device_result.target_lun = 23098b8a9b1dSJustin T. Gibbs device->lun_id; 23108b8a9b1dSJustin T. Gibbs bcopy(&device->inq_data, 23118b8a9b1dSJustin T. Gibbs &cdm->matches[j].result.device_result.inq_data, 23128b8a9b1dSJustin T. Gibbs sizeof(struct scsi_inquiry_data)); 23139deea857SKenneth D. Merry 23149deea857SKenneth D. Merry /* Let the user know whether this device is unconfigured */ 23159deea857SKenneth D. Merry if (device->flags & CAM_DEV_UNCONFIGURED) 23169deea857SKenneth D. Merry cdm->matches[j].result.device_result.flags = 23179deea857SKenneth D. Merry DEV_RESULT_UNCONFIGURED; 23189deea857SKenneth D. Merry else 23199deea857SKenneth D. Merry cdm->matches[j].result.device_result.flags = 23209deea857SKenneth D. Merry DEV_RESULT_NOFLAG; 23218b8a9b1dSJustin T. Gibbs } 23228b8a9b1dSJustin T. Gibbs 23238b8a9b1dSJustin T. Gibbs /* 23248b8a9b1dSJustin T. Gibbs * If the user isn't interested in peripherals, don't descend 23258b8a9b1dSJustin T. Gibbs * the tree any further. 23268b8a9b1dSJustin T. Gibbs */ 23278b8a9b1dSJustin T. Gibbs if ((retval & DM_RET_ACTION_MASK) == DM_RET_STOP) 23288b8a9b1dSJustin T. Gibbs return(1); 23298b8a9b1dSJustin T. Gibbs 23308b8a9b1dSJustin T. Gibbs /* 23318b8a9b1dSJustin T. Gibbs * If there is a peripheral list generation recorded, make sure 23328b8a9b1dSJustin T. Gibbs * it hasn't changed. 23338b8a9b1dSJustin T. Gibbs */ 23348b8a9b1dSJustin T. Gibbs if ((cdm->pos.position_type & CAM_DEV_POS_BUS) 23358b8a9b1dSJustin T. Gibbs && (device->target->bus == cdm->pos.cookie.bus) 23368b8a9b1dSJustin T. Gibbs && (cdm->pos.position_type & CAM_DEV_POS_TARGET) 23378b8a9b1dSJustin T. Gibbs && (device->target == cdm->pos.cookie.target) 23388b8a9b1dSJustin T. Gibbs && (cdm->pos.position_type & CAM_DEV_POS_DEVICE) 23398b8a9b1dSJustin T. Gibbs && (device == cdm->pos.cookie.device) 23408b8a9b1dSJustin T. Gibbs && (cdm->pos.position_type & CAM_DEV_POS_PERIPH) 23418b8a9b1dSJustin T. Gibbs && (cdm->pos.generations[CAM_PERIPH_GENERATION] != 0) 23428b8a9b1dSJustin T. Gibbs && (cdm->pos.generations[CAM_PERIPH_GENERATION] != 23438b8a9b1dSJustin T. Gibbs device->generation)){ 23448b8a9b1dSJustin T. Gibbs cdm->status = CAM_DEV_MATCH_LIST_CHANGED; 23458b8a9b1dSJustin T. Gibbs return(0); 23468b8a9b1dSJustin T. Gibbs } 23478b8a9b1dSJustin T. Gibbs 23488b8a9b1dSJustin T. Gibbs if ((cdm->pos.position_type & CAM_DEV_POS_BUS) 23498b8a9b1dSJustin T. Gibbs && (cdm->pos.cookie.bus == device->target->bus) 23508b8a9b1dSJustin T. Gibbs && (cdm->pos.position_type & CAM_DEV_POS_TARGET) 23518b8a9b1dSJustin T. Gibbs && (cdm->pos.cookie.target == device->target) 23528b8a9b1dSJustin T. Gibbs && (cdm->pos.position_type & CAM_DEV_POS_DEVICE) 23538b8a9b1dSJustin T. Gibbs && (cdm->pos.cookie.device == device) 23548b8a9b1dSJustin T. Gibbs && (cdm->pos.position_type & CAM_DEV_POS_PERIPH) 23558b8a9b1dSJustin T. Gibbs && (cdm->pos.cookie.periph != NULL)) 23568b8a9b1dSJustin T. Gibbs return(xptperiphtraverse(device, 23578b8a9b1dSJustin T. Gibbs (struct cam_periph *)cdm->pos.cookie.periph, 23588b8a9b1dSJustin T. Gibbs xptedtperiphfunc, arg)); 23598b8a9b1dSJustin T. Gibbs else 23608b8a9b1dSJustin T. Gibbs return(xptperiphtraverse(device, NULL, xptedtperiphfunc, arg)); 23618b8a9b1dSJustin T. Gibbs } 23628b8a9b1dSJustin T. Gibbs 23638b8a9b1dSJustin T. Gibbs static int 23648b8a9b1dSJustin T. Gibbs xptedtperiphfunc(struct cam_periph *periph, void *arg) 23658b8a9b1dSJustin T. Gibbs { 23668b8a9b1dSJustin T. Gibbs struct ccb_dev_match *cdm; 23678b8a9b1dSJustin T. Gibbs dev_match_ret retval; 23688b8a9b1dSJustin T. Gibbs 23698b8a9b1dSJustin T. Gibbs cdm = (struct ccb_dev_match *)arg; 23708b8a9b1dSJustin T. Gibbs 23718b8a9b1dSJustin T. Gibbs retval = xptperiphmatch(cdm->patterns, cdm->num_patterns, periph); 23728b8a9b1dSJustin T. Gibbs 23738b8a9b1dSJustin T. Gibbs if ((retval & DM_RET_ACTION_MASK) == DM_RET_ERROR) { 23748b8a9b1dSJustin T. Gibbs cdm->status = CAM_DEV_MATCH_ERROR; 23758b8a9b1dSJustin T. Gibbs return(0); 23768b8a9b1dSJustin T. Gibbs } 23778b8a9b1dSJustin T. Gibbs 23788b8a9b1dSJustin T. Gibbs /* 23798b8a9b1dSJustin T. Gibbs * If the copy flag is set, copy this peripheral out. 23808b8a9b1dSJustin T. Gibbs */ 23818b8a9b1dSJustin T. Gibbs if (retval & DM_RET_COPY) { 23828b8a9b1dSJustin T. Gibbs int spaceleft, j; 23838b8a9b1dSJustin T. Gibbs 23848b8a9b1dSJustin T. Gibbs spaceleft = cdm->match_buf_len - (cdm->num_matches * 23858b8a9b1dSJustin T. Gibbs sizeof(struct dev_match_result)); 23868b8a9b1dSJustin T. Gibbs 23878b8a9b1dSJustin T. Gibbs /* 23888b8a9b1dSJustin T. Gibbs * If we don't have enough space to put in another 23898b8a9b1dSJustin T. Gibbs * match result, save our position and tell the 23908b8a9b1dSJustin T. Gibbs * user there are more devices to check. 23918b8a9b1dSJustin T. Gibbs */ 23928b8a9b1dSJustin T. Gibbs if (spaceleft < sizeof(struct dev_match_result)) { 23938b8a9b1dSJustin T. Gibbs bzero(&cdm->pos, sizeof(cdm->pos)); 23948b8a9b1dSJustin T. Gibbs cdm->pos.position_type = 23958b8a9b1dSJustin T. Gibbs CAM_DEV_POS_EDT | CAM_DEV_POS_BUS | 23968b8a9b1dSJustin T. Gibbs CAM_DEV_POS_TARGET | CAM_DEV_POS_DEVICE | 23978b8a9b1dSJustin T. Gibbs CAM_DEV_POS_PERIPH; 23988b8a9b1dSJustin T. Gibbs 23998b8a9b1dSJustin T. Gibbs cdm->pos.cookie.bus = periph->path->bus; 24008b8a9b1dSJustin T. Gibbs cdm->pos.generations[CAM_BUS_GENERATION]= 24018b8a9b1dSJustin T. Gibbs bus_generation; 24028b8a9b1dSJustin T. Gibbs cdm->pos.cookie.target = periph->path->target; 24038b8a9b1dSJustin T. Gibbs cdm->pos.generations[CAM_TARGET_GENERATION] = 24048b8a9b1dSJustin T. Gibbs periph->path->bus->generation; 24058b8a9b1dSJustin T. Gibbs cdm->pos.cookie.device = periph->path->device; 24068b8a9b1dSJustin T. Gibbs cdm->pos.generations[CAM_DEV_GENERATION] = 24078b8a9b1dSJustin T. Gibbs periph->path->target->generation; 24088b8a9b1dSJustin T. Gibbs cdm->pos.cookie.periph = periph; 24098b8a9b1dSJustin T. Gibbs cdm->pos.generations[CAM_PERIPH_GENERATION] = 24108b8a9b1dSJustin T. Gibbs periph->path->device->generation; 24118b8a9b1dSJustin T. Gibbs cdm->status = CAM_DEV_MATCH_MORE; 24128b8a9b1dSJustin T. Gibbs return(0); 24138b8a9b1dSJustin T. Gibbs } 24148b8a9b1dSJustin T. Gibbs 24158b8a9b1dSJustin T. Gibbs j = cdm->num_matches; 24168b8a9b1dSJustin T. Gibbs cdm->num_matches++; 24178b8a9b1dSJustin T. Gibbs cdm->matches[j].type = DEV_MATCH_PERIPH; 24188b8a9b1dSJustin T. Gibbs cdm->matches[j].result.periph_result.path_id = 24198b8a9b1dSJustin T. Gibbs periph->path->bus->path_id; 24208b8a9b1dSJustin T. Gibbs cdm->matches[j].result.periph_result.target_id = 24218b8a9b1dSJustin T. Gibbs periph->path->target->target_id; 24228b8a9b1dSJustin T. Gibbs cdm->matches[j].result.periph_result.target_lun = 24238b8a9b1dSJustin T. Gibbs periph->path->device->lun_id; 24248b8a9b1dSJustin T. Gibbs cdm->matches[j].result.periph_result.unit_number = 24258b8a9b1dSJustin T. Gibbs periph->unit_number; 24268b8a9b1dSJustin T. Gibbs strncpy(cdm->matches[j].result.periph_result.periph_name, 24278b8a9b1dSJustin T. Gibbs periph->periph_name, DEV_IDLEN); 24288b8a9b1dSJustin T. Gibbs } 24298b8a9b1dSJustin T. Gibbs 24308b8a9b1dSJustin T. Gibbs return(1); 24318b8a9b1dSJustin T. Gibbs } 24328b8a9b1dSJustin T. Gibbs 24338b8a9b1dSJustin T. Gibbs static int 24348b8a9b1dSJustin T. Gibbs xptedtmatch(struct ccb_dev_match *cdm) 24358b8a9b1dSJustin T. Gibbs { 24368b8a9b1dSJustin T. Gibbs int ret; 24378b8a9b1dSJustin T. Gibbs 24388b8a9b1dSJustin T. Gibbs cdm->num_matches = 0; 24398b8a9b1dSJustin T. Gibbs 24408b8a9b1dSJustin T. Gibbs /* 24418b8a9b1dSJustin T. Gibbs * Check the bus list generation. If it has changed, the user 24428b8a9b1dSJustin T. Gibbs * needs to reset everything and start over. 24438b8a9b1dSJustin T. Gibbs */ 24448b8a9b1dSJustin T. Gibbs if ((cdm->pos.position_type & CAM_DEV_POS_BUS) 24458b8a9b1dSJustin T. Gibbs && (cdm->pos.generations[CAM_BUS_GENERATION] != 0) 24468b8a9b1dSJustin T. Gibbs && (cdm->pos.generations[CAM_BUS_GENERATION] != bus_generation)) { 24478b8a9b1dSJustin T. Gibbs cdm->status = CAM_DEV_MATCH_LIST_CHANGED; 24488b8a9b1dSJustin T. Gibbs return(0); 24498b8a9b1dSJustin T. Gibbs } 24508b8a9b1dSJustin T. Gibbs 24518b8a9b1dSJustin T. Gibbs if ((cdm->pos.position_type & CAM_DEV_POS_BUS) 24528b8a9b1dSJustin T. Gibbs && (cdm->pos.cookie.bus != NULL)) 24538b8a9b1dSJustin T. Gibbs ret = xptbustraverse((struct cam_eb *)cdm->pos.cookie.bus, 24548b8a9b1dSJustin T. Gibbs xptedtbusfunc, cdm); 24558b8a9b1dSJustin T. Gibbs else 24568b8a9b1dSJustin T. Gibbs ret = xptbustraverse(NULL, xptedtbusfunc, cdm); 24578b8a9b1dSJustin T. Gibbs 24588b8a9b1dSJustin T. Gibbs /* 24598b8a9b1dSJustin T. Gibbs * If we get back 0, that means that we had to stop before fully 24608b8a9b1dSJustin T. Gibbs * traversing the EDT. It also means that one of the subroutines 24618b8a9b1dSJustin T. Gibbs * has set the status field to the proper value. If we get back 1, 24628b8a9b1dSJustin T. Gibbs * we've fully traversed the EDT and copied out any matching entries. 24638b8a9b1dSJustin T. Gibbs */ 24648b8a9b1dSJustin T. Gibbs if (ret == 1) 24658b8a9b1dSJustin T. Gibbs cdm->status = CAM_DEV_MATCH_LAST; 24668b8a9b1dSJustin T. Gibbs 24678b8a9b1dSJustin T. Gibbs return(ret); 24688b8a9b1dSJustin T. Gibbs } 24698b8a9b1dSJustin T. Gibbs 24708b8a9b1dSJustin T. Gibbs static int 24718b8a9b1dSJustin T. Gibbs xptplistpdrvfunc(struct periph_driver **pdrv, void *arg) 24728b8a9b1dSJustin T. Gibbs { 24738b8a9b1dSJustin T. Gibbs struct ccb_dev_match *cdm; 24748b8a9b1dSJustin T. Gibbs 24758b8a9b1dSJustin T. Gibbs cdm = (struct ccb_dev_match *)arg; 24768b8a9b1dSJustin T. Gibbs 24778b8a9b1dSJustin T. Gibbs if ((cdm->pos.position_type & CAM_DEV_POS_PDPTR) 24788b8a9b1dSJustin T. Gibbs && (cdm->pos.cookie.pdrv == pdrv) 24798b8a9b1dSJustin T. Gibbs && (cdm->pos.position_type & CAM_DEV_POS_PERIPH) 24808b8a9b1dSJustin T. Gibbs && (cdm->pos.generations[CAM_PERIPH_GENERATION] != 0) 24818b8a9b1dSJustin T. Gibbs && (cdm->pos.generations[CAM_PERIPH_GENERATION] != 24828b8a9b1dSJustin T. Gibbs (*pdrv)->generation)) { 24838b8a9b1dSJustin T. Gibbs cdm->status = CAM_DEV_MATCH_LIST_CHANGED; 24848b8a9b1dSJustin T. Gibbs return(0); 24858b8a9b1dSJustin T. Gibbs } 24868b8a9b1dSJustin T. Gibbs 24878b8a9b1dSJustin T. Gibbs if ((cdm->pos.position_type & CAM_DEV_POS_PDPTR) 24888b8a9b1dSJustin T. Gibbs && (cdm->pos.cookie.pdrv == pdrv) 24898b8a9b1dSJustin T. Gibbs && (cdm->pos.position_type & CAM_DEV_POS_PERIPH) 24908b8a9b1dSJustin T. Gibbs && (cdm->pos.cookie.periph != NULL)) 24918b8a9b1dSJustin T. Gibbs return(xptpdperiphtraverse(pdrv, 24928b8a9b1dSJustin T. Gibbs (struct cam_periph *)cdm->pos.cookie.periph, 24938b8a9b1dSJustin T. Gibbs xptplistperiphfunc, arg)); 24948b8a9b1dSJustin T. Gibbs else 24958b8a9b1dSJustin T. Gibbs return(xptpdperiphtraverse(pdrv, NULL,xptplistperiphfunc, arg)); 24968b8a9b1dSJustin T. Gibbs } 24978b8a9b1dSJustin T. Gibbs 24988b8a9b1dSJustin T. Gibbs static int 24998b8a9b1dSJustin T. Gibbs xptplistperiphfunc(struct cam_periph *periph, void *arg) 25008b8a9b1dSJustin T. Gibbs { 25018b8a9b1dSJustin T. Gibbs struct ccb_dev_match *cdm; 25028b8a9b1dSJustin T. Gibbs dev_match_ret retval; 25038b8a9b1dSJustin T. Gibbs 25048b8a9b1dSJustin T. Gibbs cdm = (struct ccb_dev_match *)arg; 25058b8a9b1dSJustin T. Gibbs 25068b8a9b1dSJustin T. Gibbs retval = xptperiphmatch(cdm->patterns, cdm->num_patterns, periph); 25078b8a9b1dSJustin T. Gibbs 25088b8a9b1dSJustin T. Gibbs if ((retval & DM_RET_ACTION_MASK) == DM_RET_ERROR) { 25098b8a9b1dSJustin T. Gibbs cdm->status = CAM_DEV_MATCH_ERROR; 25108b8a9b1dSJustin T. Gibbs return(0); 25118b8a9b1dSJustin T. Gibbs } 25128b8a9b1dSJustin T. Gibbs 25138b8a9b1dSJustin T. Gibbs /* 25148b8a9b1dSJustin T. Gibbs * If the copy flag is set, copy this peripheral out. 25158b8a9b1dSJustin T. Gibbs */ 25168b8a9b1dSJustin T. Gibbs if (retval & DM_RET_COPY) { 25178b8a9b1dSJustin T. Gibbs int spaceleft, j; 25188b8a9b1dSJustin T. Gibbs 25198b8a9b1dSJustin T. Gibbs spaceleft = cdm->match_buf_len - (cdm->num_matches * 25208b8a9b1dSJustin T. Gibbs sizeof(struct dev_match_result)); 25218b8a9b1dSJustin T. Gibbs 25228b8a9b1dSJustin T. Gibbs /* 25238b8a9b1dSJustin T. Gibbs * If we don't have enough space to put in another 25248b8a9b1dSJustin T. Gibbs * match result, save our position and tell the 25258b8a9b1dSJustin T. Gibbs * user there are more devices to check. 25268b8a9b1dSJustin T. Gibbs */ 25278b8a9b1dSJustin T. Gibbs if (spaceleft < sizeof(struct dev_match_result)) { 25288b8a9b1dSJustin T. Gibbs struct periph_driver **pdrv; 25298b8a9b1dSJustin T. Gibbs 25308b8a9b1dSJustin T. Gibbs pdrv = NULL; 25318b8a9b1dSJustin T. Gibbs bzero(&cdm->pos, sizeof(cdm->pos)); 25328b8a9b1dSJustin T. Gibbs cdm->pos.position_type = 25338b8a9b1dSJustin T. Gibbs CAM_DEV_POS_PDRV | CAM_DEV_POS_PDPTR | 25348b8a9b1dSJustin T. Gibbs CAM_DEV_POS_PERIPH; 25358b8a9b1dSJustin T. Gibbs 25368b8a9b1dSJustin T. Gibbs /* 25378b8a9b1dSJustin T. Gibbs * This may look a bit non-sensical, but it is 25388b8a9b1dSJustin T. Gibbs * actually quite logical. There are very few 25398b8a9b1dSJustin T. Gibbs * peripheral drivers, and bloating every peripheral 25408b8a9b1dSJustin T. Gibbs * structure with a pointer back to its parent 25418b8a9b1dSJustin T. Gibbs * peripheral driver linker set entry would cost 25428b8a9b1dSJustin T. Gibbs * more in the long run than doing this quick lookup. 25438b8a9b1dSJustin T. Gibbs */ 25440b7c27b9SPeter Wemm for (pdrv = periph_drivers; *pdrv != NULL; pdrv++) { 25458b8a9b1dSJustin T. Gibbs if (strcmp((*pdrv)->driver_name, 25468b8a9b1dSJustin T. Gibbs periph->periph_name) == 0) 25478b8a9b1dSJustin T. Gibbs break; 25488b8a9b1dSJustin T. Gibbs } 25498b8a9b1dSJustin T. Gibbs 255001910babSScott Long if (*pdrv == NULL) { 25518b8a9b1dSJustin T. Gibbs cdm->status = CAM_DEV_MATCH_ERROR; 25528b8a9b1dSJustin T. Gibbs return(0); 25538b8a9b1dSJustin T. Gibbs } 25548b8a9b1dSJustin T. Gibbs 25558b8a9b1dSJustin T. Gibbs cdm->pos.cookie.pdrv = pdrv; 25568b8a9b1dSJustin T. Gibbs /* 25578b8a9b1dSJustin T. Gibbs * The periph generation slot does double duty, as 25588b8a9b1dSJustin T. Gibbs * does the periph pointer slot. They are used for 25598b8a9b1dSJustin T. Gibbs * both edt and pdrv lookups and positioning. 25608b8a9b1dSJustin T. Gibbs */ 25618b8a9b1dSJustin T. Gibbs cdm->pos.cookie.periph = periph; 25628b8a9b1dSJustin T. Gibbs cdm->pos.generations[CAM_PERIPH_GENERATION] = 25638b8a9b1dSJustin T. Gibbs (*pdrv)->generation; 25648b8a9b1dSJustin T. Gibbs cdm->status = CAM_DEV_MATCH_MORE; 25658b8a9b1dSJustin T. Gibbs return(0); 25668b8a9b1dSJustin T. Gibbs } 25678b8a9b1dSJustin T. Gibbs 25688b8a9b1dSJustin T. Gibbs j = cdm->num_matches; 25698b8a9b1dSJustin T. Gibbs cdm->num_matches++; 25708b8a9b1dSJustin T. Gibbs cdm->matches[j].type = DEV_MATCH_PERIPH; 25718b8a9b1dSJustin T. Gibbs cdm->matches[j].result.periph_result.path_id = 25728b8a9b1dSJustin T. Gibbs periph->path->bus->path_id; 25738b8a9b1dSJustin T. Gibbs 25748b8a9b1dSJustin T. Gibbs /* 25758b8a9b1dSJustin T. Gibbs * The transport layer peripheral doesn't have a target or 25768b8a9b1dSJustin T. Gibbs * lun. 25778b8a9b1dSJustin T. Gibbs */ 25788b8a9b1dSJustin T. Gibbs if (periph->path->target) 25798b8a9b1dSJustin T. Gibbs cdm->matches[j].result.periph_result.target_id = 25808b8a9b1dSJustin T. Gibbs periph->path->target->target_id; 25818b8a9b1dSJustin T. Gibbs else 25828b8a9b1dSJustin T. Gibbs cdm->matches[j].result.periph_result.target_id = -1; 25838b8a9b1dSJustin T. Gibbs 25848b8a9b1dSJustin T. Gibbs if (periph->path->device) 25858b8a9b1dSJustin T. Gibbs cdm->matches[j].result.periph_result.target_lun = 25868b8a9b1dSJustin T. Gibbs periph->path->device->lun_id; 25878b8a9b1dSJustin T. Gibbs else 25888b8a9b1dSJustin T. Gibbs cdm->matches[j].result.periph_result.target_lun = -1; 25898b8a9b1dSJustin T. Gibbs 25908b8a9b1dSJustin T. Gibbs cdm->matches[j].result.periph_result.unit_number = 25918b8a9b1dSJustin T. Gibbs periph->unit_number; 25928b8a9b1dSJustin T. Gibbs strncpy(cdm->matches[j].result.periph_result.periph_name, 25938b8a9b1dSJustin T. Gibbs periph->periph_name, DEV_IDLEN); 25948b8a9b1dSJustin T. Gibbs } 25958b8a9b1dSJustin T. Gibbs 25968b8a9b1dSJustin T. Gibbs return(1); 25978b8a9b1dSJustin T. Gibbs } 25988b8a9b1dSJustin T. Gibbs 25998b8a9b1dSJustin T. Gibbs static int 26008b8a9b1dSJustin T. Gibbs xptperiphlistmatch(struct ccb_dev_match *cdm) 26018b8a9b1dSJustin T. Gibbs { 26028b8a9b1dSJustin T. Gibbs int ret; 26038b8a9b1dSJustin T. Gibbs 26048b8a9b1dSJustin T. Gibbs cdm->num_matches = 0; 26058b8a9b1dSJustin T. Gibbs 26068b8a9b1dSJustin T. Gibbs /* 26078b8a9b1dSJustin T. Gibbs * At this point in the edt traversal function, we check the bus 26088b8a9b1dSJustin T. Gibbs * list generation to make sure that no busses have been added or 26098b8a9b1dSJustin T. Gibbs * removed since the user last sent a XPT_DEV_MATCH ccb through. 26108b8a9b1dSJustin T. Gibbs * For the peripheral driver list traversal function, however, we 26118b8a9b1dSJustin T. Gibbs * don't have to worry about new peripheral driver types coming or 26128b8a9b1dSJustin T. Gibbs * going; they're in a linker set, and therefore can't change 26138b8a9b1dSJustin T. Gibbs * without a recompile. 26148b8a9b1dSJustin T. Gibbs */ 26158b8a9b1dSJustin T. Gibbs 26168b8a9b1dSJustin T. Gibbs if ((cdm->pos.position_type & CAM_DEV_POS_PDPTR) 26178b8a9b1dSJustin T. Gibbs && (cdm->pos.cookie.pdrv != NULL)) 26188b8a9b1dSJustin T. Gibbs ret = xptpdrvtraverse( 26198b8a9b1dSJustin T. Gibbs (struct periph_driver **)cdm->pos.cookie.pdrv, 26208b8a9b1dSJustin T. Gibbs xptplistpdrvfunc, cdm); 26218b8a9b1dSJustin T. Gibbs else 26228b8a9b1dSJustin T. Gibbs ret = xptpdrvtraverse(NULL, xptplistpdrvfunc, cdm); 26238b8a9b1dSJustin T. Gibbs 26248b8a9b1dSJustin T. Gibbs /* 26258b8a9b1dSJustin T. Gibbs * If we get back 0, that means that we had to stop before fully 26268b8a9b1dSJustin T. Gibbs * traversing the peripheral driver tree. It also means that one of 26278b8a9b1dSJustin T. Gibbs * the subroutines has set the status field to the proper value. If 26288b8a9b1dSJustin T. Gibbs * we get back 1, we've fully traversed the EDT and copied out any 26298b8a9b1dSJustin T. Gibbs * matching entries. 26308b8a9b1dSJustin T. Gibbs */ 26318b8a9b1dSJustin T. Gibbs if (ret == 1) 26328b8a9b1dSJustin T. Gibbs cdm->status = CAM_DEV_MATCH_LAST; 26338b8a9b1dSJustin T. Gibbs 26348b8a9b1dSJustin T. Gibbs return(ret); 26358b8a9b1dSJustin T. Gibbs } 26368b8a9b1dSJustin T. Gibbs 26378b8a9b1dSJustin T. Gibbs static int 26388b8a9b1dSJustin T. Gibbs xptbustraverse(struct cam_eb *start_bus, xpt_busfunc_t *tr_func, void *arg) 26398b8a9b1dSJustin T. Gibbs { 26408b8a9b1dSJustin T. Gibbs struct cam_eb *bus, *next_bus; 26418b8a9b1dSJustin T. Gibbs int retval; 26428b8a9b1dSJustin T. Gibbs 26438b8a9b1dSJustin T. Gibbs retval = 1; 26448b8a9b1dSJustin T. Gibbs 26458b8a9b1dSJustin T. Gibbs for (bus = (start_bus ? start_bus : TAILQ_FIRST(&xpt_busses)); 26468b8a9b1dSJustin T. Gibbs bus != NULL; 26478b8a9b1dSJustin T. Gibbs bus = next_bus) { 26488b8a9b1dSJustin T. Gibbs next_bus = TAILQ_NEXT(bus, links); 26498b8a9b1dSJustin T. Gibbs 26508b8a9b1dSJustin T. Gibbs retval = tr_func(bus, arg); 26518b8a9b1dSJustin T. Gibbs if (retval == 0) 26528b8a9b1dSJustin T. Gibbs return(retval); 26538b8a9b1dSJustin T. Gibbs } 26548b8a9b1dSJustin T. Gibbs 26558b8a9b1dSJustin T. Gibbs return(retval); 26568b8a9b1dSJustin T. Gibbs } 26578b8a9b1dSJustin T. Gibbs 26588b8a9b1dSJustin T. Gibbs static int 26598b8a9b1dSJustin T. Gibbs xpttargettraverse(struct cam_eb *bus, struct cam_et *start_target, 26608b8a9b1dSJustin T. Gibbs xpt_targetfunc_t *tr_func, void *arg) 26618b8a9b1dSJustin T. Gibbs { 26628b8a9b1dSJustin T. Gibbs struct cam_et *target, *next_target; 26638b8a9b1dSJustin T. Gibbs int retval; 26648b8a9b1dSJustin T. Gibbs 26658b8a9b1dSJustin T. Gibbs retval = 1; 26668b8a9b1dSJustin T. Gibbs for (target = (start_target ? start_target : 26678b8a9b1dSJustin T. Gibbs TAILQ_FIRST(&bus->et_entries)); 26688b8a9b1dSJustin T. Gibbs target != NULL; target = next_target) { 26698b8a9b1dSJustin T. Gibbs 26708b8a9b1dSJustin T. Gibbs next_target = TAILQ_NEXT(target, links); 26718b8a9b1dSJustin T. Gibbs 26728b8a9b1dSJustin T. Gibbs retval = tr_func(target, arg); 26738b8a9b1dSJustin T. Gibbs 26748b8a9b1dSJustin T. Gibbs if (retval == 0) 26758b8a9b1dSJustin T. Gibbs return(retval); 26768b8a9b1dSJustin T. Gibbs } 26778b8a9b1dSJustin T. Gibbs 26788b8a9b1dSJustin T. Gibbs return(retval); 26798b8a9b1dSJustin T. Gibbs } 26808b8a9b1dSJustin T. Gibbs 26818b8a9b1dSJustin T. Gibbs static int 26828b8a9b1dSJustin T. Gibbs xptdevicetraverse(struct cam_et *target, struct cam_ed *start_device, 26838b8a9b1dSJustin T. Gibbs xpt_devicefunc_t *tr_func, void *arg) 26848b8a9b1dSJustin T. Gibbs { 26858b8a9b1dSJustin T. Gibbs struct cam_ed *device, *next_device; 26868b8a9b1dSJustin T. Gibbs int retval; 26878b8a9b1dSJustin T. Gibbs 26888b8a9b1dSJustin T. Gibbs retval = 1; 26898b8a9b1dSJustin T. Gibbs for (device = (start_device ? start_device : 26908b8a9b1dSJustin T. Gibbs TAILQ_FIRST(&target->ed_entries)); 26918b8a9b1dSJustin T. Gibbs device != NULL; 26928b8a9b1dSJustin T. Gibbs device = next_device) { 26938b8a9b1dSJustin T. Gibbs 26948b8a9b1dSJustin T. Gibbs next_device = TAILQ_NEXT(device, links); 26958b8a9b1dSJustin T. Gibbs 26968b8a9b1dSJustin T. Gibbs retval = tr_func(device, arg); 26978b8a9b1dSJustin T. Gibbs 26988b8a9b1dSJustin T. Gibbs if (retval == 0) 26998b8a9b1dSJustin T. Gibbs return(retval); 27008b8a9b1dSJustin T. Gibbs } 27018b8a9b1dSJustin T. Gibbs 27028b8a9b1dSJustin T. Gibbs return(retval); 27038b8a9b1dSJustin T. Gibbs } 27048b8a9b1dSJustin T. Gibbs 27058b8a9b1dSJustin T. Gibbs static int 27068b8a9b1dSJustin T. Gibbs xptperiphtraverse(struct cam_ed *device, struct cam_periph *start_periph, 27078b8a9b1dSJustin T. Gibbs xpt_periphfunc_t *tr_func, void *arg) 27088b8a9b1dSJustin T. Gibbs { 27098b8a9b1dSJustin T. Gibbs struct cam_periph *periph, *next_periph; 27108b8a9b1dSJustin T. Gibbs int retval; 27118b8a9b1dSJustin T. Gibbs 27128b8a9b1dSJustin T. Gibbs retval = 1; 27138b8a9b1dSJustin T. Gibbs 27148b8a9b1dSJustin T. Gibbs for (periph = (start_periph ? start_periph : 27158b8a9b1dSJustin T. Gibbs SLIST_FIRST(&device->periphs)); 27168b8a9b1dSJustin T. Gibbs periph != NULL; 27178b8a9b1dSJustin T. Gibbs periph = next_periph) { 27188b8a9b1dSJustin T. Gibbs 27198b8a9b1dSJustin T. Gibbs next_periph = SLIST_NEXT(periph, periph_links); 27208b8a9b1dSJustin T. Gibbs 27218b8a9b1dSJustin T. Gibbs retval = tr_func(periph, arg); 27228b8a9b1dSJustin T. Gibbs if (retval == 0) 27238b8a9b1dSJustin T. Gibbs return(retval); 27248b8a9b1dSJustin T. Gibbs } 27258b8a9b1dSJustin T. Gibbs 27268b8a9b1dSJustin T. Gibbs return(retval); 27278b8a9b1dSJustin T. Gibbs } 27288b8a9b1dSJustin T. Gibbs 27298b8a9b1dSJustin T. Gibbs static int 27308b8a9b1dSJustin T. Gibbs xptpdrvtraverse(struct periph_driver **start_pdrv, 27318b8a9b1dSJustin T. Gibbs xpt_pdrvfunc_t *tr_func, void *arg) 27328b8a9b1dSJustin T. Gibbs { 27338b8a9b1dSJustin T. Gibbs struct periph_driver **pdrv; 27348b8a9b1dSJustin T. Gibbs int retval; 27358b8a9b1dSJustin T. Gibbs 27368b8a9b1dSJustin T. Gibbs retval = 1; 27378b8a9b1dSJustin T. Gibbs 27388b8a9b1dSJustin T. Gibbs /* 27398b8a9b1dSJustin T. Gibbs * We don't traverse the peripheral driver list like we do the 27408b8a9b1dSJustin T. Gibbs * other lists, because it is a linker set, and therefore cannot be 27418b8a9b1dSJustin T. Gibbs * changed during runtime. If the peripheral driver list is ever 27428b8a9b1dSJustin T. Gibbs * re-done to be something other than a linker set (i.e. it can 27438b8a9b1dSJustin T. Gibbs * change while the system is running), the list traversal should 27448b8a9b1dSJustin T. Gibbs * be modified to work like the other traversal functions. 27458b8a9b1dSJustin T. Gibbs */ 27460b7c27b9SPeter Wemm for (pdrv = (start_pdrv ? start_pdrv : periph_drivers); 27478b8a9b1dSJustin T. Gibbs *pdrv != NULL; pdrv++) { 27488b8a9b1dSJustin T. Gibbs retval = tr_func(pdrv, arg); 27498b8a9b1dSJustin T. Gibbs 27508b8a9b1dSJustin T. Gibbs if (retval == 0) 27518b8a9b1dSJustin T. Gibbs return(retval); 27528b8a9b1dSJustin T. Gibbs } 27538b8a9b1dSJustin T. Gibbs 27548b8a9b1dSJustin T. Gibbs return(retval); 27558b8a9b1dSJustin T. Gibbs } 27568b8a9b1dSJustin T. Gibbs 27578b8a9b1dSJustin T. Gibbs static int 27588b8a9b1dSJustin T. Gibbs xptpdperiphtraverse(struct periph_driver **pdrv, 27598b8a9b1dSJustin T. Gibbs struct cam_periph *start_periph, 27608b8a9b1dSJustin T. Gibbs xpt_periphfunc_t *tr_func, void *arg) 27618b8a9b1dSJustin T. Gibbs { 27628b8a9b1dSJustin T. Gibbs struct cam_periph *periph, *next_periph; 27638b8a9b1dSJustin T. Gibbs int retval; 27648b8a9b1dSJustin T. Gibbs 27658b8a9b1dSJustin T. Gibbs retval = 1; 27668b8a9b1dSJustin T. Gibbs 27678b8a9b1dSJustin T. Gibbs for (periph = (start_periph ? start_periph : 27688b8a9b1dSJustin T. Gibbs TAILQ_FIRST(&(*pdrv)->units)); periph != NULL; 27698b8a9b1dSJustin T. Gibbs periph = next_periph) { 27708b8a9b1dSJustin T. Gibbs 27718b8a9b1dSJustin T. Gibbs next_periph = TAILQ_NEXT(periph, unit_links); 27728b8a9b1dSJustin T. Gibbs 27738b8a9b1dSJustin T. Gibbs retval = tr_func(periph, arg); 27748b8a9b1dSJustin T. Gibbs if (retval == 0) 27758b8a9b1dSJustin T. Gibbs return(retval); 27768b8a9b1dSJustin T. Gibbs } 27778b8a9b1dSJustin T. Gibbs return(retval); 27788b8a9b1dSJustin T. Gibbs } 27798b8a9b1dSJustin T. Gibbs 27808b8a9b1dSJustin T. Gibbs static int 27818b8a9b1dSJustin T. Gibbs xptdefbusfunc(struct cam_eb *bus, void *arg) 27828b8a9b1dSJustin T. Gibbs { 27838b8a9b1dSJustin T. Gibbs struct xpt_traverse_config *tr_config; 27848b8a9b1dSJustin T. Gibbs 27858b8a9b1dSJustin T. Gibbs tr_config = (struct xpt_traverse_config *)arg; 27868b8a9b1dSJustin T. Gibbs 27878b8a9b1dSJustin T. Gibbs if (tr_config->depth == XPT_DEPTH_BUS) { 27888b8a9b1dSJustin T. Gibbs xpt_busfunc_t *tr_func; 27898b8a9b1dSJustin T. Gibbs 27908b8a9b1dSJustin T. Gibbs tr_func = (xpt_busfunc_t *)tr_config->tr_func; 27918b8a9b1dSJustin T. Gibbs 27928b8a9b1dSJustin T. Gibbs return(tr_func(bus, tr_config->tr_arg)); 27938b8a9b1dSJustin T. Gibbs } else 27948b8a9b1dSJustin T. Gibbs return(xpttargettraverse(bus, NULL, xptdeftargetfunc, arg)); 27958b8a9b1dSJustin T. Gibbs } 27968b8a9b1dSJustin T. Gibbs 27978b8a9b1dSJustin T. Gibbs static int 27988b8a9b1dSJustin T. Gibbs xptdeftargetfunc(struct cam_et *target, void *arg) 27998b8a9b1dSJustin T. Gibbs { 28008b8a9b1dSJustin T. Gibbs struct xpt_traverse_config *tr_config; 28018b8a9b1dSJustin T. Gibbs 28028b8a9b1dSJustin T. Gibbs tr_config = (struct xpt_traverse_config *)arg; 28038b8a9b1dSJustin T. Gibbs 28048b8a9b1dSJustin T. Gibbs if (tr_config->depth == XPT_DEPTH_TARGET) { 28058b8a9b1dSJustin T. Gibbs xpt_targetfunc_t *tr_func; 28068b8a9b1dSJustin T. Gibbs 28078b8a9b1dSJustin T. Gibbs tr_func = (xpt_targetfunc_t *)tr_config->tr_func; 28088b8a9b1dSJustin T. Gibbs 28098b8a9b1dSJustin T. Gibbs return(tr_func(target, tr_config->tr_arg)); 28108b8a9b1dSJustin T. Gibbs } else 28118b8a9b1dSJustin T. Gibbs return(xptdevicetraverse(target, NULL, xptdefdevicefunc, arg)); 28128b8a9b1dSJustin T. Gibbs } 28138b8a9b1dSJustin T. Gibbs 28148b8a9b1dSJustin T. Gibbs static int 28158b8a9b1dSJustin T. Gibbs xptdefdevicefunc(struct cam_ed *device, void *arg) 28168b8a9b1dSJustin T. Gibbs { 28178b8a9b1dSJustin T. Gibbs struct xpt_traverse_config *tr_config; 28188b8a9b1dSJustin T. Gibbs 28198b8a9b1dSJustin T. Gibbs tr_config = (struct xpt_traverse_config *)arg; 28208b8a9b1dSJustin T. Gibbs 28218b8a9b1dSJustin T. Gibbs if (tr_config->depth == XPT_DEPTH_DEVICE) { 28228b8a9b1dSJustin T. Gibbs xpt_devicefunc_t *tr_func; 28238b8a9b1dSJustin T. Gibbs 28248b8a9b1dSJustin T. Gibbs tr_func = (xpt_devicefunc_t *)tr_config->tr_func; 28258b8a9b1dSJustin T. Gibbs 28268b8a9b1dSJustin T. Gibbs return(tr_func(device, tr_config->tr_arg)); 28278b8a9b1dSJustin T. Gibbs } else 28288b8a9b1dSJustin T. Gibbs return(xptperiphtraverse(device, NULL, xptdefperiphfunc, arg)); 28298b8a9b1dSJustin T. Gibbs } 28308b8a9b1dSJustin T. Gibbs 28318b8a9b1dSJustin T. Gibbs static int 28328b8a9b1dSJustin T. Gibbs xptdefperiphfunc(struct cam_periph *periph, void *arg) 28338b8a9b1dSJustin T. Gibbs { 28348b8a9b1dSJustin T. Gibbs struct xpt_traverse_config *tr_config; 28358b8a9b1dSJustin T. Gibbs xpt_periphfunc_t *tr_func; 28368b8a9b1dSJustin T. Gibbs 28378b8a9b1dSJustin T. Gibbs tr_config = (struct xpt_traverse_config *)arg; 28388b8a9b1dSJustin T. Gibbs 28398b8a9b1dSJustin T. Gibbs tr_func = (xpt_periphfunc_t *)tr_config->tr_func; 28408b8a9b1dSJustin T. Gibbs 28418b8a9b1dSJustin T. Gibbs /* 28428b8a9b1dSJustin T. Gibbs * Unlike the other default functions, we don't check for depth 28438b8a9b1dSJustin T. Gibbs * here. The peripheral driver level is the last level in the EDT, 28448b8a9b1dSJustin T. Gibbs * so if we're here, we should execute the function in question. 28458b8a9b1dSJustin T. Gibbs */ 28468b8a9b1dSJustin T. Gibbs return(tr_func(periph, tr_config->tr_arg)); 28478b8a9b1dSJustin T. Gibbs } 28488b8a9b1dSJustin T. Gibbs 28498b8a9b1dSJustin T. Gibbs /* 28508b8a9b1dSJustin T. Gibbs * Execute the given function for every bus in the EDT. 28518b8a9b1dSJustin T. Gibbs */ 28528b8a9b1dSJustin T. Gibbs static int 28538b8a9b1dSJustin T. Gibbs xpt_for_all_busses(xpt_busfunc_t *tr_func, void *arg) 28548b8a9b1dSJustin T. Gibbs { 28558b8a9b1dSJustin T. Gibbs struct xpt_traverse_config tr_config; 28568b8a9b1dSJustin T. Gibbs 28578b8a9b1dSJustin T. Gibbs tr_config.depth = XPT_DEPTH_BUS; 28588b8a9b1dSJustin T. Gibbs tr_config.tr_func = tr_func; 28598b8a9b1dSJustin T. Gibbs tr_config.tr_arg = arg; 28608b8a9b1dSJustin T. Gibbs 28618b8a9b1dSJustin T. Gibbs return(xptbustraverse(NULL, xptdefbusfunc, &tr_config)); 28628b8a9b1dSJustin T. Gibbs } 28638b8a9b1dSJustin T. Gibbs 2864bfc0eb0fSKenneth D. Merry #ifdef notusedyet 28658b8a9b1dSJustin T. Gibbs /* 28668b8a9b1dSJustin T. Gibbs * Execute the given function for every target in the EDT. 28678b8a9b1dSJustin T. Gibbs */ 28688b8a9b1dSJustin T. Gibbs static int 28698b8a9b1dSJustin T. Gibbs xpt_for_all_targets(xpt_targetfunc_t *tr_func, void *arg) 28708b8a9b1dSJustin T. Gibbs { 28718b8a9b1dSJustin T. Gibbs struct xpt_traverse_config tr_config; 28728b8a9b1dSJustin T. Gibbs 28738b8a9b1dSJustin T. Gibbs tr_config.depth = XPT_DEPTH_TARGET; 28748b8a9b1dSJustin T. Gibbs tr_config.tr_func = tr_func; 28758b8a9b1dSJustin T. Gibbs tr_config.tr_arg = arg; 28768b8a9b1dSJustin T. Gibbs 28778b8a9b1dSJustin T. Gibbs return(xptbustraverse(NULL, xptdefbusfunc, &tr_config)); 28788b8a9b1dSJustin T. Gibbs } 2879bfc0eb0fSKenneth D. Merry #endif /* notusedyet */ 28808b8a9b1dSJustin T. Gibbs 28818b8a9b1dSJustin T. Gibbs /* 28828b8a9b1dSJustin T. Gibbs * Execute the given function for every device in the EDT. 28838b8a9b1dSJustin T. Gibbs */ 28848b8a9b1dSJustin T. Gibbs static int 28858b8a9b1dSJustin T. Gibbs xpt_for_all_devices(xpt_devicefunc_t *tr_func, void *arg) 28868b8a9b1dSJustin T. Gibbs { 28878b8a9b1dSJustin T. Gibbs struct xpt_traverse_config tr_config; 28888b8a9b1dSJustin T. Gibbs 28898b8a9b1dSJustin T. Gibbs tr_config.depth = XPT_DEPTH_DEVICE; 28908b8a9b1dSJustin T. Gibbs tr_config.tr_func = tr_func; 28918b8a9b1dSJustin T. Gibbs tr_config.tr_arg = arg; 28928b8a9b1dSJustin T. Gibbs 28938b8a9b1dSJustin T. Gibbs return(xptbustraverse(NULL, xptdefbusfunc, &tr_config)); 28948b8a9b1dSJustin T. Gibbs } 28958b8a9b1dSJustin T. Gibbs 2896bfc0eb0fSKenneth D. Merry #ifdef notusedyet 28978b8a9b1dSJustin T. Gibbs /* 28988b8a9b1dSJustin T. Gibbs * Execute the given function for every peripheral in the EDT. 28998b8a9b1dSJustin T. Gibbs */ 29008b8a9b1dSJustin T. Gibbs static int 29018b8a9b1dSJustin T. Gibbs xpt_for_all_periphs(xpt_periphfunc_t *tr_func, void *arg) 29028b8a9b1dSJustin T. Gibbs { 29038b8a9b1dSJustin T. Gibbs struct xpt_traverse_config tr_config; 29048b8a9b1dSJustin T. Gibbs 29058b8a9b1dSJustin T. Gibbs tr_config.depth = XPT_DEPTH_PERIPH; 29068b8a9b1dSJustin T. Gibbs tr_config.tr_func = tr_func; 29078b8a9b1dSJustin T. Gibbs tr_config.tr_arg = arg; 29088b8a9b1dSJustin T. Gibbs 29098b8a9b1dSJustin T. Gibbs return(xptbustraverse(NULL, xptdefbusfunc, &tr_config)); 29108b8a9b1dSJustin T. Gibbs } 2911bfc0eb0fSKenneth D. Merry #endif /* notusedyet */ 29128b8a9b1dSJustin T. Gibbs 29138b8a9b1dSJustin T. Gibbs static int 29148b8a9b1dSJustin T. Gibbs xptsetasyncfunc(struct cam_ed *device, void *arg) 29158b8a9b1dSJustin T. Gibbs { 29168b8a9b1dSJustin T. Gibbs struct cam_path path; 29178b8a9b1dSJustin T. Gibbs struct ccb_getdev cgd; 29188b8a9b1dSJustin T. Gibbs struct async_node *cur_entry; 29198b8a9b1dSJustin T. Gibbs 29208b8a9b1dSJustin T. Gibbs cur_entry = (struct async_node *)arg; 29218b8a9b1dSJustin T. Gibbs 2922c8bead2aSJustin T. Gibbs /* 2923c8bead2aSJustin T. Gibbs * Don't report unconfigured devices (Wildcard devs, 2924c8bead2aSJustin T. Gibbs * devices only for target mode, device instances 2925c8bead2aSJustin T. Gibbs * that have been invalidated but are waiting for 2926c8bead2aSJustin T. Gibbs * their last reference count to be released). 2927c8bead2aSJustin T. Gibbs */ 2928c8bead2aSJustin T. Gibbs if ((device->flags & CAM_DEV_UNCONFIGURED) != 0) 2929c8bead2aSJustin T. Gibbs return (1); 2930c8bead2aSJustin T. Gibbs 29318b8a9b1dSJustin T. Gibbs xpt_compile_path(&path, 29328b8a9b1dSJustin T. Gibbs NULL, 29338b8a9b1dSJustin T. Gibbs device->target->bus->path_id, 29348b8a9b1dSJustin T. Gibbs device->target->target_id, 29358b8a9b1dSJustin T. Gibbs device->lun_id); 29368b8a9b1dSJustin T. Gibbs xpt_setup_ccb(&cgd.ccb_h, &path, /*priority*/1); 29378b8a9b1dSJustin T. Gibbs cgd.ccb_h.func_code = XPT_GDEV_TYPE; 29388b8a9b1dSJustin T. Gibbs xpt_action((union ccb *)&cgd); 29398b8a9b1dSJustin T. Gibbs cur_entry->callback(cur_entry->callback_arg, 29408b8a9b1dSJustin T. Gibbs AC_FOUND_DEVICE, 29418b8a9b1dSJustin T. Gibbs &path, &cgd); 29428b8a9b1dSJustin T. Gibbs xpt_release_path(&path); 29438b8a9b1dSJustin T. Gibbs 29448b8a9b1dSJustin T. Gibbs return(1); 29458b8a9b1dSJustin T. Gibbs } 2946c8bead2aSJustin T. Gibbs 29478b8a9b1dSJustin T. Gibbs static int 29488b8a9b1dSJustin T. Gibbs xptsetasyncbusfunc(struct cam_eb *bus, void *arg) 29498b8a9b1dSJustin T. Gibbs { 29508b8a9b1dSJustin T. Gibbs struct cam_path path; 29518b8a9b1dSJustin T. Gibbs struct ccb_pathinq cpi; 29528b8a9b1dSJustin T. Gibbs struct async_node *cur_entry; 29538b8a9b1dSJustin T. Gibbs 29548b8a9b1dSJustin T. Gibbs cur_entry = (struct async_node *)arg; 29558b8a9b1dSJustin T. Gibbs 29568b8a9b1dSJustin T. Gibbs xpt_compile_path(&path, /*periph*/NULL, 29578b8a9b1dSJustin T. Gibbs bus->sim->path_id, 29588b8a9b1dSJustin T. Gibbs CAM_TARGET_WILDCARD, 29598b8a9b1dSJustin T. Gibbs CAM_LUN_WILDCARD); 29608b8a9b1dSJustin T. Gibbs xpt_setup_ccb(&cpi.ccb_h, &path, /*priority*/1); 29618b8a9b1dSJustin T. Gibbs cpi.ccb_h.func_code = XPT_PATH_INQ; 29628b8a9b1dSJustin T. Gibbs xpt_action((union ccb *)&cpi); 29638b8a9b1dSJustin T. Gibbs cur_entry->callback(cur_entry->callback_arg, 29648b8a9b1dSJustin T. Gibbs AC_PATH_REGISTERED, 29658b8a9b1dSJustin T. Gibbs &path, &cpi); 29668b8a9b1dSJustin T. Gibbs xpt_release_path(&path); 29678b8a9b1dSJustin T. Gibbs 29688b8a9b1dSJustin T. Gibbs return(1); 29698b8a9b1dSJustin T. Gibbs } 29708b8a9b1dSJustin T. Gibbs 29718b8a9b1dSJustin T. Gibbs void 29728b8a9b1dSJustin T. Gibbs xpt_action(union ccb *start_ccb) 29738b8a9b1dSJustin T. Gibbs { 29749911ecf9SJustin T. Gibbs int iopl; 29759911ecf9SJustin T. Gibbs 297668153f43SScott Long GIANT_REQUIRED; 297768153f43SScott Long 29788b8a9b1dSJustin T. Gibbs CAM_DEBUG(start_ccb->ccb_h.path, CAM_DEBUG_TRACE, ("xpt_action\n")); 29798b8a9b1dSJustin T. Gibbs 29808b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.status = CAM_REQ_INPROG; 29818b8a9b1dSJustin T. Gibbs 29829911ecf9SJustin T. Gibbs iopl = splsoftcam(); 29838b8a9b1dSJustin T. Gibbs switch (start_ccb->ccb_h.func_code) { 29848b8a9b1dSJustin T. Gibbs case XPT_SCSI_IO: 2985d05caa00SKenneth D. Merry { 29863393f8daSKenneth D. Merry #ifdef CAM_NEW_TRAN_CODE 29873393f8daSKenneth D. Merry struct cam_ed *device; 29883393f8daSKenneth D. Merry #endif /* CAM_NEW_TRAN_CODE */ 2989d05caa00SKenneth D. Merry #ifdef CAMDEBUG 2990d05caa00SKenneth D. Merry char cdb_str[(SCSI_MAX_CDBLEN * 3) + 1]; 2991d05caa00SKenneth D. Merry struct cam_path *path; 2992d05caa00SKenneth D. Merry 2993d05caa00SKenneth D. Merry path = start_ccb->ccb_h.path; 2994d05caa00SKenneth D. Merry #endif 2995d05caa00SKenneth D. Merry 29968b8a9b1dSJustin T. Gibbs /* 29978b8a9b1dSJustin T. Gibbs * For the sake of compatibility with SCSI-1 29988b8a9b1dSJustin T. Gibbs * devices that may not understand the identify 29998b8a9b1dSJustin T. Gibbs * message, we include lun information in the 30008b8a9b1dSJustin T. Gibbs * second byte of all commands. SCSI-1 specifies 30018b8a9b1dSJustin T. Gibbs * that luns are a 3 bit value and reserves only 3 30028b8a9b1dSJustin T. Gibbs * bits for lun information in the CDB. Later 30038b8a9b1dSJustin T. Gibbs * revisions of the SCSI spec allow for more than 8 30048b8a9b1dSJustin T. Gibbs * luns, but have deprecated lun information in the 30058b8a9b1dSJustin T. Gibbs * CDB. So, if the lun won't fit, we must omit. 30068b8a9b1dSJustin T. Gibbs * 30078b8a9b1dSJustin T. Gibbs * Also be aware that during initial probing for devices, 30088b8a9b1dSJustin T. Gibbs * the inquiry information is unknown but initialized to 0. 30098b8a9b1dSJustin T. Gibbs * This means that this code will be exercised while probing 30108b8a9b1dSJustin T. Gibbs * devices with an ANSI revision greater than 2. 30118b8a9b1dSJustin T. Gibbs */ 30123393f8daSKenneth D. Merry #ifdef CAM_NEW_TRAN_CODE 30133393f8daSKenneth D. Merry device = start_ccb->ccb_h.path->device; 30143393f8daSKenneth D. Merry if (device->protocol_version <= SCSI_REV_2 30153393f8daSKenneth D. Merry #else /* CAM_NEW_TRAN_CODE */ 30168b8a9b1dSJustin T. Gibbs if (SID_ANSI_REV(&start_ccb->ccb_h.path->device->inq_data) <= 2 30173393f8daSKenneth D. Merry #endif /* CAM_NEW_TRAN_CODE */ 30188b8a9b1dSJustin T. Gibbs && start_ccb->ccb_h.target_lun < 8 30198b8a9b1dSJustin T. Gibbs && (start_ccb->ccb_h.flags & CAM_CDB_POINTER) == 0) { 30208b8a9b1dSJustin T. Gibbs 30218b8a9b1dSJustin T. Gibbs start_ccb->csio.cdb_io.cdb_bytes[1] |= 30228b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.target_lun << 5; 30238b8a9b1dSJustin T. Gibbs } 30248b8a9b1dSJustin T. Gibbs start_ccb->csio.scsi_status = SCSI_STATUS_OK; 3025d05caa00SKenneth D. Merry CAM_DEBUG(path, CAM_DEBUG_CDB,("%s. CDB: %s\n", 3026d05caa00SKenneth D. Merry scsi_op_desc(start_ccb->csio.cdb_io.cdb_bytes[0], 3027d05caa00SKenneth D. Merry &path->device->inq_data), 3028d05caa00SKenneth D. Merry scsi_cdb_string(start_ccb->csio.cdb_io.cdb_bytes, 302950642f18SKenneth D. Merry cdb_str, sizeof(cdb_str)))); 3030d05caa00SKenneth D. Merry } 303107c6eac9SPoul-Henning Kamp /* FALLTHROUGH */ 30328b8a9b1dSJustin T. Gibbs case XPT_TARGET_IO: 30338b8a9b1dSJustin T. Gibbs case XPT_CONT_TARGET_IO: 30342cefde5fSJustin T. Gibbs start_ccb->csio.sense_resid = 0; 30352cefde5fSJustin T. Gibbs start_ccb->csio.resid = 0; 30362cefde5fSJustin T. Gibbs /* FALLTHROUGH */ 303710e1cf63SKenneth D. Merry case XPT_RESET_DEV: 30388b8a9b1dSJustin T. Gibbs case XPT_ENG_EXEC: 30398b8a9b1dSJustin T. Gibbs { 30408b8a9b1dSJustin T. Gibbs struct cam_path *path; 30418b8a9b1dSJustin T. Gibbs int s; 30428b8a9b1dSJustin T. Gibbs int runq; 30438b8a9b1dSJustin T. Gibbs 30448b8a9b1dSJustin T. Gibbs path = start_ccb->ccb_h.path; 30458b8a9b1dSJustin T. Gibbs s = splsoftcam(); 30468b8a9b1dSJustin T. Gibbs 30478b8a9b1dSJustin T. Gibbs cam_ccbq_insert_ccb(&path->device->ccbq, start_ccb); 30488b8a9b1dSJustin T. Gibbs if (path->device->qfrozen_cnt == 0) 30498b8a9b1dSJustin T. Gibbs runq = xpt_schedule_dev_sendq(path->bus, path->device); 30508b8a9b1dSJustin T. Gibbs else 30518b8a9b1dSJustin T. Gibbs runq = 0; 30528b8a9b1dSJustin T. Gibbs splx(s); 30538b8a9b1dSJustin T. Gibbs if (runq != 0) 30548b8a9b1dSJustin T. Gibbs xpt_run_dev_sendq(path->bus); 30558b8a9b1dSJustin T. Gibbs break; 30568b8a9b1dSJustin T. Gibbs } 30578b8a9b1dSJustin T. Gibbs case XPT_SET_TRAN_SETTINGS: 30588b8a9b1dSJustin T. Gibbs { 30598b8a9b1dSJustin T. Gibbs xpt_set_transfer_settings(&start_ccb->cts, 306003e3511bSJustin T. Gibbs start_ccb->ccb_h.path->device, 30618b8a9b1dSJustin T. Gibbs /*async_update*/FALSE); 30628b8a9b1dSJustin T. Gibbs break; 30638b8a9b1dSJustin T. Gibbs } 30648b8a9b1dSJustin T. Gibbs case XPT_CALC_GEOMETRY: 30652cefde5fSJustin T. Gibbs { 30662cefde5fSJustin T. Gibbs struct cam_sim *sim; 30672cefde5fSJustin T. Gibbs 30688b8a9b1dSJustin T. Gibbs /* Filter out garbage */ 30698b8a9b1dSJustin T. Gibbs if (start_ccb->ccg.block_size == 0 30708b8a9b1dSJustin T. Gibbs || start_ccb->ccg.volume_size == 0) { 30718b8a9b1dSJustin T. Gibbs start_ccb->ccg.cylinders = 0; 30728b8a9b1dSJustin T. Gibbs start_ccb->ccg.heads = 0; 30738b8a9b1dSJustin T. Gibbs start_ccb->ccg.secs_per_track = 0; 30748b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.status = CAM_REQ_CMP; 30758b8a9b1dSJustin T. Gibbs break; 30768b8a9b1dSJustin T. Gibbs } 30778b8a9b1dSJustin T. Gibbs #ifdef PC98 30788b8a9b1dSJustin T. Gibbs /* 30798b8a9b1dSJustin T. Gibbs * In a PC-98 system, geometry translation depens on 30808b8a9b1dSJustin T. Gibbs * the "real" device geometry obtained from mode page 4. 30818b8a9b1dSJustin T. Gibbs * SCSI geometry translation is performed in the 30828b8a9b1dSJustin T. Gibbs * initialization routine of the SCSI BIOS and the result 30838b8a9b1dSJustin T. Gibbs * stored in host memory. If the translation is available 30848b8a9b1dSJustin T. Gibbs * in host memory, use it. If not, rely on the default 30858b8a9b1dSJustin T. Gibbs * translation the device driver performs. 30868b8a9b1dSJustin T. Gibbs */ 30878b8a9b1dSJustin T. Gibbs if (scsi_da_bios_params(&start_ccb->ccg) != 0) { 30888b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.status = CAM_REQ_CMP; 30898b8a9b1dSJustin T. Gibbs break; 30908b8a9b1dSJustin T. Gibbs } 30918b8a9b1dSJustin T. Gibbs #endif 30922cefde5fSJustin T. Gibbs sim = start_ccb->ccb_h.path->bus->sim; 30932cefde5fSJustin T. Gibbs (*(sim->sim_action))(sim, start_ccb); 30942cefde5fSJustin T. Gibbs break; 30952cefde5fSJustin T. Gibbs } 3096bb6087e5SJustin T. Gibbs case XPT_ABORT: 30972cefde5fSJustin T. Gibbs { 30982cefde5fSJustin T. Gibbs union ccb* abort_ccb; 30992cefde5fSJustin T. Gibbs int s; 31002cefde5fSJustin T. Gibbs 31012cefde5fSJustin T. Gibbs abort_ccb = start_ccb->cab.abort_ccb; 31022cefde5fSJustin T. Gibbs if (XPT_FC_IS_DEV_QUEUED(abort_ccb)) { 31032cefde5fSJustin T. Gibbs 31042cefde5fSJustin T. Gibbs if (abort_ccb->ccb_h.pinfo.index >= 0) { 31052cefde5fSJustin T. Gibbs struct cam_ccbq *ccbq; 31062cefde5fSJustin T. Gibbs 31072cefde5fSJustin T. Gibbs ccbq = &abort_ccb->ccb_h.path->device->ccbq; 31082cefde5fSJustin T. Gibbs cam_ccbq_remove_ccb(ccbq, abort_ccb); 31092cefde5fSJustin T. Gibbs abort_ccb->ccb_h.status = 31102cefde5fSJustin T. Gibbs CAM_REQ_ABORTED|CAM_DEV_QFRZN; 31112cefde5fSJustin T. Gibbs xpt_freeze_devq(abort_ccb->ccb_h.path, 1); 31122cefde5fSJustin T. Gibbs s = splcam(); 31132cefde5fSJustin T. Gibbs xpt_done(abort_ccb); 31142cefde5fSJustin T. Gibbs splx(s); 31152cefde5fSJustin T. Gibbs start_ccb->ccb_h.status = CAM_REQ_CMP; 31162cefde5fSJustin T. Gibbs break; 31172cefde5fSJustin T. Gibbs } 31182cefde5fSJustin T. Gibbs if (abort_ccb->ccb_h.pinfo.index == CAM_UNQUEUED_INDEX 31192cefde5fSJustin T. Gibbs && (abort_ccb->ccb_h.status & CAM_SIM_QUEUED) == 0) { 31202cefde5fSJustin T. Gibbs /* 31212cefde5fSJustin T. Gibbs * We've caught this ccb en route to 31222cefde5fSJustin T. Gibbs * the SIM. Flag it for abort and the 31232cefde5fSJustin T. Gibbs * SIM will do so just before starting 31242cefde5fSJustin T. Gibbs * real work on the CCB. 31252cefde5fSJustin T. Gibbs */ 31262cefde5fSJustin T. Gibbs abort_ccb->ccb_h.status = 31272cefde5fSJustin T. Gibbs CAM_REQ_ABORTED|CAM_DEV_QFRZN; 31282cefde5fSJustin T. Gibbs xpt_freeze_devq(abort_ccb->ccb_h.path, 1); 31292cefde5fSJustin T. Gibbs start_ccb->ccb_h.status = CAM_REQ_CMP; 31302cefde5fSJustin T. Gibbs break; 31312cefde5fSJustin T. Gibbs } 31322cefde5fSJustin T. Gibbs } 31332cefde5fSJustin T. Gibbs if (XPT_FC_IS_QUEUED(abort_ccb) 31342cefde5fSJustin T. Gibbs && (abort_ccb->ccb_h.pinfo.index == CAM_DONEQ_INDEX)) { 31352cefde5fSJustin T. Gibbs /* 31362cefde5fSJustin T. Gibbs * It's already completed but waiting 31372cefde5fSJustin T. Gibbs * for our SWI to get to it. 31382cefde5fSJustin T. Gibbs */ 31392cefde5fSJustin T. Gibbs start_ccb->ccb_h.status = CAM_UA_ABORT; 31402cefde5fSJustin T. Gibbs break; 31412cefde5fSJustin T. Gibbs } 31422cefde5fSJustin T. Gibbs /* 31432cefde5fSJustin T. Gibbs * If we weren't able to take care of the abort request 31442cefde5fSJustin T. Gibbs * in the XPT, pass the request down to the SIM for processing. 31452cefde5fSJustin T. Gibbs */ 31462cefde5fSJustin T. Gibbs } 314707c6eac9SPoul-Henning Kamp /* FALLTHROUGH */ 31488b8a9b1dSJustin T. Gibbs case XPT_ACCEPT_TARGET_IO: 31498b8a9b1dSJustin T. Gibbs case XPT_EN_LUN: 31508b8a9b1dSJustin T. Gibbs case XPT_IMMED_NOTIFY: 31518b8a9b1dSJustin T. Gibbs case XPT_NOTIFY_ACK: 31528b8a9b1dSJustin T. Gibbs case XPT_GET_TRAN_SETTINGS: 31538b8a9b1dSJustin T. Gibbs case XPT_RESET_BUS: 31548b8a9b1dSJustin T. Gibbs { 31558b8a9b1dSJustin T. Gibbs struct cam_sim *sim; 31568b8a9b1dSJustin T. Gibbs 31578b8a9b1dSJustin T. Gibbs sim = start_ccb->ccb_h.path->bus->sim; 31588b8a9b1dSJustin T. Gibbs (*(sim->sim_action))(sim, start_ccb); 31598b8a9b1dSJustin T. Gibbs break; 31608b8a9b1dSJustin T. Gibbs } 316187cfaf0eSJustin T. Gibbs case XPT_PATH_INQ: 316287cfaf0eSJustin T. Gibbs { 316387cfaf0eSJustin T. Gibbs struct cam_sim *sim; 316487cfaf0eSJustin T. Gibbs 316587cfaf0eSJustin T. Gibbs sim = start_ccb->ccb_h.path->bus->sim; 316687cfaf0eSJustin T. Gibbs (*(sim->sim_action))(sim, start_ccb); 316787cfaf0eSJustin T. Gibbs break; 316887cfaf0eSJustin T. Gibbs } 316987cfaf0eSJustin T. Gibbs case XPT_PATH_STATS: 317087cfaf0eSJustin T. Gibbs start_ccb->cpis.last_reset = 317187cfaf0eSJustin T. Gibbs start_ccb->ccb_h.path->bus->last_reset; 317287cfaf0eSJustin T. Gibbs start_ccb->ccb_h.status = CAM_REQ_CMP; 317387cfaf0eSJustin T. Gibbs break; 31748b8a9b1dSJustin T. Gibbs case XPT_GDEV_TYPE: 3175a5479bc5SJustin T. Gibbs { 317687cfaf0eSJustin T. Gibbs struct cam_ed *dev; 3177a5479bc5SJustin T. Gibbs int s; 3178a5479bc5SJustin T. Gibbs 317987cfaf0eSJustin T. Gibbs dev = start_ccb->ccb_h.path->device; 3180a5479bc5SJustin T. Gibbs s = splcam(); 318187cfaf0eSJustin T. Gibbs if ((dev->flags & CAM_DEV_UNCONFIGURED) != 0) { 31828b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.status = CAM_DEV_NOT_THERE; 31838b8a9b1dSJustin T. Gibbs } else { 31848b8a9b1dSJustin T. Gibbs struct ccb_getdev *cgd; 318587cfaf0eSJustin T. Gibbs struct cam_eb *bus; 31868b8a9b1dSJustin T. Gibbs struct cam_et *tar; 31878b8a9b1dSJustin T. Gibbs 31888b8a9b1dSJustin T. Gibbs cgd = &start_ccb->cgd; 318987cfaf0eSJustin T. Gibbs bus = cgd->ccb_h.path->bus; 31908b8a9b1dSJustin T. Gibbs tar = cgd->ccb_h.path->target; 31918b8a9b1dSJustin T. Gibbs cgd->inq_data = dev->inq_data; 31928b8a9b1dSJustin T. Gibbs cgd->ccb_h.status = CAM_REQ_CMP; 31938b8a9b1dSJustin T. Gibbs cgd->serial_num_len = dev->serial_num_len; 31948b8a9b1dSJustin T. Gibbs if ((dev->serial_num_len > 0) 31958b8a9b1dSJustin T. Gibbs && (dev->serial_num != NULL)) 31968b8a9b1dSJustin T. Gibbs bcopy(dev->serial_num, cgd->serial_num, 31978b8a9b1dSJustin T. Gibbs dev->serial_num_len); 31988b8a9b1dSJustin T. Gibbs } 3199a5479bc5SJustin T. Gibbs splx(s); 32008b8a9b1dSJustin T. Gibbs break; 3201a5479bc5SJustin T. Gibbs } 320287cfaf0eSJustin T. Gibbs case XPT_GDEV_STATS: 320387cfaf0eSJustin T. Gibbs { 320487cfaf0eSJustin T. Gibbs struct cam_ed *dev; 320587cfaf0eSJustin T. Gibbs int s; 320687cfaf0eSJustin T. Gibbs 320787cfaf0eSJustin T. Gibbs dev = start_ccb->ccb_h.path->device; 320887cfaf0eSJustin T. Gibbs s = splcam(); 320987cfaf0eSJustin T. Gibbs if ((dev->flags & CAM_DEV_UNCONFIGURED) != 0) { 321087cfaf0eSJustin T. Gibbs start_ccb->ccb_h.status = CAM_DEV_NOT_THERE; 321187cfaf0eSJustin T. Gibbs } else { 321287cfaf0eSJustin T. Gibbs struct ccb_getdevstats *cgds; 321387cfaf0eSJustin T. Gibbs struct cam_eb *bus; 321487cfaf0eSJustin T. Gibbs struct cam_et *tar; 321587cfaf0eSJustin T. Gibbs 321687cfaf0eSJustin T. Gibbs cgds = &start_ccb->cgds; 321787cfaf0eSJustin T. Gibbs bus = cgds->ccb_h.path->bus; 321887cfaf0eSJustin T. Gibbs tar = cgds->ccb_h.path->target; 321987cfaf0eSJustin T. Gibbs cgds->dev_openings = dev->ccbq.dev_openings; 322087cfaf0eSJustin T. Gibbs cgds->dev_active = dev->ccbq.dev_active; 322187cfaf0eSJustin T. Gibbs cgds->devq_openings = dev->ccbq.devq_openings; 322287cfaf0eSJustin T. Gibbs cgds->devq_queued = dev->ccbq.queue.entries; 322387cfaf0eSJustin T. Gibbs cgds->held = dev->ccbq.held; 322487cfaf0eSJustin T. Gibbs cgds->last_reset = tar->last_reset; 322582815562SJustin T. Gibbs cgds->maxtags = dev->quirk->maxtags; 322682815562SJustin T. Gibbs cgds->mintags = dev->quirk->mintags; 322787cfaf0eSJustin T. Gibbs if (timevalcmp(&tar->last_reset, &bus->last_reset, <)) 322887cfaf0eSJustin T. Gibbs cgds->last_reset = bus->last_reset; 322987cfaf0eSJustin T. Gibbs cgds->ccb_h.status = CAM_REQ_CMP; 323087cfaf0eSJustin T. Gibbs } 323187cfaf0eSJustin T. Gibbs splx(s); 323287cfaf0eSJustin T. Gibbs break; 323387cfaf0eSJustin T. Gibbs } 32348b8a9b1dSJustin T. Gibbs case XPT_GDEVLIST: 32358b8a9b1dSJustin T. Gibbs { 32368b8a9b1dSJustin T. Gibbs struct cam_periph *nperiph; 32378b8a9b1dSJustin T. Gibbs struct periph_list *periph_head; 32388b8a9b1dSJustin T. Gibbs struct ccb_getdevlist *cgdl; 32393393f8daSKenneth D. Merry u_int i; 32408b8a9b1dSJustin T. Gibbs int s; 32418b8a9b1dSJustin T. Gibbs struct cam_ed *device; 32428b8a9b1dSJustin T. Gibbs int found; 32438b8a9b1dSJustin T. Gibbs 32448b8a9b1dSJustin T. Gibbs 32458b8a9b1dSJustin T. Gibbs found = 0; 32468b8a9b1dSJustin T. Gibbs 32478b8a9b1dSJustin T. Gibbs /* 32488b8a9b1dSJustin T. Gibbs * Don't want anyone mucking with our data. 32498b8a9b1dSJustin T. Gibbs */ 3250a5479bc5SJustin T. Gibbs s = splcam(); 32518b8a9b1dSJustin T. Gibbs device = start_ccb->ccb_h.path->device; 32528b8a9b1dSJustin T. Gibbs periph_head = &device->periphs; 32538b8a9b1dSJustin T. Gibbs cgdl = &start_ccb->cgdl; 32548b8a9b1dSJustin T. Gibbs 32558b8a9b1dSJustin T. Gibbs /* 32568b8a9b1dSJustin T. Gibbs * Check and see if the list has changed since the user 32578b8a9b1dSJustin T. Gibbs * last requested a list member. If so, tell them that the 32588b8a9b1dSJustin T. Gibbs * list has changed, and therefore they need to start over 32598b8a9b1dSJustin T. Gibbs * from the beginning. 32608b8a9b1dSJustin T. Gibbs */ 32618b8a9b1dSJustin T. Gibbs if ((cgdl->index != 0) && 32628b8a9b1dSJustin T. Gibbs (cgdl->generation != device->generation)) { 32638b8a9b1dSJustin T. Gibbs cgdl->status = CAM_GDEVLIST_LIST_CHANGED; 32648b8a9b1dSJustin T. Gibbs splx(s); 32658b8a9b1dSJustin T. Gibbs break; 32668b8a9b1dSJustin T. Gibbs } 32678b8a9b1dSJustin T. Gibbs 32688b8a9b1dSJustin T. Gibbs /* 32698b8a9b1dSJustin T. Gibbs * Traverse the list of peripherals and attempt to find 32708b8a9b1dSJustin T. Gibbs * the requested peripheral. 32718b8a9b1dSJustin T. Gibbs */ 3272fc2ffbe6SPoul-Henning Kamp for (nperiph = SLIST_FIRST(periph_head), i = 0; 32738b8a9b1dSJustin T. Gibbs (nperiph != NULL) && (i <= cgdl->index); 3274fc2ffbe6SPoul-Henning Kamp nperiph = SLIST_NEXT(nperiph, periph_links), i++) { 32758b8a9b1dSJustin T. Gibbs if (i == cgdl->index) { 32768b8a9b1dSJustin T. Gibbs strncpy(cgdl->periph_name, 32778b8a9b1dSJustin T. Gibbs nperiph->periph_name, 32788b8a9b1dSJustin T. Gibbs DEV_IDLEN); 32798b8a9b1dSJustin T. Gibbs cgdl->unit_number = nperiph->unit_number; 32808b8a9b1dSJustin T. Gibbs found = 1; 32818b8a9b1dSJustin T. Gibbs } 32828b8a9b1dSJustin T. Gibbs } 32838b8a9b1dSJustin T. Gibbs if (found == 0) { 32848b8a9b1dSJustin T. Gibbs cgdl->status = CAM_GDEVLIST_ERROR; 32858b8a9b1dSJustin T. Gibbs splx(s); 32868b8a9b1dSJustin T. Gibbs break; 32878b8a9b1dSJustin T. Gibbs } 32888b8a9b1dSJustin T. Gibbs 32898b8a9b1dSJustin T. Gibbs if (nperiph == NULL) 32908b8a9b1dSJustin T. Gibbs cgdl->status = CAM_GDEVLIST_LAST_DEVICE; 32918b8a9b1dSJustin T. Gibbs else 32928b8a9b1dSJustin T. Gibbs cgdl->status = CAM_GDEVLIST_MORE_DEVS; 32938b8a9b1dSJustin T. Gibbs 32948b8a9b1dSJustin T. Gibbs cgdl->index++; 32958b8a9b1dSJustin T. Gibbs cgdl->generation = device->generation; 32968b8a9b1dSJustin T. Gibbs 32978b8a9b1dSJustin T. Gibbs splx(s); 32988b8a9b1dSJustin T. Gibbs cgdl->ccb_h.status = CAM_REQ_CMP; 32998b8a9b1dSJustin T. Gibbs break; 33008b8a9b1dSJustin T. Gibbs } 33018b8a9b1dSJustin T. Gibbs case XPT_DEV_MATCH: 33028b8a9b1dSJustin T. Gibbs { 33038b8a9b1dSJustin T. Gibbs int s; 33048b8a9b1dSJustin T. Gibbs dev_pos_type position_type; 33058b8a9b1dSJustin T. Gibbs struct ccb_dev_match *cdm; 33068b8a9b1dSJustin T. Gibbs 33078b8a9b1dSJustin T. Gibbs cdm = &start_ccb->cdm; 33088b8a9b1dSJustin T. Gibbs 33098b8a9b1dSJustin T. Gibbs /* 33108b8a9b1dSJustin T. Gibbs * Prevent EDT changes while we traverse it. 33118b8a9b1dSJustin T. Gibbs */ 3312a5479bc5SJustin T. Gibbs s = splcam(); 33138b8a9b1dSJustin T. Gibbs /* 33148b8a9b1dSJustin T. Gibbs * There are two ways of getting at information in the EDT. 33158b8a9b1dSJustin T. Gibbs * The first way is via the primary EDT tree. It starts 33168b8a9b1dSJustin T. Gibbs * with a list of busses, then a list of targets on a bus, 33178b8a9b1dSJustin T. Gibbs * then devices/luns on a target, and then peripherals on a 33188b8a9b1dSJustin T. Gibbs * device/lun. The "other" way is by the peripheral driver 33198b8a9b1dSJustin T. Gibbs * lists. The peripheral driver lists are organized by 33208b8a9b1dSJustin T. Gibbs * peripheral driver. (obviously) So it makes sense to 33218b8a9b1dSJustin T. Gibbs * use the peripheral driver list if the user is looking 33228b8a9b1dSJustin T. Gibbs * for something like "da1", or all "da" devices. If the 33238b8a9b1dSJustin T. Gibbs * user is looking for something on a particular bus/target 33248b8a9b1dSJustin T. Gibbs * or lun, it's generally better to go through the EDT tree. 33258b8a9b1dSJustin T. Gibbs */ 33268b8a9b1dSJustin T. Gibbs 33278b8a9b1dSJustin T. Gibbs if (cdm->pos.position_type != CAM_DEV_POS_NONE) 33288b8a9b1dSJustin T. Gibbs position_type = cdm->pos.position_type; 33298b8a9b1dSJustin T. Gibbs else { 33303393f8daSKenneth D. Merry u_int i; 33318b8a9b1dSJustin T. Gibbs 33328b8a9b1dSJustin T. Gibbs position_type = CAM_DEV_POS_NONE; 33338b8a9b1dSJustin T. Gibbs 33348b8a9b1dSJustin T. Gibbs for (i = 0; i < cdm->num_patterns; i++) { 33358b8a9b1dSJustin T. Gibbs if ((cdm->patterns[i].type == DEV_MATCH_BUS) 33368b8a9b1dSJustin T. Gibbs ||(cdm->patterns[i].type == DEV_MATCH_DEVICE)){ 33378b8a9b1dSJustin T. Gibbs position_type = CAM_DEV_POS_EDT; 33388b8a9b1dSJustin T. Gibbs break; 33398b8a9b1dSJustin T. Gibbs } 33408b8a9b1dSJustin T. Gibbs } 33418b8a9b1dSJustin T. Gibbs 33428b8a9b1dSJustin T. Gibbs if (cdm->num_patterns == 0) 33438b8a9b1dSJustin T. Gibbs position_type = CAM_DEV_POS_EDT; 33448b8a9b1dSJustin T. Gibbs else if (position_type == CAM_DEV_POS_NONE) 33458b8a9b1dSJustin T. Gibbs position_type = CAM_DEV_POS_PDRV; 33468b8a9b1dSJustin T. Gibbs } 33478b8a9b1dSJustin T. Gibbs 33488b8a9b1dSJustin T. Gibbs switch(position_type & CAM_DEV_POS_TYPEMASK) { 33498b8a9b1dSJustin T. Gibbs case CAM_DEV_POS_EDT: 335007c6eac9SPoul-Henning Kamp xptedtmatch(cdm); 33518b8a9b1dSJustin T. Gibbs break; 33528b8a9b1dSJustin T. Gibbs case CAM_DEV_POS_PDRV: 335307c6eac9SPoul-Henning Kamp xptperiphlistmatch(cdm); 33548b8a9b1dSJustin T. Gibbs break; 33558b8a9b1dSJustin T. Gibbs default: 33568b8a9b1dSJustin T. Gibbs cdm->status = CAM_DEV_MATCH_ERROR; 33578b8a9b1dSJustin T. Gibbs break; 33588b8a9b1dSJustin T. Gibbs } 33598b8a9b1dSJustin T. Gibbs 33608b8a9b1dSJustin T. Gibbs splx(s); 33618b8a9b1dSJustin T. Gibbs 33628b8a9b1dSJustin T. Gibbs if (cdm->status == CAM_DEV_MATCH_ERROR) 33638b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.status = CAM_REQ_CMP_ERR; 33648b8a9b1dSJustin T. Gibbs else 33658b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.status = CAM_REQ_CMP; 33668b8a9b1dSJustin T. Gibbs 33678b8a9b1dSJustin T. Gibbs break; 33688b8a9b1dSJustin T. Gibbs } 33698b8a9b1dSJustin T. Gibbs case XPT_SASYNC_CB: 33708b8a9b1dSJustin T. Gibbs { 33718b8a9b1dSJustin T. Gibbs struct ccb_setasync *csa; 33728b8a9b1dSJustin T. Gibbs struct async_node *cur_entry; 33738b8a9b1dSJustin T. Gibbs struct async_list *async_head; 33748b8a9b1dSJustin T. Gibbs u_int32_t added; 33758b8a9b1dSJustin T. Gibbs int s; 33768b8a9b1dSJustin T. Gibbs 33778b8a9b1dSJustin T. Gibbs csa = &start_ccb->csa; 33788b8a9b1dSJustin T. Gibbs added = csa->event_enable; 33798b8a9b1dSJustin T. Gibbs async_head = &csa->ccb_h.path->device->asyncs; 33808b8a9b1dSJustin T. Gibbs 33818b8a9b1dSJustin T. Gibbs /* 33828b8a9b1dSJustin T. Gibbs * If there is already an entry for us, simply 33838b8a9b1dSJustin T. Gibbs * update it. 33848b8a9b1dSJustin T. Gibbs */ 3385a5479bc5SJustin T. Gibbs s = splcam(); 33868b8a9b1dSJustin T. Gibbs cur_entry = SLIST_FIRST(async_head); 33878b8a9b1dSJustin T. Gibbs while (cur_entry != NULL) { 33888b8a9b1dSJustin T. Gibbs if ((cur_entry->callback_arg == csa->callback_arg) 33898b8a9b1dSJustin T. Gibbs && (cur_entry->callback == csa->callback)) 33908b8a9b1dSJustin T. Gibbs break; 33918b8a9b1dSJustin T. Gibbs cur_entry = SLIST_NEXT(cur_entry, links); 33928b8a9b1dSJustin T. Gibbs } 33938b8a9b1dSJustin T. Gibbs 33948b8a9b1dSJustin T. Gibbs if (cur_entry != NULL) { 33958b8a9b1dSJustin T. Gibbs /* 33968b8a9b1dSJustin T. Gibbs * If the request has no flags set, 33978b8a9b1dSJustin T. Gibbs * remove the entry. 33988b8a9b1dSJustin T. Gibbs */ 33998b8a9b1dSJustin T. Gibbs added &= ~cur_entry->event_enable; 34008b8a9b1dSJustin T. Gibbs if (csa->event_enable == 0) { 34018b8a9b1dSJustin T. Gibbs SLIST_REMOVE(async_head, cur_entry, 3402e3975643SJake Burkholder async_node, links); 3403c8bead2aSJustin T. Gibbs csa->ccb_h.path->device->refcount--; 34048b8a9b1dSJustin T. Gibbs free(cur_entry, M_DEVBUF); 34058b8a9b1dSJustin T. Gibbs } else { 34068b8a9b1dSJustin T. Gibbs cur_entry->event_enable = csa->event_enable; 34078b8a9b1dSJustin T. Gibbs } 34088b8a9b1dSJustin T. Gibbs } else { 34098b8a9b1dSJustin T. Gibbs cur_entry = malloc(sizeof(*cur_entry), M_DEVBUF, 34108b8a9b1dSJustin T. Gibbs M_NOWAIT); 34118b8a9b1dSJustin T. Gibbs if (cur_entry == NULL) { 34128b8a9b1dSJustin T. Gibbs splx(s); 34138b8a9b1dSJustin T. Gibbs csa->ccb_h.status = CAM_RESRC_UNAVAIL; 34148b8a9b1dSJustin T. Gibbs break; 34158b8a9b1dSJustin T. Gibbs } 3416434bbf6eSJustin T. Gibbs cur_entry->event_enable = csa->event_enable; 34178b8a9b1dSJustin T. Gibbs cur_entry->callback_arg = csa->callback_arg; 34188b8a9b1dSJustin T. Gibbs cur_entry->callback = csa->callback; 34198b8a9b1dSJustin T. Gibbs SLIST_INSERT_HEAD(async_head, cur_entry, links); 3420c8bead2aSJustin T. Gibbs csa->ccb_h.path->device->refcount++; 34218b8a9b1dSJustin T. Gibbs } 34228b8a9b1dSJustin T. Gibbs 34238b8a9b1dSJustin T. Gibbs if ((added & AC_FOUND_DEVICE) != 0) { 34248b8a9b1dSJustin T. Gibbs /* 34258b8a9b1dSJustin T. Gibbs * Get this peripheral up to date with all 34268b8a9b1dSJustin T. Gibbs * the currently existing devices. 34278b8a9b1dSJustin T. Gibbs */ 34288b8a9b1dSJustin T. Gibbs xpt_for_all_devices(xptsetasyncfunc, cur_entry); 34298b8a9b1dSJustin T. Gibbs } 34308b8a9b1dSJustin T. Gibbs if ((added & AC_PATH_REGISTERED) != 0) { 34318b8a9b1dSJustin T. Gibbs /* 34328b8a9b1dSJustin T. Gibbs * Get this peripheral up to date with all 34338b8a9b1dSJustin T. Gibbs * the currently existing busses. 34348b8a9b1dSJustin T. Gibbs */ 34358b8a9b1dSJustin T. Gibbs xpt_for_all_busses(xptsetasyncbusfunc, cur_entry); 34368b8a9b1dSJustin T. Gibbs } 34378b8a9b1dSJustin T. Gibbs splx(s); 34388b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.status = CAM_REQ_CMP; 34398b8a9b1dSJustin T. Gibbs break; 34408b8a9b1dSJustin T. Gibbs } 34418b8a9b1dSJustin T. Gibbs case XPT_REL_SIMQ: 34428b8a9b1dSJustin T. Gibbs { 34438b8a9b1dSJustin T. Gibbs struct ccb_relsim *crs; 34448b8a9b1dSJustin T. Gibbs struct cam_ed *dev; 34458b8a9b1dSJustin T. Gibbs int s; 34468b8a9b1dSJustin T. Gibbs 34478b8a9b1dSJustin T. Gibbs crs = &start_ccb->crs; 34488b8a9b1dSJustin T. Gibbs dev = crs->ccb_h.path->device; 34498b8a9b1dSJustin T. Gibbs if (dev == NULL) { 34508b8a9b1dSJustin T. Gibbs 34518b8a9b1dSJustin T. Gibbs crs->ccb_h.status = CAM_DEV_NOT_THERE; 34528b8a9b1dSJustin T. Gibbs break; 34538b8a9b1dSJustin T. Gibbs } 34548b8a9b1dSJustin T. Gibbs 34558b8a9b1dSJustin T. Gibbs s = splcam(); 34568b8a9b1dSJustin T. Gibbs 34578b8a9b1dSJustin T. Gibbs if ((crs->release_flags & RELSIM_ADJUST_OPENINGS) != 0) { 34588b8a9b1dSJustin T. Gibbs 34598b8a9b1dSJustin T. Gibbs if ((dev->inq_data.flags & SID_CmdQue) != 0) { 34608b8a9b1dSJustin T. Gibbs 34618b8a9b1dSJustin T. Gibbs /* Don't ever go below one opening */ 34628b8a9b1dSJustin T. Gibbs if (crs->openings > 0) { 34638b8a9b1dSJustin T. Gibbs xpt_dev_ccbq_resize(crs->ccb_h.path, 34648b8a9b1dSJustin T. Gibbs crs->openings); 34658b8a9b1dSJustin T. Gibbs 346679ccc199SJordan K. Hubbard if (bootverbose) { 34678b8a9b1dSJustin T. Gibbs xpt_print_path(crs->ccb_h.path); 34688b8a9b1dSJustin T. Gibbs printf("tagged openings " 34698b8a9b1dSJustin T. Gibbs "now %d\n", 34708b8a9b1dSJustin T. Gibbs crs->openings); 34718b8a9b1dSJustin T. Gibbs } 34728b8a9b1dSJustin T. Gibbs } 34738b8a9b1dSJustin T. Gibbs } 34748b8a9b1dSJustin T. Gibbs } 34758b8a9b1dSJustin T. Gibbs 34768b8a9b1dSJustin T. Gibbs if ((crs->release_flags & RELSIM_RELEASE_AFTER_TIMEOUT) != 0) { 34778b8a9b1dSJustin T. Gibbs 34788b8a9b1dSJustin T. Gibbs if ((dev->flags & CAM_DEV_REL_TIMEOUT_PENDING) != 0) { 34798b8a9b1dSJustin T. Gibbs 34808b8a9b1dSJustin T. Gibbs /* 34818b8a9b1dSJustin T. Gibbs * Just extend the old timeout and decrement 34828b8a9b1dSJustin T. Gibbs * the freeze count so that a single timeout 34838b8a9b1dSJustin T. Gibbs * is sufficient for releasing the queue. 34848b8a9b1dSJustin T. Gibbs */ 34858b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.flags &= ~CAM_DEV_QFREEZE; 34868b8a9b1dSJustin T. Gibbs untimeout(xpt_release_devq_timeout, 34878b8a9b1dSJustin T. Gibbs dev, dev->c_handle); 34888b8a9b1dSJustin T. Gibbs } else { 34898b8a9b1dSJustin T. Gibbs 34908b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.flags |= CAM_DEV_QFREEZE; 34918b8a9b1dSJustin T. Gibbs } 34928b8a9b1dSJustin T. Gibbs 34938b8a9b1dSJustin T. Gibbs dev->c_handle = 34948b8a9b1dSJustin T. Gibbs timeout(xpt_release_devq_timeout, 34958b8a9b1dSJustin T. Gibbs dev, 34968b8a9b1dSJustin T. Gibbs (crs->release_timeout * hz) / 1000); 34978b8a9b1dSJustin T. Gibbs 34988b8a9b1dSJustin T. Gibbs dev->flags |= CAM_DEV_REL_TIMEOUT_PENDING; 34998b8a9b1dSJustin T. Gibbs 35008b8a9b1dSJustin T. Gibbs } 35018b8a9b1dSJustin T. Gibbs 35028b8a9b1dSJustin T. Gibbs if ((crs->release_flags & RELSIM_RELEASE_AFTER_CMDCMPLT) != 0) { 35038b8a9b1dSJustin T. Gibbs 35048b8a9b1dSJustin T. Gibbs if ((dev->flags & CAM_DEV_REL_ON_COMPLETE) != 0) { 35058b8a9b1dSJustin T. Gibbs /* 35068b8a9b1dSJustin T. Gibbs * Decrement the freeze count so that a single 35078b8a9b1dSJustin T. Gibbs * completion is still sufficient to unfreeze 35088b8a9b1dSJustin T. Gibbs * the queue. 35098b8a9b1dSJustin T. Gibbs */ 35108b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.flags &= ~CAM_DEV_QFREEZE; 35118b8a9b1dSJustin T. Gibbs } else { 35128b8a9b1dSJustin T. Gibbs 35138b8a9b1dSJustin T. Gibbs dev->flags |= CAM_DEV_REL_ON_COMPLETE; 35148b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.flags |= CAM_DEV_QFREEZE; 35158b8a9b1dSJustin T. Gibbs } 35168b8a9b1dSJustin T. Gibbs } 35178b8a9b1dSJustin T. Gibbs 35188b8a9b1dSJustin T. Gibbs if ((crs->release_flags & RELSIM_RELEASE_AFTER_QEMPTY) != 0) { 35198b8a9b1dSJustin T. Gibbs 35208b8a9b1dSJustin T. Gibbs if ((dev->flags & CAM_DEV_REL_ON_QUEUE_EMPTY) != 0 35218b8a9b1dSJustin T. Gibbs || (dev->ccbq.dev_active == 0)) { 35228b8a9b1dSJustin T. Gibbs 35238b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.flags &= ~CAM_DEV_QFREEZE; 35248b8a9b1dSJustin T. Gibbs } else { 35258b8a9b1dSJustin T. Gibbs 35268b8a9b1dSJustin T. Gibbs dev->flags |= CAM_DEV_REL_ON_QUEUE_EMPTY; 35278b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.flags |= CAM_DEV_QFREEZE; 35288b8a9b1dSJustin T. Gibbs } 35298b8a9b1dSJustin T. Gibbs } 35308b8a9b1dSJustin T. Gibbs splx(s); 35318b8a9b1dSJustin T. Gibbs 35328b8a9b1dSJustin T. Gibbs if ((start_ccb->ccb_h.flags & CAM_DEV_QFREEZE) == 0) { 35338b8a9b1dSJustin T. Gibbs 35342cefde5fSJustin T. Gibbs xpt_release_devq(crs->ccb_h.path, /*count*/1, 35358b8a9b1dSJustin T. Gibbs /*run_queue*/TRUE); 35368b8a9b1dSJustin T. Gibbs } 35378b8a9b1dSJustin T. Gibbs start_ccb->crs.qfrozen_cnt = dev->qfrozen_cnt; 35388b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.status = CAM_REQ_CMP; 35398b8a9b1dSJustin T. Gibbs break; 35408b8a9b1dSJustin T. Gibbs } 35418b8a9b1dSJustin T. Gibbs case XPT_SCAN_BUS: 35428b8a9b1dSJustin T. Gibbs xpt_scan_bus(start_ccb->ccb_h.path->periph, start_ccb); 35438b8a9b1dSJustin T. Gibbs break; 35448b8a9b1dSJustin T. Gibbs case XPT_SCAN_LUN: 35458b8a9b1dSJustin T. Gibbs xpt_scan_lun(start_ccb->ccb_h.path->periph, 35468b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.path, start_ccb->crcn.flags, 35478b8a9b1dSJustin T. Gibbs start_ccb); 35488b8a9b1dSJustin T. Gibbs break; 35498b8a9b1dSJustin T. Gibbs case XPT_DEBUG: { 35508b8a9b1dSJustin T. Gibbs #ifdef CAMDEBUG 35518b8a9b1dSJustin T. Gibbs int s; 35528b8a9b1dSJustin T. Gibbs 35538b8a9b1dSJustin T. Gibbs s = splcam(); 35542cefde5fSJustin T. Gibbs #ifdef CAM_DEBUG_DELAY 35552cefde5fSJustin T. Gibbs cam_debug_delay = CAM_DEBUG_DELAY; 35562cefde5fSJustin T. Gibbs #endif 35578b8a9b1dSJustin T. Gibbs cam_dflags = start_ccb->cdbg.flags; 35588b8a9b1dSJustin T. Gibbs if (cam_dpath != NULL) { 35598b8a9b1dSJustin T. Gibbs xpt_free_path(cam_dpath); 35608b8a9b1dSJustin T. Gibbs cam_dpath = NULL; 35618b8a9b1dSJustin T. Gibbs } 35628b8a9b1dSJustin T. Gibbs 35638b8a9b1dSJustin T. Gibbs if (cam_dflags != CAM_DEBUG_NONE) { 35648b8a9b1dSJustin T. Gibbs if (xpt_create_path(&cam_dpath, xpt_periph, 35658b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.path_id, 35668b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.target_id, 35678b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.target_lun) != 35688b8a9b1dSJustin T. Gibbs CAM_REQ_CMP) { 35698b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.status = CAM_RESRC_UNAVAIL; 35708b8a9b1dSJustin T. Gibbs cam_dflags = CAM_DEBUG_NONE; 3571aa872be6SMatt Jacob } else { 35728b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.status = CAM_REQ_CMP; 3573aa872be6SMatt Jacob xpt_print_path(cam_dpath); 3574aa872be6SMatt Jacob printf("debugging flags now %x\n", cam_dflags); 3575aa872be6SMatt Jacob } 35768b8a9b1dSJustin T. Gibbs } else { 35778b8a9b1dSJustin T. Gibbs cam_dpath = NULL; 35788b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.status = CAM_REQ_CMP; 35798b8a9b1dSJustin T. Gibbs } 35808b8a9b1dSJustin T. Gibbs splx(s); 35818b8a9b1dSJustin T. Gibbs #else /* !CAMDEBUG */ 35828b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.status = CAM_FUNC_NOTAVAIL; 35838b8a9b1dSJustin T. Gibbs #endif /* CAMDEBUG */ 35848b8a9b1dSJustin T. Gibbs break; 35858b8a9b1dSJustin T. Gibbs } 35868b8a9b1dSJustin T. Gibbs case XPT_NOOP: 358787cfaf0eSJustin T. Gibbs if ((start_ccb->ccb_h.flags & CAM_DEV_QFREEZE) != 0) 358887cfaf0eSJustin T. Gibbs xpt_freeze_devq(start_ccb->ccb_h.path, 1); 35898b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.status = CAM_REQ_CMP; 35908b8a9b1dSJustin T. Gibbs break; 35918b8a9b1dSJustin T. Gibbs default: 35928b8a9b1dSJustin T. Gibbs case XPT_SDEV_TYPE: 35938b8a9b1dSJustin T. Gibbs case XPT_TERM_IO: 35948b8a9b1dSJustin T. Gibbs case XPT_ENG_INQ: 35958b8a9b1dSJustin T. Gibbs /* XXX Implement */ 35968b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.status = CAM_PROVIDE_FAIL; 35978b8a9b1dSJustin T. Gibbs break; 35988b8a9b1dSJustin T. Gibbs } 35999911ecf9SJustin T. Gibbs splx(iopl); 36008b8a9b1dSJustin T. Gibbs } 36018b8a9b1dSJustin T. Gibbs 36028b8a9b1dSJustin T. Gibbs void 36038b8a9b1dSJustin T. Gibbs xpt_polled_action(union ccb *start_ccb) 36048b8a9b1dSJustin T. Gibbs { 36058b8a9b1dSJustin T. Gibbs int s; 36068b8a9b1dSJustin T. Gibbs u_int32_t timeout; 36078b8a9b1dSJustin T. Gibbs struct cam_sim *sim; 36088b8a9b1dSJustin T. Gibbs struct cam_devq *devq; 36098b8a9b1dSJustin T. Gibbs struct cam_ed *dev; 36108b8a9b1dSJustin T. Gibbs 361168153f43SScott Long GIANT_REQUIRED; 361268153f43SScott Long 36138b8a9b1dSJustin T. Gibbs timeout = start_ccb->ccb_h.timeout; 36148b8a9b1dSJustin T. Gibbs sim = start_ccb->ccb_h.path->bus->sim; 36158b8a9b1dSJustin T. Gibbs devq = sim->devq; 36168b8a9b1dSJustin T. Gibbs dev = start_ccb->ccb_h.path->device; 36178b8a9b1dSJustin T. Gibbs 36188b8a9b1dSJustin T. Gibbs s = splcam(); 36198b8a9b1dSJustin T. Gibbs 36208b8a9b1dSJustin T. Gibbs /* 36218b8a9b1dSJustin T. Gibbs * Steal an opening so that no other queued requests 36228b8a9b1dSJustin T. Gibbs * can get it before us while we simulate interrupts. 36238b8a9b1dSJustin T. Gibbs */ 36248b8a9b1dSJustin T. Gibbs dev->ccbq.devq_openings--; 36258b8a9b1dSJustin T. Gibbs dev->ccbq.dev_openings--; 36268b8a9b1dSJustin T. Gibbs 36278b8a9b1dSJustin T. Gibbs while((devq->send_openings <= 0 || dev->ccbq.dev_openings < 0) 36288b8a9b1dSJustin T. Gibbs && (--timeout > 0)) { 36298b8a9b1dSJustin T. Gibbs DELAY(1000); 36308b8a9b1dSJustin T. Gibbs (*(sim->sim_poll))(sim); 36318088699fSJohn Baldwin camisr(&cam_bioq); 36328b8a9b1dSJustin T. Gibbs } 36338b8a9b1dSJustin T. Gibbs 36348b8a9b1dSJustin T. Gibbs dev->ccbq.devq_openings++; 36358b8a9b1dSJustin T. Gibbs dev->ccbq.dev_openings++; 36368b8a9b1dSJustin T. Gibbs 36378b8a9b1dSJustin T. Gibbs if (timeout != 0) { 36388b8a9b1dSJustin T. Gibbs xpt_action(start_ccb); 36398b8a9b1dSJustin T. Gibbs while(--timeout > 0) { 36408b8a9b1dSJustin T. Gibbs (*(sim->sim_poll))(sim); 36418088699fSJohn Baldwin camisr(&cam_bioq); 36428b8a9b1dSJustin T. Gibbs if ((start_ccb->ccb_h.status & CAM_STATUS_MASK) 36438b8a9b1dSJustin T. Gibbs != CAM_REQ_INPROG) 36448b8a9b1dSJustin T. Gibbs break; 36458b8a9b1dSJustin T. Gibbs DELAY(1000); 36468b8a9b1dSJustin T. Gibbs } 36478b8a9b1dSJustin T. Gibbs if (timeout == 0) { 36488b8a9b1dSJustin T. Gibbs /* 36498b8a9b1dSJustin T. Gibbs * XXX Is it worth adding a sim_timeout entry 36508b8a9b1dSJustin T. Gibbs * point so we can attempt recovery? If 36518b8a9b1dSJustin T. Gibbs * this is only used for dumps, I don't think 36528b8a9b1dSJustin T. Gibbs * it is. 36538b8a9b1dSJustin T. Gibbs */ 36548b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.status = CAM_CMD_TIMEOUT; 36558b8a9b1dSJustin T. Gibbs } 36568b8a9b1dSJustin T. Gibbs } else { 36578b8a9b1dSJustin T. Gibbs start_ccb->ccb_h.status = CAM_RESRC_UNAVAIL; 36588b8a9b1dSJustin T. Gibbs } 36598b8a9b1dSJustin T. Gibbs splx(s); 36608b8a9b1dSJustin T. Gibbs } 36618b8a9b1dSJustin T. Gibbs 36628b8a9b1dSJustin T. Gibbs /* 36638b8a9b1dSJustin T. Gibbs * Schedule a peripheral driver to receive a ccb when it's 36648b8a9b1dSJustin T. Gibbs * target device has space for more transactions. 36658b8a9b1dSJustin T. Gibbs */ 36668b8a9b1dSJustin T. Gibbs void 36678b8a9b1dSJustin T. Gibbs xpt_schedule(struct cam_periph *perph, u_int32_t new_priority) 36688b8a9b1dSJustin T. Gibbs { 36698b8a9b1dSJustin T. Gibbs struct cam_ed *device; 36708b8a9b1dSJustin T. Gibbs int s; 36718b8a9b1dSJustin T. Gibbs int runq; 36728b8a9b1dSJustin T. Gibbs 367368153f43SScott Long GIANT_REQUIRED; 367468153f43SScott Long 36758b8a9b1dSJustin T. Gibbs CAM_DEBUG(perph->path, CAM_DEBUG_TRACE, ("xpt_schedule\n")); 36768b8a9b1dSJustin T. Gibbs device = perph->path->device; 36778b8a9b1dSJustin T. Gibbs s = splsoftcam(); 36788b8a9b1dSJustin T. Gibbs if (periph_is_queued(perph)) { 36798b8a9b1dSJustin T. Gibbs /* Simply reorder based on new priority */ 36808b8a9b1dSJustin T. Gibbs CAM_DEBUG(perph->path, CAM_DEBUG_SUBTRACE, 36818b8a9b1dSJustin T. Gibbs (" change priority to %d\n", new_priority)); 36828b8a9b1dSJustin T. Gibbs if (new_priority < perph->pinfo.priority) { 36838b8a9b1dSJustin T. Gibbs camq_change_priority(&device->drvq, 36848b8a9b1dSJustin T. Gibbs perph->pinfo.index, 36858b8a9b1dSJustin T. Gibbs new_priority); 36868b8a9b1dSJustin T. Gibbs } 36878b8a9b1dSJustin T. Gibbs runq = 0; 36888b8a9b1dSJustin T. Gibbs } else { 36898b8a9b1dSJustin T. Gibbs /* New entry on the queue */ 36908b8a9b1dSJustin T. Gibbs CAM_DEBUG(perph->path, CAM_DEBUG_SUBTRACE, 36918b8a9b1dSJustin T. Gibbs (" added periph to queue\n")); 36928b8a9b1dSJustin T. Gibbs perph->pinfo.priority = new_priority; 36938bad620dSJustin T. Gibbs perph->pinfo.generation = ++device->drvq.generation; 36948b8a9b1dSJustin T. Gibbs camq_insert(&device->drvq, &perph->pinfo); 36958b8a9b1dSJustin T. Gibbs runq = xpt_schedule_dev_allocq(perph->path->bus, device); 36968b8a9b1dSJustin T. Gibbs } 36978b8a9b1dSJustin T. Gibbs splx(s); 36988b8a9b1dSJustin T. Gibbs if (runq != 0) { 36998b8a9b1dSJustin T. Gibbs CAM_DEBUG(perph->path, CAM_DEBUG_SUBTRACE, 37008b8a9b1dSJustin T. Gibbs (" calling xpt_run_devq\n")); 37018b8a9b1dSJustin T. Gibbs xpt_run_dev_allocq(perph->path->bus); 37028b8a9b1dSJustin T. Gibbs } 37038b8a9b1dSJustin T. Gibbs } 37048b8a9b1dSJustin T. Gibbs 37058b8a9b1dSJustin T. Gibbs 37068b8a9b1dSJustin T. Gibbs /* 37078b8a9b1dSJustin T. Gibbs * Schedule a device to run on a given queue. 37088b8a9b1dSJustin T. Gibbs * If the device was inserted as a new entry on the queue, 37098b8a9b1dSJustin T. Gibbs * return 1 meaning the device queue should be run. If we 37108b8a9b1dSJustin T. Gibbs * were already queued, implying someone else has already 37118b8a9b1dSJustin T. Gibbs * started the queue, return 0 so the caller doesn't attempt 37128b8a9b1dSJustin T. Gibbs * to run the queue. Must be run at either splsoftcam 37138b8a9b1dSJustin T. Gibbs * (or splcam since that encompases splsoftcam). 37148b8a9b1dSJustin T. Gibbs */ 37158b8a9b1dSJustin T. Gibbs static int 37168b8a9b1dSJustin T. Gibbs xpt_schedule_dev(struct camq *queue, cam_pinfo *pinfo, 37178b8a9b1dSJustin T. Gibbs u_int32_t new_priority) 37188b8a9b1dSJustin T. Gibbs { 37198b8a9b1dSJustin T. Gibbs int retval; 37208b8a9b1dSJustin T. Gibbs u_int32_t old_priority; 37218b8a9b1dSJustin T. Gibbs 3722aa872be6SMatt Jacob CAM_DEBUG_PRINT(CAM_DEBUG_XPT, ("xpt_schedule_dev\n")); 37238b8a9b1dSJustin T. Gibbs 37248b8a9b1dSJustin T. Gibbs old_priority = pinfo->priority; 37258b8a9b1dSJustin T. Gibbs 37268b8a9b1dSJustin T. Gibbs /* 37278b8a9b1dSJustin T. Gibbs * Are we already queued? 37288b8a9b1dSJustin T. Gibbs */ 37298b8a9b1dSJustin T. Gibbs if (pinfo->index != CAM_UNQUEUED_INDEX) { 37308b8a9b1dSJustin T. Gibbs /* Simply reorder based on new priority */ 37318b8a9b1dSJustin T. Gibbs if (new_priority < old_priority) { 37328b8a9b1dSJustin T. Gibbs camq_change_priority(queue, pinfo->index, 37338b8a9b1dSJustin T. Gibbs new_priority); 3734aa872be6SMatt Jacob CAM_DEBUG_PRINT(CAM_DEBUG_XPT, 37358b8a9b1dSJustin T. Gibbs ("changed priority to %d\n", 37368b8a9b1dSJustin T. Gibbs new_priority)); 37378b8a9b1dSJustin T. Gibbs } 37388b8a9b1dSJustin T. Gibbs retval = 0; 37398b8a9b1dSJustin T. Gibbs } else { 37408b8a9b1dSJustin T. Gibbs /* New entry on the queue */ 37418b8a9b1dSJustin T. Gibbs if (new_priority < old_priority) 37428b8a9b1dSJustin T. Gibbs pinfo->priority = new_priority; 37438b8a9b1dSJustin T. Gibbs 3744aa872be6SMatt Jacob CAM_DEBUG_PRINT(CAM_DEBUG_XPT, 37458b8a9b1dSJustin T. Gibbs ("Inserting onto queue\n")); 37468bad620dSJustin T. Gibbs pinfo->generation = ++queue->generation; 37478b8a9b1dSJustin T. Gibbs camq_insert(queue, pinfo); 37488b8a9b1dSJustin T. Gibbs retval = 1; 37498b8a9b1dSJustin T. Gibbs } 37508b8a9b1dSJustin T. Gibbs return (retval); 37518b8a9b1dSJustin T. Gibbs } 37528b8a9b1dSJustin T. Gibbs 37538b8a9b1dSJustin T. Gibbs static void 37548b8a9b1dSJustin T. Gibbs xpt_run_dev_allocq(struct cam_eb *bus) 37558b8a9b1dSJustin T. Gibbs { 37568b8a9b1dSJustin T. Gibbs struct cam_devq *devq; 37578b8a9b1dSJustin T. Gibbs int s; 37588b8a9b1dSJustin T. Gibbs 3759aa872be6SMatt Jacob CAM_DEBUG_PRINT(CAM_DEBUG_XPT, ("xpt_run_dev_allocq\n")); 37608b8a9b1dSJustin T. Gibbs devq = bus->sim->devq; 37618b8a9b1dSJustin T. Gibbs 3762aa872be6SMatt Jacob CAM_DEBUG_PRINT(CAM_DEBUG_XPT, 37638b8a9b1dSJustin T. Gibbs (" qfrozen_cnt == 0x%x, entries == %d, " 37648b8a9b1dSJustin T. Gibbs "openings == %d, active == %d\n", 37658b8a9b1dSJustin T. Gibbs devq->alloc_queue.qfrozen_cnt, 37668b8a9b1dSJustin T. Gibbs devq->alloc_queue.entries, 37678b8a9b1dSJustin T. Gibbs devq->alloc_openings, 37688b8a9b1dSJustin T. Gibbs devq->alloc_active)); 37698b8a9b1dSJustin T. Gibbs 37708b8a9b1dSJustin T. Gibbs s = splsoftcam(); 37718b8a9b1dSJustin T. Gibbs devq->alloc_queue.qfrozen_cnt++; 37728b8a9b1dSJustin T. Gibbs while ((devq->alloc_queue.entries > 0) 37738b8a9b1dSJustin T. Gibbs && (devq->alloc_openings > 0) 37748b8a9b1dSJustin T. Gibbs && (devq->alloc_queue.qfrozen_cnt <= 1)) { 37758b8a9b1dSJustin T. Gibbs struct cam_ed_qinfo *qinfo; 37768b8a9b1dSJustin T. Gibbs struct cam_ed *device; 37778b8a9b1dSJustin T. Gibbs union ccb *work_ccb; 37788b8a9b1dSJustin T. Gibbs struct cam_periph *drv; 37798b8a9b1dSJustin T. Gibbs struct camq *drvq; 37808b8a9b1dSJustin T. Gibbs 37818b8a9b1dSJustin T. Gibbs qinfo = (struct cam_ed_qinfo *)camq_remove(&devq->alloc_queue, 37825a526431SJustin T. Gibbs CAMQ_HEAD); 37838b8a9b1dSJustin T. Gibbs device = qinfo->device; 37848b8a9b1dSJustin T. Gibbs 3785aa872be6SMatt Jacob CAM_DEBUG_PRINT(CAM_DEBUG_XPT, 378650642f18SKenneth D. Merry ("running device %p\n", device)); 37878b8a9b1dSJustin T. Gibbs 37888b8a9b1dSJustin T. Gibbs drvq = &device->drvq; 37898b8a9b1dSJustin T. Gibbs 37908b8a9b1dSJustin T. Gibbs #ifdef CAMDEBUG 37918b8a9b1dSJustin T. Gibbs if (drvq->entries <= 0) { 37928b8a9b1dSJustin T. Gibbs panic("xpt_run_dev_allocq: " 37938b8a9b1dSJustin T. Gibbs "Device on queue without any work to do"); 37948b8a9b1dSJustin T. Gibbs } 37958b8a9b1dSJustin T. Gibbs #endif 37968b8a9b1dSJustin T. Gibbs if ((work_ccb = xpt_get_ccb(device)) != NULL) { 37978b8a9b1dSJustin T. Gibbs devq->alloc_openings--; 37988b8a9b1dSJustin T. Gibbs devq->alloc_active++; 37995a526431SJustin T. Gibbs drv = (struct cam_periph*)camq_remove(drvq, CAMQ_HEAD); 38008b8a9b1dSJustin T. Gibbs splx(s); 38018b8a9b1dSJustin T. Gibbs xpt_setup_ccb(&work_ccb->ccb_h, drv->path, 38028b8a9b1dSJustin T. Gibbs drv->pinfo.priority); 3803aa872be6SMatt Jacob CAM_DEBUG_PRINT(CAM_DEBUG_XPT, 38048b8a9b1dSJustin T. Gibbs ("calling periph start\n")); 38058b8a9b1dSJustin T. Gibbs drv->periph_start(drv, work_ccb); 38068b8a9b1dSJustin T. Gibbs } else { 38078b8a9b1dSJustin T. Gibbs /* 38088b8a9b1dSJustin T. Gibbs * Malloc failure in alloc_ccb 38098b8a9b1dSJustin T. Gibbs */ 38108b8a9b1dSJustin T. Gibbs /* 38118b8a9b1dSJustin T. Gibbs * XXX add us to a list to be run from free_ccb 38128b8a9b1dSJustin T. Gibbs * if we don't have any ccbs active on this 38138b8a9b1dSJustin T. Gibbs * device queue otherwise we may never get run 38148b8a9b1dSJustin T. Gibbs * again. 38158b8a9b1dSJustin T. Gibbs */ 38168b8a9b1dSJustin T. Gibbs break; 38178b8a9b1dSJustin T. Gibbs } 38188b8a9b1dSJustin T. Gibbs 38198b8a9b1dSJustin T. Gibbs /* Raise IPL for possible insertion and test at top of loop */ 38208b8a9b1dSJustin T. Gibbs s = splsoftcam(); 38218b8a9b1dSJustin T. Gibbs 38228b8a9b1dSJustin T. Gibbs if (drvq->entries > 0) { 38238b8a9b1dSJustin T. Gibbs /* We have more work. Attempt to reschedule */ 38248b8a9b1dSJustin T. Gibbs xpt_schedule_dev_allocq(bus, device); 38258b8a9b1dSJustin T. Gibbs } 38268b8a9b1dSJustin T. Gibbs } 38278b8a9b1dSJustin T. Gibbs devq->alloc_queue.qfrozen_cnt--; 38288b8a9b1dSJustin T. Gibbs splx(s); 38298b8a9b1dSJustin T. Gibbs } 38308b8a9b1dSJustin T. Gibbs 38318b8a9b1dSJustin T. Gibbs static void 38328b8a9b1dSJustin T. Gibbs xpt_run_dev_sendq(struct cam_eb *bus) 38338b8a9b1dSJustin T. Gibbs { 38348b8a9b1dSJustin T. Gibbs struct cam_devq *devq; 38358b8a9b1dSJustin T. Gibbs int s; 38368b8a9b1dSJustin T. Gibbs 3837aa872be6SMatt Jacob CAM_DEBUG_PRINT(CAM_DEBUG_XPT, ("xpt_run_dev_sendq\n")); 38388b8a9b1dSJustin T. Gibbs 38398b8a9b1dSJustin T. Gibbs devq = bus->sim->devq; 38408b8a9b1dSJustin T. Gibbs 38418b8a9b1dSJustin T. Gibbs s = splcam(); 38428b8a9b1dSJustin T. Gibbs devq->send_queue.qfrozen_cnt++; 38438b8a9b1dSJustin T. Gibbs splx(s); 38448b8a9b1dSJustin T. Gibbs s = splsoftcam(); 38458b8a9b1dSJustin T. Gibbs while ((devq->send_queue.entries > 0) 38468b8a9b1dSJustin T. Gibbs && (devq->send_openings > 0)) { 38478b8a9b1dSJustin T. Gibbs struct cam_ed_qinfo *qinfo; 38488b8a9b1dSJustin T. Gibbs struct cam_ed *device; 38498b8a9b1dSJustin T. Gibbs union ccb *work_ccb; 38508b8a9b1dSJustin T. Gibbs struct cam_sim *sim; 38518b8a9b1dSJustin T. Gibbs int ospl; 38528b8a9b1dSJustin T. Gibbs 38538b8a9b1dSJustin T. Gibbs ospl = splcam(); 38548b8a9b1dSJustin T. Gibbs if (devq->send_queue.qfrozen_cnt > 1) { 38558b8a9b1dSJustin T. Gibbs splx(ospl); 38568b8a9b1dSJustin T. Gibbs break; 38578b8a9b1dSJustin T. Gibbs } 38588b8a9b1dSJustin T. Gibbs 38598b8a9b1dSJustin T. Gibbs qinfo = (struct cam_ed_qinfo *)camq_remove(&devq->send_queue, 38605a526431SJustin T. Gibbs CAMQ_HEAD); 38618b8a9b1dSJustin T. Gibbs device = qinfo->device; 38628b8a9b1dSJustin T. Gibbs 38638b8a9b1dSJustin T. Gibbs /* 38648b8a9b1dSJustin T. Gibbs * If the device has been "frozen", don't attempt 38658b8a9b1dSJustin T. Gibbs * to run it. 38668b8a9b1dSJustin T. Gibbs */ 38678b8a9b1dSJustin T. Gibbs if (device->qfrozen_cnt > 0) { 38688b8a9b1dSJustin T. Gibbs splx(ospl); 38698b8a9b1dSJustin T. Gibbs continue; 38708b8a9b1dSJustin T. Gibbs } 38718b8a9b1dSJustin T. Gibbs 3872aa872be6SMatt Jacob CAM_DEBUG_PRINT(CAM_DEBUG_XPT, 387350642f18SKenneth D. Merry ("running device %p\n", device)); 38748b8a9b1dSJustin T. Gibbs 38755a526431SJustin T. Gibbs work_ccb = cam_ccbq_peek_ccb(&device->ccbq, CAMQ_HEAD); 38768b8a9b1dSJustin T. Gibbs if (work_ccb == NULL) { 387757b89bbcSNate Lawson printf("device on run queue with no ccbs???\n"); 38788b8a9b1dSJustin T. Gibbs splx(ospl); 38798b8a9b1dSJustin T. Gibbs continue; 38808b8a9b1dSJustin T. Gibbs } 38818b8a9b1dSJustin T. Gibbs 38828b8a9b1dSJustin T. Gibbs if ((work_ccb->ccb_h.flags & CAM_HIGH_POWER) != 0) { 38838b8a9b1dSJustin T. Gibbs 38848b8a9b1dSJustin T. Gibbs if (num_highpower <= 0) { 38858b8a9b1dSJustin T. Gibbs /* 38868b8a9b1dSJustin T. Gibbs * We got a high power command, but we 38878b8a9b1dSJustin T. Gibbs * don't have any available slots. Freeze 38888b8a9b1dSJustin T. Gibbs * the device queue until we have a slot 38898b8a9b1dSJustin T. Gibbs * available. 38908b8a9b1dSJustin T. Gibbs */ 38918b8a9b1dSJustin T. Gibbs device->qfrozen_cnt++; 38928b8a9b1dSJustin T. Gibbs STAILQ_INSERT_TAIL(&highpowerq, 38938b8a9b1dSJustin T. Gibbs &work_ccb->ccb_h, 38948b8a9b1dSJustin T. Gibbs xpt_links.stqe); 38958b8a9b1dSJustin T. Gibbs 38968b8a9b1dSJustin T. Gibbs splx(ospl); 38978b8a9b1dSJustin T. Gibbs continue; 38988b8a9b1dSJustin T. Gibbs } else { 38998b8a9b1dSJustin T. Gibbs /* 39008b8a9b1dSJustin T. Gibbs * Consume a high power slot while 39018b8a9b1dSJustin T. Gibbs * this ccb runs. 39028b8a9b1dSJustin T. Gibbs */ 39038b8a9b1dSJustin T. Gibbs num_highpower--; 39048b8a9b1dSJustin T. Gibbs } 39058b8a9b1dSJustin T. Gibbs } 39068b8a9b1dSJustin T. Gibbs devq->active_dev = device; 39078b8a9b1dSJustin T. Gibbs cam_ccbq_remove_ccb(&device->ccbq, work_ccb); 39088b8a9b1dSJustin T. Gibbs 39098b8a9b1dSJustin T. Gibbs cam_ccbq_send_ccb(&device->ccbq, work_ccb); 39108b8a9b1dSJustin T. Gibbs splx(ospl); 39118b8a9b1dSJustin T. Gibbs 39128b8a9b1dSJustin T. Gibbs devq->send_openings--; 39138b8a9b1dSJustin T. Gibbs devq->send_active++; 39148b8a9b1dSJustin T. Gibbs 39155a526431SJustin T. Gibbs if (device->ccbq.queue.entries > 0) 39168b8a9b1dSJustin T. Gibbs xpt_schedule_dev_sendq(bus, device); 39178b8a9b1dSJustin T. Gibbs 39188b8a9b1dSJustin T. Gibbs if (work_ccb && (work_ccb->ccb_h.flags & CAM_DEV_QFREEZE) != 0){ 39198b8a9b1dSJustin T. Gibbs /* 39208b8a9b1dSJustin T. Gibbs * The client wants to freeze the queue 39218b8a9b1dSJustin T. Gibbs * after this CCB is sent. 39228b8a9b1dSJustin T. Gibbs */ 39238b8a9b1dSJustin T. Gibbs ospl = splcam(); 39248b8a9b1dSJustin T. Gibbs device->qfrozen_cnt++; 39258b8a9b1dSJustin T. Gibbs splx(ospl); 39268b8a9b1dSJustin T. Gibbs } 39278b8a9b1dSJustin T. Gibbs 39288b8a9b1dSJustin T. Gibbs splx(s); 39298b8a9b1dSJustin T. Gibbs 3930a4eb4f16SMatt Jacob /* In Target mode, the peripheral driver knows best... */ 3931a4eb4f16SMatt Jacob if (work_ccb->ccb_h.func_code == XPT_SCSI_IO) { 3932a4eb4f16SMatt Jacob if ((device->inq_flags & SID_CmdQue) != 0 3933a4eb4f16SMatt Jacob && work_ccb->csio.tag_action != CAM_TAG_ACTION_NONE) 39348b8a9b1dSJustin T. Gibbs work_ccb->ccb_h.flags |= CAM_TAG_ACTION_VALID; 39358b8a9b1dSJustin T. Gibbs else 39368b8a9b1dSJustin T. Gibbs /* 3937a4eb4f16SMatt Jacob * Clear this in case of a retried CCB that 3938a4eb4f16SMatt Jacob * failed due to a rejected tag. 39398b8a9b1dSJustin T. Gibbs */ 39408b8a9b1dSJustin T. Gibbs work_ccb->ccb_h.flags &= ~CAM_TAG_ACTION_VALID; 3941a4eb4f16SMatt Jacob } 39428b8a9b1dSJustin T. Gibbs 39438b8a9b1dSJustin T. Gibbs /* 39448b8a9b1dSJustin T. Gibbs * Device queues can be shared among multiple sim instances 39458b8a9b1dSJustin T. Gibbs * that reside on different busses. Use the SIM in the queue 39468b8a9b1dSJustin T. Gibbs * CCB's path, rather than the one in the bus that was passed 39478b8a9b1dSJustin T. Gibbs * into this function. 39488b8a9b1dSJustin T. Gibbs */ 39498b8a9b1dSJustin T. Gibbs sim = work_ccb->ccb_h.path->bus->sim; 39508b8a9b1dSJustin T. Gibbs (*(sim->sim_action))(sim, work_ccb); 39518b8a9b1dSJustin T. Gibbs 39528b8a9b1dSJustin T. Gibbs ospl = splcam(); 39538b8a9b1dSJustin T. Gibbs devq->active_dev = NULL; 39548b8a9b1dSJustin T. Gibbs splx(ospl); 39558b8a9b1dSJustin T. Gibbs /* Raise IPL for possible insertion and test at top of loop */ 39568b8a9b1dSJustin T. Gibbs s = splsoftcam(); 39578b8a9b1dSJustin T. Gibbs } 39588b8a9b1dSJustin T. Gibbs splx(s); 39598b8a9b1dSJustin T. Gibbs s = splcam(); 39608b8a9b1dSJustin T. Gibbs devq->send_queue.qfrozen_cnt--; 39618b8a9b1dSJustin T. Gibbs splx(s); 39628b8a9b1dSJustin T. Gibbs } 39638b8a9b1dSJustin T. Gibbs 39648b8a9b1dSJustin T. Gibbs /* 39658b8a9b1dSJustin T. Gibbs * This function merges stuff from the slave ccb into the master ccb, while 39668b8a9b1dSJustin T. Gibbs * keeping important fields in the master ccb constant. 39678b8a9b1dSJustin T. Gibbs */ 39688b8a9b1dSJustin T. Gibbs void 39698b8a9b1dSJustin T. Gibbs xpt_merge_ccb(union ccb *master_ccb, union ccb *slave_ccb) 39708b8a9b1dSJustin T. Gibbs { 397168153f43SScott Long GIANT_REQUIRED; 397268153f43SScott Long 39738b8a9b1dSJustin T. Gibbs /* 39748b8a9b1dSJustin T. Gibbs * Pull fields that are valid for peripheral drivers to set 39758b8a9b1dSJustin T. Gibbs * into the master CCB along with the CCB "payload". 39768b8a9b1dSJustin T. Gibbs */ 39778b8a9b1dSJustin T. Gibbs master_ccb->ccb_h.retry_count = slave_ccb->ccb_h.retry_count; 39788b8a9b1dSJustin T. Gibbs master_ccb->ccb_h.func_code = slave_ccb->ccb_h.func_code; 39798b8a9b1dSJustin T. Gibbs master_ccb->ccb_h.timeout = slave_ccb->ccb_h.timeout; 39808b8a9b1dSJustin T. Gibbs master_ccb->ccb_h.flags = slave_ccb->ccb_h.flags; 39818b8a9b1dSJustin T. Gibbs bcopy(&(&slave_ccb->ccb_h)[1], &(&master_ccb->ccb_h)[1], 39828b8a9b1dSJustin T. Gibbs sizeof(union ccb) - sizeof(struct ccb_hdr)); 39838b8a9b1dSJustin T. Gibbs } 39848b8a9b1dSJustin T. Gibbs 39858b8a9b1dSJustin T. Gibbs void 39868b8a9b1dSJustin T. Gibbs xpt_setup_ccb(struct ccb_hdr *ccb_h, struct cam_path *path, u_int32_t priority) 39878b8a9b1dSJustin T. Gibbs { 398868153f43SScott Long GIANT_REQUIRED; 398968153f43SScott Long 39908b8a9b1dSJustin T. Gibbs CAM_DEBUG(path, CAM_DEBUG_TRACE, ("xpt_setup_ccb\n")); 39918b8a9b1dSJustin T. Gibbs ccb_h->pinfo.priority = priority; 39928b8a9b1dSJustin T. Gibbs ccb_h->path = path; 39938b8a9b1dSJustin T. Gibbs ccb_h->path_id = path->bus->path_id; 39948b8a9b1dSJustin T. Gibbs if (path->target) 39958b8a9b1dSJustin T. Gibbs ccb_h->target_id = path->target->target_id; 39968b8a9b1dSJustin T. Gibbs else 39978b8a9b1dSJustin T. Gibbs ccb_h->target_id = CAM_TARGET_WILDCARD; 39988b8a9b1dSJustin T. Gibbs if (path->device) { 39998b8a9b1dSJustin T. Gibbs ccb_h->target_lun = path->device->lun_id; 40008bad620dSJustin T. Gibbs ccb_h->pinfo.generation = ++path->device->ccbq.queue.generation; 40018b8a9b1dSJustin T. Gibbs } else { 40028b8a9b1dSJustin T. Gibbs ccb_h->target_lun = CAM_TARGET_WILDCARD; 40038b8a9b1dSJustin T. Gibbs } 40048b8a9b1dSJustin T. Gibbs ccb_h->pinfo.index = CAM_UNQUEUED_INDEX; 40058b8a9b1dSJustin T. Gibbs ccb_h->flags = 0; 40068b8a9b1dSJustin T. Gibbs } 40078b8a9b1dSJustin T. Gibbs 40088b8a9b1dSJustin T. Gibbs /* Path manipulation functions */ 40098b8a9b1dSJustin T. Gibbs cam_status 40108b8a9b1dSJustin T. Gibbs xpt_create_path(struct cam_path **new_path_ptr, struct cam_periph *perph, 40118b8a9b1dSJustin T. Gibbs path_id_t path_id, target_id_t target_id, lun_id_t lun_id) 40128b8a9b1dSJustin T. Gibbs { 40138b8a9b1dSJustin T. Gibbs struct cam_path *path; 40148b8a9b1dSJustin T. Gibbs cam_status status; 40158b8a9b1dSJustin T. Gibbs 401668153f43SScott Long GIANT_REQUIRED; 401768153f43SScott Long 40188b8a9b1dSJustin T. Gibbs path = (struct cam_path *)malloc(sizeof(*path), M_DEVBUF, M_NOWAIT); 40198b8a9b1dSJustin T. Gibbs 40208b8a9b1dSJustin T. Gibbs if (path == NULL) { 40218b8a9b1dSJustin T. Gibbs status = CAM_RESRC_UNAVAIL; 40228b8a9b1dSJustin T. Gibbs return(status); 40238b8a9b1dSJustin T. Gibbs } 40248b8a9b1dSJustin T. Gibbs status = xpt_compile_path(path, perph, path_id, target_id, lun_id); 40258b8a9b1dSJustin T. Gibbs if (status != CAM_REQ_CMP) { 40268b8a9b1dSJustin T. Gibbs free(path, M_DEVBUF); 40278b8a9b1dSJustin T. Gibbs path = NULL; 40288b8a9b1dSJustin T. Gibbs } 40298b8a9b1dSJustin T. Gibbs *new_path_ptr = path; 40308b8a9b1dSJustin T. Gibbs return (status); 40318b8a9b1dSJustin T. Gibbs } 40328b8a9b1dSJustin T. Gibbs 40338b8a9b1dSJustin T. Gibbs static cam_status 40348b8a9b1dSJustin T. Gibbs xpt_compile_path(struct cam_path *new_path, struct cam_periph *perph, 40358b8a9b1dSJustin T. Gibbs path_id_t path_id, target_id_t target_id, lun_id_t lun_id) 40368b8a9b1dSJustin T. Gibbs { 40378b8a9b1dSJustin T. Gibbs struct cam_eb *bus; 40388b8a9b1dSJustin T. Gibbs struct cam_et *target; 40398b8a9b1dSJustin T. Gibbs struct cam_ed *device; 40408b8a9b1dSJustin T. Gibbs cam_status status; 40418b8a9b1dSJustin T. Gibbs int s; 40428b8a9b1dSJustin T. Gibbs 40438b8a9b1dSJustin T. Gibbs status = CAM_REQ_CMP; /* Completed without error */ 40448b8a9b1dSJustin T. Gibbs target = NULL; /* Wildcarded */ 40458b8a9b1dSJustin T. Gibbs device = NULL; /* Wildcarded */ 4046a5479bc5SJustin T. Gibbs 4047a5479bc5SJustin T. Gibbs /* 4048a5479bc5SJustin T. Gibbs * We will potentially modify the EDT, so block interrupts 4049a5479bc5SJustin T. Gibbs * that may attempt to create cam paths. 4050a5479bc5SJustin T. Gibbs */ 4051a5479bc5SJustin T. Gibbs s = splcam(); 40528b8a9b1dSJustin T. Gibbs bus = xpt_find_bus(path_id); 40538b8a9b1dSJustin T. Gibbs if (bus == NULL) { 40548b8a9b1dSJustin T. Gibbs status = CAM_PATH_INVALID; 4055c8bead2aSJustin T. Gibbs } else { 40568b8a9b1dSJustin T. Gibbs target = xpt_find_target(bus, target_id); 40578b8a9b1dSJustin T. Gibbs if (target == NULL) { 40588b8a9b1dSJustin T. Gibbs /* Create one */ 40598b8a9b1dSJustin T. Gibbs struct cam_et *new_target; 40608b8a9b1dSJustin T. Gibbs 40618b8a9b1dSJustin T. Gibbs new_target = xpt_alloc_target(bus, target_id); 40628b8a9b1dSJustin T. Gibbs if (new_target == NULL) { 40638b8a9b1dSJustin T. Gibbs status = CAM_RESRC_UNAVAIL; 40648b8a9b1dSJustin T. Gibbs } else { 40658b8a9b1dSJustin T. Gibbs target = new_target; 40668b8a9b1dSJustin T. Gibbs } 40678b8a9b1dSJustin T. Gibbs } 4068c8bead2aSJustin T. Gibbs if (target != NULL) { 40698b8a9b1dSJustin T. Gibbs device = xpt_find_device(target, lun_id); 40708b8a9b1dSJustin T. Gibbs if (device == NULL) { 40718b8a9b1dSJustin T. Gibbs /* Create one */ 40728b8a9b1dSJustin T. Gibbs struct cam_ed *new_device; 40738b8a9b1dSJustin T. Gibbs 40748b8a9b1dSJustin T. Gibbs new_device = xpt_alloc_device(bus, 40758b8a9b1dSJustin T. Gibbs target, 40768b8a9b1dSJustin T. Gibbs lun_id); 40778b8a9b1dSJustin T. Gibbs if (new_device == NULL) { 40788b8a9b1dSJustin T. Gibbs status = CAM_RESRC_UNAVAIL; 40798b8a9b1dSJustin T. Gibbs } else { 40808b8a9b1dSJustin T. Gibbs device = new_device; 40818b8a9b1dSJustin T. Gibbs } 40828b8a9b1dSJustin T. Gibbs } 40838b8a9b1dSJustin T. Gibbs } 40848b8a9b1dSJustin T. Gibbs } 4085a5479bc5SJustin T. Gibbs splx(s); 40868b8a9b1dSJustin T. Gibbs 40878b8a9b1dSJustin T. Gibbs /* 40888b8a9b1dSJustin T. Gibbs * Only touch the user's data if we are successful. 40898b8a9b1dSJustin T. Gibbs */ 40908b8a9b1dSJustin T. Gibbs if (status == CAM_REQ_CMP) { 40918b8a9b1dSJustin T. Gibbs new_path->periph = perph; 40928b8a9b1dSJustin T. Gibbs new_path->bus = bus; 40938b8a9b1dSJustin T. Gibbs new_path->target = target; 40948b8a9b1dSJustin T. Gibbs new_path->device = device; 40958b8a9b1dSJustin T. Gibbs CAM_DEBUG(new_path, CAM_DEBUG_TRACE, ("xpt_compile_path\n")); 40968b8a9b1dSJustin T. Gibbs } else { 40978b8a9b1dSJustin T. Gibbs if (device != NULL) 40988b8a9b1dSJustin T. Gibbs xpt_release_device(bus, target, device); 40998b8a9b1dSJustin T. Gibbs if (target != NULL) 41008b8a9b1dSJustin T. Gibbs xpt_release_target(bus, target); 4101a5479bc5SJustin T. Gibbs if (bus != NULL) 4102a5479bc5SJustin T. Gibbs xpt_release_bus(bus); 41038b8a9b1dSJustin T. Gibbs } 41048b8a9b1dSJustin T. Gibbs return (status); 41058b8a9b1dSJustin T. Gibbs } 41068b8a9b1dSJustin T. Gibbs 41078b8a9b1dSJustin T. Gibbs static void 41088b8a9b1dSJustin T. Gibbs xpt_release_path(struct cam_path *path) 41098b8a9b1dSJustin T. Gibbs { 41108b8a9b1dSJustin T. Gibbs CAM_DEBUG(path, CAM_DEBUG_TRACE, ("xpt_release_path\n")); 41119dd03ecfSJustin T. Gibbs if (path->device != NULL) { 41128b8a9b1dSJustin T. Gibbs xpt_release_device(path->bus, path->target, path->device); 41139dd03ecfSJustin T. Gibbs path->device = NULL; 41149dd03ecfSJustin T. Gibbs } 41159dd03ecfSJustin T. Gibbs if (path->target != NULL) { 41168b8a9b1dSJustin T. Gibbs xpt_release_target(path->bus, path->target); 41179dd03ecfSJustin T. Gibbs path->target = NULL; 41189dd03ecfSJustin T. Gibbs } 41199dd03ecfSJustin T. Gibbs if (path->bus != NULL) { 41209dd03ecfSJustin T. Gibbs xpt_release_bus(path->bus); 41219dd03ecfSJustin T. Gibbs path->bus = NULL; 41229dd03ecfSJustin T. Gibbs } 41238b8a9b1dSJustin T. Gibbs } 41248b8a9b1dSJustin T. Gibbs 41258b8a9b1dSJustin T. Gibbs void 41268b8a9b1dSJustin T. Gibbs xpt_free_path(struct cam_path *path) 41278b8a9b1dSJustin T. Gibbs { 412868153f43SScott Long GIANT_REQUIRED; 412968153f43SScott Long 41308b8a9b1dSJustin T. Gibbs CAM_DEBUG(path, CAM_DEBUG_TRACE, ("xpt_free_path\n")); 41318b8a9b1dSJustin T. Gibbs xpt_release_path(path); 41328b8a9b1dSJustin T. Gibbs free(path, M_DEVBUF); 41338b8a9b1dSJustin T. Gibbs } 41348b8a9b1dSJustin T. Gibbs 41358b8a9b1dSJustin T. Gibbs 41368b8a9b1dSJustin T. Gibbs /* 41372cefde5fSJustin T. Gibbs * Return -1 for failure, 0 for exact match, 1 for match with wildcards 41382cefde5fSJustin T. Gibbs * in path1, 2 for match with wildcards in path2. 41398b8a9b1dSJustin T. Gibbs */ 41408b8a9b1dSJustin T. Gibbs int 41418b8a9b1dSJustin T. Gibbs xpt_path_comp(struct cam_path *path1, struct cam_path *path2) 41428b8a9b1dSJustin T. Gibbs { 414368153f43SScott Long GIANT_REQUIRED; 414468153f43SScott Long 41458b8a9b1dSJustin T. Gibbs int retval = 0; 41468b8a9b1dSJustin T. Gibbs 41478b8a9b1dSJustin T. Gibbs if (path1->bus != path2->bus) { 41482cefde5fSJustin T. Gibbs if (path1->bus->path_id == CAM_BUS_WILDCARD) 41498b8a9b1dSJustin T. Gibbs retval = 1; 41502cefde5fSJustin T. Gibbs else if (path2->bus->path_id == CAM_BUS_WILDCARD) 41512cefde5fSJustin T. Gibbs retval = 2; 41528b8a9b1dSJustin T. Gibbs else 41538b8a9b1dSJustin T. Gibbs return (-1); 41548b8a9b1dSJustin T. Gibbs } 41558b8a9b1dSJustin T. Gibbs if (path1->target != path2->target) { 41562cefde5fSJustin T. Gibbs if (path1->target->target_id == CAM_TARGET_WILDCARD) { 41572cefde5fSJustin T. Gibbs if (retval == 0) 41588b8a9b1dSJustin T. Gibbs retval = 1; 41592cefde5fSJustin T. Gibbs } else if (path2->target->target_id == CAM_TARGET_WILDCARD) 41602cefde5fSJustin T. Gibbs retval = 2; 41618b8a9b1dSJustin T. Gibbs else 41628b8a9b1dSJustin T. Gibbs return (-1); 41638b8a9b1dSJustin T. Gibbs } 41648b8a9b1dSJustin T. Gibbs if (path1->device != path2->device) { 41652cefde5fSJustin T. Gibbs if (path1->device->lun_id == CAM_LUN_WILDCARD) { 41662cefde5fSJustin T. Gibbs if (retval == 0) 41678b8a9b1dSJustin T. Gibbs retval = 1; 41682cefde5fSJustin T. Gibbs } else if (path2->device->lun_id == CAM_LUN_WILDCARD) 41692cefde5fSJustin T. Gibbs retval = 2; 41708b8a9b1dSJustin T. Gibbs else 41718b8a9b1dSJustin T. Gibbs return (-1); 41728b8a9b1dSJustin T. Gibbs } 41738b8a9b1dSJustin T. Gibbs return (retval); 41748b8a9b1dSJustin T. Gibbs } 41758b8a9b1dSJustin T. Gibbs 41768b8a9b1dSJustin T. Gibbs void 41778b8a9b1dSJustin T. Gibbs xpt_print_path(struct cam_path *path) 41788b8a9b1dSJustin T. Gibbs { 417968153f43SScott Long GIANT_REQUIRED; 418068153f43SScott Long 41818b8a9b1dSJustin T. Gibbs if (path == NULL) 41828b8a9b1dSJustin T. Gibbs printf("(nopath): "); 41838b8a9b1dSJustin T. Gibbs else { 41848b8a9b1dSJustin T. Gibbs if (path->periph != NULL) 41858b8a9b1dSJustin T. Gibbs printf("(%s%d:", path->periph->periph_name, 41868b8a9b1dSJustin T. Gibbs path->periph->unit_number); 41878b8a9b1dSJustin T. Gibbs else 41888b8a9b1dSJustin T. Gibbs printf("(noperiph:"); 41898b8a9b1dSJustin T. Gibbs 41908b8a9b1dSJustin T. Gibbs if (path->bus != NULL) 41918b8a9b1dSJustin T. Gibbs printf("%s%d:%d:", path->bus->sim->sim_name, 41928b8a9b1dSJustin T. Gibbs path->bus->sim->unit_number, 41938b8a9b1dSJustin T. Gibbs path->bus->sim->bus_id); 41948b8a9b1dSJustin T. Gibbs else 41958b8a9b1dSJustin T. Gibbs printf("nobus:"); 41968b8a9b1dSJustin T. Gibbs 41978b8a9b1dSJustin T. Gibbs if (path->target != NULL) 41988b8a9b1dSJustin T. Gibbs printf("%d:", path->target->target_id); 41998b8a9b1dSJustin T. Gibbs else 42008b8a9b1dSJustin T. Gibbs printf("X:"); 42018b8a9b1dSJustin T. Gibbs 42028b8a9b1dSJustin T. Gibbs if (path->device != NULL) 42038b8a9b1dSJustin T. Gibbs printf("%d): ", path->device->lun_id); 42048b8a9b1dSJustin T. Gibbs else 42058b8a9b1dSJustin T. Gibbs printf("X): "); 42068b8a9b1dSJustin T. Gibbs } 42078b8a9b1dSJustin T. Gibbs } 42088b8a9b1dSJustin T. Gibbs 42093393f8daSKenneth D. Merry int 42103393f8daSKenneth D. Merry xpt_path_string(struct cam_path *path, char *str, size_t str_len) 42113393f8daSKenneth D. Merry { 42123393f8daSKenneth D. Merry struct sbuf sb; 42133393f8daSKenneth D. Merry 421468153f43SScott Long GIANT_REQUIRED; 421568153f43SScott Long 42163393f8daSKenneth D. Merry sbuf_new(&sb, str, str_len, 0); 42173393f8daSKenneth D. Merry 42183393f8daSKenneth D. Merry if (path == NULL) 42193393f8daSKenneth D. Merry sbuf_printf(&sb, "(nopath): "); 42203393f8daSKenneth D. Merry else { 42213393f8daSKenneth D. Merry if (path->periph != NULL) 42223393f8daSKenneth D. Merry sbuf_printf(&sb, "(%s%d:", path->periph->periph_name, 42233393f8daSKenneth D. Merry path->periph->unit_number); 42243393f8daSKenneth D. Merry else 42253393f8daSKenneth D. Merry sbuf_printf(&sb, "(noperiph:"); 42263393f8daSKenneth D. Merry 42273393f8daSKenneth D. Merry if (path->bus != NULL) 42283393f8daSKenneth D. Merry sbuf_printf(&sb, "%s%d:%d:", path->bus->sim->sim_name, 42293393f8daSKenneth D. Merry path->bus->sim->unit_number, 42303393f8daSKenneth D. Merry path->bus->sim->bus_id); 42313393f8daSKenneth D. Merry else 42323393f8daSKenneth D. Merry sbuf_printf(&sb, "nobus:"); 42333393f8daSKenneth D. Merry 42343393f8daSKenneth D. Merry if (path->target != NULL) 42353393f8daSKenneth D. Merry sbuf_printf(&sb, "%d:", path->target->target_id); 42363393f8daSKenneth D. Merry else 42373393f8daSKenneth D. Merry sbuf_printf(&sb, "X:"); 42383393f8daSKenneth D. Merry 42393393f8daSKenneth D. Merry if (path->device != NULL) 42403393f8daSKenneth D. Merry sbuf_printf(&sb, "%d): ", path->device->lun_id); 42413393f8daSKenneth D. Merry else 42423393f8daSKenneth D. Merry sbuf_printf(&sb, "X): "); 42433393f8daSKenneth D. Merry } 42443393f8daSKenneth D. Merry sbuf_finish(&sb); 42453393f8daSKenneth D. Merry 42463393f8daSKenneth D. Merry return(sbuf_len(&sb)); 42473393f8daSKenneth D. Merry } 42483393f8daSKenneth D. Merry 42498b8a9b1dSJustin T. Gibbs path_id_t 42508b8a9b1dSJustin T. Gibbs xpt_path_path_id(struct cam_path *path) 42518b8a9b1dSJustin T. Gibbs { 425268153f43SScott Long GIANT_REQUIRED; 425368153f43SScott Long 42548b8a9b1dSJustin T. Gibbs return(path->bus->path_id); 42558b8a9b1dSJustin T. Gibbs } 42568b8a9b1dSJustin T. Gibbs 42578b8a9b1dSJustin T. Gibbs target_id_t 42588b8a9b1dSJustin T. Gibbs xpt_path_target_id(struct cam_path *path) 42598b8a9b1dSJustin T. Gibbs { 426068153f43SScott Long GIANT_REQUIRED; 426168153f43SScott Long 42628b8a9b1dSJustin T. Gibbs if (path->target != NULL) 42638b8a9b1dSJustin T. Gibbs return (path->target->target_id); 42648b8a9b1dSJustin T. Gibbs else 42658b8a9b1dSJustin T. Gibbs return (CAM_TARGET_WILDCARD); 42668b8a9b1dSJustin T. Gibbs } 42678b8a9b1dSJustin T. Gibbs 42688b8a9b1dSJustin T. Gibbs lun_id_t 42698b8a9b1dSJustin T. Gibbs xpt_path_lun_id(struct cam_path *path) 42708b8a9b1dSJustin T. Gibbs { 427168153f43SScott Long GIANT_REQUIRED; 427268153f43SScott Long 42738b8a9b1dSJustin T. Gibbs if (path->device != NULL) 42748b8a9b1dSJustin T. Gibbs return (path->device->lun_id); 42758b8a9b1dSJustin T. Gibbs else 42768b8a9b1dSJustin T. Gibbs return (CAM_LUN_WILDCARD); 42778b8a9b1dSJustin T. Gibbs } 42788b8a9b1dSJustin T. Gibbs 42798b8a9b1dSJustin T. Gibbs struct cam_sim * 42808b8a9b1dSJustin T. Gibbs xpt_path_sim(struct cam_path *path) 42818b8a9b1dSJustin T. Gibbs { 428268153f43SScott Long GIANT_REQUIRED; 428368153f43SScott Long 42848b8a9b1dSJustin T. Gibbs return (path->bus->sim); 42858b8a9b1dSJustin T. Gibbs } 42868b8a9b1dSJustin T. Gibbs 42878b8a9b1dSJustin T. Gibbs struct cam_periph* 42888b8a9b1dSJustin T. Gibbs xpt_path_periph(struct cam_path *path) 42898b8a9b1dSJustin T. Gibbs { 429068153f43SScott Long GIANT_REQUIRED; 429168153f43SScott Long 42928b8a9b1dSJustin T. Gibbs return (path->periph); 42938b8a9b1dSJustin T. Gibbs } 42948b8a9b1dSJustin T. Gibbs 42958b8a9b1dSJustin T. Gibbs /* 42968b8a9b1dSJustin T. Gibbs * Release a CAM control block for the caller. Remit the cost of the structure 42978b8a9b1dSJustin T. Gibbs * to the device referenced by the path. If the this device had no 'credits' 42988b8a9b1dSJustin T. Gibbs * and peripheral drivers have registered async callbacks for this notification 42998b8a9b1dSJustin T. Gibbs * call them now. 43008b8a9b1dSJustin T. Gibbs */ 43018b8a9b1dSJustin T. Gibbs void 43028b8a9b1dSJustin T. Gibbs xpt_release_ccb(union ccb *free_ccb) 43038b8a9b1dSJustin T. Gibbs { 43048b8a9b1dSJustin T. Gibbs int s; 43058b8a9b1dSJustin T. Gibbs struct cam_path *path; 43068b8a9b1dSJustin T. Gibbs struct cam_ed *device; 43078b8a9b1dSJustin T. Gibbs struct cam_eb *bus; 43088b8a9b1dSJustin T. Gibbs 430968153f43SScott Long GIANT_REQUIRED; 431068153f43SScott Long 4311aa872be6SMatt Jacob CAM_DEBUG_PRINT(CAM_DEBUG_XPT, ("xpt_release_ccb\n")); 43128b8a9b1dSJustin T. Gibbs path = free_ccb->ccb_h.path; 43138b8a9b1dSJustin T. Gibbs device = path->device; 43148b8a9b1dSJustin T. Gibbs bus = path->bus; 43158b8a9b1dSJustin T. Gibbs s = splsoftcam(); 43168b8a9b1dSJustin T. Gibbs cam_ccbq_release_opening(&device->ccbq); 43178b8a9b1dSJustin T. Gibbs if (xpt_ccb_count > xpt_max_ccbs) { 43188b8a9b1dSJustin T. Gibbs xpt_free_ccb(free_ccb); 43198b8a9b1dSJustin T. Gibbs xpt_ccb_count--; 43208b8a9b1dSJustin T. Gibbs } else { 43218b8a9b1dSJustin T. Gibbs SLIST_INSERT_HEAD(&ccb_freeq, &free_ccb->ccb_h, xpt_links.sle); 43228b8a9b1dSJustin T. Gibbs } 43238b8a9b1dSJustin T. Gibbs bus->sim->devq->alloc_openings++; 43248b8a9b1dSJustin T. Gibbs bus->sim->devq->alloc_active--; 43258b8a9b1dSJustin T. Gibbs /* XXX Turn this into an inline function - xpt_run_device?? */ 43268b8a9b1dSJustin T. Gibbs if ((device_is_alloc_queued(device) == 0) 43278b8a9b1dSJustin T. Gibbs && (device->drvq.entries > 0)) { 43288b8a9b1dSJustin T. Gibbs xpt_schedule_dev_allocq(bus, device); 43298b8a9b1dSJustin T. Gibbs } 43308b8a9b1dSJustin T. Gibbs splx(s); 43318b8a9b1dSJustin T. Gibbs if (dev_allocq_is_runnable(bus->sim->devq)) 43328b8a9b1dSJustin T. Gibbs xpt_run_dev_allocq(bus); 43338b8a9b1dSJustin T. Gibbs } 43348b8a9b1dSJustin T. Gibbs 43358b8a9b1dSJustin T. Gibbs /* Functions accessed by SIM drivers */ 43368b8a9b1dSJustin T. Gibbs 43378b8a9b1dSJustin T. Gibbs /* 43388b8a9b1dSJustin T. Gibbs * A sim structure, listing the SIM entry points and instance 43398b8a9b1dSJustin T. Gibbs * identification info is passed to xpt_bus_register to hook the SIM 43408b8a9b1dSJustin T. Gibbs * into the CAM framework. xpt_bus_register creates a cam_eb entry 43418b8a9b1dSJustin T. Gibbs * for this new bus and places it in the array of busses and assigns 43428b8a9b1dSJustin T. Gibbs * it a path_id. The path_id may be influenced by "hard wiring" 43438b8a9b1dSJustin T. Gibbs * information specified by the user. Once interrupt services are 43448b8a9b1dSJustin T. Gibbs * availible, the bus will be probed. 43458b8a9b1dSJustin T. Gibbs */ 43468b8a9b1dSJustin T. Gibbs int32_t 43478b8a9b1dSJustin T. Gibbs xpt_bus_register(struct cam_sim *sim, u_int32_t bus) 43488b8a9b1dSJustin T. Gibbs { 43498b8a9b1dSJustin T. Gibbs struct cam_eb *new_bus; 4350434bbf6eSJustin T. Gibbs struct cam_eb *old_bus; 43518b8a9b1dSJustin T. Gibbs struct ccb_pathinq cpi; 43528b8a9b1dSJustin T. Gibbs int s; 43538b8a9b1dSJustin T. Gibbs 435468153f43SScott Long GIANT_REQUIRED; 435568153f43SScott Long 43568b8a9b1dSJustin T. Gibbs sim->bus_id = bus; 43578b8a9b1dSJustin T. Gibbs new_bus = (struct cam_eb *)malloc(sizeof(*new_bus), 43588b8a9b1dSJustin T. Gibbs M_DEVBUF, M_NOWAIT); 43598b8a9b1dSJustin T. Gibbs if (new_bus == NULL) { 43608b8a9b1dSJustin T. Gibbs /* Couldn't satisfy request */ 43618b8a9b1dSJustin T. Gibbs return (CAM_RESRC_UNAVAIL); 43628b8a9b1dSJustin T. Gibbs } 43638b8a9b1dSJustin T. Gibbs 43648b8a9b1dSJustin T. Gibbs if (strcmp(sim->sim_name, "xpt") != 0) { 43658b8a9b1dSJustin T. Gibbs 4366434bbf6eSJustin T. Gibbs sim->path_id = 4367434bbf6eSJustin T. Gibbs xptpathid(sim->sim_name, sim->unit_number, sim->bus_id); 43688b8a9b1dSJustin T. Gibbs } 43698b8a9b1dSJustin T. Gibbs 4370434bbf6eSJustin T. Gibbs TAILQ_INIT(&new_bus->et_entries); 43718b8a9b1dSJustin T. Gibbs new_bus->path_id = sim->path_id; 43728b8a9b1dSJustin T. Gibbs new_bus->sim = sim; 437387cfaf0eSJustin T. Gibbs timevalclear(&new_bus->last_reset); 4374434bbf6eSJustin T. Gibbs new_bus->flags = 0; 4375a5479bc5SJustin T. Gibbs new_bus->refcount = 1; /* Held until a bus_deregister event */ 4376434bbf6eSJustin T. Gibbs new_bus->generation = 0; 4377a5479bc5SJustin T. Gibbs s = splcam(); 4378434bbf6eSJustin T. Gibbs old_bus = TAILQ_FIRST(&xpt_busses); 4379434bbf6eSJustin T. Gibbs while (old_bus != NULL 4380434bbf6eSJustin T. Gibbs && old_bus->path_id < new_bus->path_id) 4381434bbf6eSJustin T. Gibbs old_bus = TAILQ_NEXT(old_bus, links); 4382434bbf6eSJustin T. Gibbs if (old_bus != NULL) 4383434bbf6eSJustin T. Gibbs TAILQ_INSERT_BEFORE(old_bus, new_bus, links); 4384434bbf6eSJustin T. Gibbs else 43858b8a9b1dSJustin T. Gibbs TAILQ_INSERT_TAIL(&xpt_busses, new_bus, links); 43868b8a9b1dSJustin T. Gibbs bus_generation++; 4387a5479bc5SJustin T. Gibbs splx(s); 43888b8a9b1dSJustin T. Gibbs 43898b8a9b1dSJustin T. Gibbs /* Notify interested parties */ 43908b8a9b1dSJustin T. Gibbs if (sim->path_id != CAM_XPT_PATH_ID) { 43918b8a9b1dSJustin T. Gibbs struct cam_path path; 43928b8a9b1dSJustin T. Gibbs 43938b8a9b1dSJustin T. Gibbs xpt_compile_path(&path, /*periph*/NULL, sim->path_id, 43948b8a9b1dSJustin T. Gibbs CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD); 43958b8a9b1dSJustin T. Gibbs xpt_setup_ccb(&cpi.ccb_h, &path, /*priority*/1); 43968b8a9b1dSJustin T. Gibbs cpi.ccb_h.func_code = XPT_PATH_INQ; 43978b8a9b1dSJustin T. Gibbs xpt_action((union ccb *)&cpi); 43983393f8daSKenneth D. Merry xpt_async(AC_PATH_REGISTERED, &path, &cpi); 43998b8a9b1dSJustin T. Gibbs xpt_release_path(&path); 44008b8a9b1dSJustin T. Gibbs } 44018b8a9b1dSJustin T. Gibbs return (CAM_SUCCESS); 44028b8a9b1dSJustin T. Gibbs } 44038b8a9b1dSJustin T. Gibbs 4404434bbf6eSJustin T. Gibbs int32_t 4405434bbf6eSJustin T. Gibbs xpt_bus_deregister(path_id_t pathid) 44068b8a9b1dSJustin T. Gibbs { 4407434bbf6eSJustin T. Gibbs struct cam_path bus_path; 4408434bbf6eSJustin T. Gibbs cam_status status; 4409434bbf6eSJustin T. Gibbs 441068153f43SScott Long GIANT_REQUIRED; 441168153f43SScott Long 4412434bbf6eSJustin T. Gibbs status = xpt_compile_path(&bus_path, NULL, pathid, 4413434bbf6eSJustin T. Gibbs CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD); 4414434bbf6eSJustin T. Gibbs if (status != CAM_REQ_CMP) 4415434bbf6eSJustin T. Gibbs return (status); 4416434bbf6eSJustin T. Gibbs 4417434bbf6eSJustin T. Gibbs xpt_async(AC_LOST_DEVICE, &bus_path, NULL); 4418434bbf6eSJustin T. Gibbs xpt_async(AC_PATH_DEREGISTERED, &bus_path, NULL); 4419434bbf6eSJustin T. Gibbs 4420434bbf6eSJustin T. Gibbs /* Release the reference count held while registered. */ 4421434bbf6eSJustin T. Gibbs xpt_release_bus(bus_path.bus); 4422434bbf6eSJustin T. Gibbs xpt_release_path(&bus_path); 4423434bbf6eSJustin T. Gibbs 4424434bbf6eSJustin T. Gibbs return (CAM_REQ_CMP); 4425434bbf6eSJustin T. Gibbs } 4426434bbf6eSJustin T. Gibbs 4427434bbf6eSJustin T. Gibbs static path_id_t 4428434bbf6eSJustin T. Gibbs xptnextfreepathid(void) 4429434bbf6eSJustin T. Gibbs { 4430434bbf6eSJustin T. Gibbs struct cam_eb *bus; 4431434bbf6eSJustin T. Gibbs path_id_t pathid; 44322398f0cdSPeter Wemm const char *strval; 44338b8a9b1dSJustin T. Gibbs 4434434bbf6eSJustin T. Gibbs pathid = 0; 4435434bbf6eSJustin T. Gibbs bus = TAILQ_FIRST(&xpt_busses); 4436434bbf6eSJustin T. Gibbs retry: 4437434bbf6eSJustin T. Gibbs /* Find an unoccupied pathid */ 4438434bbf6eSJustin T. Gibbs while (bus != NULL 4439434bbf6eSJustin T. Gibbs && bus->path_id <= pathid) { 4440434bbf6eSJustin T. Gibbs if (bus->path_id == pathid) 4441434bbf6eSJustin T. Gibbs pathid++; 4442434bbf6eSJustin T. Gibbs bus = TAILQ_NEXT(bus, links); 4443434bbf6eSJustin T. Gibbs } 4444434bbf6eSJustin T. Gibbs 4445434bbf6eSJustin T. Gibbs /* 4446434bbf6eSJustin T. Gibbs * Ensure that this pathid is not reserved for 4447434bbf6eSJustin T. Gibbs * a bus that may be registered in the future. 4448434bbf6eSJustin T. Gibbs */ 444975f51904SPeter Wemm if (resource_string_value("scbus", pathid, "at", &strval) == 0) { 4450434bbf6eSJustin T. Gibbs ++pathid; 44518b8a9b1dSJustin T. Gibbs /* Start the search over */ 4452434bbf6eSJustin T. Gibbs goto retry; 44538b8a9b1dSJustin T. Gibbs } 4454434bbf6eSJustin T. Gibbs return (pathid); 44558b8a9b1dSJustin T. Gibbs } 44568b8a9b1dSJustin T. Gibbs 4457434bbf6eSJustin T. Gibbs static path_id_t 4458434bbf6eSJustin T. Gibbs xptpathid(const char *sim_name, int sim_unit, int sim_bus) 44598b8a9b1dSJustin T. Gibbs { 44608b8a9b1dSJustin T. Gibbs path_id_t pathid; 446175f51904SPeter Wemm int i, dunit, val; 4462642f0c46SPeter Wemm char buf[32]; 44632398f0cdSPeter Wemm const char *dname; 44648b8a9b1dSJustin T. Gibbs 44658b8a9b1dSJustin T. Gibbs pathid = CAM_XPT_PATH_ID; 446675f51904SPeter Wemm snprintf(buf, sizeof(buf), "%s%d", sim_name, sim_unit); 44672398f0cdSPeter Wemm i = 0; 44682398f0cdSPeter Wemm while ((resource_find_match(&i, &dname, &dunit, "at", buf)) == 0) { 44692398f0cdSPeter Wemm if (strcmp(dname, "scbus")) { 4470642f0c46SPeter Wemm /* Avoid a bit of foot shooting. */ 4471642f0c46SPeter Wemm continue; 4472642f0c46SPeter Wemm } 447375f51904SPeter Wemm if (dunit < 0) /* unwired?! */ 44748b8a9b1dSJustin T. Gibbs continue; 447575f51904SPeter Wemm if (resource_int_value("scbus", dunit, "bus", &val) == 0) { 447675f51904SPeter Wemm if (sim_bus == val) { 447775f51904SPeter Wemm pathid = dunit; 44788b8a9b1dSJustin T. Gibbs break; 44798b8a9b1dSJustin T. Gibbs } 44808b8a9b1dSJustin T. Gibbs } else if (sim_bus == 0) { 44818b8a9b1dSJustin T. Gibbs /* Unspecified matches bus 0 */ 448275f51904SPeter Wemm pathid = dunit; 44838b8a9b1dSJustin T. Gibbs break; 44848b8a9b1dSJustin T. Gibbs } else { 44858b8a9b1dSJustin T. Gibbs printf("Ambiguous scbus configuration for %s%d " 44868b8a9b1dSJustin T. Gibbs "bus %d, cannot wire down. The kernel " 44878b8a9b1dSJustin T. Gibbs "config entry for scbus%d should " 44888b8a9b1dSJustin T. Gibbs "specify a controller bus.\n" 44898b8a9b1dSJustin T. Gibbs "Scbus will be assigned dynamically.\n", 449075f51904SPeter Wemm sim_name, sim_unit, sim_bus, dunit); 44918b8a9b1dSJustin T. Gibbs break; 44928b8a9b1dSJustin T. Gibbs } 44938b8a9b1dSJustin T. Gibbs } 44948b8a9b1dSJustin T. Gibbs 4495434bbf6eSJustin T. Gibbs if (pathid == CAM_XPT_PATH_ID) 4496434bbf6eSJustin T. Gibbs pathid = xptnextfreepathid(); 44978b8a9b1dSJustin T. Gibbs return (pathid); 44988b8a9b1dSJustin T. Gibbs } 44998b8a9b1dSJustin T. Gibbs 45008b8a9b1dSJustin T. Gibbs void 45018b8a9b1dSJustin T. Gibbs xpt_async(u_int32_t async_code, struct cam_path *path, void *async_arg) 45028b8a9b1dSJustin T. Gibbs { 45038b8a9b1dSJustin T. Gibbs struct cam_eb *bus; 45048b8a9b1dSJustin T. Gibbs struct cam_et *target, *next_target; 45058b8a9b1dSJustin T. Gibbs struct cam_ed *device, *next_device; 45068b8a9b1dSJustin T. Gibbs int s; 45078b8a9b1dSJustin T. Gibbs 450868153f43SScott Long GIANT_REQUIRED; 450968153f43SScott Long 45108b8a9b1dSJustin T. Gibbs CAM_DEBUG(path, CAM_DEBUG_TRACE, ("xpt_async\n")); 45118b8a9b1dSJustin T. Gibbs 4512a5479bc5SJustin T. Gibbs /* 4513a5479bc5SJustin T. Gibbs * Most async events come from a CAM interrupt context. In 4514a5479bc5SJustin T. Gibbs * a few cases, the error recovery code at the peripheral layer, 4515a5479bc5SJustin T. Gibbs * which may run from our SWI or a process context, may signal 4516a5479bc5SJustin T. Gibbs * deferred events with a call to xpt_async. Ensure async 4517a5479bc5SJustin T. Gibbs * notifications are serialized by blocking cam interrupts. 4518a5479bc5SJustin T. Gibbs */ 4519a5479bc5SJustin T. Gibbs s = splcam(); 45208b8a9b1dSJustin T. Gibbs 45218b8a9b1dSJustin T. Gibbs bus = path->bus; 45228b8a9b1dSJustin T. Gibbs 45238b8a9b1dSJustin T. Gibbs if (async_code == AC_BUS_RESET) { 452487cfaf0eSJustin T. Gibbs int s; 45258b8a9b1dSJustin T. Gibbs 452687cfaf0eSJustin T. Gibbs s = splclock(); 452787cfaf0eSJustin T. Gibbs /* Update our notion of when the last reset occurred */ 452887cfaf0eSJustin T. Gibbs microtime(&bus->last_reset); 452987cfaf0eSJustin T. Gibbs splx(s); 45308b8a9b1dSJustin T. Gibbs } 45318b8a9b1dSJustin T. Gibbs 45328b8a9b1dSJustin T. Gibbs for (target = TAILQ_FIRST(&bus->et_entries); 45338b8a9b1dSJustin T. Gibbs target != NULL; 45348b8a9b1dSJustin T. Gibbs target = next_target) { 45358b8a9b1dSJustin T. Gibbs 45368b8a9b1dSJustin T. Gibbs next_target = TAILQ_NEXT(target, links); 45378b8a9b1dSJustin T. Gibbs 45388b8a9b1dSJustin T. Gibbs if (path->target != target 45392f22d08dSJustin T. Gibbs && path->target->target_id != CAM_TARGET_WILDCARD 45402f22d08dSJustin T. Gibbs && target->target_id != CAM_TARGET_WILDCARD) 45418b8a9b1dSJustin T. Gibbs continue; 45428b8a9b1dSJustin T. Gibbs 454387cfaf0eSJustin T. Gibbs if (async_code == AC_SENT_BDR) { 454487cfaf0eSJustin T. Gibbs int s; 454587cfaf0eSJustin T. Gibbs 454687cfaf0eSJustin T. Gibbs /* Update our notion of when the last reset occurred */ 454787cfaf0eSJustin T. Gibbs s = splclock(); 454887cfaf0eSJustin T. Gibbs microtime(&path->target->last_reset); 454987cfaf0eSJustin T. Gibbs splx(s); 455087cfaf0eSJustin T. Gibbs } 455187cfaf0eSJustin T. Gibbs 45528b8a9b1dSJustin T. Gibbs for (device = TAILQ_FIRST(&target->ed_entries); 45538b8a9b1dSJustin T. Gibbs device != NULL; 45548b8a9b1dSJustin T. Gibbs device = next_device) { 45558b8a9b1dSJustin T. Gibbs 45568b8a9b1dSJustin T. Gibbs next_device = TAILQ_NEXT(device, links); 45578b8a9b1dSJustin T. Gibbs 45588b8a9b1dSJustin T. Gibbs if (path->device != device 45592f22d08dSJustin T. Gibbs && path->device->lun_id != CAM_LUN_WILDCARD 45602f22d08dSJustin T. Gibbs && device->lun_id != CAM_LUN_WILDCARD) 45618b8a9b1dSJustin T. Gibbs continue; 45628b8a9b1dSJustin T. Gibbs 45632f22d08dSJustin T. Gibbs xpt_dev_async(async_code, bus, target, 45642f22d08dSJustin T. Gibbs device, async_arg); 45658b8a9b1dSJustin T. Gibbs 45662f22d08dSJustin T. Gibbs xpt_async_bcast(&device->asyncs, async_code, 45672f22d08dSJustin T. Gibbs path, async_arg); 45688b8a9b1dSJustin T. Gibbs } 45698b8a9b1dSJustin T. Gibbs } 4570c8bead2aSJustin T. Gibbs 4571c8bead2aSJustin T. Gibbs /* 4572c8bead2aSJustin T. Gibbs * If this wasn't a fully wildcarded async, tell all 4573c8bead2aSJustin T. Gibbs * clients that want all async events. 4574c8bead2aSJustin T. Gibbs */ 4575c8bead2aSJustin T. Gibbs if (bus != xpt_periph->path->bus) 4576c8bead2aSJustin T. Gibbs xpt_async_bcast(&xpt_periph->path->device->asyncs, async_code, 45778b8a9b1dSJustin T. Gibbs path, async_arg); 45788b8a9b1dSJustin T. Gibbs splx(s); 45798b8a9b1dSJustin T. Gibbs } 45808b8a9b1dSJustin T. Gibbs 45818b8a9b1dSJustin T. Gibbs static void 45828b8a9b1dSJustin T. Gibbs xpt_async_bcast(struct async_list *async_head, 45838b8a9b1dSJustin T. Gibbs u_int32_t async_code, 45848b8a9b1dSJustin T. Gibbs struct cam_path *path, void *async_arg) 45858b8a9b1dSJustin T. Gibbs { 45868b8a9b1dSJustin T. Gibbs struct async_node *cur_entry; 45878b8a9b1dSJustin T. Gibbs 45888b8a9b1dSJustin T. Gibbs cur_entry = SLIST_FIRST(async_head); 45898b8a9b1dSJustin T. Gibbs while (cur_entry != NULL) { 45908b8a9b1dSJustin T. Gibbs struct async_node *next_entry; 45918b8a9b1dSJustin T. Gibbs /* 45928b8a9b1dSJustin T. Gibbs * Grab the next list entry before we call the current 45938b8a9b1dSJustin T. Gibbs * entry's callback. This is because the callback function 45948b8a9b1dSJustin T. Gibbs * can delete its async callback entry. 45958b8a9b1dSJustin T. Gibbs */ 45968b8a9b1dSJustin T. Gibbs next_entry = SLIST_NEXT(cur_entry, links); 45978b8a9b1dSJustin T. Gibbs if ((cur_entry->event_enable & async_code) != 0) 45988b8a9b1dSJustin T. Gibbs cur_entry->callback(cur_entry->callback_arg, 45998b8a9b1dSJustin T. Gibbs async_code, path, 46008b8a9b1dSJustin T. Gibbs async_arg); 46018b8a9b1dSJustin T. Gibbs cur_entry = next_entry; 46028b8a9b1dSJustin T. Gibbs } 46038b8a9b1dSJustin T. Gibbs } 46048b8a9b1dSJustin T. Gibbs 46052f22d08dSJustin T. Gibbs /* 46062f22d08dSJustin T. Gibbs * Handle any per-device event notifications that require action by the XPT. 46072f22d08dSJustin T. Gibbs */ 46082f22d08dSJustin T. Gibbs static void 46092f22d08dSJustin T. Gibbs xpt_dev_async(u_int32_t async_code, struct cam_eb *bus, struct cam_et *target, 46102f22d08dSJustin T. Gibbs struct cam_ed *device, void *async_arg) 46112f22d08dSJustin T. Gibbs { 46122f22d08dSJustin T. Gibbs cam_status status; 46132f22d08dSJustin T. Gibbs struct cam_path newpath; 46142f22d08dSJustin T. Gibbs 46152f22d08dSJustin T. Gibbs /* 46162f22d08dSJustin T. Gibbs * We only need to handle events for real devices. 46172f22d08dSJustin T. Gibbs */ 46182f22d08dSJustin T. Gibbs if (target->target_id == CAM_TARGET_WILDCARD 46192f22d08dSJustin T. Gibbs || device->lun_id == CAM_LUN_WILDCARD) 46202f22d08dSJustin T. Gibbs return; 46212f22d08dSJustin T. Gibbs 46222f22d08dSJustin T. Gibbs /* 46232f22d08dSJustin T. Gibbs * We need our own path with wildcards expanded to 46242f22d08dSJustin T. Gibbs * handle certain types of events. 46252f22d08dSJustin T. Gibbs */ 46262f22d08dSJustin T. Gibbs if ((async_code == AC_SENT_BDR) 46272f22d08dSJustin T. Gibbs || (async_code == AC_BUS_RESET) 46282f22d08dSJustin T. Gibbs || (async_code == AC_INQ_CHANGED)) 46292f22d08dSJustin T. Gibbs status = xpt_compile_path(&newpath, NULL, 46302f22d08dSJustin T. Gibbs bus->path_id, 46312f22d08dSJustin T. Gibbs target->target_id, 46322f22d08dSJustin T. Gibbs device->lun_id); 46332f22d08dSJustin T. Gibbs else 46342f22d08dSJustin T. Gibbs status = CAM_REQ_CMP_ERR; 46352f22d08dSJustin T. Gibbs 46362f22d08dSJustin T. Gibbs if (status == CAM_REQ_CMP) { 46372f22d08dSJustin T. Gibbs 46382f22d08dSJustin T. Gibbs /* 46392f22d08dSJustin T. Gibbs * Allow transfer negotiation to occur in a 46402f22d08dSJustin T. Gibbs * tag free environment. 46412f22d08dSJustin T. Gibbs */ 46422f22d08dSJustin T. Gibbs if (async_code == AC_SENT_BDR 46432f22d08dSJustin T. Gibbs || async_code == AC_BUS_RESET) 46442f22d08dSJustin T. Gibbs xpt_toggle_tags(&newpath); 46452f22d08dSJustin T. Gibbs 46462f22d08dSJustin T. Gibbs if (async_code == AC_INQ_CHANGED) { 46472f22d08dSJustin T. Gibbs /* 46482f22d08dSJustin T. Gibbs * We've sent a start unit command, or 46492f22d08dSJustin T. Gibbs * something similar to a device that 46502f22d08dSJustin T. Gibbs * may have caused its inquiry data to 46512f22d08dSJustin T. Gibbs * change. So we re-scan the device to 46522f22d08dSJustin T. Gibbs * refresh the inquiry data for it. 46532f22d08dSJustin T. Gibbs */ 46542f22d08dSJustin T. Gibbs xpt_scan_lun(newpath.periph, &newpath, 46552f22d08dSJustin T. Gibbs CAM_EXPECT_INQ_CHANGE, NULL); 46562f22d08dSJustin T. Gibbs } 46572f22d08dSJustin T. Gibbs xpt_release_path(&newpath); 46582f22d08dSJustin T. Gibbs } else if (async_code == AC_LOST_DEVICE) { 46592f22d08dSJustin T. Gibbs device->flags |= CAM_DEV_UNCONFIGURED; 46602f22d08dSJustin T. Gibbs } else if (async_code == AC_TRANSFER_NEG) { 46612f22d08dSJustin T. Gibbs struct ccb_trans_settings *settings; 46622f22d08dSJustin T. Gibbs 46632f22d08dSJustin T. Gibbs settings = (struct ccb_trans_settings *)async_arg; 46642f22d08dSJustin T. Gibbs xpt_set_transfer_settings(settings, device, 46652f22d08dSJustin T. Gibbs /*async_update*/TRUE); 46662f22d08dSJustin T. Gibbs } 46672f22d08dSJustin T. Gibbs } 46682f22d08dSJustin T. Gibbs 46698b8a9b1dSJustin T. Gibbs u_int32_t 46708b8a9b1dSJustin T. Gibbs xpt_freeze_devq(struct cam_path *path, u_int count) 46718b8a9b1dSJustin T. Gibbs { 46728b8a9b1dSJustin T. Gibbs int s; 46738b8a9b1dSJustin T. Gibbs struct ccb_hdr *ccbh; 46748b8a9b1dSJustin T. Gibbs 467568153f43SScott Long GIANT_REQUIRED; 467668153f43SScott Long 46778b8a9b1dSJustin T. Gibbs s = splcam(); 46788b8a9b1dSJustin T. Gibbs path->device->qfrozen_cnt += count; 46798b8a9b1dSJustin T. Gibbs 46808b8a9b1dSJustin T. Gibbs /* 46818b8a9b1dSJustin T. Gibbs * Mark the last CCB in the queue as needing 46828b8a9b1dSJustin T. Gibbs * to be requeued if the driver hasn't 46838b8a9b1dSJustin T. Gibbs * changed it's state yet. This fixes a race 46848b8a9b1dSJustin T. Gibbs * where a ccb is just about to be queued to 46858b8a9b1dSJustin T. Gibbs * a controller driver when it's interrupt routine 46868b8a9b1dSJustin T. Gibbs * freezes the queue. To completly close the 46878b8a9b1dSJustin T. Gibbs * hole, controller drives must check to see 46888b8a9b1dSJustin T. Gibbs * if a ccb's status is still CAM_REQ_INPROG 46898b8a9b1dSJustin T. Gibbs * under spl protection just before they queue 46908b8a9b1dSJustin T. Gibbs * the CCB. See ahc_action/ahc_freeze_devq for 46918b8a9b1dSJustin T. Gibbs * an example. 46928b8a9b1dSJustin T. Gibbs */ 4693bb6087e5SJustin T. Gibbs ccbh = TAILQ_LAST(&path->device->ccbq.active_ccbs, ccb_hdr_tailq); 46948b8a9b1dSJustin T. Gibbs if (ccbh && ccbh->status == CAM_REQ_INPROG) 46958b8a9b1dSJustin T. Gibbs ccbh->status = CAM_REQUEUE_REQ; 46968b8a9b1dSJustin T. Gibbs splx(s); 46978b8a9b1dSJustin T. Gibbs return (path->device->qfrozen_cnt); 46988b8a9b1dSJustin T. Gibbs } 46998b8a9b1dSJustin T. Gibbs 47008b8a9b1dSJustin T. Gibbs u_int32_t 47018b8a9b1dSJustin T. Gibbs xpt_freeze_simq(struct cam_sim *sim, u_int count) 47028b8a9b1dSJustin T. Gibbs { 470368153f43SScott Long GIANT_REQUIRED; 470468153f43SScott Long 47058b8a9b1dSJustin T. Gibbs sim->devq->send_queue.qfrozen_cnt += count; 47068b8a9b1dSJustin T. Gibbs if (sim->devq->active_dev != NULL) { 47078b8a9b1dSJustin T. Gibbs struct ccb_hdr *ccbh; 47088b8a9b1dSJustin T. Gibbs 47098b8a9b1dSJustin T. Gibbs ccbh = TAILQ_LAST(&sim->devq->active_dev->ccbq.active_ccbs, 4710bb6087e5SJustin T. Gibbs ccb_hdr_tailq); 47118b8a9b1dSJustin T. Gibbs if (ccbh && ccbh->status == CAM_REQ_INPROG) 47128b8a9b1dSJustin T. Gibbs ccbh->status = CAM_REQUEUE_REQ; 47138b8a9b1dSJustin T. Gibbs } 47148b8a9b1dSJustin T. Gibbs return (sim->devq->send_queue.qfrozen_cnt); 47158b8a9b1dSJustin T. Gibbs } 47168b8a9b1dSJustin T. Gibbs 47178b8a9b1dSJustin T. Gibbs static void 47188b8a9b1dSJustin T. Gibbs xpt_release_devq_timeout(void *arg) 47198b8a9b1dSJustin T. Gibbs { 47208b8a9b1dSJustin T. Gibbs struct cam_ed *device; 47218b8a9b1dSJustin T. Gibbs 47228b8a9b1dSJustin T. Gibbs device = (struct cam_ed *)arg; 47238b8a9b1dSJustin T. Gibbs 47242cefde5fSJustin T. Gibbs xpt_release_devq_device(device, /*count*/1, /*run_queue*/TRUE); 47258b8a9b1dSJustin T. Gibbs } 47268b8a9b1dSJustin T. Gibbs 47278b8a9b1dSJustin T. Gibbs void 47282cefde5fSJustin T. Gibbs xpt_release_devq(struct cam_path *path, u_int count, int run_queue) 47292cefde5fSJustin T. Gibbs { 473068153f43SScott Long GIANT_REQUIRED; 473168153f43SScott Long 47322cefde5fSJustin T. Gibbs xpt_release_devq_device(path->device, count, run_queue); 47332cefde5fSJustin T. Gibbs } 47342cefde5fSJustin T. Gibbs 47352cefde5fSJustin T. Gibbs static void 47362cefde5fSJustin T. Gibbs xpt_release_devq_device(struct cam_ed *dev, u_int count, int run_queue) 47378b8a9b1dSJustin T. Gibbs { 47388b8a9b1dSJustin T. Gibbs int rundevq; 47390642b69aSMatt Jacob int s0, s1; 47408b8a9b1dSJustin T. Gibbs 47418b8a9b1dSJustin T. Gibbs rundevq = 0; 47420642b69aSMatt Jacob s0 = splsoftcam(); 47430642b69aSMatt Jacob s1 = splcam(); 47448b8a9b1dSJustin T. Gibbs if (dev->qfrozen_cnt > 0) { 47458b8a9b1dSJustin T. Gibbs 47462cefde5fSJustin T. Gibbs count = (count > dev->qfrozen_cnt) ? dev->qfrozen_cnt : count; 47472cefde5fSJustin T. Gibbs dev->qfrozen_cnt -= count; 47488b8a9b1dSJustin T. Gibbs if (dev->qfrozen_cnt == 0) { 47498b8a9b1dSJustin T. Gibbs 47508b8a9b1dSJustin T. Gibbs /* 47518b8a9b1dSJustin T. Gibbs * No longer need to wait for a successful 47528b8a9b1dSJustin T. Gibbs * command completion. 47538b8a9b1dSJustin T. Gibbs */ 47548b8a9b1dSJustin T. Gibbs dev->flags &= ~CAM_DEV_REL_ON_COMPLETE; 47558b8a9b1dSJustin T. Gibbs 47568b8a9b1dSJustin T. Gibbs /* 47578b8a9b1dSJustin T. Gibbs * Remove any timeouts that might be scheduled 47588b8a9b1dSJustin T. Gibbs * to release this queue. 47598b8a9b1dSJustin T. Gibbs */ 47608b8a9b1dSJustin T. Gibbs if ((dev->flags & CAM_DEV_REL_TIMEOUT_PENDING) != 0) { 47618b8a9b1dSJustin T. Gibbs untimeout(xpt_release_devq_timeout, dev, 47628b8a9b1dSJustin T. Gibbs dev->c_handle); 47638b8a9b1dSJustin T. Gibbs dev->flags &= ~CAM_DEV_REL_TIMEOUT_PENDING; 47648b8a9b1dSJustin T. Gibbs } 47658b8a9b1dSJustin T. Gibbs 47668b8a9b1dSJustin T. Gibbs /* 47678b8a9b1dSJustin T. Gibbs * Now that we are unfrozen schedule the 47688b8a9b1dSJustin T. Gibbs * device so any pending transactions are 47698b8a9b1dSJustin T. Gibbs * run. 47708b8a9b1dSJustin T. Gibbs */ 47718b8a9b1dSJustin T. Gibbs if ((dev->ccbq.queue.entries > 0) 47728b8a9b1dSJustin T. Gibbs && (xpt_schedule_dev_sendq(dev->target->bus, dev)) 47738b8a9b1dSJustin T. Gibbs && (run_queue != 0)) { 47748b8a9b1dSJustin T. Gibbs rundevq = 1; 47758b8a9b1dSJustin T. Gibbs } 47768b8a9b1dSJustin T. Gibbs } 47778b8a9b1dSJustin T. Gibbs } 47780642b69aSMatt Jacob splx(s1); 47798b8a9b1dSJustin T. Gibbs if (rundevq != 0) 47808b8a9b1dSJustin T. Gibbs xpt_run_dev_sendq(dev->target->bus); 47810642b69aSMatt Jacob splx(s0); 47828b8a9b1dSJustin T. Gibbs } 47838b8a9b1dSJustin T. Gibbs 47848b8a9b1dSJustin T. Gibbs void 47858b8a9b1dSJustin T. Gibbs xpt_release_simq(struct cam_sim *sim, int run_queue) 47868b8a9b1dSJustin T. Gibbs { 47878b8a9b1dSJustin T. Gibbs int s; 47888b8a9b1dSJustin T. Gibbs struct camq *sendq; 47898b8a9b1dSJustin T. Gibbs 479068153f43SScott Long GIANT_REQUIRED; 479168153f43SScott Long 47928b8a9b1dSJustin T. Gibbs sendq = &(sim->devq->send_queue); 47938b8a9b1dSJustin T. Gibbs s = splcam(); 47948b8a9b1dSJustin T. Gibbs if (sendq->qfrozen_cnt > 0) { 47958b8a9b1dSJustin T. Gibbs 47968b8a9b1dSJustin T. Gibbs sendq->qfrozen_cnt--; 47978b8a9b1dSJustin T. Gibbs if (sendq->qfrozen_cnt == 0) { 4798a5479bc5SJustin T. Gibbs struct cam_eb *bus; 47998b8a9b1dSJustin T. Gibbs 48008b8a9b1dSJustin T. Gibbs /* 48018b8a9b1dSJustin T. Gibbs * If there is a timeout scheduled to release this 48028b8a9b1dSJustin T. Gibbs * sim queue, remove it. The queue frozen count is 48038b8a9b1dSJustin T. Gibbs * already at 0. 48048b8a9b1dSJustin T. Gibbs */ 48058b8a9b1dSJustin T. Gibbs if ((sim->flags & CAM_SIM_REL_TIMEOUT_PENDING) != 0){ 48068b8a9b1dSJustin T. Gibbs untimeout(xpt_release_simq_timeout, sim, 48078b8a9b1dSJustin T. Gibbs sim->c_handle); 48088b8a9b1dSJustin T. Gibbs sim->flags &= ~CAM_SIM_REL_TIMEOUT_PENDING; 48098b8a9b1dSJustin T. Gibbs } 4810a5479bc5SJustin T. Gibbs bus = xpt_find_bus(sim->path_id); 48118b8a9b1dSJustin T. Gibbs splx(s); 48128b8a9b1dSJustin T. Gibbs 48138b8a9b1dSJustin T. Gibbs if (run_queue) { 48148b8a9b1dSJustin T. Gibbs /* 48158b8a9b1dSJustin T. Gibbs * Now that we are unfrozen run the send queue. 48168b8a9b1dSJustin T. Gibbs */ 4817a5479bc5SJustin T. Gibbs xpt_run_dev_sendq(bus); 48188b8a9b1dSJustin T. Gibbs } 4819a5479bc5SJustin T. Gibbs xpt_release_bus(bus); 48208b8a9b1dSJustin T. Gibbs } else 48218b8a9b1dSJustin T. Gibbs splx(s); 48228b8a9b1dSJustin T. Gibbs } else 48238b8a9b1dSJustin T. Gibbs splx(s); 48248b8a9b1dSJustin T. Gibbs } 48258b8a9b1dSJustin T. Gibbs 48268b8a9b1dSJustin T. Gibbs static void 48278b8a9b1dSJustin T. Gibbs xpt_release_simq_timeout(void *arg) 48288b8a9b1dSJustin T. Gibbs { 48298b8a9b1dSJustin T. Gibbs struct cam_sim *sim; 48308b8a9b1dSJustin T. Gibbs 48318b8a9b1dSJustin T. Gibbs sim = (struct cam_sim *)arg; 48328b8a9b1dSJustin T. Gibbs xpt_release_simq(sim, /* run_queue */ TRUE); 48338b8a9b1dSJustin T. Gibbs } 48348b8a9b1dSJustin T. Gibbs 48358b8a9b1dSJustin T. Gibbs void 4836a5479bc5SJustin T. Gibbs xpt_done(union ccb *done_ccb) 48378b8a9b1dSJustin T. Gibbs { 48388b8a9b1dSJustin T. Gibbs int s; 48398b8a9b1dSJustin T. Gibbs 48408b8a9b1dSJustin T. Gibbs s = splcam(); 48418b8a9b1dSJustin T. Gibbs 48428b8a9b1dSJustin T. Gibbs CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_TRACE, ("xpt_done\n")); 48439deea857SKenneth D. Merry if ((done_ccb->ccb_h.func_code & XPT_FC_QUEUED) != 0) { 48448b8a9b1dSJustin T. Gibbs /* 48458b8a9b1dSJustin T. Gibbs * Queue up the request for handling by our SWI handler 48468b8a9b1dSJustin T. Gibbs * any of the "non-immediate" type of ccbs. 48478b8a9b1dSJustin T. Gibbs */ 48488b8a9b1dSJustin T. Gibbs switch (done_ccb->ccb_h.path->periph->type) { 48498b8a9b1dSJustin T. Gibbs case CAM_PERIPH_BIO: 4850ef3cf714SScott Long mtx_lock(&cam_bioq_lock); 48518b8a9b1dSJustin T. Gibbs TAILQ_INSERT_TAIL(&cam_bioq, &done_ccb->ccb_h, 48528b8a9b1dSJustin T. Gibbs sim_links.tqe); 48538b8a9b1dSJustin T. Gibbs done_ccb->ccb_h.pinfo.index = CAM_DONEQ_INDEX; 4854ef3cf714SScott Long mtx_unlock(&cam_bioq_lock); 4855c86b6ff5SJohn Baldwin swi_sched(cambio_ih, 0); 48568b8a9b1dSJustin T. Gibbs break; 48572e8f0ae6SScott Long default: 48582e8f0ae6SScott Long panic("unknown periph type %d", 48592e8f0ae6SScott Long done_ccb->ccb_h.path->periph->type); 48608b8a9b1dSJustin T. Gibbs } 48618b8a9b1dSJustin T. Gibbs } 48628b8a9b1dSJustin T. Gibbs splx(s); 48638b8a9b1dSJustin T. Gibbs } 48648b8a9b1dSJustin T. Gibbs 48658b8a9b1dSJustin T. Gibbs union ccb * 48668b8a9b1dSJustin T. Gibbs xpt_alloc_ccb() 48678b8a9b1dSJustin T. Gibbs { 48688b8a9b1dSJustin T. Gibbs union ccb *new_ccb; 48698b8a9b1dSJustin T. Gibbs 487068153f43SScott Long GIANT_REQUIRED; 487168153f43SScott Long 4872a163d034SWarner Losh new_ccb = malloc(sizeof(*new_ccb), M_DEVBUF, M_WAITOK); 48738b8a9b1dSJustin T. Gibbs return (new_ccb); 48748b8a9b1dSJustin T. Gibbs } 48758b8a9b1dSJustin T. Gibbs 48768b8a9b1dSJustin T. Gibbs void 48778b8a9b1dSJustin T. Gibbs xpt_free_ccb(union ccb *free_ccb) 48788b8a9b1dSJustin T. Gibbs { 48798b8a9b1dSJustin T. Gibbs free(free_ccb, M_DEVBUF); 48808b8a9b1dSJustin T. Gibbs } 48818b8a9b1dSJustin T. Gibbs 48828b8a9b1dSJustin T. Gibbs 48838b8a9b1dSJustin T. Gibbs 48848b8a9b1dSJustin T. Gibbs /* Private XPT functions */ 48858b8a9b1dSJustin T. Gibbs 48868b8a9b1dSJustin T. Gibbs /* 48878b8a9b1dSJustin T. Gibbs * Get a CAM control block for the caller. Charge the structure to the device 48888b8a9b1dSJustin T. Gibbs * referenced by the path. If the this device has no 'credits' then the 48898b8a9b1dSJustin T. Gibbs * device already has the maximum number of outstanding operations under way 48908b8a9b1dSJustin T. Gibbs * and we return NULL. If we don't have sufficient resources to allocate more 48918b8a9b1dSJustin T. Gibbs * ccbs, we also return NULL. 48928b8a9b1dSJustin T. Gibbs */ 48938b8a9b1dSJustin T. Gibbs static union ccb * 48948b8a9b1dSJustin T. Gibbs xpt_get_ccb(struct cam_ed *device) 48958b8a9b1dSJustin T. Gibbs { 48968b8a9b1dSJustin T. Gibbs union ccb *new_ccb; 48978b8a9b1dSJustin T. Gibbs int s; 48988b8a9b1dSJustin T. Gibbs 48998b8a9b1dSJustin T. Gibbs s = splsoftcam(); 4900fc2ffbe6SPoul-Henning Kamp if ((new_ccb = (union ccb *)SLIST_FIRST(&ccb_freeq)) == NULL) { 49018b8a9b1dSJustin T. Gibbs new_ccb = malloc(sizeof(*new_ccb), M_DEVBUF, M_NOWAIT); 49028b8a9b1dSJustin T. Gibbs if (new_ccb == NULL) { 49038b8a9b1dSJustin T. Gibbs splx(s); 49048b8a9b1dSJustin T. Gibbs return (NULL); 49058b8a9b1dSJustin T. Gibbs } 49068b8a9b1dSJustin T. Gibbs callout_handle_init(&new_ccb->ccb_h.timeout_ch); 49078b8a9b1dSJustin T. Gibbs SLIST_INSERT_HEAD(&ccb_freeq, &new_ccb->ccb_h, 49088b8a9b1dSJustin T. Gibbs xpt_links.sle); 49098b8a9b1dSJustin T. Gibbs xpt_ccb_count++; 49108b8a9b1dSJustin T. Gibbs } 49118b8a9b1dSJustin T. Gibbs cam_ccbq_take_opening(&device->ccbq); 49128b8a9b1dSJustin T. Gibbs SLIST_REMOVE_HEAD(&ccb_freeq, xpt_links.sle); 49138b8a9b1dSJustin T. Gibbs splx(s); 49148b8a9b1dSJustin T. Gibbs return (new_ccb); 49158b8a9b1dSJustin T. Gibbs } 49168b8a9b1dSJustin T. Gibbs 4917a5479bc5SJustin T. Gibbs static void 4918a5479bc5SJustin T. Gibbs xpt_release_bus(struct cam_eb *bus) 4919a5479bc5SJustin T. Gibbs { 4920a5479bc5SJustin T. Gibbs int s; 4921a5479bc5SJustin T. Gibbs 4922a5479bc5SJustin T. Gibbs s = splcam(); 4923a5479bc5SJustin T. Gibbs if ((--bus->refcount == 0) 4924a5479bc5SJustin T. Gibbs && (TAILQ_FIRST(&bus->et_entries) == NULL)) { 4925a5479bc5SJustin T. Gibbs TAILQ_REMOVE(&xpt_busses, bus, links); 4926a5479bc5SJustin T. Gibbs bus_generation++; 4927a5479bc5SJustin T. Gibbs splx(s); 4928a5479bc5SJustin T. Gibbs free(bus, M_DEVBUF); 4929a5479bc5SJustin T. Gibbs } else 4930a5479bc5SJustin T. Gibbs splx(s); 4931a5479bc5SJustin T. Gibbs } 49328b8a9b1dSJustin T. Gibbs 49338b8a9b1dSJustin T. Gibbs static struct cam_et * 49348b8a9b1dSJustin T. Gibbs xpt_alloc_target(struct cam_eb *bus, target_id_t target_id) 49358b8a9b1dSJustin T. Gibbs { 49368b8a9b1dSJustin T. Gibbs struct cam_et *target; 49378b8a9b1dSJustin T. Gibbs 49388b8a9b1dSJustin T. Gibbs target = (struct cam_et *)malloc(sizeof(*target), M_DEVBUF, M_NOWAIT); 49398b8a9b1dSJustin T. Gibbs if (target != NULL) { 49408b8a9b1dSJustin T. Gibbs struct cam_et *cur_target; 49418b8a9b1dSJustin T. Gibbs 4942434bbf6eSJustin T. Gibbs TAILQ_INIT(&target->ed_entries); 49438b8a9b1dSJustin T. Gibbs target->bus = bus; 49448b8a9b1dSJustin T. Gibbs target->target_id = target_id; 49458b8a9b1dSJustin T. Gibbs target->refcount = 1; 4946434bbf6eSJustin T. Gibbs target->generation = 0; 4947434bbf6eSJustin T. Gibbs timevalclear(&target->last_reset); 4948a5479bc5SJustin T. Gibbs /* 4949a5479bc5SJustin T. Gibbs * Hold a reference to our parent bus so it 4950a5479bc5SJustin T. Gibbs * will not go away before we do. 4951a5479bc5SJustin T. Gibbs */ 4952a5479bc5SJustin T. Gibbs bus->refcount++; 49538b8a9b1dSJustin T. Gibbs 49548b8a9b1dSJustin T. Gibbs /* Insertion sort into our bus's target list */ 49558b8a9b1dSJustin T. Gibbs cur_target = TAILQ_FIRST(&bus->et_entries); 49568b8a9b1dSJustin T. Gibbs while (cur_target != NULL && cur_target->target_id < target_id) 49578b8a9b1dSJustin T. Gibbs cur_target = TAILQ_NEXT(cur_target, links); 49588b8a9b1dSJustin T. Gibbs 49598b8a9b1dSJustin T. Gibbs if (cur_target != NULL) { 49608b8a9b1dSJustin T. Gibbs TAILQ_INSERT_BEFORE(cur_target, target, links); 49618b8a9b1dSJustin T. Gibbs } else { 49628b8a9b1dSJustin T. Gibbs TAILQ_INSERT_TAIL(&bus->et_entries, target, links); 49638b8a9b1dSJustin T. Gibbs } 4964a5479bc5SJustin T. Gibbs bus->generation++; 49658b8a9b1dSJustin T. Gibbs } 49668b8a9b1dSJustin T. Gibbs return (target); 49678b8a9b1dSJustin T. Gibbs } 49688b8a9b1dSJustin T. Gibbs 4969a5479bc5SJustin T. Gibbs static void 49708b8a9b1dSJustin T. Gibbs xpt_release_target(struct cam_eb *bus, struct cam_et *target) 49718b8a9b1dSJustin T. Gibbs { 4972a5479bc5SJustin T. Gibbs int s; 4973a5479bc5SJustin T. Gibbs 4974a5479bc5SJustin T. Gibbs s = splcam(); 49758b8a9b1dSJustin T. Gibbs if ((--target->refcount == 0) 49768b8a9b1dSJustin T. Gibbs && (TAILQ_FIRST(&target->ed_entries) == NULL)) { 49778b8a9b1dSJustin T. Gibbs TAILQ_REMOVE(&bus->et_entries, target, links); 49788b8a9b1dSJustin T. Gibbs bus->generation++; 4979a5479bc5SJustin T. Gibbs splx(s); 49808b8a9b1dSJustin T. Gibbs free(target, M_DEVBUF); 4981a5479bc5SJustin T. Gibbs xpt_release_bus(bus); 4982a5479bc5SJustin T. Gibbs } else 4983a5479bc5SJustin T. Gibbs splx(s); 49848b8a9b1dSJustin T. Gibbs } 49858b8a9b1dSJustin T. Gibbs 49868b8a9b1dSJustin T. Gibbs static struct cam_ed * 49878b8a9b1dSJustin T. Gibbs xpt_alloc_device(struct cam_eb *bus, struct cam_et *target, lun_id_t lun_id) 49888b8a9b1dSJustin T. Gibbs { 49893393f8daSKenneth D. Merry #ifdef CAM_NEW_TRAN_CODE 49903393f8daSKenneth D. Merry struct cam_path path; 49913393f8daSKenneth D. Merry #endif /* CAM_NEW_TRAN_CODE */ 49928b8a9b1dSJustin T. Gibbs struct cam_ed *device; 49938b8a9b1dSJustin T. Gibbs struct cam_devq *devq; 4994a5479bc5SJustin T. Gibbs cam_status status; 49958b8a9b1dSJustin T. Gibbs 49968b8a9b1dSJustin T. Gibbs /* Make space for us in the device queue on our bus */ 49978b8a9b1dSJustin T. Gibbs devq = bus->sim->devq; 49988b8a9b1dSJustin T. Gibbs status = cam_devq_resize(devq, devq->alloc_queue.array_size + 1); 49998b8a9b1dSJustin T. Gibbs 50008b8a9b1dSJustin T. Gibbs if (status != CAM_REQ_CMP) { 50018b8a9b1dSJustin T. Gibbs device = NULL; 50028b8a9b1dSJustin T. Gibbs } else { 50038b8a9b1dSJustin T. Gibbs device = (struct cam_ed *)malloc(sizeof(*device), 50048b8a9b1dSJustin T. Gibbs M_DEVBUF, M_NOWAIT); 50058b8a9b1dSJustin T. Gibbs } 50068b8a9b1dSJustin T. Gibbs 50078b8a9b1dSJustin T. Gibbs if (device != NULL) { 50088b8a9b1dSJustin T. Gibbs struct cam_ed *cur_device; 50098b8a9b1dSJustin T. Gibbs 50108b8a9b1dSJustin T. Gibbs cam_init_pinfo(&device->alloc_ccb_entry.pinfo); 50118b8a9b1dSJustin T. Gibbs device->alloc_ccb_entry.device = device; 50128b8a9b1dSJustin T. Gibbs cam_init_pinfo(&device->send_ccb_entry.pinfo); 50138b8a9b1dSJustin T. Gibbs device->send_ccb_entry.device = device; 50148b8a9b1dSJustin T. Gibbs device->target = target; 50158b8a9b1dSJustin T. Gibbs device->lun_id = lun_id; 50168b8a9b1dSJustin T. Gibbs /* Initialize our queues */ 50178b8a9b1dSJustin T. Gibbs if (camq_init(&device->drvq, 0) != 0) { 50188b8a9b1dSJustin T. Gibbs free(device, M_DEVBUF); 50198b8a9b1dSJustin T. Gibbs return (NULL); 50208b8a9b1dSJustin T. Gibbs } 50218b8a9b1dSJustin T. Gibbs if (cam_ccbq_init(&device->ccbq, 50228b8a9b1dSJustin T. Gibbs bus->sim->max_dev_openings) != 0) { 50238b8a9b1dSJustin T. Gibbs camq_fini(&device->drvq); 50248b8a9b1dSJustin T. Gibbs free(device, M_DEVBUF); 50258b8a9b1dSJustin T. Gibbs return (NULL); 50268b8a9b1dSJustin T. Gibbs } 5027434bbf6eSJustin T. Gibbs SLIST_INIT(&device->asyncs); 5028434bbf6eSJustin T. Gibbs SLIST_INIT(&device->periphs); 5029434bbf6eSJustin T. Gibbs device->generation = 0; 5030434bbf6eSJustin T. Gibbs device->owner = NULL; 5031434bbf6eSJustin T. Gibbs /* 5032434bbf6eSJustin T. Gibbs * Take the default quirk entry until we have inquiry 5033434bbf6eSJustin T. Gibbs * data and can determine a better quirk to use. 5034434bbf6eSJustin T. Gibbs */ 5035434bbf6eSJustin T. Gibbs device->quirk = &xpt_quirk_table[xpt_quirk_table_size - 1]; 5036434bbf6eSJustin T. Gibbs bzero(&device->inq_data, sizeof(device->inq_data)); 5037434bbf6eSJustin T. Gibbs device->inq_flags = 0; 5038434bbf6eSJustin T. Gibbs device->queue_flags = 0; 5039434bbf6eSJustin T. Gibbs device->serial_num = NULL; 5040434bbf6eSJustin T. Gibbs device->serial_num_len = 0; 5041434bbf6eSJustin T. Gibbs device->qfrozen_cnt = 0; 5042434bbf6eSJustin T. Gibbs device->flags = CAM_DEV_UNCONFIGURED; 5043434bbf6eSJustin T. Gibbs device->tag_delay_count = 0; 5044df8f9080SJustin T. Gibbs device->tag_saved_openings = 0; 5045434bbf6eSJustin T. Gibbs device->refcount = 1; 5046434bbf6eSJustin T. Gibbs callout_handle_init(&device->c_handle); 5047434bbf6eSJustin T. Gibbs 5048434bbf6eSJustin T. Gibbs /* 5049434bbf6eSJustin T. Gibbs * Hold a reference to our parent target so it 5050434bbf6eSJustin T. Gibbs * will not go away before we do. 5051434bbf6eSJustin T. Gibbs */ 5052434bbf6eSJustin T. Gibbs target->refcount++; 5053434bbf6eSJustin T. Gibbs 50548b8a9b1dSJustin T. Gibbs /* 50558b8a9b1dSJustin T. Gibbs * XXX should be limited by number of CCBs this bus can 50568b8a9b1dSJustin T. Gibbs * do. 50578b8a9b1dSJustin T. Gibbs */ 50588b8a9b1dSJustin T. Gibbs xpt_max_ccbs += device->ccbq.devq_openings; 50598b8a9b1dSJustin T. Gibbs /* Insertion sort into our target's device list */ 50608b8a9b1dSJustin T. Gibbs cur_device = TAILQ_FIRST(&target->ed_entries); 50618b8a9b1dSJustin T. Gibbs while (cur_device != NULL && cur_device->lun_id < lun_id) 50628b8a9b1dSJustin T. Gibbs cur_device = TAILQ_NEXT(cur_device, links); 50638b8a9b1dSJustin T. Gibbs if (cur_device != NULL) { 50648b8a9b1dSJustin T. Gibbs TAILQ_INSERT_BEFORE(cur_device, device, links); 50658b8a9b1dSJustin T. Gibbs } else { 50668b8a9b1dSJustin T. Gibbs TAILQ_INSERT_TAIL(&target->ed_entries, device, links); 50678b8a9b1dSJustin T. Gibbs } 5068a5479bc5SJustin T. Gibbs target->generation++; 50693393f8daSKenneth D. Merry #ifdef CAM_NEW_TRAN_CODE 50703393f8daSKenneth D. Merry if (lun_id != CAM_LUN_WILDCARD) { 50713393f8daSKenneth D. Merry xpt_compile_path(&path, 50723393f8daSKenneth D. Merry NULL, 50733393f8daSKenneth D. Merry bus->path_id, 50743393f8daSKenneth D. Merry target->target_id, 50753393f8daSKenneth D. Merry lun_id); 50763393f8daSKenneth D. Merry xpt_devise_transport(&path); 50773393f8daSKenneth D. Merry xpt_release_path(&path); 50783393f8daSKenneth D. Merry } 50793393f8daSKenneth D. Merry #endif /* CAM_NEW_TRAN_CODE */ 50808b8a9b1dSJustin T. Gibbs } 50818b8a9b1dSJustin T. Gibbs return (device); 50828b8a9b1dSJustin T. Gibbs } 50838b8a9b1dSJustin T. Gibbs 50848b8a9b1dSJustin T. Gibbs static void 50858b8a9b1dSJustin T. Gibbs xpt_release_device(struct cam_eb *bus, struct cam_et *target, 50868b8a9b1dSJustin T. Gibbs struct cam_ed *device) 50878b8a9b1dSJustin T. Gibbs { 50888b8a9b1dSJustin T. Gibbs int s; 50898b8a9b1dSJustin T. Gibbs 5090a5479bc5SJustin T. Gibbs s = splcam(); 50918b8a9b1dSJustin T. Gibbs if ((--device->refcount == 0) 50928b8a9b1dSJustin T. Gibbs && ((device->flags & CAM_DEV_UNCONFIGURED) != 0)) { 50938b8a9b1dSJustin T. Gibbs struct cam_devq *devq; 50948b8a9b1dSJustin T. Gibbs 5095a5479bc5SJustin T. Gibbs if (device->alloc_ccb_entry.pinfo.index != CAM_UNQUEUED_INDEX 5096a5479bc5SJustin T. Gibbs || device->send_ccb_entry.pinfo.index != CAM_UNQUEUED_INDEX) 5097a5479bc5SJustin T. Gibbs panic("Removing device while still queued for ccbs"); 50982cefde5fSJustin T. Gibbs 50992cefde5fSJustin T. Gibbs if ((device->flags & CAM_DEV_REL_TIMEOUT_PENDING) != 0) 51002cefde5fSJustin T. Gibbs untimeout(xpt_release_devq_timeout, device, 51012cefde5fSJustin T. Gibbs device->c_handle); 51022cefde5fSJustin T. Gibbs 51038b8a9b1dSJustin T. Gibbs TAILQ_REMOVE(&target->ed_entries, device,links); 51048b8a9b1dSJustin T. Gibbs target->generation++; 51058b8a9b1dSJustin T. Gibbs xpt_max_ccbs -= device->ccbq.devq_openings; 51068b8a9b1dSJustin T. Gibbs /* Release our slot in the devq */ 51078b8a9b1dSJustin T. Gibbs devq = bus->sim->devq; 51088b8a9b1dSJustin T. Gibbs cam_devq_resize(devq, devq->alloc_queue.array_size - 1); 51098b8a9b1dSJustin T. Gibbs splx(s); 5110a5479bc5SJustin T. Gibbs free(device, M_DEVBUF); 5111434bbf6eSJustin T. Gibbs xpt_release_target(bus, target); 5112a5479bc5SJustin T. Gibbs } else 5113a5479bc5SJustin T. Gibbs splx(s); 51148b8a9b1dSJustin T. Gibbs } 51158b8a9b1dSJustin T. Gibbs 51168b8a9b1dSJustin T. Gibbs static u_int32_t 51178b8a9b1dSJustin T. Gibbs xpt_dev_ccbq_resize(struct cam_path *path, int newopenings) 51188b8a9b1dSJustin T. Gibbs { 51198b8a9b1dSJustin T. Gibbs int s; 51208b8a9b1dSJustin T. Gibbs int diff; 51218b8a9b1dSJustin T. Gibbs int result; 51228b8a9b1dSJustin T. Gibbs struct cam_ed *dev; 51238b8a9b1dSJustin T. Gibbs 51248b8a9b1dSJustin T. Gibbs dev = path->device; 51258b8a9b1dSJustin T. Gibbs s = splsoftcam(); 51268b8a9b1dSJustin T. Gibbs 51278b8a9b1dSJustin T. Gibbs diff = newopenings - (dev->ccbq.dev_active + dev->ccbq.dev_openings); 51288b8a9b1dSJustin T. Gibbs result = cam_ccbq_resize(&dev->ccbq, newopenings); 51298b8a9b1dSJustin T. Gibbs if (result == CAM_REQ_CMP && (diff < 0)) { 51308b8a9b1dSJustin T. Gibbs dev->flags |= CAM_DEV_RESIZE_QUEUE_NEEDED; 51318b8a9b1dSJustin T. Gibbs } 5132df8f9080SJustin T. Gibbs if ((dev->flags & CAM_DEV_TAG_AFTER_COUNT) != 0 5133df8f9080SJustin T. Gibbs || (dev->inq_flags & SID_CmdQue) != 0) 5134df8f9080SJustin T. Gibbs dev->tag_saved_openings = newopenings; 51358b8a9b1dSJustin T. Gibbs /* Adjust the global limit */ 51368b8a9b1dSJustin T. Gibbs xpt_max_ccbs += diff; 51378b8a9b1dSJustin T. Gibbs splx(s); 51388b8a9b1dSJustin T. Gibbs return (result); 51398b8a9b1dSJustin T. Gibbs } 51408b8a9b1dSJustin T. Gibbs 51418b8a9b1dSJustin T. Gibbs static struct cam_eb * 51428b8a9b1dSJustin T. Gibbs xpt_find_bus(path_id_t path_id) 51438b8a9b1dSJustin T. Gibbs { 51448b8a9b1dSJustin T. Gibbs struct cam_eb *bus; 51458b8a9b1dSJustin T. Gibbs 51468b8a9b1dSJustin T. Gibbs for (bus = TAILQ_FIRST(&xpt_busses); 51478b8a9b1dSJustin T. Gibbs bus != NULL; 51488b8a9b1dSJustin T. Gibbs bus = TAILQ_NEXT(bus, links)) { 5149a5479bc5SJustin T. Gibbs if (bus->path_id == path_id) { 5150a5479bc5SJustin T. Gibbs bus->refcount++; 51518b8a9b1dSJustin T. Gibbs break; 51528b8a9b1dSJustin T. Gibbs } 5153a5479bc5SJustin T. Gibbs } 51548b8a9b1dSJustin T. Gibbs return (bus); 51558b8a9b1dSJustin T. Gibbs } 51568b8a9b1dSJustin T. Gibbs 51578b8a9b1dSJustin T. Gibbs static struct cam_et * 51588b8a9b1dSJustin T. Gibbs xpt_find_target(struct cam_eb *bus, target_id_t target_id) 51598b8a9b1dSJustin T. Gibbs { 51608b8a9b1dSJustin T. Gibbs struct cam_et *target; 51618b8a9b1dSJustin T. Gibbs 51628b8a9b1dSJustin T. Gibbs for (target = TAILQ_FIRST(&bus->et_entries); 51638b8a9b1dSJustin T. Gibbs target != NULL; 51648b8a9b1dSJustin T. Gibbs target = TAILQ_NEXT(target, links)) { 51658b8a9b1dSJustin T. Gibbs if (target->target_id == target_id) { 51668b8a9b1dSJustin T. Gibbs target->refcount++; 51678b8a9b1dSJustin T. Gibbs break; 51688b8a9b1dSJustin T. Gibbs } 51698b8a9b1dSJustin T. Gibbs } 51708b8a9b1dSJustin T. Gibbs return (target); 51718b8a9b1dSJustin T. Gibbs } 51728b8a9b1dSJustin T. Gibbs 51738b8a9b1dSJustin T. Gibbs static struct cam_ed * 51748b8a9b1dSJustin T. Gibbs xpt_find_device(struct cam_et *target, lun_id_t lun_id) 51758b8a9b1dSJustin T. Gibbs { 51768b8a9b1dSJustin T. Gibbs struct cam_ed *device; 51778b8a9b1dSJustin T. Gibbs 51788b8a9b1dSJustin T. Gibbs for (device = TAILQ_FIRST(&target->ed_entries); 51798b8a9b1dSJustin T. Gibbs device != NULL; 51808b8a9b1dSJustin T. Gibbs device = TAILQ_NEXT(device, links)) { 51818b8a9b1dSJustin T. Gibbs if (device->lun_id == lun_id) { 51828b8a9b1dSJustin T. Gibbs device->refcount++; 51838b8a9b1dSJustin T. Gibbs break; 51848b8a9b1dSJustin T. Gibbs } 51858b8a9b1dSJustin T. Gibbs } 51868b8a9b1dSJustin T. Gibbs return (device); 51878b8a9b1dSJustin T. Gibbs } 51888b8a9b1dSJustin T. Gibbs 51898b8a9b1dSJustin T. Gibbs typedef struct { 51908b8a9b1dSJustin T. Gibbs union ccb *request_ccb; 51918b8a9b1dSJustin T. Gibbs struct ccb_pathinq *cpi; 51928b8a9b1dSJustin T. Gibbs int pending_count; 51938b8a9b1dSJustin T. Gibbs } xpt_scan_bus_info; 51948b8a9b1dSJustin T. Gibbs 51958b8a9b1dSJustin T. Gibbs /* 51968b8a9b1dSJustin T. Gibbs * To start a scan, request_ccb is an XPT_SCAN_BUS ccb. 51978b8a9b1dSJustin T. Gibbs * As the scan progresses, xpt_scan_bus is used as the 51988b8a9b1dSJustin T. Gibbs * callback on completion function. 51998b8a9b1dSJustin T. Gibbs */ 52008b8a9b1dSJustin T. Gibbs static void 52018b8a9b1dSJustin T. Gibbs xpt_scan_bus(struct cam_periph *periph, union ccb *request_ccb) 52028b8a9b1dSJustin T. Gibbs { 52038b8a9b1dSJustin T. Gibbs CAM_DEBUG(request_ccb->ccb_h.path, CAM_DEBUG_TRACE, 52048b8a9b1dSJustin T. Gibbs ("xpt_scan_bus\n")); 52058b8a9b1dSJustin T. Gibbs switch (request_ccb->ccb_h.func_code) { 52068b8a9b1dSJustin T. Gibbs case XPT_SCAN_BUS: 52078b8a9b1dSJustin T. Gibbs { 52088b8a9b1dSJustin T. Gibbs xpt_scan_bus_info *scan_info; 52098b8a9b1dSJustin T. Gibbs union ccb *work_ccb; 52108b8a9b1dSJustin T. Gibbs struct cam_path *path; 52118b8a9b1dSJustin T. Gibbs u_int i; 52128b8a9b1dSJustin T. Gibbs u_int max_target; 52138b8a9b1dSJustin T. Gibbs u_int initiator_id; 52148b8a9b1dSJustin T. Gibbs 52158b8a9b1dSJustin T. Gibbs /* Find out the characteristics of the bus */ 52168b8a9b1dSJustin T. Gibbs work_ccb = xpt_alloc_ccb(); 52178b8a9b1dSJustin T. Gibbs xpt_setup_ccb(&work_ccb->ccb_h, request_ccb->ccb_h.path, 52188b8a9b1dSJustin T. Gibbs request_ccb->ccb_h.pinfo.priority); 52198b8a9b1dSJustin T. Gibbs work_ccb->ccb_h.func_code = XPT_PATH_INQ; 52208b8a9b1dSJustin T. Gibbs xpt_action(work_ccb); 52218b8a9b1dSJustin T. Gibbs if (work_ccb->ccb_h.status != CAM_REQ_CMP) { 52228b8a9b1dSJustin T. Gibbs request_ccb->ccb_h.status = work_ccb->ccb_h.status; 52238b8a9b1dSJustin T. Gibbs xpt_free_ccb(work_ccb); 52248b8a9b1dSJustin T. Gibbs xpt_done(request_ccb); 52258b8a9b1dSJustin T. Gibbs return; 52268b8a9b1dSJustin T. Gibbs } 52278b8a9b1dSJustin T. Gibbs 522898192658SJustin T. Gibbs if ((work_ccb->cpi.hba_misc & PIM_NOINITIATOR) != 0) { 522998192658SJustin T. Gibbs /* 523098192658SJustin T. Gibbs * Can't scan the bus on an adapter that 523198192658SJustin T. Gibbs * cannot perform the initiator role. 523298192658SJustin T. Gibbs */ 523398192658SJustin T. Gibbs request_ccb->ccb_h.status = CAM_REQ_CMP; 523498192658SJustin T. Gibbs xpt_free_ccb(work_ccb); 523598192658SJustin T. Gibbs xpt_done(request_ccb); 523698192658SJustin T. Gibbs return; 523798192658SJustin T. Gibbs } 523898192658SJustin T. Gibbs 52398b8a9b1dSJustin T. Gibbs /* Save some state for use while we probe for devices */ 52408b8a9b1dSJustin T. Gibbs scan_info = (xpt_scan_bus_info *) 5241a163d034SWarner Losh malloc(sizeof(xpt_scan_bus_info), M_TEMP, M_WAITOK); 52428b8a9b1dSJustin T. Gibbs scan_info->request_ccb = request_ccb; 52438b8a9b1dSJustin T. Gibbs scan_info->cpi = &work_ccb->cpi; 52448b8a9b1dSJustin T. Gibbs 52458b8a9b1dSJustin T. Gibbs /* Cache on our stack so we can work asynchronously */ 52468b8a9b1dSJustin T. Gibbs max_target = scan_info->cpi->max_target; 52478b8a9b1dSJustin T. Gibbs initiator_id = scan_info->cpi->initiator_id; 52488b8a9b1dSJustin T. Gibbs 52498b8a9b1dSJustin T. Gibbs /* 52508b8a9b1dSJustin T. Gibbs * Don't count the initiator if the 52518b8a9b1dSJustin T. Gibbs * initiator is addressable. 52528b8a9b1dSJustin T. Gibbs */ 52538b8a9b1dSJustin T. Gibbs scan_info->pending_count = max_target + 1; 52548b8a9b1dSJustin T. Gibbs if (initiator_id <= max_target) 52558b8a9b1dSJustin T. Gibbs scan_info->pending_count--; 52568b8a9b1dSJustin T. Gibbs 52578b8a9b1dSJustin T. Gibbs for (i = 0; i <= max_target; i++) { 52588b8a9b1dSJustin T. Gibbs cam_status status; 52598b8a9b1dSJustin T. Gibbs if (i == initiator_id) 52608b8a9b1dSJustin T. Gibbs continue; 52618b8a9b1dSJustin T. Gibbs 52628b8a9b1dSJustin T. Gibbs status = xpt_create_path(&path, xpt_periph, 52638b8a9b1dSJustin T. Gibbs request_ccb->ccb_h.path_id, 52648b8a9b1dSJustin T. Gibbs i, 0); 52658b8a9b1dSJustin T. Gibbs if (status != CAM_REQ_CMP) { 52668b8a9b1dSJustin T. Gibbs printf("xpt_scan_bus: xpt_create_path failed" 52678b8a9b1dSJustin T. Gibbs " with status %#x, bus scan halted\n", 52688b8a9b1dSJustin T. Gibbs status); 52698b8a9b1dSJustin T. Gibbs break; 52708b8a9b1dSJustin T. Gibbs } 52718b8a9b1dSJustin T. Gibbs work_ccb = xpt_alloc_ccb(); 52728b8a9b1dSJustin T. Gibbs xpt_setup_ccb(&work_ccb->ccb_h, path, 52738b8a9b1dSJustin T. Gibbs request_ccb->ccb_h.pinfo.priority); 52748b8a9b1dSJustin T. Gibbs work_ccb->ccb_h.func_code = XPT_SCAN_LUN; 52758b8a9b1dSJustin T. Gibbs work_ccb->ccb_h.cbfcnp = xpt_scan_bus; 52768b8a9b1dSJustin T. Gibbs work_ccb->ccb_h.ppriv_ptr0 = scan_info; 52778b8a9b1dSJustin T. Gibbs work_ccb->crcn.flags = request_ccb->crcn.flags; 52788b8a9b1dSJustin T. Gibbs xpt_action(work_ccb); 52798b8a9b1dSJustin T. Gibbs } 52808b8a9b1dSJustin T. Gibbs break; 52818b8a9b1dSJustin T. Gibbs } 52828b8a9b1dSJustin T. Gibbs case XPT_SCAN_LUN: 52838b8a9b1dSJustin T. Gibbs { 52848b8a9b1dSJustin T. Gibbs xpt_scan_bus_info *scan_info; 52858b8a9b1dSJustin T. Gibbs path_id_t path_id; 52868b8a9b1dSJustin T. Gibbs target_id_t target_id; 52878b8a9b1dSJustin T. Gibbs lun_id_t lun_id; 52888b8a9b1dSJustin T. Gibbs 52898b8a9b1dSJustin T. Gibbs /* Reuse the same CCB to query if a device was really found */ 52908b8a9b1dSJustin T. Gibbs scan_info = (xpt_scan_bus_info *)request_ccb->ccb_h.ppriv_ptr0; 52918b8a9b1dSJustin T. Gibbs xpt_setup_ccb(&request_ccb->ccb_h, request_ccb->ccb_h.path, 52928b8a9b1dSJustin T. Gibbs request_ccb->ccb_h.pinfo.priority); 52938b8a9b1dSJustin T. Gibbs request_ccb->ccb_h.func_code = XPT_GDEV_TYPE; 52948b8a9b1dSJustin T. Gibbs 52958b8a9b1dSJustin T. Gibbs path_id = request_ccb->ccb_h.path_id; 52968b8a9b1dSJustin T. Gibbs target_id = request_ccb->ccb_h.target_id; 52978b8a9b1dSJustin T. Gibbs lun_id = request_ccb->ccb_h.target_lun; 52988b8a9b1dSJustin T. Gibbs xpt_action(request_ccb); 52998b8a9b1dSJustin T. Gibbs 53008b8a9b1dSJustin T. Gibbs if (request_ccb->ccb_h.status != CAM_REQ_CMP) { 53018b8a9b1dSJustin T. Gibbs struct cam_ed *device; 53028b8a9b1dSJustin T. Gibbs struct cam_et *target; 5303b6a0d1abSMatt Jacob int s, phl; 53048b8a9b1dSJustin T. Gibbs 53058b8a9b1dSJustin T. Gibbs /* 53068b8a9b1dSJustin T. Gibbs * If we already probed lun 0 successfully, or 53078b8a9b1dSJustin T. Gibbs * we have additional configured luns on this 53088b8a9b1dSJustin T. Gibbs * target that might have "gone away", go onto 53098b8a9b1dSJustin T. Gibbs * the next lun. 53108b8a9b1dSJustin T. Gibbs */ 53118b8a9b1dSJustin T. Gibbs target = request_ccb->ccb_h.path->target; 5312b6a0d1abSMatt Jacob /* 5313b6a0d1abSMatt Jacob * We may touch devices that we don't 5314b6a0d1abSMatt Jacob * hold references too, so ensure they 5315b6a0d1abSMatt Jacob * don't disappear out from under us. 5316b6a0d1abSMatt Jacob * The target above is referenced by the 5317b6a0d1abSMatt Jacob * path in the request ccb. 5318b6a0d1abSMatt Jacob */ 5319b6a0d1abSMatt Jacob phl = 0; 5320a5479bc5SJustin T. Gibbs s = splcam(); 53218b8a9b1dSJustin T. Gibbs device = TAILQ_FIRST(&target->ed_entries); 5322b6a0d1abSMatt Jacob if (device != NULL) { 5323f4322bc8SMatt Jacob phl = CAN_SRCH_HI(device); 5324b6a0d1abSMatt Jacob if (device->lun_id == 0) 53258b8a9b1dSJustin T. Gibbs device = TAILQ_NEXT(device, links); 5326b6a0d1abSMatt Jacob } 5327a5479bc5SJustin T. Gibbs splx(s); 53288b8a9b1dSJustin T. Gibbs if ((lun_id != 0) || (device != NULL)) { 5329b6a0d1abSMatt Jacob if (lun_id < (CAM_SCSI2_MAXLUN-1) || phl) 53308b8a9b1dSJustin T. Gibbs lun_id++; 53318b8a9b1dSJustin T. Gibbs } 53328b8a9b1dSJustin T. Gibbs } else { 53338b8a9b1dSJustin T. Gibbs struct cam_ed *device; 53348b8a9b1dSJustin T. Gibbs 53358b8a9b1dSJustin T. Gibbs device = request_ccb->ccb_h.path->device; 53368b8a9b1dSJustin T. Gibbs 53378b8a9b1dSJustin T. Gibbs if ((device->quirk->quirks & CAM_QUIRK_NOLUNS) == 0) { 53388b8a9b1dSJustin T. Gibbs /* Try the next lun */ 5339f4322bc8SMatt Jacob if (lun_id < (CAM_SCSI2_MAXLUN-1) 5340f4322bc8SMatt Jacob || CAN_SRCH_HI(device)) 53418b8a9b1dSJustin T. Gibbs lun_id++; 53428b8a9b1dSJustin T. Gibbs } 53438b8a9b1dSJustin T. Gibbs } 53448b8a9b1dSJustin T. Gibbs 53458b8a9b1dSJustin T. Gibbs xpt_free_path(request_ccb->ccb_h.path); 53468b8a9b1dSJustin T. Gibbs 53478b8a9b1dSJustin T. Gibbs /* Check Bounds */ 53488b8a9b1dSJustin T. Gibbs if ((lun_id == request_ccb->ccb_h.target_lun) 53498b8a9b1dSJustin T. Gibbs || lun_id > scan_info->cpi->max_lun) { 53508b8a9b1dSJustin T. Gibbs /* We're done */ 53518b8a9b1dSJustin T. Gibbs 53528b8a9b1dSJustin T. Gibbs xpt_free_ccb(request_ccb); 53538b8a9b1dSJustin T. Gibbs scan_info->pending_count--; 53548b8a9b1dSJustin T. Gibbs if (scan_info->pending_count == 0) { 53558b8a9b1dSJustin T. Gibbs xpt_free_ccb((union ccb *)scan_info->cpi); 53568b8a9b1dSJustin T. Gibbs request_ccb = scan_info->request_ccb; 53578b8a9b1dSJustin T. Gibbs free(scan_info, M_TEMP); 53588b8a9b1dSJustin T. Gibbs request_ccb->ccb_h.status = CAM_REQ_CMP; 53598b8a9b1dSJustin T. Gibbs xpt_done(request_ccb); 53608b8a9b1dSJustin T. Gibbs } 53618b8a9b1dSJustin T. Gibbs } else { 53628b8a9b1dSJustin T. Gibbs /* Try the next device */ 53638b8a9b1dSJustin T. Gibbs struct cam_path *path; 53648b8a9b1dSJustin T. Gibbs cam_status status; 53658b8a9b1dSJustin T. Gibbs 53668b8a9b1dSJustin T. Gibbs path = request_ccb->ccb_h.path; 53678b8a9b1dSJustin T. Gibbs status = xpt_create_path(&path, xpt_periph, 53688b8a9b1dSJustin T. Gibbs path_id, target_id, lun_id); 53698b8a9b1dSJustin T. Gibbs if (status != CAM_REQ_CMP) { 53708b8a9b1dSJustin T. Gibbs printf("xpt_scan_bus: xpt_create_path failed " 53718b8a9b1dSJustin T. Gibbs "with status %#x, halting LUN scan\n", 53728b8a9b1dSJustin T. Gibbs status); 53738b8a9b1dSJustin T. Gibbs xpt_free_ccb(request_ccb); 53748b8a9b1dSJustin T. Gibbs scan_info->pending_count--; 53758b8a9b1dSJustin T. Gibbs if (scan_info->pending_count == 0) { 53768b8a9b1dSJustin T. Gibbs xpt_free_ccb( 53778b8a9b1dSJustin T. Gibbs (union ccb *)scan_info->cpi); 53788b8a9b1dSJustin T. Gibbs request_ccb = scan_info->request_ccb; 53798b8a9b1dSJustin T. Gibbs free(scan_info, M_TEMP); 53808b8a9b1dSJustin T. Gibbs request_ccb->ccb_h.status = CAM_REQ_CMP; 53818b8a9b1dSJustin T. Gibbs xpt_done(request_ccb); 53828b8a9b1dSJustin T. Gibbs break; 53838b8a9b1dSJustin T. Gibbs } 53848b8a9b1dSJustin T. Gibbs } 53858b8a9b1dSJustin T. Gibbs xpt_setup_ccb(&request_ccb->ccb_h, path, 53868b8a9b1dSJustin T. Gibbs request_ccb->ccb_h.pinfo.priority); 53878b8a9b1dSJustin T. Gibbs request_ccb->ccb_h.func_code = XPT_SCAN_LUN; 53888b8a9b1dSJustin T. Gibbs request_ccb->ccb_h.cbfcnp = xpt_scan_bus; 53898b8a9b1dSJustin T. Gibbs request_ccb->ccb_h.ppriv_ptr0 = scan_info; 53908b8a9b1dSJustin T. Gibbs request_ccb->crcn.flags = 53918b8a9b1dSJustin T. Gibbs scan_info->request_ccb->crcn.flags; 53928b8a9b1dSJustin T. Gibbs xpt_action(request_ccb); 53938b8a9b1dSJustin T. Gibbs } 53948b8a9b1dSJustin T. Gibbs break; 53958b8a9b1dSJustin T. Gibbs } 53968b8a9b1dSJustin T. Gibbs default: 53978b8a9b1dSJustin T. Gibbs break; 53988b8a9b1dSJustin T. Gibbs } 53998b8a9b1dSJustin T. Gibbs } 54008b8a9b1dSJustin T. Gibbs 54018b8a9b1dSJustin T. Gibbs typedef enum { 54028b8a9b1dSJustin T. Gibbs PROBE_TUR, 54038b8a9b1dSJustin T. Gibbs PROBE_INQUIRY, 54049ec5d7cdSMatt Jacob PROBE_FULL_INQUIRY, 54058b8a9b1dSJustin T. Gibbs PROBE_MODE_SENSE, 54068b8a9b1dSJustin T. Gibbs PROBE_SERIAL_NUM, 54078b8a9b1dSJustin T. Gibbs PROBE_TUR_FOR_NEGOTIATION 54088b8a9b1dSJustin T. Gibbs } probe_action; 54098b8a9b1dSJustin T. Gibbs 54108b8a9b1dSJustin T. Gibbs typedef enum { 54118b8a9b1dSJustin T. Gibbs PROBE_INQUIRY_CKSUM = 0x01, 54128b8a9b1dSJustin T. Gibbs PROBE_SERIAL_CKSUM = 0x02, 54138b8a9b1dSJustin T. Gibbs PROBE_NO_ANNOUNCE = 0x04 54148b8a9b1dSJustin T. Gibbs } probe_flags; 54158b8a9b1dSJustin T. Gibbs 54168b8a9b1dSJustin T. Gibbs typedef struct { 5417e3975643SJake Burkholder TAILQ_HEAD(, ccb_hdr) request_ccbs; 54188b8a9b1dSJustin T. Gibbs probe_action action; 54198b8a9b1dSJustin T. Gibbs union ccb saved_ccb; 54208b8a9b1dSJustin T. Gibbs probe_flags flags; 54218b8a9b1dSJustin T. Gibbs MD5_CTX context; 54228b8a9b1dSJustin T. Gibbs u_int8_t digest[16]; 54238b8a9b1dSJustin T. Gibbs } probe_softc; 54248b8a9b1dSJustin T. Gibbs 54258b8a9b1dSJustin T. Gibbs static void 54268b8a9b1dSJustin T. Gibbs xpt_scan_lun(struct cam_periph *periph, struct cam_path *path, 54278b8a9b1dSJustin T. Gibbs cam_flags flags, union ccb *request_ccb) 54288b8a9b1dSJustin T. Gibbs { 542998192658SJustin T. Gibbs struct ccb_pathinq cpi; 54308b8a9b1dSJustin T. Gibbs cam_status status; 54318b8a9b1dSJustin T. Gibbs struct cam_path *new_path; 54328b8a9b1dSJustin T. Gibbs struct cam_periph *old_periph; 54338b8a9b1dSJustin T. Gibbs int s; 54348b8a9b1dSJustin T. Gibbs 54358b8a9b1dSJustin T. Gibbs CAM_DEBUG(request_ccb->ccb_h.path, CAM_DEBUG_TRACE, 54368b8a9b1dSJustin T. Gibbs ("xpt_scan_lun\n")); 54378b8a9b1dSJustin T. Gibbs 543898192658SJustin T. Gibbs xpt_setup_ccb(&cpi.ccb_h, path, /*priority*/1); 543998192658SJustin T. Gibbs cpi.ccb_h.func_code = XPT_PATH_INQ; 544098192658SJustin T. Gibbs xpt_action((union ccb *)&cpi); 544198192658SJustin T. Gibbs 544298192658SJustin T. Gibbs if (cpi.ccb_h.status != CAM_REQ_CMP) { 544398192658SJustin T. Gibbs if (request_ccb != NULL) { 544498192658SJustin T. Gibbs request_ccb->ccb_h.status = cpi.ccb_h.status; 544598192658SJustin T. Gibbs xpt_done(request_ccb); 544698192658SJustin T. Gibbs } 544798192658SJustin T. Gibbs return; 544898192658SJustin T. Gibbs } 544998192658SJustin T. Gibbs 545098192658SJustin T. Gibbs if ((cpi.hba_misc & PIM_NOINITIATOR) != 0) { 545198192658SJustin T. Gibbs /* 545298192658SJustin T. Gibbs * Can't scan the bus on an adapter that 545398192658SJustin T. Gibbs * cannot perform the initiator role. 545498192658SJustin T. Gibbs */ 545598192658SJustin T. Gibbs if (request_ccb != NULL) { 545698192658SJustin T. Gibbs request_ccb->ccb_h.status = CAM_REQ_CMP; 545798192658SJustin T. Gibbs xpt_done(request_ccb); 545898192658SJustin T. Gibbs } 545998192658SJustin T. Gibbs return; 546098192658SJustin T. Gibbs } 546198192658SJustin T. Gibbs 54628b8a9b1dSJustin T. Gibbs if (request_ccb == NULL) { 54638b8a9b1dSJustin T. Gibbs request_ccb = malloc(sizeof(union ccb), M_TEMP, M_NOWAIT); 54648b8a9b1dSJustin T. Gibbs if (request_ccb == NULL) { 54658b8a9b1dSJustin T. Gibbs xpt_print_path(path); 54668b8a9b1dSJustin T. Gibbs printf("xpt_scan_lun: can't allocate CCB, can't " 54678b8a9b1dSJustin T. Gibbs "continue\n"); 54688b8a9b1dSJustin T. Gibbs return; 54698b8a9b1dSJustin T. Gibbs } 54708b8a9b1dSJustin T. Gibbs new_path = malloc(sizeof(*new_path), M_TEMP, M_NOWAIT); 54718b8a9b1dSJustin T. Gibbs if (new_path == NULL) { 54728b8a9b1dSJustin T. Gibbs xpt_print_path(path); 54738b8a9b1dSJustin T. Gibbs printf("xpt_scan_lun: can't allocate path, can't " 54748b8a9b1dSJustin T. Gibbs "continue\n"); 54758b8a9b1dSJustin T. Gibbs free(request_ccb, M_TEMP); 54768b8a9b1dSJustin T. Gibbs return; 54778b8a9b1dSJustin T. Gibbs } 5478fce84cb4SKenneth D. Merry status = xpt_compile_path(new_path, xpt_periph, 5479fce84cb4SKenneth D. Merry path->bus->path_id, 54808b8a9b1dSJustin T. Gibbs path->target->target_id, 54818b8a9b1dSJustin T. Gibbs path->device->lun_id); 54828b8a9b1dSJustin T. Gibbs 54838b8a9b1dSJustin T. Gibbs if (status != CAM_REQ_CMP) { 54848b8a9b1dSJustin T. Gibbs xpt_print_path(path); 54858b8a9b1dSJustin T. Gibbs printf("xpt_scan_lun: can't compile path, can't " 54868b8a9b1dSJustin T. Gibbs "continue\n"); 54878b8a9b1dSJustin T. Gibbs free(request_ccb, M_TEMP); 54888b8a9b1dSJustin T. Gibbs free(new_path, M_TEMP); 54898b8a9b1dSJustin T. Gibbs return; 54908b8a9b1dSJustin T. Gibbs } 54918b8a9b1dSJustin T. Gibbs xpt_setup_ccb(&request_ccb->ccb_h, new_path, /*priority*/ 1); 54928b8a9b1dSJustin T. Gibbs request_ccb->ccb_h.cbfcnp = xptscandone; 54938b8a9b1dSJustin T. Gibbs request_ccb->ccb_h.func_code = XPT_SCAN_LUN; 54948b8a9b1dSJustin T. Gibbs request_ccb->crcn.flags = flags; 54958b8a9b1dSJustin T. Gibbs } 54968b8a9b1dSJustin T. Gibbs 54978b8a9b1dSJustin T. Gibbs s = splsoftcam(); 54988b8a9b1dSJustin T. Gibbs if ((old_periph = cam_periph_find(path, "probe")) != NULL) { 54998b8a9b1dSJustin T. Gibbs probe_softc *softc; 55008b8a9b1dSJustin T. Gibbs 55018b8a9b1dSJustin T. Gibbs softc = (probe_softc *)old_periph->softc; 55028b8a9b1dSJustin T. Gibbs TAILQ_INSERT_TAIL(&softc->request_ccbs, &request_ccb->ccb_h, 55038b8a9b1dSJustin T. Gibbs periph_links.tqe); 55048b8a9b1dSJustin T. Gibbs } else { 5505ee9c90c7SKenneth D. Merry status = cam_periph_alloc(proberegister, NULL, probecleanup, 55068b8a9b1dSJustin T. Gibbs probestart, "probe", 55078b8a9b1dSJustin T. Gibbs CAM_PERIPH_BIO, 55088b8a9b1dSJustin T. Gibbs request_ccb->ccb_h.path, NULL, 0, 55098b8a9b1dSJustin T. Gibbs request_ccb); 55108b8a9b1dSJustin T. Gibbs 55118b8a9b1dSJustin T. Gibbs if (status != CAM_REQ_CMP) { 55128b8a9b1dSJustin T. Gibbs xpt_print_path(path); 55138b8a9b1dSJustin T. Gibbs printf("xpt_scan_lun: cam_alloc_periph returned an " 55148b8a9b1dSJustin T. Gibbs "error, can't continue probe\n"); 55158b8a9b1dSJustin T. Gibbs request_ccb->ccb_h.status = status; 55168b8a9b1dSJustin T. Gibbs xpt_done(request_ccb); 55178b8a9b1dSJustin T. Gibbs } 55188b8a9b1dSJustin T. Gibbs } 55198b8a9b1dSJustin T. Gibbs splx(s); 55208b8a9b1dSJustin T. Gibbs } 55218b8a9b1dSJustin T. Gibbs 55228b8a9b1dSJustin T. Gibbs static void 55238b8a9b1dSJustin T. Gibbs xptscandone(struct cam_periph *periph, union ccb *done_ccb) 55248b8a9b1dSJustin T. Gibbs { 55258b8a9b1dSJustin T. Gibbs xpt_release_path(done_ccb->ccb_h.path); 55268b8a9b1dSJustin T. Gibbs free(done_ccb->ccb_h.path, M_TEMP); 55278b8a9b1dSJustin T. Gibbs free(done_ccb, M_TEMP); 55288b8a9b1dSJustin T. Gibbs } 55298b8a9b1dSJustin T. Gibbs 55308b8a9b1dSJustin T. Gibbs static cam_status 55318b8a9b1dSJustin T. Gibbs proberegister(struct cam_periph *periph, void *arg) 55328b8a9b1dSJustin T. Gibbs { 553387cfaf0eSJustin T. Gibbs union ccb *request_ccb; /* CCB representing the probe request */ 55348b8a9b1dSJustin T. Gibbs probe_softc *softc; 55358b8a9b1dSJustin T. Gibbs 553687cfaf0eSJustin T. Gibbs request_ccb = (union ccb *)arg; 55378b8a9b1dSJustin T. Gibbs if (periph == NULL) { 55388b8a9b1dSJustin T. Gibbs printf("proberegister: periph was NULL!!\n"); 55398b8a9b1dSJustin T. Gibbs return(CAM_REQ_CMP_ERR); 55408b8a9b1dSJustin T. Gibbs } 55418b8a9b1dSJustin T. Gibbs 554287cfaf0eSJustin T. Gibbs if (request_ccb == NULL) { 5543434bbf6eSJustin T. Gibbs printf("proberegister: no probe CCB, " 5544434bbf6eSJustin T. Gibbs "can't register device\n"); 55458b8a9b1dSJustin T. Gibbs return(CAM_REQ_CMP_ERR); 55468b8a9b1dSJustin T. Gibbs } 55478b8a9b1dSJustin T. Gibbs 55489bc66b83SJustin T. Gibbs softc = (probe_softc *)malloc(sizeof(*softc), M_TEMP, M_NOWAIT); 55498b8a9b1dSJustin T. Gibbs 55508b8a9b1dSJustin T. Gibbs if (softc == NULL) { 55518b8a9b1dSJustin T. Gibbs printf("proberegister: Unable to probe new device. " 55528b8a9b1dSJustin T. Gibbs "Unable to allocate softc\n"); 55538b8a9b1dSJustin T. Gibbs return(CAM_REQ_CMP_ERR); 55548b8a9b1dSJustin T. Gibbs } 55558b8a9b1dSJustin T. Gibbs TAILQ_INIT(&softc->request_ccbs); 555687cfaf0eSJustin T. Gibbs TAILQ_INSERT_TAIL(&softc->request_ccbs, &request_ccb->ccb_h, 555787cfaf0eSJustin T. Gibbs periph_links.tqe); 55588b8a9b1dSJustin T. Gibbs softc->flags = 0; 55598b8a9b1dSJustin T. Gibbs periph->softc = softc; 55608b8a9b1dSJustin T. Gibbs cam_periph_acquire(periph); 556187cfaf0eSJustin T. Gibbs /* 556287cfaf0eSJustin T. Gibbs * Ensure we've waited at least a bus settle 556387cfaf0eSJustin T. Gibbs * delay before attempting to probe the device. 5564cda9006fSMatt Jacob * For HBAs that don't do bus resets, this won't make a difference. 556587cfaf0eSJustin T. Gibbs */ 556687cfaf0eSJustin T. Gibbs cam_periph_freeze_after_event(periph, &periph->path->bus->last_reset, 55673a937198SBrooks Davis scsi_delay); 55688b8a9b1dSJustin T. Gibbs probeschedule(periph); 55698b8a9b1dSJustin T. Gibbs return(CAM_REQ_CMP); 55708b8a9b1dSJustin T. Gibbs } 55718b8a9b1dSJustin T. Gibbs 55728b8a9b1dSJustin T. Gibbs static void 55738b8a9b1dSJustin T. Gibbs probeschedule(struct cam_periph *periph) 55748b8a9b1dSJustin T. Gibbs { 557587cfaf0eSJustin T. Gibbs struct ccb_pathinq cpi; 55768b8a9b1dSJustin T. Gibbs union ccb *ccb; 55778b8a9b1dSJustin T. Gibbs probe_softc *softc; 55788b8a9b1dSJustin T. Gibbs 55798b8a9b1dSJustin T. Gibbs softc = (probe_softc *)periph->softc; 55808b8a9b1dSJustin T. Gibbs ccb = (union ccb *)TAILQ_FIRST(&softc->request_ccbs); 55818b8a9b1dSJustin T. Gibbs 558287cfaf0eSJustin T. Gibbs xpt_setup_ccb(&cpi.ccb_h, periph->path, /*priority*/1); 558387cfaf0eSJustin T. Gibbs cpi.ccb_h.func_code = XPT_PATH_INQ; 558487cfaf0eSJustin T. Gibbs xpt_action((union ccb *)&cpi); 558587cfaf0eSJustin T. Gibbs 55868b8a9b1dSJustin T. Gibbs /* 55878b8a9b1dSJustin T. Gibbs * If a device has gone away and another device, or the same one, 55888b8a9b1dSJustin T. Gibbs * is back in the same place, it should have a unit attention 55898b8a9b1dSJustin T. Gibbs * condition pending. It will not report the unit attention in 55908b8a9b1dSJustin T. Gibbs * response to an inquiry, which may leave invalid transfer 55918b8a9b1dSJustin T. Gibbs * negotiations in effect. The TUR will reveal the unit attention 55928b8a9b1dSJustin T. Gibbs * condition. Only send the TUR for lun 0, since some devices 55938b8a9b1dSJustin T. Gibbs * will get confused by commands other than inquiry to non-existent 55948b8a9b1dSJustin T. Gibbs * luns. If you think a device has gone away start your scan from 55958b8a9b1dSJustin T. Gibbs * lun 0. This will insure that any bogus transfer settings are 55968b8a9b1dSJustin T. Gibbs * invalidated. 559787cfaf0eSJustin T. Gibbs * 559887cfaf0eSJustin T. Gibbs * If we haven't seen the device before and the controller supports 559987cfaf0eSJustin T. Gibbs * some kind of transfer negotiation, negotiate with the first 560087cfaf0eSJustin T. Gibbs * sent command if no bus reset was performed at startup. This 560187cfaf0eSJustin T. Gibbs * ensures that the device is not confused by transfer negotiation 560287cfaf0eSJustin T. Gibbs * settings left over by loader or BIOS action. 56038b8a9b1dSJustin T. Gibbs */ 56048b8a9b1dSJustin T. Gibbs if (((ccb->ccb_h.path->device->flags & CAM_DEV_UNCONFIGURED) == 0) 560587cfaf0eSJustin T. Gibbs && (ccb->ccb_h.target_lun == 0)) { 56068b8a9b1dSJustin T. Gibbs softc->action = PROBE_TUR; 560787cfaf0eSJustin T. Gibbs } else if ((cpi.hba_inquiry & (PI_WIDE_32|PI_WIDE_16|PI_SDTR_ABLE)) != 0 560887cfaf0eSJustin T. Gibbs && (cpi.hba_misc & PIM_NOBUSRESET) != 0) { 560987cfaf0eSJustin T. Gibbs proberequestdefaultnegotiation(periph); 56108b8a9b1dSJustin T. Gibbs softc->action = PROBE_INQUIRY; 561187cfaf0eSJustin T. Gibbs } else { 561287cfaf0eSJustin T. Gibbs softc->action = PROBE_INQUIRY; 561387cfaf0eSJustin T. Gibbs } 56148b8a9b1dSJustin T. Gibbs 56158b8a9b1dSJustin T. Gibbs if (ccb->crcn.flags & CAM_EXPECT_INQ_CHANGE) 56168b8a9b1dSJustin T. Gibbs softc->flags |= PROBE_NO_ANNOUNCE; 56178b8a9b1dSJustin T. Gibbs else 56188b8a9b1dSJustin T. Gibbs softc->flags &= ~PROBE_NO_ANNOUNCE; 56198b8a9b1dSJustin T. Gibbs 56208b8a9b1dSJustin T. Gibbs xpt_schedule(periph, ccb->ccb_h.pinfo.priority); 56218b8a9b1dSJustin T. Gibbs } 56228b8a9b1dSJustin T. Gibbs 56238b8a9b1dSJustin T. Gibbs static void 56248b8a9b1dSJustin T. Gibbs probestart(struct cam_periph *periph, union ccb *start_ccb) 56258b8a9b1dSJustin T. Gibbs { 56268b8a9b1dSJustin T. Gibbs /* Probe the device that our peripheral driver points to */ 56278b8a9b1dSJustin T. Gibbs struct ccb_scsiio *csio; 56288b8a9b1dSJustin T. Gibbs probe_softc *softc; 56298b8a9b1dSJustin T. Gibbs 56308b8a9b1dSJustin T. Gibbs CAM_DEBUG(start_ccb->ccb_h.path, CAM_DEBUG_TRACE, ("probestart\n")); 56318b8a9b1dSJustin T. Gibbs 56328b8a9b1dSJustin T. Gibbs softc = (probe_softc *)periph->softc; 56338b8a9b1dSJustin T. Gibbs csio = &start_ccb->csio; 56348b8a9b1dSJustin T. Gibbs 56358b8a9b1dSJustin T. Gibbs switch (softc->action) { 56368b8a9b1dSJustin T. Gibbs case PROBE_TUR: 56378b8a9b1dSJustin T. Gibbs case PROBE_TUR_FOR_NEGOTIATION: 56388b8a9b1dSJustin T. Gibbs { 56398b8a9b1dSJustin T. Gibbs scsi_test_unit_ready(csio, 56408b8a9b1dSJustin T. Gibbs /*retries*/4, 56418b8a9b1dSJustin T. Gibbs probedone, 56428b8a9b1dSJustin T. Gibbs MSG_SIMPLE_Q_TAG, 56438b8a9b1dSJustin T. Gibbs SSD_FULL_SIZE, 5644e471e974SJustin T. Gibbs /*timeout*/60000); 56458b8a9b1dSJustin T. Gibbs break; 56468b8a9b1dSJustin T. Gibbs } 56478b8a9b1dSJustin T. Gibbs case PROBE_INQUIRY: 56489ec5d7cdSMatt Jacob case PROBE_FULL_INQUIRY: 56498b8a9b1dSJustin T. Gibbs { 5650c19cf05dSMatt Jacob u_int inquiry_len; 56518b8a9b1dSJustin T. Gibbs struct scsi_inquiry_data *inq_buf; 56528b8a9b1dSJustin T. Gibbs 56538b8a9b1dSJustin T. Gibbs inq_buf = &periph->path->device->inq_data; 56548b8a9b1dSJustin T. Gibbs /* 56558b8a9b1dSJustin T. Gibbs * If the device is currently configured, we calculate an 56568b8a9b1dSJustin T. Gibbs * MD5 checksum of the inquiry data, and if the serial number 56578b8a9b1dSJustin T. Gibbs * length is greater than 0, add the serial number data 56588b8a9b1dSJustin T. Gibbs * into the checksum as well. Once the inquiry and the 56598b8a9b1dSJustin T. Gibbs * serial number check finish, we attempt to figure out 56608b8a9b1dSJustin T. Gibbs * whether we still have the same device. 56618b8a9b1dSJustin T. Gibbs */ 56628b8a9b1dSJustin T. Gibbs if ((periph->path->device->flags & CAM_DEV_UNCONFIGURED) == 0) { 56638b8a9b1dSJustin T. Gibbs 56648b8a9b1dSJustin T. Gibbs MD5Init(&softc->context); 56658b8a9b1dSJustin T. Gibbs MD5Update(&softc->context, (unsigned char *)inq_buf, 56668b8a9b1dSJustin T. Gibbs sizeof(struct scsi_inquiry_data)); 56678b8a9b1dSJustin T. Gibbs softc->flags |= PROBE_INQUIRY_CKSUM; 56688b8a9b1dSJustin T. Gibbs if (periph->path->device->serial_num_len > 0) { 56698b8a9b1dSJustin T. Gibbs MD5Update(&softc->context, 56708b8a9b1dSJustin T. Gibbs periph->path->device->serial_num, 56718b8a9b1dSJustin T. Gibbs periph->path->device->serial_num_len); 56728b8a9b1dSJustin T. Gibbs softc->flags |= PROBE_SERIAL_CKSUM; 56738b8a9b1dSJustin T. Gibbs } 56748b8a9b1dSJustin T. Gibbs MD5Final(softc->digest, &softc->context); 56758b8a9b1dSJustin T. Gibbs } 56768b8a9b1dSJustin T. Gibbs 56779ec5d7cdSMatt Jacob if (softc->action == PROBE_INQUIRY) 5678c19cf05dSMatt Jacob inquiry_len = SHORT_INQUIRY_LENGTH; 5679c19cf05dSMatt Jacob else 5680709a936fSJustin T. Gibbs inquiry_len = inq_buf->additional_length 5681709a936fSJustin T. Gibbs + offsetof(struct scsi_inquiry_data, 5682709a936fSJustin T. Gibbs additional_length) + 1; 5683709a936fSJustin T. Gibbs 5684709a936fSJustin T. Gibbs /* 5685709a936fSJustin T. Gibbs * Some parallel SCSI devices fail to send an 5686709a936fSJustin T. Gibbs * ignore wide residue message when dealing with 5687709a936fSJustin T. Gibbs * odd length inquiry requests. Round up to be 5688709a936fSJustin T. Gibbs * safe. 5689709a936fSJustin T. Gibbs */ 5690709a936fSJustin T. Gibbs inquiry_len = roundup2(inquiry_len, 2); 56919ec5d7cdSMatt Jacob 56928b8a9b1dSJustin T. Gibbs scsi_inquiry(csio, 56938b8a9b1dSJustin T. Gibbs /*retries*/4, 56948b8a9b1dSJustin T. Gibbs probedone, 56958b8a9b1dSJustin T. Gibbs MSG_SIMPLE_Q_TAG, 56968b8a9b1dSJustin T. Gibbs (u_int8_t *)inq_buf, 5697c19cf05dSMatt Jacob inquiry_len, 56988b8a9b1dSJustin T. Gibbs /*evpd*/FALSE, 56998b8a9b1dSJustin T. Gibbs /*page_code*/0, 57008b8a9b1dSJustin T. Gibbs SSD_MIN_SIZE, 5701e471e974SJustin T. Gibbs /*timeout*/60 * 1000); 57028b8a9b1dSJustin T. Gibbs break; 57038b8a9b1dSJustin T. Gibbs } 57048b8a9b1dSJustin T. Gibbs case PROBE_MODE_SENSE: 57058b8a9b1dSJustin T. Gibbs { 57068b8a9b1dSJustin T. Gibbs void *mode_buf; 57078b8a9b1dSJustin T. Gibbs int mode_buf_len; 57088b8a9b1dSJustin T. Gibbs 57098b8a9b1dSJustin T. Gibbs mode_buf_len = sizeof(struct scsi_mode_header_6) 57108b8a9b1dSJustin T. Gibbs + sizeof(struct scsi_mode_blk_desc) 57118b8a9b1dSJustin T. Gibbs + sizeof(struct scsi_control_page); 57128b8a9b1dSJustin T. Gibbs mode_buf = malloc(mode_buf_len, M_TEMP, M_NOWAIT); 57138b8a9b1dSJustin T. Gibbs if (mode_buf != NULL) { 57148b8a9b1dSJustin T. Gibbs scsi_mode_sense(csio, 57158b8a9b1dSJustin T. Gibbs /*retries*/4, 57168b8a9b1dSJustin T. Gibbs probedone, 57178b8a9b1dSJustin T. Gibbs MSG_SIMPLE_Q_TAG, 57188b8a9b1dSJustin T. Gibbs /*dbd*/FALSE, 57198b8a9b1dSJustin T. Gibbs SMS_PAGE_CTRL_CURRENT, 57208b8a9b1dSJustin T. Gibbs SMS_CONTROL_MODE_PAGE, 57218b8a9b1dSJustin T. Gibbs mode_buf, 57228b8a9b1dSJustin T. Gibbs mode_buf_len, 57238b8a9b1dSJustin T. Gibbs SSD_FULL_SIZE, 5724e471e974SJustin T. Gibbs /*timeout*/60000); 57258b8a9b1dSJustin T. Gibbs break; 57268b8a9b1dSJustin T. Gibbs } 57278b8a9b1dSJustin T. Gibbs xpt_print_path(periph->path); 57288b8a9b1dSJustin T. Gibbs printf("Unable to mode sense control page - malloc failure\n"); 57298b8a9b1dSJustin T. Gibbs softc->action = PROBE_SERIAL_NUM; 57308b8a9b1dSJustin T. Gibbs } 573107c6eac9SPoul-Henning Kamp /* FALLTHROUGH */ 57328b8a9b1dSJustin T. Gibbs case PROBE_SERIAL_NUM: 57338b8a9b1dSJustin T. Gibbs { 57348b8a9b1dSJustin T. Gibbs struct scsi_vpd_unit_serial_number *serial_buf; 57358b8a9b1dSJustin T. Gibbs struct cam_ed* device; 57368b8a9b1dSJustin T. Gibbs 57378b8a9b1dSJustin T. Gibbs serial_buf = NULL; 57388b8a9b1dSJustin T. Gibbs device = periph->path->device; 57398b8a9b1dSJustin T. Gibbs device->serial_num = NULL; 57408b8a9b1dSJustin T. Gibbs device->serial_num_len = 0; 57418b8a9b1dSJustin T. Gibbs 57428b8a9b1dSJustin T. Gibbs if ((device->quirk->quirks & CAM_QUIRK_NOSERIAL) == 0) 57438b8a9b1dSJustin T. Gibbs serial_buf = (struct scsi_vpd_unit_serial_number *) 57445417ec4dSDavid Malone malloc(sizeof(*serial_buf), M_TEMP, 57455417ec4dSDavid Malone M_NOWAIT | M_ZERO); 57468b8a9b1dSJustin T. Gibbs 57478b8a9b1dSJustin T. Gibbs if (serial_buf != NULL) { 57488b8a9b1dSJustin T. Gibbs scsi_inquiry(csio, 57498b8a9b1dSJustin T. Gibbs /*retries*/4, 57508b8a9b1dSJustin T. Gibbs probedone, 57518b8a9b1dSJustin T. Gibbs MSG_SIMPLE_Q_TAG, 57528b8a9b1dSJustin T. Gibbs (u_int8_t *)serial_buf, 57538b8a9b1dSJustin T. Gibbs sizeof(*serial_buf), 57548b8a9b1dSJustin T. Gibbs /*evpd*/TRUE, 57558b8a9b1dSJustin T. Gibbs SVPD_UNIT_SERIAL_NUMBER, 57568b8a9b1dSJustin T. Gibbs SSD_MIN_SIZE, 5757e471e974SJustin T. Gibbs /*timeout*/60 * 1000); 57588b8a9b1dSJustin T. Gibbs break; 57598b8a9b1dSJustin T. Gibbs } 57608b8a9b1dSJustin T. Gibbs /* 57618b8a9b1dSJustin T. Gibbs * We'll have to do without, let our probedone 57628b8a9b1dSJustin T. Gibbs * routine finish up for us. 57638b8a9b1dSJustin T. Gibbs */ 57648b8a9b1dSJustin T. Gibbs start_ccb->csio.data_ptr = NULL; 57658b8a9b1dSJustin T. Gibbs probedone(periph, start_ccb); 57668b8a9b1dSJustin T. Gibbs return; 57678b8a9b1dSJustin T. Gibbs } 57688b8a9b1dSJustin T. Gibbs } 57698b8a9b1dSJustin T. Gibbs xpt_action(start_ccb); 57708b8a9b1dSJustin T. Gibbs } 57718b8a9b1dSJustin T. Gibbs 57728b8a9b1dSJustin T. Gibbs static void 577387cfaf0eSJustin T. Gibbs proberequestdefaultnegotiation(struct cam_periph *periph) 577487cfaf0eSJustin T. Gibbs { 577587cfaf0eSJustin T. Gibbs struct ccb_trans_settings cts; 577687cfaf0eSJustin T. Gibbs 577787cfaf0eSJustin T. Gibbs xpt_setup_ccb(&cts.ccb_h, periph->path, /*priority*/1); 577887cfaf0eSJustin T. Gibbs cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS; 57793393f8daSKenneth D. Merry #ifdef CAM_NEW_TRAN_CODE 57803393f8daSKenneth D. Merry cts.type = CTS_TYPE_USER_SETTINGS; 57813393f8daSKenneth D. Merry #else /* CAM_NEW_TRAN_CODE */ 578287cfaf0eSJustin T. Gibbs cts.flags = CCB_TRANS_USER_SETTINGS; 57833393f8daSKenneth D. Merry #endif /* CAM_NEW_TRAN_CODE */ 578487cfaf0eSJustin T. Gibbs xpt_action((union ccb *)&cts); 578587cfaf0eSJustin T. Gibbs cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS; 57863393f8daSKenneth D. Merry #ifdef CAM_NEW_TRAN_CODE 57873393f8daSKenneth D. Merry cts.type = CTS_TYPE_CURRENT_SETTINGS; 57883393f8daSKenneth D. Merry #else /* CAM_NEW_TRAN_CODE */ 578987cfaf0eSJustin T. Gibbs cts.flags &= ~CCB_TRANS_USER_SETTINGS; 579087cfaf0eSJustin T. Gibbs cts.flags |= CCB_TRANS_CURRENT_SETTINGS; 57913393f8daSKenneth D. Merry #endif /* CAM_NEW_TRAN_CODE */ 579287cfaf0eSJustin T. Gibbs xpt_action((union ccb *)&cts); 579387cfaf0eSJustin T. Gibbs } 579487cfaf0eSJustin T. Gibbs 579587cfaf0eSJustin T. Gibbs static void 57968b8a9b1dSJustin T. Gibbs probedone(struct cam_periph *periph, union ccb *done_ccb) 57978b8a9b1dSJustin T. Gibbs { 57988b8a9b1dSJustin T. Gibbs probe_softc *softc; 57998b8a9b1dSJustin T. Gibbs struct cam_path *path; 58008b8a9b1dSJustin T. Gibbs u_int32_t priority; 58018b8a9b1dSJustin T. Gibbs 58028b8a9b1dSJustin T. Gibbs CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_TRACE, ("probedone\n")); 58038b8a9b1dSJustin T. Gibbs 58048b8a9b1dSJustin T. Gibbs softc = (probe_softc *)periph->softc; 58058b8a9b1dSJustin T. Gibbs path = done_ccb->ccb_h.path; 58068b8a9b1dSJustin T. Gibbs priority = done_ccb->ccb_h.pinfo.priority; 58078b8a9b1dSJustin T. Gibbs 58088b8a9b1dSJustin T. Gibbs switch (softc->action) { 58098b8a9b1dSJustin T. Gibbs case PROBE_TUR: 58108b8a9b1dSJustin T. Gibbs { 58118b8a9b1dSJustin T. Gibbs if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 58128b8a9b1dSJustin T. Gibbs 58138b8a9b1dSJustin T. Gibbs if (cam_periph_error(done_ccb, 0, 58148b8a9b1dSJustin T. Gibbs SF_NO_PRINT, NULL) == ERESTART) 58158b8a9b1dSJustin T. Gibbs return; 58168b8a9b1dSJustin T. Gibbs else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) 58178b8a9b1dSJustin T. Gibbs /* Don't wedge the queue */ 58182cefde5fSJustin T. Gibbs xpt_release_devq(done_ccb->ccb_h.path, 58192cefde5fSJustin T. Gibbs /*count*/1, 58208b8a9b1dSJustin T. Gibbs /*run_queue*/TRUE); 58218b8a9b1dSJustin T. Gibbs } 58228b8a9b1dSJustin T. Gibbs softc->action = PROBE_INQUIRY; 58238b8a9b1dSJustin T. Gibbs xpt_release_ccb(done_ccb); 58248b8a9b1dSJustin T. Gibbs xpt_schedule(periph, priority); 58258b8a9b1dSJustin T. Gibbs return; 58268b8a9b1dSJustin T. Gibbs } 58278b8a9b1dSJustin T. Gibbs case PROBE_INQUIRY: 58289ec5d7cdSMatt Jacob case PROBE_FULL_INQUIRY: 58298b8a9b1dSJustin T. Gibbs { 58308b8a9b1dSJustin T. Gibbs if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) { 58318b8a9b1dSJustin T. Gibbs struct scsi_inquiry_data *inq_buf; 58328b8a9b1dSJustin T. Gibbs u_int8_t periph_qual; 58338b8a9b1dSJustin T. Gibbs 583487cfaf0eSJustin T. Gibbs path->device->flags |= CAM_DEV_INQUIRY_DATA_VALID; 58358b8a9b1dSJustin T. Gibbs inq_buf = &path->device->inq_data; 58368b8a9b1dSJustin T. Gibbs 58378b8a9b1dSJustin T. Gibbs periph_qual = SID_QUAL(inq_buf); 58389ec5d7cdSMatt Jacob 5839c19cf05dSMatt Jacob switch(periph_qual) { 5840c19cf05dSMatt Jacob case SID_QUAL_LU_CONNECTED: 5841c19cf05dSMatt Jacob { 58429a4f1a4dSJustin T. Gibbs u_int8_t len; 5843c19cf05dSMatt Jacob 58449ec5d7cdSMatt Jacob /* 5845c19cf05dSMatt Jacob * We conservatively request only 5846c19cf05dSMatt Jacob * SHORT_INQUIRY_LEN bytes of inquiry 5847c19cf05dSMatt Jacob * information during our first try 5848c19cf05dSMatt Jacob * at sending an INQUIRY. If the device 5849c19cf05dSMatt Jacob * has more information to give, 5850c19cf05dSMatt Jacob * perform a second request specifying 5851c19cf05dSMatt Jacob * the amount of information the device 5852c19cf05dSMatt Jacob * is willing to give. 58539ec5d7cdSMatt Jacob */ 58549a4f1a4dSJustin T. Gibbs len = inq_buf->additional_length 58559a4f1a4dSJustin T. Gibbs + offsetof(struct scsi_inquiry_data, 58569a4f1a4dSJustin T. Gibbs additional_length) + 1; 5857c19cf05dSMatt Jacob if (softc->action == PROBE_INQUIRY 58589a4f1a4dSJustin T. Gibbs && len > SHORT_INQUIRY_LENGTH) { 58595cd818b1SKenneth D. Merry softc->action = PROBE_FULL_INQUIRY; 58609ec5d7cdSMatt Jacob xpt_release_ccb(done_ccb); 58619ec5d7cdSMatt Jacob xpt_schedule(periph, priority); 58629ec5d7cdSMatt Jacob return; 58639ec5d7cdSMatt Jacob } 58649ec5d7cdSMatt Jacob 58658b8a9b1dSJustin T. Gibbs xpt_find_quirk(path->device); 58668b8a9b1dSJustin T. Gibbs 58673393f8daSKenneth D. Merry #ifdef CAM_NEW_TRAN_CODE 58683393f8daSKenneth D. Merry xpt_devise_transport(path); 58693393f8daSKenneth D. Merry #endif /* CAM_NEW_TRAN_CODE */ 58708b8a9b1dSJustin T. Gibbs if ((inq_buf->flags & SID_CmdQue) != 0) 58715cd818b1SKenneth D. Merry softc->action = PROBE_MODE_SENSE; 58728b8a9b1dSJustin T. Gibbs else 58735cd818b1SKenneth D. Merry softc->action = PROBE_SERIAL_NUM; 58748b8a9b1dSJustin T. Gibbs 58755cd818b1SKenneth D. Merry path->device->flags &= ~CAM_DEV_UNCONFIGURED; 58768b8a9b1dSJustin T. Gibbs 58778b8a9b1dSJustin T. Gibbs xpt_release_ccb(done_ccb); 58788b8a9b1dSJustin T. Gibbs xpt_schedule(periph, priority); 58798b8a9b1dSJustin T. Gibbs return; 58808b8a9b1dSJustin T. Gibbs } 58818b8a9b1dSJustin T. Gibbs default: 58828b8a9b1dSJustin T. Gibbs break; 58838b8a9b1dSJustin T. Gibbs } 58848b8a9b1dSJustin T. Gibbs } else if (cam_periph_error(done_ccb, 0, 58858b8a9b1dSJustin T. Gibbs done_ccb->ccb_h.target_lun > 0 58868b8a9b1dSJustin T. Gibbs ? SF_RETRY_UA|SF_QUIET_IR 58878b8a9b1dSJustin T. Gibbs : SF_RETRY_UA, 58888b8a9b1dSJustin T. Gibbs &softc->saved_ccb) == ERESTART) { 58898b8a9b1dSJustin T. Gibbs return; 58908b8a9b1dSJustin T. Gibbs } else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) { 58918b8a9b1dSJustin T. Gibbs /* Don't wedge the queue */ 58922cefde5fSJustin T. Gibbs xpt_release_devq(done_ccb->ccb_h.path, /*count*/1, 58938b8a9b1dSJustin T. Gibbs /*run_queue*/TRUE); 58948b8a9b1dSJustin T. Gibbs } 58958b8a9b1dSJustin T. Gibbs /* 58968b8a9b1dSJustin T. Gibbs * If we get to this point, we got an error status back 58978b8a9b1dSJustin T. Gibbs * from the inquiry and the error status doesn't require 58988b8a9b1dSJustin T. Gibbs * automatically retrying the command. Therefore, the 58998b8a9b1dSJustin T. Gibbs * inquiry failed. If we had inquiry information before 59008b8a9b1dSJustin T. Gibbs * for this device, but this latest inquiry command failed, 59018b8a9b1dSJustin T. Gibbs * the device has probably gone away. If this device isn't 59028b8a9b1dSJustin T. Gibbs * already marked unconfigured, notify the peripheral 59038b8a9b1dSJustin T. Gibbs * drivers that this device is no more. 59048b8a9b1dSJustin T. Gibbs */ 59058b8a9b1dSJustin T. Gibbs if ((path->device->flags & CAM_DEV_UNCONFIGURED) == 0) 59068b8a9b1dSJustin T. Gibbs /* Send the async notification. */ 59078b8a9b1dSJustin T. Gibbs xpt_async(AC_LOST_DEVICE, path, NULL); 59088b8a9b1dSJustin T. Gibbs 59098b8a9b1dSJustin T. Gibbs xpt_release_ccb(done_ccb); 59108b8a9b1dSJustin T. Gibbs break; 59118b8a9b1dSJustin T. Gibbs } 59128b8a9b1dSJustin T. Gibbs case PROBE_MODE_SENSE: 59138b8a9b1dSJustin T. Gibbs { 59148b8a9b1dSJustin T. Gibbs struct ccb_scsiio *csio; 59158b8a9b1dSJustin T. Gibbs struct scsi_mode_header_6 *mode_hdr; 59168b8a9b1dSJustin T. Gibbs 59178b8a9b1dSJustin T. Gibbs csio = &done_ccb->csio; 59188b8a9b1dSJustin T. Gibbs mode_hdr = (struct scsi_mode_header_6 *)csio->data_ptr; 59198b8a9b1dSJustin T. Gibbs if ((csio->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) { 59208b8a9b1dSJustin T. Gibbs struct scsi_control_page *page; 59218b8a9b1dSJustin T. Gibbs u_int8_t *offset; 59228b8a9b1dSJustin T. Gibbs 59238b8a9b1dSJustin T. Gibbs offset = ((u_int8_t *)&mode_hdr[1]) 59248b8a9b1dSJustin T. Gibbs + mode_hdr->blk_desc_len; 59258b8a9b1dSJustin T. Gibbs page = (struct scsi_control_page *)offset; 59268b8a9b1dSJustin T. Gibbs path->device->queue_flags = page->queue_flags; 59278b8a9b1dSJustin T. Gibbs } else if (cam_periph_error(done_ccb, 0, 59288b8a9b1dSJustin T. Gibbs SF_RETRY_UA|SF_NO_PRINT, 59298b8a9b1dSJustin T. Gibbs &softc->saved_ccb) == ERESTART) { 59308b8a9b1dSJustin T. Gibbs return; 59318b8a9b1dSJustin T. Gibbs } else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) { 59328b8a9b1dSJustin T. Gibbs /* Don't wedge the queue */ 59332cefde5fSJustin T. Gibbs xpt_release_devq(done_ccb->ccb_h.path, 59342cefde5fSJustin T. Gibbs /*count*/1, /*run_queue*/TRUE); 59358b8a9b1dSJustin T. Gibbs } 59368b8a9b1dSJustin T. Gibbs xpt_release_ccb(done_ccb); 59378b8a9b1dSJustin T. Gibbs free(mode_hdr, M_TEMP); 59388b8a9b1dSJustin T. Gibbs softc->action = PROBE_SERIAL_NUM; 59398b8a9b1dSJustin T. Gibbs xpt_schedule(periph, priority); 59408b8a9b1dSJustin T. Gibbs return; 59418b8a9b1dSJustin T. Gibbs } 59428b8a9b1dSJustin T. Gibbs case PROBE_SERIAL_NUM: 59438b8a9b1dSJustin T. Gibbs { 59448b8a9b1dSJustin T. Gibbs struct ccb_scsiio *csio; 59458b8a9b1dSJustin T. Gibbs struct scsi_vpd_unit_serial_number *serial_buf; 59468b8a9b1dSJustin T. Gibbs u_int32_t priority; 59478b8a9b1dSJustin T. Gibbs int changed; 59488b8a9b1dSJustin T. Gibbs int have_serialnum; 59498b8a9b1dSJustin T. Gibbs 59508b8a9b1dSJustin T. Gibbs changed = 1; 59518b8a9b1dSJustin T. Gibbs have_serialnum = 0; 59528b8a9b1dSJustin T. Gibbs csio = &done_ccb->csio; 59538b8a9b1dSJustin T. Gibbs priority = done_ccb->ccb_h.pinfo.priority; 59548b8a9b1dSJustin T. Gibbs serial_buf = 59558b8a9b1dSJustin T. Gibbs (struct scsi_vpd_unit_serial_number *)csio->data_ptr; 59568b8a9b1dSJustin T. Gibbs 59578b8a9b1dSJustin T. Gibbs /* Clean up from previous instance of this device */ 59588b8a9b1dSJustin T. Gibbs if (path->device->serial_num != NULL) { 59598b8a9b1dSJustin T. Gibbs free(path->device->serial_num, M_DEVBUF); 59608b8a9b1dSJustin T. Gibbs path->device->serial_num = NULL; 59618b8a9b1dSJustin T. Gibbs path->device->serial_num_len = 0; 59628b8a9b1dSJustin T. Gibbs } 59638b8a9b1dSJustin T. Gibbs 59648b8a9b1dSJustin T. Gibbs if (serial_buf == NULL) { 59658b8a9b1dSJustin T. Gibbs /* 59668b8a9b1dSJustin T. Gibbs * Don't process the command as it was never sent 59678b8a9b1dSJustin T. Gibbs */ 59688b8a9b1dSJustin T. Gibbs } else if ((csio->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP 59698b8a9b1dSJustin T. Gibbs && (serial_buf->length > 0)) { 59708b8a9b1dSJustin T. Gibbs 59718b8a9b1dSJustin T. Gibbs have_serialnum = 1; 59728b8a9b1dSJustin T. Gibbs path->device->serial_num = 59738b8a9b1dSJustin T. Gibbs (u_int8_t *)malloc((serial_buf->length + 1), 59748b8a9b1dSJustin T. Gibbs M_DEVBUF, M_NOWAIT); 59758b8a9b1dSJustin T. Gibbs if (path->device->serial_num != NULL) { 59768b8a9b1dSJustin T. Gibbs bcopy(serial_buf->serial_num, 59778b8a9b1dSJustin T. Gibbs path->device->serial_num, 59788b8a9b1dSJustin T. Gibbs serial_buf->length); 59798b8a9b1dSJustin T. Gibbs path->device->serial_num_len = 59808b8a9b1dSJustin T. Gibbs serial_buf->length; 59818b8a9b1dSJustin T. Gibbs path->device->serial_num[serial_buf->length] 59828b8a9b1dSJustin T. Gibbs = '\0'; 59838b8a9b1dSJustin T. Gibbs } 59848b8a9b1dSJustin T. Gibbs } else if (cam_periph_error(done_ccb, 0, 59858b8a9b1dSJustin T. Gibbs SF_RETRY_UA|SF_NO_PRINT, 59868b8a9b1dSJustin T. Gibbs &softc->saved_ccb) == ERESTART) { 59878b8a9b1dSJustin T. Gibbs return; 59888b8a9b1dSJustin T. Gibbs } else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) { 59898b8a9b1dSJustin T. Gibbs /* Don't wedge the queue */ 59902cefde5fSJustin T. Gibbs xpt_release_devq(done_ccb->ccb_h.path, /*count*/1, 59918b8a9b1dSJustin T. Gibbs /*run_queue*/TRUE); 59928b8a9b1dSJustin T. Gibbs } 59938b8a9b1dSJustin T. Gibbs 59948b8a9b1dSJustin T. Gibbs /* 59958b8a9b1dSJustin T. Gibbs * Let's see if we have seen this device before. 59968b8a9b1dSJustin T. Gibbs */ 59978b8a9b1dSJustin T. Gibbs if ((softc->flags & PROBE_INQUIRY_CKSUM) != 0) { 59988b8a9b1dSJustin T. Gibbs MD5_CTX context; 59998b8a9b1dSJustin T. Gibbs u_int8_t digest[16]; 60008b8a9b1dSJustin T. Gibbs 60018b8a9b1dSJustin T. Gibbs MD5Init(&context); 60028b8a9b1dSJustin T. Gibbs 60038b8a9b1dSJustin T. Gibbs MD5Update(&context, 60048b8a9b1dSJustin T. Gibbs (unsigned char *)&path->device->inq_data, 60058b8a9b1dSJustin T. Gibbs sizeof(struct scsi_inquiry_data)); 60068b8a9b1dSJustin T. Gibbs 60078b8a9b1dSJustin T. Gibbs if (have_serialnum) 60088b8a9b1dSJustin T. Gibbs MD5Update(&context, serial_buf->serial_num, 60098b8a9b1dSJustin T. Gibbs serial_buf->length); 60108b8a9b1dSJustin T. Gibbs 60118b8a9b1dSJustin T. Gibbs MD5Final(digest, &context); 60128b8a9b1dSJustin T. Gibbs if (bcmp(softc->digest, digest, 16) == 0) 60138b8a9b1dSJustin T. Gibbs changed = 0; 60148b8a9b1dSJustin T. Gibbs 60158b8a9b1dSJustin T. Gibbs /* 60168b8a9b1dSJustin T. Gibbs * XXX Do we need to do a TUR in order to ensure 60178b8a9b1dSJustin T. Gibbs * that the device really hasn't changed??? 60188b8a9b1dSJustin T. Gibbs */ 60198b8a9b1dSJustin T. Gibbs if ((changed != 0) 60208b8a9b1dSJustin T. Gibbs && ((softc->flags & PROBE_NO_ANNOUNCE) == 0)) 60218b8a9b1dSJustin T. Gibbs xpt_async(AC_LOST_DEVICE, path, NULL); 60228b8a9b1dSJustin T. Gibbs } 60238b8a9b1dSJustin T. Gibbs if (serial_buf != NULL) 60248b8a9b1dSJustin T. Gibbs free(serial_buf, M_TEMP); 60258b8a9b1dSJustin T. Gibbs 60268b8a9b1dSJustin T. Gibbs if (changed != 0) { 60278b8a9b1dSJustin T. Gibbs /* 60288b8a9b1dSJustin T. Gibbs * Now that we have all the necessary 60298b8a9b1dSJustin T. Gibbs * information to safely perform transfer 60308b8a9b1dSJustin T. Gibbs * negotiations... Controllers don't perform 60318b8a9b1dSJustin T. Gibbs * any negotiation or tagged queuing until 60328b8a9b1dSJustin T. Gibbs * after the first XPT_SET_TRAN_SETTINGS ccb is 60338b8a9b1dSJustin T. Gibbs * received. So, on a new device, just retreive 60348b8a9b1dSJustin T. Gibbs * the user settings, and set them as the current 60358b8a9b1dSJustin T. Gibbs * settings to set the device up. 60368b8a9b1dSJustin T. Gibbs */ 603787cfaf0eSJustin T. Gibbs proberequestdefaultnegotiation(periph); 60388b8a9b1dSJustin T. Gibbs xpt_release_ccb(done_ccb); 60398b8a9b1dSJustin T. Gibbs 60408b8a9b1dSJustin T. Gibbs /* 60418b8a9b1dSJustin T. Gibbs * Perform a TUR to allow the controller to 60428b8a9b1dSJustin T. Gibbs * perform any necessary transfer negotiation. 60438b8a9b1dSJustin T. Gibbs */ 60448b8a9b1dSJustin T. Gibbs softc->action = PROBE_TUR_FOR_NEGOTIATION; 60458b8a9b1dSJustin T. Gibbs xpt_schedule(periph, priority); 60468b8a9b1dSJustin T. Gibbs return; 60478b8a9b1dSJustin T. Gibbs } 60488b8a9b1dSJustin T. Gibbs xpt_release_ccb(done_ccb); 60498b8a9b1dSJustin T. Gibbs break; 60508b8a9b1dSJustin T. Gibbs } 60518b8a9b1dSJustin T. Gibbs case PROBE_TUR_FOR_NEGOTIATION: 60528b8a9b1dSJustin T. Gibbs if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) { 60538b8a9b1dSJustin T. Gibbs /* Don't wedge the queue */ 60542cefde5fSJustin T. Gibbs xpt_release_devq(done_ccb->ccb_h.path, /*count*/1, 60558b8a9b1dSJustin T. Gibbs /*run_queue*/TRUE); 60568b8a9b1dSJustin T. Gibbs } 60578b8a9b1dSJustin T. Gibbs 60588b8a9b1dSJustin T. Gibbs path->device->flags &= ~CAM_DEV_UNCONFIGURED; 60598b8a9b1dSJustin T. Gibbs 60608b8a9b1dSJustin T. Gibbs if ((softc->flags & PROBE_NO_ANNOUNCE) == 0) { 60618b8a9b1dSJustin T. Gibbs /* Inform the XPT that a new device has been found */ 60628b8a9b1dSJustin T. Gibbs done_ccb->ccb_h.func_code = XPT_GDEV_TYPE; 60638b8a9b1dSJustin T. Gibbs xpt_action(done_ccb); 60648b8a9b1dSJustin T. Gibbs 6065df8f9080SJustin T. Gibbs xpt_async(AC_FOUND_DEVICE, done_ccb->ccb_h.path, 6066df8f9080SJustin T. Gibbs done_ccb); 60678b8a9b1dSJustin T. Gibbs } 60688b8a9b1dSJustin T. Gibbs xpt_release_ccb(done_ccb); 60698b8a9b1dSJustin T. Gibbs break; 60708b8a9b1dSJustin T. Gibbs } 60718b8a9b1dSJustin T. Gibbs done_ccb = (union ccb *)TAILQ_FIRST(&softc->request_ccbs); 60728b8a9b1dSJustin T. Gibbs TAILQ_REMOVE(&softc->request_ccbs, &done_ccb->ccb_h, periph_links.tqe); 60738b8a9b1dSJustin T. Gibbs done_ccb->ccb_h.status = CAM_REQ_CMP; 60748b8a9b1dSJustin T. Gibbs xpt_done(done_ccb); 60758b8a9b1dSJustin T. Gibbs if (TAILQ_FIRST(&softc->request_ccbs) == NULL) { 60768b8a9b1dSJustin T. Gibbs cam_periph_invalidate(periph); 60778b8a9b1dSJustin T. Gibbs cam_periph_release(periph); 60788b8a9b1dSJustin T. Gibbs } else { 60798b8a9b1dSJustin T. Gibbs probeschedule(periph); 60808b8a9b1dSJustin T. Gibbs } 60818b8a9b1dSJustin T. Gibbs } 60828b8a9b1dSJustin T. Gibbs 60838b8a9b1dSJustin T. Gibbs static void 60848b8a9b1dSJustin T. Gibbs probecleanup(struct cam_periph *periph) 60858b8a9b1dSJustin T. Gibbs { 60868b8a9b1dSJustin T. Gibbs free(periph->softc, M_TEMP); 60878b8a9b1dSJustin T. Gibbs } 60888b8a9b1dSJustin T. Gibbs 60898b8a9b1dSJustin T. Gibbs static void 60908b8a9b1dSJustin T. Gibbs xpt_find_quirk(struct cam_ed *device) 60918b8a9b1dSJustin T. Gibbs { 60928b8a9b1dSJustin T. Gibbs caddr_t match; 60938b8a9b1dSJustin T. Gibbs 60948b8a9b1dSJustin T. Gibbs match = cam_quirkmatch((caddr_t)&device->inq_data, 60958b8a9b1dSJustin T. Gibbs (caddr_t)xpt_quirk_table, 60968b8a9b1dSJustin T. Gibbs sizeof(xpt_quirk_table)/sizeof(*xpt_quirk_table), 60978b8a9b1dSJustin T. Gibbs sizeof(*xpt_quirk_table), scsi_inquiry_match); 60988b8a9b1dSJustin T. Gibbs 60998b8a9b1dSJustin T. Gibbs if (match == NULL) 61008b8a9b1dSJustin T. Gibbs panic("xpt_find_quirk: device didn't match wildcard entry!!"); 61018b8a9b1dSJustin T. Gibbs 61028b8a9b1dSJustin T. Gibbs device->quirk = (struct xpt_quirk_entry *)match; 61038b8a9b1dSJustin T. Gibbs } 61048b8a9b1dSJustin T. Gibbs 61053393f8daSKenneth D. Merry #ifdef CAM_NEW_TRAN_CODE 61063393f8daSKenneth D. Merry 61073393f8daSKenneth D. Merry static void 61083393f8daSKenneth D. Merry xpt_devise_transport(struct cam_path *path) 61093393f8daSKenneth D. Merry { 61103393f8daSKenneth D. Merry struct ccb_pathinq cpi; 61113393f8daSKenneth D. Merry struct ccb_trans_settings cts; 61123393f8daSKenneth D. Merry struct scsi_inquiry_data *inq_buf; 61133393f8daSKenneth D. Merry 61143393f8daSKenneth D. Merry /* Get transport information from the SIM */ 61153393f8daSKenneth D. Merry xpt_setup_ccb(&cpi.ccb_h, path, /*priority*/1); 61163393f8daSKenneth D. Merry cpi.ccb_h.func_code = XPT_PATH_INQ; 61173393f8daSKenneth D. Merry xpt_action((union ccb *)&cpi); 61183393f8daSKenneth D. Merry 61193393f8daSKenneth D. Merry inq_buf = NULL; 61203393f8daSKenneth D. Merry if ((path->device->flags & CAM_DEV_INQUIRY_DATA_VALID) != 0) 61213393f8daSKenneth D. Merry inq_buf = &path->device->inq_data; 61223393f8daSKenneth D. Merry path->device->protocol = PROTO_SCSI; 61233393f8daSKenneth D. Merry path->device->protocol_version = 61243393f8daSKenneth D. Merry inq_buf != NULL ? SID_ANSI_REV(inq_buf) : cpi.protocol_version; 61253393f8daSKenneth D. Merry path->device->transport = cpi.transport; 61263393f8daSKenneth D. Merry path->device->transport_version = cpi.transport_version; 61273393f8daSKenneth D. Merry 61283393f8daSKenneth D. Merry /* 61293393f8daSKenneth D. Merry * Any device not using SPI3 features should 61303393f8daSKenneth D. Merry * be considered SPI2 or lower. 61313393f8daSKenneth D. Merry */ 61323393f8daSKenneth D. Merry if (inq_buf != NULL) { 61333393f8daSKenneth D. Merry if (path->device->transport == XPORT_SPI 61343393f8daSKenneth D. Merry && (inq_buf->spi3data & SID_SPI_MASK) == 0 61353393f8daSKenneth D. Merry && path->device->transport_version > 2) 61363393f8daSKenneth D. Merry path->device->transport_version = 2; 61373393f8daSKenneth D. Merry } else { 61383393f8daSKenneth D. Merry struct cam_ed* otherdev; 61393393f8daSKenneth D. Merry 61403393f8daSKenneth D. Merry for (otherdev = TAILQ_FIRST(&path->target->ed_entries); 61413393f8daSKenneth D. Merry otherdev != NULL; 61423393f8daSKenneth D. Merry otherdev = TAILQ_NEXT(otherdev, links)) { 61433393f8daSKenneth D. Merry if (otherdev != path->device) 61443393f8daSKenneth D. Merry break; 61453393f8daSKenneth D. Merry } 61463393f8daSKenneth D. Merry 61473393f8daSKenneth D. Merry if (otherdev != NULL) { 61483393f8daSKenneth D. Merry /* 61493393f8daSKenneth D. Merry * Initially assume the same versioning as 61503393f8daSKenneth D. Merry * prior luns for this target. 61513393f8daSKenneth D. Merry */ 61523393f8daSKenneth D. Merry path->device->protocol_version = 61533393f8daSKenneth D. Merry otherdev->protocol_version; 61543393f8daSKenneth D. Merry path->device->transport_version = 61553393f8daSKenneth D. Merry otherdev->transport_version; 61563393f8daSKenneth D. Merry } else { 61573393f8daSKenneth D. Merry /* Until we know better, opt for safty */ 61583393f8daSKenneth D. Merry path->device->protocol_version = 2; 61593393f8daSKenneth D. Merry if (path->device->transport == XPORT_SPI) 61603393f8daSKenneth D. Merry path->device->transport_version = 2; 61613393f8daSKenneth D. Merry else 61623393f8daSKenneth D. Merry path->device->transport_version = 0; 61633393f8daSKenneth D. Merry } 61643393f8daSKenneth D. Merry } 61653393f8daSKenneth D. Merry 61663393f8daSKenneth D. Merry /* 61673393f8daSKenneth D. Merry * XXX 61683393f8daSKenneth D. Merry * For a device compliant with SPC-2 we should be able 61693393f8daSKenneth D. Merry * to determine the transport version supported by 61703393f8daSKenneth D. Merry * scrutinizing the version descriptors in the 61713393f8daSKenneth D. Merry * inquiry buffer. 61723393f8daSKenneth D. Merry */ 61733393f8daSKenneth D. Merry 61743393f8daSKenneth D. Merry /* Tell the controller what we think */ 61753393f8daSKenneth D. Merry xpt_setup_ccb(&cts.ccb_h, path, /*priority*/1); 61763393f8daSKenneth D. Merry cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS; 61773393f8daSKenneth D. Merry cts.type = CTS_TYPE_CURRENT_SETTINGS; 61783393f8daSKenneth D. Merry cts.transport = path->device->transport; 61793393f8daSKenneth D. Merry cts.transport_version = path->device->transport_version; 61803393f8daSKenneth D. Merry cts.protocol = path->device->protocol; 61813393f8daSKenneth D. Merry cts.protocol_version = path->device->protocol_version; 61823393f8daSKenneth D. Merry cts.proto_specific.valid = 0; 61833393f8daSKenneth D. Merry cts.xport_specific.valid = 0; 61843393f8daSKenneth D. Merry xpt_action((union ccb *)&cts); 61853393f8daSKenneth D. Merry } 61863393f8daSKenneth D. Merry 61873393f8daSKenneth D. Merry static void 61883393f8daSKenneth D. Merry xpt_set_transfer_settings(struct ccb_trans_settings *cts, struct cam_ed *device, 61893393f8daSKenneth D. Merry int async_update) 61903393f8daSKenneth D. Merry { 61913393f8daSKenneth D. Merry struct ccb_pathinq cpi; 61923393f8daSKenneth D. Merry struct ccb_trans_settings cur_cts; 61933393f8daSKenneth D. Merry struct ccb_trans_settings_scsi *scsi; 61943393f8daSKenneth D. Merry struct ccb_trans_settings_scsi *cur_scsi; 61953393f8daSKenneth D. Merry struct cam_sim *sim; 61963393f8daSKenneth D. Merry struct scsi_inquiry_data *inq_data; 61973393f8daSKenneth D. Merry 61983393f8daSKenneth D. Merry if (device == NULL) { 61993393f8daSKenneth D. Merry cts->ccb_h.status = CAM_PATH_INVALID; 62003393f8daSKenneth D. Merry xpt_done((union ccb *)cts); 62013393f8daSKenneth D. Merry return; 62023393f8daSKenneth D. Merry } 62033393f8daSKenneth D. Merry 62043393f8daSKenneth D. Merry if (cts->protocol == PROTO_UNKNOWN 62053393f8daSKenneth D. Merry || cts->protocol == PROTO_UNSPECIFIED) { 62063393f8daSKenneth D. Merry cts->protocol = device->protocol; 62073393f8daSKenneth D. Merry cts->protocol_version = device->protocol_version; 62083393f8daSKenneth D. Merry } 62093393f8daSKenneth D. Merry 62103393f8daSKenneth D. Merry if (cts->protocol_version == PROTO_VERSION_UNKNOWN 62113393f8daSKenneth D. Merry || cts->protocol_version == PROTO_VERSION_UNSPECIFIED) 62123393f8daSKenneth D. Merry cts->protocol_version = device->protocol_version; 62133393f8daSKenneth D. Merry 62143393f8daSKenneth D. Merry if (cts->protocol != device->protocol) { 62153393f8daSKenneth D. Merry xpt_print_path(cts->ccb_h.path); 62163393f8daSKenneth D. Merry printf("Uninitialized Protocol %x:%x?\n", 62173393f8daSKenneth D. Merry cts->protocol, device->protocol); 62183393f8daSKenneth D. Merry cts->protocol = device->protocol; 62193393f8daSKenneth D. Merry } 62203393f8daSKenneth D. Merry 62213393f8daSKenneth D. Merry if (cts->protocol_version > device->protocol_version) { 62223393f8daSKenneth D. Merry if (bootverbose) { 62233393f8daSKenneth D. Merry xpt_print_path(cts->ccb_h.path); 62243393f8daSKenneth D. Merry printf("Down reving Protocol Version from %d to %d?\n", 62253393f8daSKenneth D. Merry cts->protocol_version, device->protocol_version); 62263393f8daSKenneth D. Merry } 62273393f8daSKenneth D. Merry cts->protocol_version = device->protocol_version; 62283393f8daSKenneth D. Merry } 62293393f8daSKenneth D. Merry 62303393f8daSKenneth D. Merry if (cts->transport == XPORT_UNKNOWN 62313393f8daSKenneth D. Merry || cts->transport == XPORT_UNSPECIFIED) { 62323393f8daSKenneth D. Merry cts->transport = device->transport; 62333393f8daSKenneth D. Merry cts->transport_version = device->transport_version; 62343393f8daSKenneth D. Merry } 62353393f8daSKenneth D. Merry 62363393f8daSKenneth D. Merry if (cts->transport_version == XPORT_VERSION_UNKNOWN 62373393f8daSKenneth D. Merry || cts->transport_version == XPORT_VERSION_UNSPECIFIED) 62383393f8daSKenneth D. Merry cts->transport_version = device->transport_version; 62393393f8daSKenneth D. Merry 62403393f8daSKenneth D. Merry if (cts->transport != device->transport) { 62413393f8daSKenneth D. Merry xpt_print_path(cts->ccb_h.path); 62423393f8daSKenneth D. Merry printf("Uninitialized Transport %x:%x?\n", 62433393f8daSKenneth D. Merry cts->transport, device->transport); 62443393f8daSKenneth D. Merry cts->transport = device->transport; 62453393f8daSKenneth D. Merry } 62463393f8daSKenneth D. Merry 62473393f8daSKenneth D. Merry if (cts->transport_version > device->transport_version) { 62483393f8daSKenneth D. Merry if (bootverbose) { 62493393f8daSKenneth D. Merry xpt_print_path(cts->ccb_h.path); 62503393f8daSKenneth D. Merry printf("Down reving Transport Version from %d to %d?\n", 62513393f8daSKenneth D. Merry cts->transport_version, 62523393f8daSKenneth D. Merry device->transport_version); 62533393f8daSKenneth D. Merry } 62543393f8daSKenneth D. Merry cts->transport_version = device->transport_version; 62553393f8daSKenneth D. Merry } 62563393f8daSKenneth D. Merry 62573393f8daSKenneth D. Merry sim = cts->ccb_h.path->bus->sim; 62583393f8daSKenneth D. Merry 62593393f8daSKenneth D. Merry /* 62603393f8daSKenneth D. Merry * Nothing more of interest to do unless 62613393f8daSKenneth D. Merry * this is a device connected via the 62623393f8daSKenneth D. Merry * SCSI protocol. 62633393f8daSKenneth D. Merry */ 62643393f8daSKenneth D. Merry if (cts->protocol != PROTO_SCSI) { 62653393f8daSKenneth D. Merry if (async_update == FALSE) 62663393f8daSKenneth D. Merry (*(sim->sim_action))(sim, (union ccb *)cts); 62673393f8daSKenneth D. Merry return; 62683393f8daSKenneth D. Merry } 62693393f8daSKenneth D. Merry 62703393f8daSKenneth D. Merry inq_data = &device->inq_data; 62713393f8daSKenneth D. Merry scsi = &cts->proto_specific.scsi; 62723393f8daSKenneth D. Merry xpt_setup_ccb(&cpi.ccb_h, cts->ccb_h.path, /*priority*/1); 62733393f8daSKenneth D. Merry cpi.ccb_h.func_code = XPT_PATH_INQ; 62743393f8daSKenneth D. Merry xpt_action((union ccb *)&cpi); 62753393f8daSKenneth D. Merry 62763393f8daSKenneth D. Merry /* SCSI specific sanity checking */ 62773393f8daSKenneth D. Merry if ((cpi.hba_inquiry & PI_TAG_ABLE) == 0 62783393f8daSKenneth D. Merry || (inq_data->flags & SID_CmdQue) == 0 62793393f8daSKenneth D. Merry || (device->queue_flags & SCP_QUEUE_DQUE) != 0 62803393f8daSKenneth D. Merry || (device->quirk->mintags == 0)) { 62813393f8daSKenneth D. Merry /* 62823393f8daSKenneth D. Merry * Can't tag on hardware that doesn't support tags, 62833393f8daSKenneth D. Merry * doesn't have it enabled, or has broken tag support. 62843393f8daSKenneth D. Merry */ 62853393f8daSKenneth D. Merry scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB; 62863393f8daSKenneth D. Merry } 62873393f8daSKenneth D. Merry 62883393f8daSKenneth D. Merry if (async_update == FALSE) { 62893393f8daSKenneth D. Merry /* 62903393f8daSKenneth D. Merry * Perform sanity checking against what the 62913393f8daSKenneth D. Merry * controller and device can do. 62923393f8daSKenneth D. Merry */ 62933393f8daSKenneth D. Merry xpt_setup_ccb(&cur_cts.ccb_h, cts->ccb_h.path, /*priority*/1); 62943393f8daSKenneth D. Merry cur_cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS; 62953393f8daSKenneth D. Merry cur_cts.type = cts->type; 62963393f8daSKenneth D. Merry xpt_action((union ccb *)&cur_cts); 62973393f8daSKenneth D. Merry 62983393f8daSKenneth D. Merry cur_scsi = &cur_cts.proto_specific.scsi; 62993393f8daSKenneth D. Merry if ((scsi->valid & CTS_SCSI_VALID_TQ) == 0) { 63003393f8daSKenneth D. Merry scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB; 63013393f8daSKenneth D. Merry scsi->flags |= cur_scsi->flags & CTS_SCSI_FLAGS_TAG_ENB; 63023393f8daSKenneth D. Merry } 63033393f8daSKenneth D. Merry if ((cur_scsi->valid & CTS_SCSI_VALID_TQ) == 0) 63043393f8daSKenneth D. Merry scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB; 63053393f8daSKenneth D. Merry } 63063393f8daSKenneth D. Merry 63073393f8daSKenneth D. Merry /* SPI specific sanity checking */ 6308f053d777SMatt Jacob if (cts->transport == XPORT_SPI && async_update == FALSE) { 63093393f8daSKenneth D. Merry u_int spi3caps; 63103393f8daSKenneth D. Merry struct ccb_trans_settings_spi *spi; 63113393f8daSKenneth D. Merry struct ccb_trans_settings_spi *cur_spi; 63123393f8daSKenneth D. Merry 63133393f8daSKenneth D. Merry spi = &cts->xport_specific.spi; 63143393f8daSKenneth D. Merry 63153393f8daSKenneth D. Merry cur_spi = &cur_cts.xport_specific.spi; 63163393f8daSKenneth D. Merry 63173393f8daSKenneth D. Merry /* Fill in any gaps in what the user gave us */ 63183393f8daSKenneth D. Merry if ((spi->valid & CTS_SPI_VALID_SYNC_RATE) == 0) 63193393f8daSKenneth D. Merry spi->sync_period = cur_spi->sync_period; 63203393f8daSKenneth D. Merry if ((cur_spi->valid & CTS_SPI_VALID_SYNC_RATE) == 0) 63213393f8daSKenneth D. Merry spi->sync_period = 0; 63223393f8daSKenneth D. Merry if ((spi->valid & CTS_SPI_VALID_SYNC_OFFSET) == 0) 63233393f8daSKenneth D. Merry spi->sync_offset = cur_spi->sync_offset; 63243393f8daSKenneth D. Merry if ((cur_spi->valid & CTS_SPI_VALID_SYNC_OFFSET) == 0) 63253393f8daSKenneth D. Merry spi->sync_offset = 0; 63263393f8daSKenneth D. Merry if ((spi->valid & CTS_SPI_VALID_PPR_OPTIONS) == 0) 63273393f8daSKenneth D. Merry spi->ppr_options = cur_spi->ppr_options; 63283393f8daSKenneth D. Merry if ((cur_spi->valid & CTS_SPI_VALID_PPR_OPTIONS) == 0) 63293393f8daSKenneth D. Merry spi->ppr_options = 0; 63303393f8daSKenneth D. Merry if ((spi->valid & CTS_SPI_VALID_BUS_WIDTH) == 0) 63313393f8daSKenneth D. Merry spi->bus_width = cur_spi->bus_width; 63323393f8daSKenneth D. Merry if ((cur_spi->valid & CTS_SPI_VALID_BUS_WIDTH) == 0) 63333393f8daSKenneth D. Merry spi->bus_width = 0; 63343393f8daSKenneth D. Merry if ((spi->valid & CTS_SPI_VALID_DISC) == 0) { 63353393f8daSKenneth D. Merry spi->flags &= ~CTS_SPI_FLAGS_DISC_ENB; 63363393f8daSKenneth D. Merry spi->flags |= cur_spi->flags & CTS_SPI_FLAGS_DISC_ENB; 63373393f8daSKenneth D. Merry } 63383393f8daSKenneth D. Merry if ((cur_spi->valid & CTS_SPI_VALID_DISC) == 0) 63393393f8daSKenneth D. Merry spi->flags &= ~CTS_SPI_FLAGS_DISC_ENB; 63403393f8daSKenneth D. Merry if (((device->flags & CAM_DEV_INQUIRY_DATA_VALID) != 0 63413393f8daSKenneth D. Merry && (inq_data->flags & SID_Sync) == 0 63423393f8daSKenneth D. Merry && cts->type == CTS_TYPE_CURRENT_SETTINGS) 63433393f8daSKenneth D. Merry || ((cpi.hba_inquiry & PI_SDTR_ABLE) == 0) 6344f053d777SMatt Jacob || (cur_spi->sync_offset == 0) 6345f053d777SMatt Jacob || (cur_spi->sync_period == 0)) { 63463393f8daSKenneth D. Merry /* Force async */ 63473393f8daSKenneth D. Merry spi->sync_period = 0; 63483393f8daSKenneth D. Merry spi->sync_offset = 0; 63493393f8daSKenneth D. Merry } 63503393f8daSKenneth D. Merry 63513393f8daSKenneth D. Merry switch (spi->bus_width) { 63523393f8daSKenneth D. Merry case MSG_EXT_WDTR_BUS_32_BIT: 63533393f8daSKenneth D. Merry if (((device->flags & CAM_DEV_INQUIRY_DATA_VALID) == 0 63543393f8daSKenneth D. Merry || (inq_data->flags & SID_WBus32) != 0 63553393f8daSKenneth D. Merry || cts->type == CTS_TYPE_USER_SETTINGS) 63563393f8daSKenneth D. Merry && (cpi.hba_inquiry & PI_WIDE_32) != 0) 63573393f8daSKenneth D. Merry break; 63583393f8daSKenneth D. Merry /* Fall Through to 16-bit */ 63593393f8daSKenneth D. Merry case MSG_EXT_WDTR_BUS_16_BIT: 63603393f8daSKenneth D. Merry if (((device->flags & CAM_DEV_INQUIRY_DATA_VALID) == 0 63613393f8daSKenneth D. Merry || (inq_data->flags & SID_WBus16) != 0 63623393f8daSKenneth D. Merry || cts->type == CTS_TYPE_USER_SETTINGS) 63633393f8daSKenneth D. Merry && (cpi.hba_inquiry & PI_WIDE_16) != 0) { 63643393f8daSKenneth D. Merry spi->bus_width = MSG_EXT_WDTR_BUS_16_BIT; 63653393f8daSKenneth D. Merry break; 63663393f8daSKenneth D. Merry } 63673393f8daSKenneth D. Merry /* Fall Through to 8-bit */ 63683393f8daSKenneth D. Merry default: /* New bus width?? */ 63693393f8daSKenneth D. Merry case MSG_EXT_WDTR_BUS_8_BIT: 63703393f8daSKenneth D. Merry /* All targets can do this */ 63713393f8daSKenneth D. Merry spi->bus_width = MSG_EXT_WDTR_BUS_8_BIT; 63723393f8daSKenneth D. Merry break; 63733393f8daSKenneth D. Merry } 63743393f8daSKenneth D. Merry 63753393f8daSKenneth D. Merry spi3caps = cpi.xport_specific.spi.ppr_options; 63763393f8daSKenneth D. Merry if ((device->flags & CAM_DEV_INQUIRY_DATA_VALID) != 0 63773393f8daSKenneth D. Merry && cts->type == CTS_TYPE_CURRENT_SETTINGS) 63783393f8daSKenneth D. Merry spi3caps &= inq_data->spi3data; 63793393f8daSKenneth D. Merry 63803393f8daSKenneth D. Merry if ((spi3caps & SID_SPI_CLOCK_DT) == 0) 63813393f8daSKenneth D. Merry spi->ppr_options &= ~MSG_EXT_PPR_DT_REQ; 63823393f8daSKenneth D. Merry 63833393f8daSKenneth D. Merry if ((spi3caps & SID_SPI_IUS) == 0) 63843393f8daSKenneth D. Merry spi->ppr_options &= ~MSG_EXT_PPR_IU_REQ; 63853393f8daSKenneth D. Merry 63863393f8daSKenneth D. Merry if ((spi3caps & SID_SPI_QAS) == 0) 63873393f8daSKenneth D. Merry spi->ppr_options &= ~MSG_EXT_PPR_QAS_REQ; 63883393f8daSKenneth D. Merry 63893393f8daSKenneth D. Merry /* No SPI Transfer settings are allowed unless we are wide */ 63903393f8daSKenneth D. Merry if (spi->bus_width == 0) 63913393f8daSKenneth D. Merry spi->ppr_options = 0; 63923393f8daSKenneth D. Merry 63933393f8daSKenneth D. Merry if ((spi->flags & CTS_SPI_FLAGS_DISC_ENB) == 0) { 63943393f8daSKenneth D. Merry /* 63953393f8daSKenneth D. Merry * Can't tag queue without disconnection. 63963393f8daSKenneth D. Merry */ 63973393f8daSKenneth D. Merry scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB; 63983393f8daSKenneth D. Merry scsi->valid |= CTS_SCSI_VALID_TQ; 63993393f8daSKenneth D. Merry } 64003393f8daSKenneth D. Merry 64013393f8daSKenneth D. Merry /* 64023393f8daSKenneth D. Merry * If we are currently performing tagged transactions to 64033393f8daSKenneth D. Merry * this device and want to change its negotiation parameters, 64043393f8daSKenneth D. Merry * go non-tagged for a bit to give the controller a chance to 64053393f8daSKenneth D. Merry * negotiate unhampered by tag messages. 64063393f8daSKenneth D. Merry */ 64073393f8daSKenneth D. Merry if (cts->type == CTS_TYPE_CURRENT_SETTINGS 64083393f8daSKenneth D. Merry && (device->inq_flags & SID_CmdQue) != 0 64093393f8daSKenneth D. Merry && (scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) != 0 64103393f8daSKenneth D. Merry && (spi->flags & (CTS_SPI_VALID_SYNC_RATE| 64113393f8daSKenneth D. Merry CTS_SPI_VALID_SYNC_OFFSET| 64123393f8daSKenneth D. Merry CTS_SPI_VALID_BUS_WIDTH)) != 0) 64133393f8daSKenneth D. Merry xpt_toggle_tags(cts->ccb_h.path); 64143393f8daSKenneth D. Merry } 64153393f8daSKenneth D. Merry 64163393f8daSKenneth D. Merry if (cts->type == CTS_TYPE_CURRENT_SETTINGS 64173393f8daSKenneth D. Merry && (scsi->valid & CTS_SCSI_VALID_TQ) != 0) { 64183393f8daSKenneth D. Merry int device_tagenb; 64193393f8daSKenneth D. Merry 64203393f8daSKenneth D. Merry /* 64213393f8daSKenneth D. Merry * If we are transitioning from tags to no-tags or 64223393f8daSKenneth D. Merry * vice-versa, we need to carefully freeze and restart 64233393f8daSKenneth D. Merry * the queue so that we don't overlap tagged and non-tagged 64243393f8daSKenneth D. Merry * commands. We also temporarily stop tags if there is 64253393f8daSKenneth D. Merry * a change in transfer negotiation settings to allow 64263393f8daSKenneth D. Merry * "tag-less" negotiation. 64273393f8daSKenneth D. Merry */ 64283393f8daSKenneth D. Merry if ((device->flags & CAM_DEV_TAG_AFTER_COUNT) != 0 64293393f8daSKenneth D. Merry || (device->inq_flags & SID_CmdQue) != 0) 64303393f8daSKenneth D. Merry device_tagenb = TRUE; 64313393f8daSKenneth D. Merry else 64323393f8daSKenneth D. Merry device_tagenb = FALSE; 64333393f8daSKenneth D. Merry 64343393f8daSKenneth D. Merry if (((scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) != 0 64353393f8daSKenneth D. Merry && device_tagenb == FALSE) 64363393f8daSKenneth D. Merry || ((scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) == 0 64373393f8daSKenneth D. Merry && device_tagenb == TRUE)) { 64383393f8daSKenneth D. Merry 64393393f8daSKenneth D. Merry if ((scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) != 0) { 64403393f8daSKenneth D. Merry /* 64413393f8daSKenneth D. Merry * Delay change to use tags until after a 64423393f8daSKenneth D. Merry * few commands have gone to this device so 64433393f8daSKenneth D. Merry * the controller has time to perform transfer 64443393f8daSKenneth D. Merry * negotiations without tagged messages getting 64453393f8daSKenneth D. Merry * in the way. 64463393f8daSKenneth D. Merry */ 64473393f8daSKenneth D. Merry device->tag_delay_count = CAM_TAG_DELAY_COUNT; 64483393f8daSKenneth D. Merry device->flags |= CAM_DEV_TAG_AFTER_COUNT; 64493393f8daSKenneth D. Merry } else { 64503393f8daSKenneth D. Merry struct ccb_relsim crs; 64513393f8daSKenneth D. Merry 64523393f8daSKenneth D. Merry xpt_freeze_devq(cts->ccb_h.path, /*count*/1); 64533393f8daSKenneth D. Merry device->inq_flags &= ~SID_CmdQue; 64543393f8daSKenneth D. Merry xpt_dev_ccbq_resize(cts->ccb_h.path, 64553393f8daSKenneth D. Merry sim->max_dev_openings); 64563393f8daSKenneth D. Merry device->flags &= ~CAM_DEV_TAG_AFTER_COUNT; 64573393f8daSKenneth D. Merry device->tag_delay_count = 0; 64583393f8daSKenneth D. Merry 64593393f8daSKenneth D. Merry xpt_setup_ccb(&crs.ccb_h, cts->ccb_h.path, 64603393f8daSKenneth D. Merry /*priority*/1); 64613393f8daSKenneth D. Merry crs.ccb_h.func_code = XPT_REL_SIMQ; 64623393f8daSKenneth D. Merry crs.release_flags = RELSIM_RELEASE_AFTER_QEMPTY; 64633393f8daSKenneth D. Merry crs.openings 64643393f8daSKenneth D. Merry = crs.release_timeout 64653393f8daSKenneth D. Merry = crs.qfrozen_cnt 64663393f8daSKenneth D. Merry = 0; 64673393f8daSKenneth D. Merry xpt_action((union ccb *)&crs); 64683393f8daSKenneth D. Merry } 64693393f8daSKenneth D. Merry } 64703393f8daSKenneth D. Merry } 64713393f8daSKenneth D. Merry if (async_update == FALSE) 64723393f8daSKenneth D. Merry (*(sim->sim_action))(sim, (union ccb *)cts); 64733393f8daSKenneth D. Merry } 64743393f8daSKenneth D. Merry 64753393f8daSKenneth D. Merry #else /* CAM_NEW_TRAN_CODE */ 64763393f8daSKenneth D. Merry 64778b8a9b1dSJustin T. Gibbs static void 647803e3511bSJustin T. Gibbs xpt_set_transfer_settings(struct ccb_trans_settings *cts, struct cam_ed *device, 647903e3511bSJustin T. Gibbs int async_update) 64808b8a9b1dSJustin T. Gibbs { 64818b8a9b1dSJustin T. Gibbs struct cam_sim *sim; 64828b8a9b1dSJustin T. Gibbs int qfrozen; 64838b8a9b1dSJustin T. Gibbs 64848b8a9b1dSJustin T. Gibbs sim = cts->ccb_h.path->bus->sim; 64858b8a9b1dSJustin T. Gibbs if (async_update == FALSE) { 64868b8a9b1dSJustin T. Gibbs struct scsi_inquiry_data *inq_data; 64878b8a9b1dSJustin T. Gibbs struct ccb_pathinq cpi; 64889deea857SKenneth D. Merry struct ccb_trans_settings cur_cts; 64898b8a9b1dSJustin T. Gibbs 649003e3511bSJustin T. Gibbs if (device == NULL) { 649103e3511bSJustin T. Gibbs cts->ccb_h.status = CAM_PATH_INVALID; 649203e3511bSJustin T. Gibbs xpt_done((union ccb *)cts); 649303e3511bSJustin T. Gibbs return; 649403e3511bSJustin T. Gibbs } 649503e3511bSJustin T. Gibbs 64968b8a9b1dSJustin T. Gibbs /* 64978b8a9b1dSJustin T. Gibbs * Perform sanity checking against what the 64988b8a9b1dSJustin T. Gibbs * controller and device can do. 64998b8a9b1dSJustin T. Gibbs */ 65008b8a9b1dSJustin T. Gibbs xpt_setup_ccb(&cpi.ccb_h, cts->ccb_h.path, /*priority*/1); 65018b8a9b1dSJustin T. Gibbs cpi.ccb_h.func_code = XPT_PATH_INQ; 65028b8a9b1dSJustin T. Gibbs xpt_action((union ccb *)&cpi); 65039deea857SKenneth D. Merry xpt_setup_ccb(&cur_cts.ccb_h, cts->ccb_h.path, /*priority*/1); 65049deea857SKenneth D. Merry cur_cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS; 65059deea857SKenneth D. Merry cur_cts.flags = CCB_TRANS_CURRENT_SETTINGS; 65069deea857SKenneth D. Merry xpt_action((union ccb *)&cur_cts); 65078b8a9b1dSJustin T. Gibbs inq_data = &device->inq_data; 65089deea857SKenneth D. Merry 65099deea857SKenneth D. Merry /* Fill in any gaps in what the user gave us */ 65109deea857SKenneth D. Merry if ((cts->valid & CCB_TRANS_SYNC_RATE_VALID) == 0) 65119deea857SKenneth D. Merry cts->sync_period = cur_cts.sync_period; 65129deea857SKenneth D. Merry if ((cts->valid & CCB_TRANS_SYNC_OFFSET_VALID) == 0) 65139deea857SKenneth D. Merry cts->sync_offset = cur_cts.sync_offset; 65149deea857SKenneth D. Merry if ((cts->valid & CCB_TRANS_BUS_WIDTH_VALID) == 0) 65159deea857SKenneth D. Merry cts->bus_width = cur_cts.bus_width; 65169deea857SKenneth D. Merry if ((cts->valid & CCB_TRANS_DISC_VALID) == 0) { 65179deea857SKenneth D. Merry cts->flags &= ~CCB_TRANS_DISC_ENB; 65189deea857SKenneth D. Merry cts->flags |= cur_cts.flags & CCB_TRANS_DISC_ENB; 65199deea857SKenneth D. Merry } 65209deea857SKenneth D. Merry if ((cts->valid & CCB_TRANS_TQ_VALID) == 0) { 65219deea857SKenneth D. Merry cts->flags &= ~CCB_TRANS_TAG_ENB; 65229deea857SKenneth D. Merry cts->flags |= cur_cts.flags & CCB_TRANS_TAG_ENB; 65239deea857SKenneth D. Merry } 6524f8d98b34SKenneth D. Merry 652587cfaf0eSJustin T. Gibbs if (((device->flags & CAM_DEV_INQUIRY_DATA_VALID) != 0 652687cfaf0eSJustin T. Gibbs && (inq_data->flags & SID_Sync) == 0) 6527f8d98b34SKenneth D. Merry || ((cpi.hba_inquiry & PI_SDTR_ABLE) == 0) 6528f8d98b34SKenneth D. Merry || (cts->sync_offset == 0) 6529f8d98b34SKenneth D. Merry || (cts->sync_period == 0)) { 65308b8a9b1dSJustin T. Gibbs /* Force async */ 65318b8a9b1dSJustin T. Gibbs cts->sync_period = 0; 65328b8a9b1dSJustin T. Gibbs cts->sync_offset = 0; 6533f8d98b34SKenneth D. Merry } else if ((device->flags & CAM_DEV_INQUIRY_DATA_VALID) != 0 6534f8d98b34SKenneth D. Merry && (inq_data->spi3data & SID_SPI_CLOCK_DT) == 0 6535f8d98b34SKenneth D. Merry && cts->sync_period <= 0x9) { 6536dd5bac9dSJustin T. Gibbs /* 6537dd5bac9dSJustin T. Gibbs * Don't allow DT transmission rates if the 6538dd5bac9dSJustin T. Gibbs * device does not support it. 6539dd5bac9dSJustin T. Gibbs */ 6540dd5bac9dSJustin T. Gibbs cts->sync_period = 0xa; 6541f8d98b34SKenneth D. Merry } 6542dd5bac9dSJustin T. Gibbs 65438b8a9b1dSJustin T. Gibbs switch (cts->bus_width) { 65448b8a9b1dSJustin T. Gibbs case MSG_EXT_WDTR_BUS_32_BIT: 654587cfaf0eSJustin T. Gibbs if (((device->flags & CAM_DEV_INQUIRY_DATA_VALID) == 0 654687cfaf0eSJustin T. Gibbs || (inq_data->flags & SID_WBus32) != 0) 65478b8a9b1dSJustin T. Gibbs && (cpi.hba_inquiry & PI_WIDE_32) != 0) 65488b8a9b1dSJustin T. Gibbs break; 654993b0017fSPhilippe Charnier /* FALLTHROUGH to 16-bit */ 65508b8a9b1dSJustin T. Gibbs case MSG_EXT_WDTR_BUS_16_BIT: 655187cfaf0eSJustin T. Gibbs if (((device->flags & CAM_DEV_INQUIRY_DATA_VALID) == 0 655287cfaf0eSJustin T. Gibbs || (inq_data->flags & SID_WBus16) != 0) 65538b8a9b1dSJustin T. Gibbs && (cpi.hba_inquiry & PI_WIDE_16) != 0) { 65548b8a9b1dSJustin T. Gibbs cts->bus_width = MSG_EXT_WDTR_BUS_16_BIT; 65558b8a9b1dSJustin T. Gibbs break; 65568b8a9b1dSJustin T. Gibbs } 655793b0017fSPhilippe Charnier /* FALLTHROUGH to 8-bit */ 65588b8a9b1dSJustin T. Gibbs default: /* New bus width?? */ 65598b8a9b1dSJustin T. Gibbs case MSG_EXT_WDTR_BUS_8_BIT: 65608b8a9b1dSJustin T. Gibbs /* All targets can do this */ 65618b8a9b1dSJustin T. Gibbs cts->bus_width = MSG_EXT_WDTR_BUS_8_BIT; 65628b8a9b1dSJustin T. Gibbs break; 65638b8a9b1dSJustin T. Gibbs } 65648b8a9b1dSJustin T. Gibbs 65658b8a9b1dSJustin T. Gibbs if ((cts->flags & CCB_TRANS_DISC_ENB) == 0) { 65668b8a9b1dSJustin T. Gibbs /* 65678b8a9b1dSJustin T. Gibbs * Can't tag queue without disconnection. 65688b8a9b1dSJustin T. Gibbs */ 65698b8a9b1dSJustin T. Gibbs cts->flags &= ~CCB_TRANS_TAG_ENB; 65702ba01e6fSJustin T. Gibbs cts->valid |= CCB_TRANS_TQ_VALID; 65718b8a9b1dSJustin T. Gibbs } 65728b8a9b1dSJustin T. Gibbs 65738b8a9b1dSJustin T. Gibbs if ((cpi.hba_inquiry & PI_TAG_ABLE) == 0 65748b8a9b1dSJustin T. Gibbs || (inq_data->flags & SID_CmdQue) == 0 65758b8a9b1dSJustin T. Gibbs || (device->queue_flags & SCP_QUEUE_DQUE) != 0 65768b8a9b1dSJustin T. Gibbs || (device->quirk->mintags == 0)) { 65778b8a9b1dSJustin T. Gibbs /* 65788b8a9b1dSJustin T. Gibbs * Can't tag on hardware that doesn't support, 65798b8a9b1dSJustin T. Gibbs * doesn't have it enabled, or has broken tag support. 65808b8a9b1dSJustin T. Gibbs */ 65818b8a9b1dSJustin T. Gibbs cts->flags &= ~CCB_TRANS_TAG_ENB; 65828b8a9b1dSJustin T. Gibbs } 65838b8a9b1dSJustin T. Gibbs } 65848b8a9b1dSJustin T. Gibbs 658503e3511bSJustin T. Gibbs qfrozen = FALSE; 658604b11324SJustin T. Gibbs if ((cts->valid & CCB_TRANS_TQ_VALID) != 0) { 65878fcf57f5SJustin T. Gibbs int device_tagenb; 658803e3511bSJustin T. Gibbs 65898b8a9b1dSJustin T. Gibbs /* 65908b8a9b1dSJustin T. Gibbs * If we are transitioning from tags to no-tags or 65918b8a9b1dSJustin T. Gibbs * vice-versa, we need to carefully freeze and restart 65928b8a9b1dSJustin T. Gibbs * the queue so that we don't overlap tagged and non-tagged 6593f0adc790SJustin T. Gibbs * commands. We also temporarily stop tags if there is 6594f0adc790SJustin T. Gibbs * a change in transfer negotiation settings to allow 6595f0adc790SJustin T. Gibbs * "tag-less" negotiation. 65968b8a9b1dSJustin T. Gibbs */ 6597f0adc790SJustin T. Gibbs if ((device->flags & CAM_DEV_TAG_AFTER_COUNT) != 0 6598f0adc790SJustin T. Gibbs || (device->inq_flags & SID_CmdQue) != 0) 6599f0adc790SJustin T. Gibbs device_tagenb = TRUE; 6600f0adc790SJustin T. Gibbs else 6601f0adc790SJustin T. Gibbs device_tagenb = FALSE; 6602f0adc790SJustin T. Gibbs 660303e3511bSJustin T. Gibbs if (((cts->flags & CCB_TRANS_TAG_ENB) != 0 6604f0adc790SJustin T. Gibbs && device_tagenb == FALSE) 66058b8a9b1dSJustin T. Gibbs || ((cts->flags & CCB_TRANS_TAG_ENB) == 0 660603e3511bSJustin T. Gibbs && device_tagenb == TRUE)) { 66078b8a9b1dSJustin T. Gibbs 66088b8a9b1dSJustin T. Gibbs if ((cts->flags & CCB_TRANS_TAG_ENB) != 0) { 6609fd21cc5eSJustin T. Gibbs /* 6610fd21cc5eSJustin T. Gibbs * Delay change to use tags until after a 6611fd21cc5eSJustin T. Gibbs * few commands have gone to this device so 6612fd21cc5eSJustin T. Gibbs * the controller has time to perform transfer 6613fd21cc5eSJustin T. Gibbs * negotiations without tagged messages getting 6614fd21cc5eSJustin T. Gibbs * in the way. 6615fd21cc5eSJustin T. Gibbs */ 6616fd21cc5eSJustin T. Gibbs device->tag_delay_count = CAM_TAG_DELAY_COUNT; 6617fd21cc5eSJustin T. Gibbs device->flags |= CAM_DEV_TAG_AFTER_COUNT; 66188b8a9b1dSJustin T. Gibbs } else { 6619fd21cc5eSJustin T. Gibbs xpt_freeze_devq(cts->ccb_h.path, /*count*/1); 6620fd21cc5eSJustin T. Gibbs qfrozen = TRUE; 66218b8a9b1dSJustin T. Gibbs device->inq_flags &= ~SID_CmdQue; 6622fd21cc5eSJustin T. Gibbs xpt_dev_ccbq_resize(cts->ccb_h.path, 6623fd21cc5eSJustin T. Gibbs sim->max_dev_openings); 6624fd21cc5eSJustin T. Gibbs device->flags &= ~CAM_DEV_TAG_AFTER_COUNT; 6625fd21cc5eSJustin T. Gibbs device->tag_delay_count = 0; 66268b8a9b1dSJustin T. Gibbs } 66278b8a9b1dSJustin T. Gibbs } 662803e3511bSJustin T. Gibbs } 66298b8a9b1dSJustin T. Gibbs 66308bad620dSJustin T. Gibbs if (async_update == FALSE) { 66318bad620dSJustin T. Gibbs /* 66328bad620dSJustin T. Gibbs * If we are currently performing tagged transactions to 66338bad620dSJustin T. Gibbs * this device and want to change its negotiation parameters, 66348bad620dSJustin T. Gibbs * go non-tagged for a bit to give the controller a chance to 66358bad620dSJustin T. Gibbs * negotiate unhampered by tag messages. 66368bad620dSJustin T. Gibbs */ 66378bad620dSJustin T. Gibbs if ((device->inq_flags & SID_CmdQue) != 0 66388bad620dSJustin T. Gibbs && (cts->flags & (CCB_TRANS_SYNC_RATE_VALID| 66398bad620dSJustin T. Gibbs CCB_TRANS_SYNC_OFFSET_VALID| 66408bad620dSJustin T. Gibbs CCB_TRANS_BUS_WIDTH_VALID)) != 0) 66418bad620dSJustin T. Gibbs xpt_toggle_tags(cts->ccb_h.path); 66428bad620dSJustin T. Gibbs 66438b8a9b1dSJustin T. Gibbs (*(sim->sim_action))(sim, (union ccb *)cts); 66448bad620dSJustin T. Gibbs } 66458b8a9b1dSJustin T. Gibbs 66468b8a9b1dSJustin T. Gibbs if (qfrozen) { 66478b8a9b1dSJustin T. Gibbs struct ccb_relsim crs; 66488b8a9b1dSJustin T. Gibbs 66498b8a9b1dSJustin T. Gibbs xpt_setup_ccb(&crs.ccb_h, cts->ccb_h.path, 66508b8a9b1dSJustin T. Gibbs /*priority*/1); 66518b8a9b1dSJustin T. Gibbs crs.ccb_h.func_code = XPT_REL_SIMQ; 66528b8a9b1dSJustin T. Gibbs crs.release_flags = RELSIM_RELEASE_AFTER_QEMPTY; 66538b8a9b1dSJustin T. Gibbs crs.openings 66548b8a9b1dSJustin T. Gibbs = crs.release_timeout 66558b8a9b1dSJustin T. Gibbs = crs.qfrozen_cnt 66568b8a9b1dSJustin T. Gibbs = 0; 66578b8a9b1dSJustin T. Gibbs xpt_action((union ccb *)&crs); 66588b8a9b1dSJustin T. Gibbs } 66598b8a9b1dSJustin T. Gibbs } 66608b8a9b1dSJustin T. Gibbs 66613393f8daSKenneth D. Merry 66623393f8daSKenneth D. Merry #endif /* CAM_NEW_TRAN_CODE */ 66633393f8daSKenneth D. Merry 6664fd21cc5eSJustin T. Gibbs static void 6665f0adc790SJustin T. Gibbs xpt_toggle_tags(struct cam_path *path) 6666f0adc790SJustin T. Gibbs { 666787cfaf0eSJustin T. Gibbs struct cam_ed *dev; 666887cfaf0eSJustin T. Gibbs 6669f0adc790SJustin T. Gibbs /* 6670f0adc790SJustin T. Gibbs * Give controllers a chance to renegotiate 6671f0adc790SJustin T. Gibbs * before starting tag operations. We 6672f0adc790SJustin T. Gibbs * "toggle" tagged queuing off then on 6673f0adc790SJustin T. Gibbs * which causes the tag enable command delay 6674f0adc790SJustin T. Gibbs * counter to come into effect. 6675f0adc790SJustin T. Gibbs */ 667687cfaf0eSJustin T. Gibbs dev = path->device; 667787cfaf0eSJustin T. Gibbs if ((dev->flags & CAM_DEV_TAG_AFTER_COUNT) != 0 667887cfaf0eSJustin T. Gibbs || ((dev->inq_flags & SID_CmdQue) != 0 667987cfaf0eSJustin T. Gibbs && (dev->inq_flags & (SID_Sync|SID_WBus16|SID_WBus32)) != 0)) { 6680f0adc790SJustin T. Gibbs struct ccb_trans_settings cts; 6681f0adc790SJustin T. Gibbs 6682f0adc790SJustin T. Gibbs xpt_setup_ccb(&cts.ccb_h, path, 1); 66833393f8daSKenneth D. Merry #ifdef CAM_NEW_TRAN_CODE 66843393f8daSKenneth D. Merry cts.protocol = PROTO_SCSI; 66853393f8daSKenneth D. Merry cts.protocol_version = PROTO_VERSION_UNSPECIFIED; 66863393f8daSKenneth D. Merry cts.transport = XPORT_UNSPECIFIED; 66873393f8daSKenneth D. Merry cts.transport_version = XPORT_VERSION_UNSPECIFIED; 66883393f8daSKenneth D. Merry cts.proto_specific.scsi.flags = 0; 66893393f8daSKenneth D. Merry cts.proto_specific.scsi.valid = CTS_SCSI_VALID_TQ; 66903393f8daSKenneth D. Merry #else /* CAM_NEW_TRAN_CODE */ 6691f0adc790SJustin T. Gibbs cts.flags = 0; 6692f0adc790SJustin T. Gibbs cts.valid = CCB_TRANS_TQ_VALID; 66933393f8daSKenneth D. Merry #endif /* CAM_NEW_TRAN_CODE */ 669403e3511bSJustin T. Gibbs xpt_set_transfer_settings(&cts, path->device, 669503e3511bSJustin T. Gibbs /*async_update*/TRUE); 66963393f8daSKenneth D. Merry #ifdef CAM_NEW_TRAN_CODE 66973393f8daSKenneth D. Merry cts.proto_specific.scsi.flags = CTS_SCSI_FLAGS_TAG_ENB; 66983393f8daSKenneth D. Merry #else /* CAM_NEW_TRAN_CODE */ 6699f0adc790SJustin T. Gibbs cts.flags = CCB_TRANS_TAG_ENB; 67003393f8daSKenneth D. Merry #endif /* CAM_NEW_TRAN_CODE */ 670103e3511bSJustin T. Gibbs xpt_set_transfer_settings(&cts, path->device, 670203e3511bSJustin T. Gibbs /*async_update*/TRUE); 6703f0adc790SJustin T. Gibbs } 6704f0adc790SJustin T. Gibbs } 6705f0adc790SJustin T. Gibbs 6706f0adc790SJustin T. Gibbs static void 6707f0adc790SJustin T. Gibbs xpt_start_tags(struct cam_path *path) 6708f0adc790SJustin T. Gibbs { 6709fd21cc5eSJustin T. Gibbs struct ccb_relsim crs; 6710fd21cc5eSJustin T. Gibbs struct cam_ed *device; 6711fd21cc5eSJustin T. Gibbs struct cam_sim *sim; 6712fd21cc5eSJustin T. Gibbs int newopenings; 6713fd21cc5eSJustin T. Gibbs 6714fd21cc5eSJustin T. Gibbs device = path->device; 6715fd21cc5eSJustin T. Gibbs sim = path->bus->sim; 6716fd21cc5eSJustin T. Gibbs device->flags &= ~CAM_DEV_TAG_AFTER_COUNT; 6717fd21cc5eSJustin T. Gibbs xpt_freeze_devq(path, /*count*/1); 6718fd21cc5eSJustin T. Gibbs device->inq_flags |= SID_CmdQue; 6719df8f9080SJustin T. Gibbs if (device->tag_saved_openings != 0) 6720df8f9080SJustin T. Gibbs newopenings = device->tag_saved_openings; 6721df8f9080SJustin T. Gibbs else 6722df8f9080SJustin T. Gibbs newopenings = min(device->quirk->maxtags, 6723df8f9080SJustin T. Gibbs sim->max_tagged_dev_openings); 6724f0adc790SJustin T. Gibbs xpt_dev_ccbq_resize(path, newopenings); 6725fd21cc5eSJustin T. Gibbs xpt_setup_ccb(&crs.ccb_h, path, /*priority*/1); 6726fd21cc5eSJustin T. Gibbs crs.ccb_h.func_code = XPT_REL_SIMQ; 6727fd21cc5eSJustin T. Gibbs crs.release_flags = RELSIM_RELEASE_AFTER_QEMPTY; 6728fd21cc5eSJustin T. Gibbs crs.openings 6729fd21cc5eSJustin T. Gibbs = crs.release_timeout 6730fd21cc5eSJustin T. Gibbs = crs.qfrozen_cnt 6731fd21cc5eSJustin T. Gibbs = 0; 6732fd21cc5eSJustin T. Gibbs xpt_action((union ccb *)&crs); 6733fd21cc5eSJustin T. Gibbs } 6734fd21cc5eSJustin T. Gibbs 67358b8a9b1dSJustin T. Gibbs static int busses_to_config; 673687cfaf0eSJustin T. Gibbs static int busses_to_reset; 67378b8a9b1dSJustin T. Gibbs 67388b8a9b1dSJustin T. Gibbs static int 67398b8a9b1dSJustin T. Gibbs xptconfigbuscountfunc(struct cam_eb *bus, void *arg) 67408b8a9b1dSJustin T. Gibbs { 674187cfaf0eSJustin T. Gibbs if (bus->path_id != CAM_XPT_PATH_ID) { 674287cfaf0eSJustin T. Gibbs struct cam_path path; 674387cfaf0eSJustin T. Gibbs struct ccb_pathinq cpi; 674487cfaf0eSJustin T. Gibbs int can_negotiate; 674587cfaf0eSJustin T. Gibbs 67468b8a9b1dSJustin T. Gibbs busses_to_config++; 674787cfaf0eSJustin T. Gibbs xpt_compile_path(&path, NULL, bus->path_id, 674887cfaf0eSJustin T. Gibbs CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD); 674987cfaf0eSJustin T. Gibbs xpt_setup_ccb(&cpi.ccb_h, &path, /*priority*/1); 675087cfaf0eSJustin T. Gibbs cpi.ccb_h.func_code = XPT_PATH_INQ; 675187cfaf0eSJustin T. Gibbs xpt_action((union ccb *)&cpi); 675287cfaf0eSJustin T. Gibbs can_negotiate = cpi.hba_inquiry; 675387cfaf0eSJustin T. Gibbs can_negotiate &= (PI_WIDE_32|PI_WIDE_16|PI_SDTR_ABLE); 675487cfaf0eSJustin T. Gibbs if ((cpi.hba_misc & PIM_NOBUSRESET) == 0 675587cfaf0eSJustin T. Gibbs && can_negotiate) 675687cfaf0eSJustin T. Gibbs busses_to_reset++; 675787cfaf0eSJustin T. Gibbs xpt_release_path(&path); 675887cfaf0eSJustin T. Gibbs } 67598b8a9b1dSJustin T. Gibbs 67608b8a9b1dSJustin T. Gibbs return(1); 67618b8a9b1dSJustin T. Gibbs } 67628b8a9b1dSJustin T. Gibbs 67638b8a9b1dSJustin T. Gibbs static int 67648b8a9b1dSJustin T. Gibbs xptconfigfunc(struct cam_eb *bus, void *arg) 67658b8a9b1dSJustin T. Gibbs { 67668b8a9b1dSJustin T. Gibbs struct cam_path *path; 67678b8a9b1dSJustin T. Gibbs union ccb *work_ccb; 67688b8a9b1dSJustin T. Gibbs 67698b8a9b1dSJustin T. Gibbs if (bus->path_id != CAM_XPT_PATH_ID) { 67708b8a9b1dSJustin T. Gibbs cam_status status; 677187cfaf0eSJustin T. Gibbs int can_negotiate; 67728b8a9b1dSJustin T. Gibbs 67738b8a9b1dSJustin T. Gibbs work_ccb = xpt_alloc_ccb(); 67748b8a9b1dSJustin T. Gibbs if ((status = xpt_create_path(&path, xpt_periph, bus->path_id, 67758b8a9b1dSJustin T. Gibbs CAM_TARGET_WILDCARD, 67768b8a9b1dSJustin T. Gibbs CAM_LUN_WILDCARD)) !=CAM_REQ_CMP){ 67778b8a9b1dSJustin T. Gibbs printf("xptconfigfunc: xpt_create_path failed with " 67788b8a9b1dSJustin T. Gibbs "status %#x for bus %d\n", status, bus->path_id); 67798b8a9b1dSJustin T. Gibbs printf("xptconfigfunc: halting bus configuration\n"); 67808b8a9b1dSJustin T. Gibbs xpt_free_ccb(work_ccb); 678198192658SJustin T. Gibbs busses_to_config--; 678298192658SJustin T. Gibbs xpt_finishconfig(xpt_periph, NULL); 67838b8a9b1dSJustin T. Gibbs return(0); 67848b8a9b1dSJustin T. Gibbs } 67858b8a9b1dSJustin T. Gibbs xpt_setup_ccb(&work_ccb->ccb_h, path, /*priority*/1); 678698192658SJustin T. Gibbs work_ccb->ccb_h.func_code = XPT_PATH_INQ; 678798192658SJustin T. Gibbs xpt_action(work_ccb); 678898192658SJustin T. Gibbs if (work_ccb->ccb_h.status != CAM_REQ_CMP) { 678998192658SJustin T. Gibbs printf("xptconfigfunc: CPI failed on bus %d " 679098192658SJustin T. Gibbs "with status %d\n", bus->path_id, 679198192658SJustin T. Gibbs work_ccb->ccb_h.status); 679298192658SJustin T. Gibbs xpt_finishconfig(xpt_periph, work_ccb); 679398192658SJustin T. Gibbs return(1); 679498192658SJustin T. Gibbs } 679598192658SJustin T. Gibbs 679687cfaf0eSJustin T. Gibbs can_negotiate = work_ccb->cpi.hba_inquiry; 679787cfaf0eSJustin T. Gibbs can_negotiate &= (PI_WIDE_32|PI_WIDE_16|PI_SDTR_ABLE); 679887cfaf0eSJustin T. Gibbs if ((work_ccb->cpi.hba_misc & PIM_NOBUSRESET) == 0 679987cfaf0eSJustin T. Gibbs && (can_negotiate != 0)) { 680098192658SJustin T. Gibbs xpt_setup_ccb(&work_ccb->ccb_h, path, /*priority*/1); 68018b8a9b1dSJustin T. Gibbs work_ccb->ccb_h.func_code = XPT_RESET_BUS; 68028b8a9b1dSJustin T. Gibbs work_ccb->ccb_h.cbfcnp = NULL; 68038b8a9b1dSJustin T. Gibbs CAM_DEBUG(path, CAM_DEBUG_SUBTRACE, 68048b8a9b1dSJustin T. Gibbs ("Resetting Bus\n")); 68058b8a9b1dSJustin T. Gibbs xpt_action(work_ccb); 68068b8a9b1dSJustin T. Gibbs xpt_finishconfig(xpt_periph, work_ccb); 680798192658SJustin T. Gibbs } else { 680898192658SJustin T. Gibbs /* Act as though we performed a successful BUS RESET */ 680998192658SJustin T. Gibbs work_ccb->ccb_h.func_code = XPT_RESET_BUS; 681098192658SJustin T. Gibbs xpt_finishconfig(xpt_periph, work_ccb); 681198192658SJustin T. Gibbs } 68128b8a9b1dSJustin T. Gibbs } 68138b8a9b1dSJustin T. Gibbs 68148b8a9b1dSJustin T. Gibbs return(1); 68158b8a9b1dSJustin T. Gibbs } 68168b8a9b1dSJustin T. Gibbs 68178b8a9b1dSJustin T. Gibbs static void 68188b8a9b1dSJustin T. Gibbs xpt_config(void *arg) 68198b8a9b1dSJustin T. Gibbs { 68203393f8daSKenneth D. Merry /* 68213393f8daSKenneth D. Merry * Now that interrupts are enabled, go find our devices 68223393f8daSKenneth D. Merry */ 68238b8a9b1dSJustin T. Gibbs 68248b8a9b1dSJustin T. Gibbs #ifdef CAMDEBUG 68258b8a9b1dSJustin T. Gibbs /* Setup debugging flags and path */ 68268b8a9b1dSJustin T. Gibbs #ifdef CAM_DEBUG_FLAGS 68278b8a9b1dSJustin T. Gibbs cam_dflags = CAM_DEBUG_FLAGS; 68288b8a9b1dSJustin T. Gibbs #else /* !CAM_DEBUG_FLAGS */ 68298b8a9b1dSJustin T. Gibbs cam_dflags = CAM_DEBUG_NONE; 68308b8a9b1dSJustin T. Gibbs #endif /* CAM_DEBUG_FLAGS */ 68318b8a9b1dSJustin T. Gibbs #ifdef CAM_DEBUG_BUS 68328b8a9b1dSJustin T. Gibbs if (cam_dflags != CAM_DEBUG_NONE) { 68338b8a9b1dSJustin T. Gibbs if (xpt_create_path(&cam_dpath, xpt_periph, 68348b8a9b1dSJustin T. Gibbs CAM_DEBUG_BUS, CAM_DEBUG_TARGET, 68358b8a9b1dSJustin T. Gibbs CAM_DEBUG_LUN) != CAM_REQ_CMP) { 68368b8a9b1dSJustin T. Gibbs printf("xpt_config: xpt_create_path() failed for debug" 68378b8a9b1dSJustin T. Gibbs " target %d:%d:%d, debugging disabled\n", 68388b8a9b1dSJustin T. Gibbs CAM_DEBUG_BUS, CAM_DEBUG_TARGET, CAM_DEBUG_LUN); 68398b8a9b1dSJustin T. Gibbs cam_dflags = CAM_DEBUG_NONE; 68408b8a9b1dSJustin T. Gibbs } 68418b8a9b1dSJustin T. Gibbs } else 68428b8a9b1dSJustin T. Gibbs cam_dpath = NULL; 68438b8a9b1dSJustin T. Gibbs #else /* !CAM_DEBUG_BUS */ 68448b8a9b1dSJustin T. Gibbs cam_dpath = NULL; 68458b8a9b1dSJustin T. Gibbs #endif /* CAM_DEBUG_BUS */ 68468b8a9b1dSJustin T. Gibbs #endif /* CAMDEBUG */ 68478b8a9b1dSJustin T. Gibbs 6848a5479bc5SJustin T. Gibbs /* 6849a5479bc5SJustin T. Gibbs * Scan all installed busses. 6850a5479bc5SJustin T. Gibbs */ 68518b8a9b1dSJustin T. Gibbs xpt_for_all_busses(xptconfigbuscountfunc, NULL); 68528b8a9b1dSJustin T. Gibbs 6853ecdf1113SJustin T. Gibbs if (busses_to_config == 0) { 6854ecdf1113SJustin T. Gibbs /* Call manually because we don't have any busses */ 68558b8a9b1dSJustin T. Gibbs xpt_finishconfig(xpt_periph, NULL); 68562863f7b1SJustin T. Gibbs } else { 68573a937198SBrooks Davis if (busses_to_reset > 0 && scsi_delay >= 2000) { 68582863f7b1SJustin T. Gibbs printf("Waiting %d seconds for SCSI " 68593a937198SBrooks Davis "devices to settle\n", scsi_delay/1000); 68602863f7b1SJustin T. Gibbs } 6861ecdf1113SJustin T. Gibbs xpt_for_all_busses(xptconfigfunc, NULL); 68628b8a9b1dSJustin T. Gibbs } 68632863f7b1SJustin T. Gibbs } 68648b8a9b1dSJustin T. Gibbs 68658b8a9b1dSJustin T. Gibbs /* 68668b8a9b1dSJustin T. Gibbs * If the given device only has one peripheral attached to it, and if that 68678b8a9b1dSJustin T. Gibbs * peripheral is the passthrough driver, announce it. This insures that the 68688b8a9b1dSJustin T. Gibbs * user sees some sort of announcement for every peripheral in their system. 68698b8a9b1dSJustin T. Gibbs */ 68708b8a9b1dSJustin T. Gibbs static int 68718b8a9b1dSJustin T. Gibbs xptpassannouncefunc(struct cam_ed *device, void *arg) 68728b8a9b1dSJustin T. Gibbs { 68738b8a9b1dSJustin T. Gibbs struct cam_periph *periph; 68748b8a9b1dSJustin T. Gibbs int i; 68758b8a9b1dSJustin T. Gibbs 68768b8a9b1dSJustin T. Gibbs for (periph = SLIST_FIRST(&device->periphs), i = 0; periph != NULL; 68778b8a9b1dSJustin T. Gibbs periph = SLIST_NEXT(periph, periph_links), i++); 68788b8a9b1dSJustin T. Gibbs 68798b8a9b1dSJustin T. Gibbs periph = SLIST_FIRST(&device->periphs); 68808b8a9b1dSJustin T. Gibbs if ((i == 1) 68818b8a9b1dSJustin T. Gibbs && (strncmp(periph->periph_name, "pass", 4) == 0)) 68828b8a9b1dSJustin T. Gibbs xpt_announce_periph(periph, NULL); 68838b8a9b1dSJustin T. Gibbs 68848b8a9b1dSJustin T. Gibbs return(1); 68858b8a9b1dSJustin T. Gibbs } 68868b8a9b1dSJustin T. Gibbs 68878b8a9b1dSJustin T. Gibbs static void 68888b8a9b1dSJustin T. Gibbs xpt_finishconfig(struct cam_periph *periph, union ccb *done_ccb) 68898b8a9b1dSJustin T. Gibbs { 68908b8a9b1dSJustin T. Gibbs struct periph_driver **p_drv; 68918b8a9b1dSJustin T. Gibbs int i; 68928b8a9b1dSJustin T. Gibbs 68938b8a9b1dSJustin T. Gibbs if (done_ccb != NULL) { 68948b8a9b1dSJustin T. Gibbs CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_TRACE, 68958b8a9b1dSJustin T. Gibbs ("xpt_finishconfig\n")); 68968b8a9b1dSJustin T. Gibbs switch(done_ccb->ccb_h.func_code) { 68978b8a9b1dSJustin T. Gibbs case XPT_RESET_BUS: 68988b8a9b1dSJustin T. Gibbs if (done_ccb->ccb_h.status == CAM_REQ_CMP) { 68998b8a9b1dSJustin T. Gibbs done_ccb->ccb_h.func_code = XPT_SCAN_BUS; 69008b8a9b1dSJustin T. Gibbs done_ccb->ccb_h.cbfcnp = xpt_finishconfig; 6901df8f9080SJustin T. Gibbs done_ccb->crcn.flags = 0; 69028b8a9b1dSJustin T. Gibbs xpt_action(done_ccb); 69038b8a9b1dSJustin T. Gibbs return; 69048b8a9b1dSJustin T. Gibbs } 69058b8a9b1dSJustin T. Gibbs /* FALLTHROUGH */ 69068b8a9b1dSJustin T. Gibbs case XPT_SCAN_BUS: 690798192658SJustin T. Gibbs default: 69088b8a9b1dSJustin T. Gibbs xpt_free_path(done_ccb->ccb_h.path); 69098b8a9b1dSJustin T. Gibbs busses_to_config--; 69108b8a9b1dSJustin T. Gibbs break; 69118b8a9b1dSJustin T. Gibbs } 69128b8a9b1dSJustin T. Gibbs } 69138b8a9b1dSJustin T. Gibbs 69148b8a9b1dSJustin T. Gibbs if (busses_to_config == 0) { 69158b8a9b1dSJustin T. Gibbs /* Register all the peripheral drivers */ 6916e9189611SPeter Wemm /* XXX This will have to change when we have loadable modules */ 69170b7c27b9SPeter Wemm p_drv = periph_drivers; 69188b8a9b1dSJustin T. Gibbs for (i = 0; p_drv[i] != NULL; i++) { 69198b8a9b1dSJustin T. Gibbs (*p_drv[i]->init)(); 69208b8a9b1dSJustin T. Gibbs } 69218b8a9b1dSJustin T. Gibbs 69228b8a9b1dSJustin T. Gibbs /* 69238b8a9b1dSJustin T. Gibbs * Check for devices with no "standard" peripheral driver 69248b8a9b1dSJustin T. Gibbs * attached. For any devices like that, announce the 69258b8a9b1dSJustin T. Gibbs * passthrough driver so the user will see something. 69268b8a9b1dSJustin T. Gibbs */ 69278b8a9b1dSJustin T. Gibbs xpt_for_all_devices(xptpassannouncefunc, NULL); 69288b8a9b1dSJustin T. Gibbs 69298b8a9b1dSJustin T. Gibbs /* Release our hook so that the boot can continue. */ 69308b8a9b1dSJustin T. Gibbs config_intrhook_disestablish(xpt_config_hook); 69319dd03ecfSJustin T. Gibbs free(xpt_config_hook, M_TEMP); 69329dd03ecfSJustin T. Gibbs xpt_config_hook = NULL; 69338b8a9b1dSJustin T. Gibbs } 69348b8a9b1dSJustin T. Gibbs if (done_ccb != NULL) 69358b8a9b1dSJustin T. Gibbs xpt_free_ccb(done_ccb); 69368b8a9b1dSJustin T. Gibbs } 69378b8a9b1dSJustin T. Gibbs 69388b8a9b1dSJustin T. Gibbs static void 69398b8a9b1dSJustin T. Gibbs xptaction(struct cam_sim *sim, union ccb *work_ccb) 69408b8a9b1dSJustin T. Gibbs { 69418b8a9b1dSJustin T. Gibbs CAM_DEBUG(work_ccb->ccb_h.path, CAM_DEBUG_TRACE, ("xptaction\n")); 69428b8a9b1dSJustin T. Gibbs 69438b8a9b1dSJustin T. Gibbs switch (work_ccb->ccb_h.func_code) { 69448b8a9b1dSJustin T. Gibbs /* Common cases first */ 69458b8a9b1dSJustin T. Gibbs case XPT_PATH_INQ: /* Path routing inquiry */ 69468b8a9b1dSJustin T. Gibbs { 69478b8a9b1dSJustin T. Gibbs struct ccb_pathinq *cpi; 69488b8a9b1dSJustin T. Gibbs 69498b8a9b1dSJustin T. Gibbs cpi = &work_ccb->cpi; 69508b8a9b1dSJustin T. Gibbs cpi->version_num = 1; /* XXX??? */ 69518b8a9b1dSJustin T. Gibbs cpi->hba_inquiry = 0; 69528b8a9b1dSJustin T. Gibbs cpi->target_sprt = 0; 69538b8a9b1dSJustin T. Gibbs cpi->hba_misc = 0; 69548b8a9b1dSJustin T. Gibbs cpi->hba_eng_cnt = 0; 69558b8a9b1dSJustin T. Gibbs cpi->max_target = 0; 69568b8a9b1dSJustin T. Gibbs cpi->max_lun = 0; 69578b8a9b1dSJustin T. Gibbs cpi->initiator_id = 0; 69588b8a9b1dSJustin T. Gibbs strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN); 69598b8a9b1dSJustin T. Gibbs strncpy(cpi->hba_vid, "", HBA_IDLEN); 69608b8a9b1dSJustin T. Gibbs strncpy(cpi->dev_name, sim->sim_name, DEV_IDLEN); 69618b8a9b1dSJustin T. Gibbs cpi->unit_number = sim->unit_number; 69628b8a9b1dSJustin T. Gibbs cpi->bus_id = sim->bus_id; 69639deea857SKenneth D. Merry cpi->base_transfer_speed = 0; 69643393f8daSKenneth D. Merry #ifdef CAM_NEW_TRAN_CODE 69653393f8daSKenneth D. Merry cpi->protocol = PROTO_UNSPECIFIED; 69663393f8daSKenneth D. Merry cpi->protocol_version = PROTO_VERSION_UNSPECIFIED; 69673393f8daSKenneth D. Merry cpi->transport = XPORT_UNSPECIFIED; 69683393f8daSKenneth D. Merry cpi->transport_version = XPORT_VERSION_UNSPECIFIED; 69693393f8daSKenneth D. Merry #endif /* CAM_NEW_TRAN_CODE */ 69708b8a9b1dSJustin T. Gibbs cpi->ccb_h.status = CAM_REQ_CMP; 69718b8a9b1dSJustin T. Gibbs xpt_done(work_ccb); 69728b8a9b1dSJustin T. Gibbs break; 69738b8a9b1dSJustin T. Gibbs } 69748b8a9b1dSJustin T. Gibbs default: 69758b8a9b1dSJustin T. Gibbs work_ccb->ccb_h.status = CAM_REQ_INVALID; 69768b8a9b1dSJustin T. Gibbs xpt_done(work_ccb); 69778b8a9b1dSJustin T. Gibbs break; 69788b8a9b1dSJustin T. Gibbs } 69798b8a9b1dSJustin T. Gibbs } 69808b8a9b1dSJustin T. Gibbs 69818b8a9b1dSJustin T. Gibbs /* 6982434bbf6eSJustin T. Gibbs * The xpt as a "controller" has no interrupt sources, so polling 6983434bbf6eSJustin T. Gibbs * is a no-op. 6984434bbf6eSJustin T. Gibbs */ 6985434bbf6eSJustin T. Gibbs static void 6986434bbf6eSJustin T. Gibbs xptpoll(struct cam_sim *sim) 6987434bbf6eSJustin T. Gibbs { 6988434bbf6eSJustin T. Gibbs } 6989434bbf6eSJustin T. Gibbs 69905d754af7SMatt Jacob static void 69918088699fSJohn Baldwin camisr(void *V_queue) 69928b8a9b1dSJustin T. Gibbs { 6993ef3cf714SScott Long cam_isrq_t *oqueue = V_queue; 6994ef3cf714SScott Long cam_isrq_t queue; 69958b8a9b1dSJustin T. Gibbs int s; 69968b8a9b1dSJustin T. Gibbs struct ccb_hdr *ccb_h; 69978b8a9b1dSJustin T. Gibbs 6998ef3cf714SScott Long /* 6999ef3cf714SScott Long * Transfer the ccb_bioq list to a temporary list so we can operate 7000ef3cf714SScott Long * on it without needing to lock/unlock on every loop. The concat 7001ef3cf714SScott Long * function with re-init the real list for us. 7002ef3cf714SScott Long */ 70038b8a9b1dSJustin T. Gibbs s = splcam(); 7004ef3cf714SScott Long mtx_lock(&cam_bioq_lock); 7005ef3cf714SScott Long TAILQ_INIT(&queue); 7006ef3cf714SScott Long TAILQ_CONCAT(&queue, oqueue, sim_links.tqe); 7007ef3cf714SScott Long mtx_unlock(&cam_bioq_lock); 7008ef3cf714SScott Long 7009ef3cf714SScott Long while ((ccb_h = TAILQ_FIRST(&queue)) != NULL) { 70108b8a9b1dSJustin T. Gibbs int runq; 70118b8a9b1dSJustin T. Gibbs 7012ef3cf714SScott Long TAILQ_REMOVE(&queue, ccb_h, sim_links.tqe); 70138b8a9b1dSJustin T. Gibbs ccb_h->pinfo.index = CAM_UNQUEUED_INDEX; 70148b8a9b1dSJustin T. Gibbs splx(s); 70158b8a9b1dSJustin T. Gibbs 70168b8a9b1dSJustin T. Gibbs CAM_DEBUG(ccb_h->path, CAM_DEBUG_TRACE, 701757b89bbcSNate Lawson ("camisr\n")); 70188b8a9b1dSJustin T. Gibbs 70198b8a9b1dSJustin T. Gibbs runq = FALSE; 70208b8a9b1dSJustin T. Gibbs 70218b8a9b1dSJustin T. Gibbs if (ccb_h->flags & CAM_HIGH_POWER) { 70228b8a9b1dSJustin T. Gibbs struct highpowerlist *hphead; 70238b8a9b1dSJustin T. Gibbs union ccb *send_ccb; 70248b8a9b1dSJustin T. Gibbs 70258b8a9b1dSJustin T. Gibbs hphead = &highpowerq; 70268b8a9b1dSJustin T. Gibbs 70278b8a9b1dSJustin T. Gibbs send_ccb = (union ccb *)STAILQ_FIRST(hphead); 70288b8a9b1dSJustin T. Gibbs 70298b8a9b1dSJustin T. Gibbs /* 70308b8a9b1dSJustin T. Gibbs * Increment the count since this command is done. 70318b8a9b1dSJustin T. Gibbs */ 70328b8a9b1dSJustin T. Gibbs num_highpower++; 70338b8a9b1dSJustin T. Gibbs 70348b8a9b1dSJustin T. Gibbs /* 70358b8a9b1dSJustin T. Gibbs * Any high powered commands queued up? 70368b8a9b1dSJustin T. Gibbs */ 70378b8a9b1dSJustin T. Gibbs if (send_ccb != NULL) { 70388b8a9b1dSJustin T. Gibbs 70398b8a9b1dSJustin T. Gibbs STAILQ_REMOVE_HEAD(hphead, xpt_links.stqe); 70408b8a9b1dSJustin T. Gibbs 70412cefde5fSJustin T. Gibbs xpt_release_devq(send_ccb->ccb_h.path, 70422cefde5fSJustin T. Gibbs /*count*/1, /*runqueue*/TRUE); 70438b8a9b1dSJustin T. Gibbs } 70448b8a9b1dSJustin T. Gibbs } 70459deea857SKenneth D. Merry if ((ccb_h->func_code & XPT_FC_USER_CCB) == 0) { 70468b8a9b1dSJustin T. Gibbs struct cam_ed *dev; 70478b8a9b1dSJustin T. Gibbs 70488b8a9b1dSJustin T. Gibbs dev = ccb_h->path->device; 70498b8a9b1dSJustin T. Gibbs 70508b8a9b1dSJustin T. Gibbs s = splcam(); 70518b8a9b1dSJustin T. Gibbs cam_ccbq_ccb_done(&dev->ccbq, (union ccb *)ccb_h); 70528b8a9b1dSJustin T. Gibbs 70538b8a9b1dSJustin T. Gibbs ccb_h->path->bus->sim->devq->send_active--; 70548b8a9b1dSJustin T. Gibbs ccb_h->path->bus->sim->devq->send_openings++; 70558b8a9b1dSJustin T. Gibbs splx(s); 70568b8a9b1dSJustin T. Gibbs 70573393f8daSKenneth D. Merry if (((dev->flags & CAM_DEV_REL_ON_COMPLETE) != 0 70583393f8daSKenneth D. Merry && (ccb_h->status&CAM_STATUS_MASK) != CAM_REQUEUE_REQ) 70598b8a9b1dSJustin T. Gibbs || ((dev->flags & CAM_DEV_REL_ON_QUEUE_EMPTY) != 0 70608b8a9b1dSJustin T. Gibbs && (dev->ccbq.dev_active == 0))) { 70618b8a9b1dSJustin T. Gibbs 70622cefde5fSJustin T. Gibbs xpt_release_devq(ccb_h->path, /*count*/1, 70638b8a9b1dSJustin T. Gibbs /*run_queue*/TRUE); 70648b8a9b1dSJustin T. Gibbs } 70658b8a9b1dSJustin T. Gibbs 7066fd21cc5eSJustin T. Gibbs if ((dev->flags & CAM_DEV_TAG_AFTER_COUNT) != 0 7067fd21cc5eSJustin T. Gibbs && (--dev->tag_delay_count == 0)) 7068fd21cc5eSJustin T. Gibbs xpt_start_tags(ccb_h->path); 7069fd21cc5eSJustin T. Gibbs 70708b8a9b1dSJustin T. Gibbs if ((dev->ccbq.queue.entries > 0) 70718b8a9b1dSJustin T. Gibbs && (dev->qfrozen_cnt == 0) 70728b8a9b1dSJustin T. Gibbs && (device_is_send_queued(dev) == 0)) { 70738b8a9b1dSJustin T. Gibbs runq = xpt_schedule_dev_sendq(ccb_h->path->bus, 70748b8a9b1dSJustin T. Gibbs dev); 70758b8a9b1dSJustin T. Gibbs } 70768b8a9b1dSJustin T. Gibbs } 70778b8a9b1dSJustin T. Gibbs 70788b8a9b1dSJustin T. Gibbs if (ccb_h->status & CAM_RELEASE_SIMQ) { 70798b8a9b1dSJustin T. Gibbs xpt_release_simq(ccb_h->path->bus->sim, 70808b8a9b1dSJustin T. Gibbs /*run_queue*/TRUE); 7081434bbf6eSJustin T. Gibbs ccb_h->status &= ~CAM_RELEASE_SIMQ; 7082434bbf6eSJustin T. Gibbs runq = FALSE; 7083434bbf6eSJustin T. Gibbs } 7084434bbf6eSJustin T. Gibbs 7085434bbf6eSJustin T. Gibbs if ((ccb_h->flags & CAM_DEV_QFRZDIS) 70868b8a9b1dSJustin T. Gibbs && (ccb_h->status & CAM_DEV_QFRZN)) { 70872cefde5fSJustin T. Gibbs xpt_release_devq(ccb_h->path, /*count*/1, 70888b8a9b1dSJustin T. Gibbs /*run_queue*/TRUE); 70898b8a9b1dSJustin T. Gibbs ccb_h->status &= ~CAM_DEV_QFRZN; 70908b8a9b1dSJustin T. Gibbs } else if (runq) { 70918b8a9b1dSJustin T. Gibbs xpt_run_dev_sendq(ccb_h->path->bus); 70928b8a9b1dSJustin T. Gibbs } 70938b8a9b1dSJustin T. Gibbs 70948b8a9b1dSJustin T. Gibbs /* Call the peripheral driver's callback */ 7095434bbf6eSJustin T. Gibbs (*ccb_h->cbfcnp)(ccb_h->path->periph, (union ccb *)ccb_h); 70968b8a9b1dSJustin T. Gibbs 70978b8a9b1dSJustin T. Gibbs /* Raise IPL for while test */ 70988b8a9b1dSJustin T. Gibbs s = splcam(); 70998b8a9b1dSJustin T. Gibbs } 71008b8a9b1dSJustin T. Gibbs splx(s); 71018b8a9b1dSJustin T. Gibbs } 7102