diff options
Diffstat (limited to 'sys/cam/cam_xpt.c')
-rw-r--r-- | sys/cam/cam_xpt.c | 2613 |
1 files changed, 142 insertions, 2471 deletions
diff --git a/sys/cam/cam_xpt.c b/sys/cam/cam_xpt.c index 08286db..fe759e9 100644 --- a/sys/cam/cam_xpt.c +++ b/sys/cam/cam_xpt.c @@ -56,10 +56,12 @@ __FBSDID("$FreeBSD$"); #include <cam/cam.h> #include <cam/cam_ccb.h> #include <cam/cam_periph.h> +#include <cam/cam_queue.h> #include <cam/cam_sim.h> #include <cam/cam_xpt.h> #include <cam/cam_xpt_sim.h> #include <cam/cam_xpt_periph.h> +#include <cam/cam_xpt_internal.h> #include <cam/cam_debug.h> #include <cam/scsi/scsi_all.h> @@ -68,31 +70,6 @@ __FBSDID("$FreeBSD$"); #include <machine/stdarg.h> /* for xpt_print below */ #include "opt_cam.h" -/* Datastructures internal to the xpt layer */ -MALLOC_DEFINE(M_CAMXPT, "CAM XPT", "CAM XPT buffers"); - -/* Object for defering XPT actions to a taskqueue */ -struct xpt_task { - struct task task; - void *data1; - uintptr_t data2; -}; - -/* - * Definition of an async handler callback block. These are used to add - * SIMs and peripherals to the async callback lists. - */ -struct async_node { - SLIST_ENTRY(async_node) links; - u_int32_t event_enable; /* Async Event enables */ - void (*callback)(void *arg, u_int32_t code, - struct cam_path *path, void *args); - void *callback_arg; -}; - -SLIST_HEAD(async_list, async_node); -SLIST_HEAD(periph_list, cam_periph); - /* * This is the maximum number of high powered commands (e.g. start unit) * that can be outstanding at a particular time. @@ -101,148 +78,16 @@ SLIST_HEAD(periph_list, cam_periph); #define CAM_MAX_HIGHPOWER 4 #endif -/* - * Structure for queueing a device in a run queue. - * There is one run queue for allocating new ccbs, - * and another for sending ccbs to the controller. - */ -struct cam_ed_qinfo { - cam_pinfo pinfo; - struct cam_ed *device; -}; - -/* - * The CAM EDT (Existing Device Table) contains the device information for - * all devices for all busses in the system. The table contains a - * cam_ed structure for each device on the bus. - */ -struct cam_ed { - TAILQ_ENTRY(cam_ed) links; - struct cam_ed_qinfo alloc_ccb_entry; - struct cam_ed_qinfo send_ccb_entry; - struct cam_et *target; - struct cam_sim *sim; - lun_id_t lun_id; - struct camq drvq; /* - * Queue of type drivers wanting to do - * work on this device. - */ - struct cam_ccbq ccbq; /* Queue of pending ccbs */ - struct async_list asyncs; /* Async callback info for this B/T/L */ - struct periph_list periphs; /* All attached devices */ - u_int generation; /* Generation number */ - struct cam_periph *owner; /* Peripheral driver's ownership tag */ - struct xpt_quirk_entry *quirk; /* Oddities about this device */ - /* Storage for the inquiry data */ - cam_proto protocol; - u_int protocol_version; - cam_xport transport; - u_int transport_version; - struct scsi_inquiry_data inq_data; - u_int8_t inq_flags; /* - * Current settings for inquiry flags. - * This allows us to override settings - * like disconnection and tagged - * queuing for a device. - */ - u_int8_t queue_flags; /* Queue flags from the control page */ - u_int8_t serial_num_len; - u_int8_t *serial_num; - u_int32_t qfrozen_cnt; - u_int32_t flags; -#define CAM_DEV_UNCONFIGURED 0x01 -#define CAM_DEV_REL_TIMEOUT_PENDING 0x02 -#define CAM_DEV_REL_ON_COMPLETE 0x04 -#define CAM_DEV_REL_ON_QUEUE_EMPTY 0x08 -#define CAM_DEV_RESIZE_QUEUE_NEEDED 0x10 -#define CAM_DEV_TAG_AFTER_COUNT 0x20 -#define CAM_DEV_INQUIRY_DATA_VALID 0x40 -#define CAM_DEV_IN_DV 0x80 -#define CAM_DEV_DV_HIT_BOTTOM 0x100 - u_int32_t tag_delay_count; -#define CAM_TAG_DELAY_COUNT 5 - u_int32_t tag_saved_openings; - u_int32_t refcount; - struct callout callout; -}; - -/* - * Each target is represented by an ET (Existing Target). These - * entries are created when a target is successfully probed with an - * identify, and removed when a device fails to respond after a number - * of retries, or a bus rescan finds the device missing. - */ -struct cam_et { - TAILQ_HEAD(, cam_ed) ed_entries; - TAILQ_ENTRY(cam_et) links; - struct cam_eb *bus; - target_id_t target_id; - u_int32_t refcount; - u_int generation; - struct timeval last_reset; -}; - -/* - * Each bus is represented by an EB (Existing Bus). These entries - * are created by calls to xpt_bus_register and deleted by calls to - * xpt_bus_deregister. - */ -struct cam_eb { - TAILQ_HEAD(, cam_et) et_entries; - TAILQ_ENTRY(cam_eb) links; - path_id_t path_id; - struct cam_sim *sim; - struct timeval last_reset; - u_int32_t flags; -#define CAM_EB_RUNQ_SCHEDULED 0x01 - u_int32_t refcount; - u_int generation; - device_t parent_dev; -}; - -struct cam_path { - struct cam_periph *periph; - struct cam_eb *bus; - struct cam_et *target; - struct cam_ed *device; -}; +/* Datastructures internal to the xpt layer */ +MALLOC_DEFINE(M_CAMXPT, "CAM XPT", "CAM XPT buffers"); -struct xpt_quirk_entry { - struct scsi_inquiry_pattern inq_pat; - u_int8_t quirks; -#define CAM_QUIRK_NOLUNS 0x01 -#define CAM_QUIRK_NOSERIAL 0x02 -#define CAM_QUIRK_HILUNS 0x04 -#define CAM_QUIRK_NOHILUNS 0x08 - u_int mintags; - u_int maxtags; +/* Object for defering XPT actions to a taskqueue */ +struct xpt_task { + struct task task; + void *data1; + uintptr_t data2; }; -static int cam_srch_hi = 0; -TUNABLE_INT("kern.cam.cam_srch_hi", &cam_srch_hi); -static int sysctl_cam_search_luns(SYSCTL_HANDLER_ARGS); -SYSCTL_PROC(_kern_cam, OID_AUTO, cam_srch_hi, CTLTYPE_INT|CTLFLAG_RW, 0, 0, - sysctl_cam_search_luns, "I", - "allow search above LUN 7 for SCSI3 and greater devices"); - -#define CAM_SCSI2_MAXLUN 8 -/* - * If we're not quirked to search <= the first 8 luns - * and we are either quirked to search above lun 8, - * or we're > SCSI-2 and we've enabled hilun searching, - * or we're > SCSI-2 and the last lun was a success, - * we can look for luns above lun 8. - */ -#define CAN_SRCH_HI_SPARSE(dv) \ - (((dv->quirk->quirks & CAM_QUIRK_NOHILUNS) == 0) \ - && ((dv->quirk->quirks & CAM_QUIRK_HILUNS) \ - || (SID_ANSI_REV(&dv->inq_data) > SCSI_REV_2 && cam_srch_hi))) - -#define CAN_SRCH_HI_DENSE(dv) \ - (((dv->quirk->quirks & CAM_QUIRK_NOHILUNS) == 0) \ - && ((dv->quirk->quirks & CAM_QUIRK_HILUNS) \ - || (SID_ANSI_REV(&dv->inq_data) > SCSI_REV_2))) - typedef enum { XPT_FLAG_OPEN = 0x01 } xpt_flags; @@ -268,359 +113,6 @@ struct xpt_softc { struct mtx xpt_lock; }; -static const char quantum[] = "QUANTUM"; -static const char sony[] = "SONY"; -static const char west_digital[] = "WDIGTL"; -static const char samsung[] = "SAMSUNG"; -static const char seagate[] = "SEAGATE"; -static const char microp[] = "MICROP"; - -static struct xpt_quirk_entry xpt_quirk_table[] = -{ - { - /* Reports QUEUE FULL for temporary resource shortages */ - { T_DIRECT, SIP_MEDIA_FIXED, quantum, "XP39100*", "*" }, - /*quirks*/0, /*mintags*/24, /*maxtags*/32 - }, - { - /* Reports QUEUE FULL for temporary resource shortages */ - { T_DIRECT, SIP_MEDIA_FIXED, quantum, "XP34550*", "*" }, - /*quirks*/0, /*mintags*/24, /*maxtags*/32 - }, - { - /* Reports QUEUE FULL for temporary resource shortages */ - { T_DIRECT, SIP_MEDIA_FIXED, quantum, "XP32275*", "*" }, - /*quirks*/0, /*mintags*/24, /*maxtags*/32 - }, - { - /* Broken tagged queuing drive */ - { T_DIRECT, SIP_MEDIA_FIXED, microp, "4421-07*", "*" }, - /*quirks*/0, /*mintags*/0, /*maxtags*/0 - }, - { - /* Broken tagged queuing drive */ - { T_DIRECT, SIP_MEDIA_FIXED, "HP", "C372*", "*" }, - /*quirks*/0, /*mintags*/0, /*maxtags*/0 - }, - { - /* Broken tagged queuing drive */ - { T_DIRECT, SIP_MEDIA_FIXED, microp, "3391*", "x43h" }, - /*quirks*/0, /*mintags*/0, /*maxtags*/0 - }, - { - /* - * Unfortunately, the Quantum Atlas III has the same - * problem as the Atlas II drives above. - * Reported by: "Johan Granlund" <johan@granlund.nu> - * - * For future reference, the drive with the problem was: - * QUANTUM QM39100TD-SW N1B0 - * - * It's possible that Quantum will fix the problem in later - * firmware revisions. If that happens, the quirk entry - * will need to be made specific to the firmware revisions - * with the problem. - * - */ - /* Reports QUEUE FULL for temporary resource shortages */ - { T_DIRECT, SIP_MEDIA_FIXED, quantum, "QM39100*", "*" }, - /*quirks*/0, /*mintags*/24, /*maxtags*/32 - }, - { - /* - * 18 Gig Atlas III, same problem as the 9G version. - * Reported by: Andre Albsmeier - * <andre.albsmeier@mchp.siemens.de> - * - * For future reference, the drive with the problem was: - * QUANTUM QM318000TD-S N491 - */ - /* Reports QUEUE FULL for temporary resource shortages */ - { T_DIRECT, SIP_MEDIA_FIXED, quantum, "QM318000*", "*" }, - /*quirks*/0, /*mintags*/24, /*maxtags*/32 - }, - { - /* - * Broken tagged queuing drive - * Reported by: Bret Ford <bford@uop.cs.uop.edu> - * and: Martin Renters <martin@tdc.on.ca> - */ - { T_DIRECT, SIP_MEDIA_FIXED, seagate, "ST410800*", "71*" }, - /*quirks*/0, /*mintags*/0, /*maxtags*/0 - }, - /* - * The Seagate Medalist Pro drives have very poor write - * performance with anything more than 2 tags. - * - * Reported by: Paul van der Zwan <paulz@trantor.xs4all.nl> - * Drive: <SEAGATE ST36530N 1444> - * - * Reported by: Jeremy Lea <reg@shale.csir.co.za> - * Drive: <SEAGATE ST34520W 1281> - * - * No one has actually reported that the 9G version - * (ST39140*) of the Medalist Pro has the same problem, but - * we're assuming that it does because the 4G and 6.5G - * versions of the drive are broken. - */ - { - { T_DIRECT, SIP_MEDIA_FIXED, seagate, "ST34520*", "*"}, - /*quirks*/0, /*mintags*/2, /*maxtags*/2 - }, - { - { T_DIRECT, SIP_MEDIA_FIXED, seagate, "ST36530*", "*"}, - /*quirks*/0, /*mintags*/2, /*maxtags*/2 - }, - { - { T_DIRECT, SIP_MEDIA_FIXED, seagate, "ST39140*", "*"}, - /*quirks*/0, /*mintags*/2, /*maxtags*/2 - }, - { - /* - * Slow when tagged queueing is enabled. Write performance - * steadily drops off with more and more concurrent - * transactions. Best sequential write performance with - * tagged queueing turned off and write caching turned on. - * - * PR: kern/10398 - * Submitted by: Hideaki Okada <hokada@isl.melco.co.jp> - * Drive: DCAS-34330 w/ "S65A" firmware. - * - * The drive with the problem had the "S65A" firmware - * revision, and has also been reported (by Stephen J. - * Roznowski <sjr@home.net>) for a drive with the "S61A" - * firmware revision. - * - * Although no one has reported problems with the 2 gig - * version of the DCAS drive, the assumption is that it - * has the same problems as the 4 gig version. Therefore - * this quirk entries disables tagged queueing for all - * DCAS drives. - */ - { T_DIRECT, SIP_MEDIA_FIXED, "IBM", "DCAS*", "*" }, - /*quirks*/0, /*mintags*/0, /*maxtags*/0 - }, - { - /* Broken tagged queuing drive */ - { T_DIRECT, SIP_MEDIA_REMOVABLE, "iomega", "jaz*", "*" }, - /*quirks*/0, /*mintags*/0, /*maxtags*/0 - }, - { - /* Broken tagged queuing drive */ - { T_DIRECT, SIP_MEDIA_FIXED, "CONNER", "CFP2107*", "*" }, - /*quirks*/0, /*mintags*/0, /*maxtags*/0 - }, - { - /* This does not support other than LUN 0 */ - { T_DIRECT, SIP_MEDIA_FIXED, "VMware*", "*", "*" }, - CAM_QUIRK_NOLUNS, /*mintags*/2, /*maxtags*/255 - }, - { - /* - * Broken tagged queuing drive. - * Submitted by: - * NAKAJI Hiroyuki <nakaji@zeisei.dpri.kyoto-u.ac.jp> - * in PR kern/9535 - */ - { T_DIRECT, SIP_MEDIA_FIXED, samsung, "WN34324U*", "*" }, - /*quirks*/0, /*mintags*/0, /*maxtags*/0 - }, - { - /* - * Slow when tagged queueing is enabled. (1.5MB/sec versus - * 8MB/sec.) - * Submitted by: Andrew Gallatin <gallatin@cs.duke.edu> - * Best performance with these drives is achieved with - * tagged queueing turned off, and write caching turned on. - */ - { T_DIRECT, SIP_MEDIA_FIXED, west_digital, "WDE*", "*" }, - /*quirks*/0, /*mintags*/0, /*maxtags*/0 - }, - { - /* - * Slow when tagged queueing is enabled. (1.5MB/sec versus - * 8MB/sec.) - * Submitted by: Andrew Gallatin <gallatin@cs.duke.edu> - * Best performance with these drives is achieved with - * tagged queueing turned off, and write caching turned on. - */ - { T_DIRECT, SIP_MEDIA_FIXED, west_digital, "ENTERPRISE", "*" }, - /*quirks*/0, /*mintags*/0, /*maxtags*/0 - }, - { - /* - * Doesn't handle queue full condition correctly, - * so we need to limit maxtags to what the device - * can handle instead of determining this automatically. - */ - { T_DIRECT, SIP_MEDIA_FIXED, samsung, "WN321010S*", "*" }, - /*quirks*/0, /*mintags*/2, /*maxtags*/32 - }, - { - /* Really only one LUN */ - { T_ENCLOSURE, SIP_MEDIA_FIXED, "SUN", "SENA", "*" }, - CAM_QUIRK_NOLUNS, /*mintags*/0, /*maxtags*/0 - }, - { - /* I can't believe we need a quirk for DPT volumes. */ - { T_ANY, SIP_MEDIA_FIXED|SIP_MEDIA_REMOVABLE, "DPT", "*", "*" }, - CAM_QUIRK_NOLUNS, - /*mintags*/0, /*maxtags*/255 - }, - { - /* - * Many Sony CDROM drives don't like multi-LUN probing. - */ - { T_CDROM, SIP_MEDIA_REMOVABLE, sony, "CD-ROM CDU*", "*" }, - CAM_QUIRK_NOLUNS, /*mintags*/0, /*maxtags*/0 - }, - { - /* - * This drive doesn't like multiple LUN probing. - * Submitted by: Parag Patel <parag@cgt.com> - */ - { T_WORM, SIP_MEDIA_REMOVABLE, sony, "CD-R CDU9*", "*" }, - CAM_QUIRK_NOLUNS, /*mintags*/0, /*maxtags*/0 - }, - { - { T_WORM, SIP_MEDIA_REMOVABLE, "YAMAHA", "CDR100*", "*" }, - CAM_QUIRK_NOLUNS, /*mintags*/0, /*maxtags*/0 - }, - { - /* - * The 8200 doesn't like multi-lun probing, and probably - * don't like serial number requests either. - */ - { - T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "EXABYTE", - "EXB-8200*", "*" - }, - CAM_QUIRK_NOLUNS, /*mintags*/0, /*maxtags*/0 - }, - { - /* - * Let's try the same as above, but for a drive that says - * it's an IPL-6860 but is actually an EXB 8200. - */ - { - T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "EXABYTE", - "IPL-6860*", "*" - }, - CAM_QUIRK_NOLUNS, /*mintags*/0, /*maxtags*/0 - }, - { - /* - * These Hitachi drives don't like multi-lun probing. - * The PR submitter has a DK319H, but says that the Linux - * kernel has a similar work-around for the DK312 and DK314, - * so all DK31* drives are quirked here. - * PR: misc/18793 - * Submitted by: Paul Haddad <paul@pth.com> - */ - { T_DIRECT, SIP_MEDIA_FIXED, "HITACHI", "DK31*", "*" }, - CAM_QUIRK_NOLUNS, /*mintags*/2, /*maxtags*/255 - }, - { - /* - * The Hitachi CJ series with J8A8 firmware apparantly has - * problems with tagged commands. - * PR: 23536 - * Reported by: amagai@nue.org - */ - { T_DIRECT, SIP_MEDIA_FIXED, "HITACHI", "DK32CJ*", "J8A8" }, - CAM_QUIRK_NOLUNS, /*mintags*/0, /*maxtags*/0 - }, - { - /* - * These are the large storage arrays. - * Submitted by: William Carrel <william.carrel@infospace.com> - */ - { T_DIRECT, SIP_MEDIA_FIXED, "HITACHI", "OPEN*", "*" }, - CAM_QUIRK_HILUNS, 2, 1024 - }, - { - /* - * This old revision of the TDC3600 is also SCSI-1, and - * hangs upon serial number probing. - */ - { - T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "TANDBERG", - " TDC 3600", "U07:" - }, - CAM_QUIRK_NOSERIAL, /*mintags*/0, /*maxtags*/0 - }, - { - /* - * Would repond to all LUNs if asked for. - */ - { - T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "CALIPER", - "CP150", "*" - }, - CAM_QUIRK_NOLUNS, /*mintags*/0, /*maxtags*/0 - }, - { - /* - * Would repond to all LUNs if asked for. - */ - { - T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "KENNEDY", - "96X2*", "*" - }, - CAM_QUIRK_NOLUNS, /*mintags*/0, /*maxtags*/0 - }, - { - /* Submitted by: Matthew Dodd <winter@jurai.net> */ - { T_PROCESSOR, SIP_MEDIA_FIXED, "Cabletrn", "EA41*", "*" }, - CAM_QUIRK_NOLUNS, /*mintags*/0, /*maxtags*/0 - }, - { - /* Submitted by: Matthew Dodd <winter@jurai.net> */ - { T_PROCESSOR, SIP_MEDIA_FIXED, "CABLETRN", "EA41*", "*" }, - CAM_QUIRK_NOLUNS, /*mintags*/0, /*maxtags*/0 - }, - { - /* TeraSolutions special settings for TRC-22 RAID */ - { T_DIRECT, SIP_MEDIA_FIXED, "TERASOLU", "TRC-22", "*" }, - /*quirks*/0, /*mintags*/55, /*maxtags*/255 - }, - { - /* Veritas Storage Appliance */ - { T_DIRECT, SIP_MEDIA_FIXED, "VERITAS", "*", "*" }, - CAM_QUIRK_HILUNS, /*mintags*/2, /*maxtags*/1024 - }, - { - /* - * Would respond to all LUNs. Device type and removable - * flag are jumper-selectable. - */ - { T_ANY, SIP_MEDIA_REMOVABLE|SIP_MEDIA_FIXED, "MaxOptix", - "Tahiti 1", "*" - }, - CAM_QUIRK_NOLUNS, /*mintags*/0, /*maxtags*/0 - }, - { - /* EasyRAID E5A aka. areca ARC-6010 */ - { T_DIRECT, SIP_MEDIA_FIXED, "easyRAID", "*", "*" }, - CAM_QUIRK_NOHILUNS, /*mintags*/2, /*maxtags*/255 - }, - { - { T_ENCLOSURE, SIP_MEDIA_FIXED, "DP", "BACKPLANE", "*" }, - CAM_QUIRK_NOLUNS, /*mintags*/0, /*maxtags*/0 - }, - { - /* Default tagged queuing parameters for all devices */ - { - T_ANY, SIP_MEDIA_REMOVABLE|SIP_MEDIA_FIXED, - /*vendor*/"*", /*product*/"*", /*revision*/"*" - }, - /*quirks*/0, /*mintags*/2, /*maxtags*/255 - }, -}; - -static const int xpt_quirk_table_size = - sizeof(xpt_quirk_table) / sizeof(*xpt_quirk_table); - typedef enum { DM_RET_COPY = 0x01, DM_RET_FLAG_MASK = 0x0f, @@ -666,23 +158,13 @@ struct cam_periph *xpt_periph; static periph_init_t xpt_periph_init; -static periph_init_t probe_periph_init; - static struct periph_driver xpt_driver = { xpt_periph_init, "xpt", TAILQ_HEAD_INITIALIZER(xpt_driver.units) }; -static struct periph_driver probe_driver = -{ - probe_periph_init, "probe", - TAILQ_HEAD_INITIALIZER(probe_driver.units) -}; - PERIPHDRIVER_DECLARE(xpt, xpt_driver); -PERIPHDRIVER_DECLARE(probe, probe_driver); - static d_open_t xptopen; static d_close_t xptclose; @@ -697,7 +179,6 @@ static struct cdevsw xpt_cdevsw = { .d_name = "xpt", }; - /* Storage for debugging datastructures */ #ifdef CAMDEBUG struct cam_path *cam_dpath; @@ -705,28 +186,6 @@ u_int32_t cam_dflags; u_int32_t cam_debug_delay; #endif -#if defined(CAM_DEBUG_FLAGS) && !defined(CAMDEBUG) -#error "You must have options CAMDEBUG to use options CAM_DEBUG_FLAGS" -#endif - -/* - * In order to enable the CAM_DEBUG_* options, the user must have CAMDEBUG - * enabled. Also, the user must have either none, or all of CAM_DEBUG_BUS, - * CAM_DEBUG_TARGET, and CAM_DEBUG_LUN specified. - */ -#if defined(CAM_DEBUG_BUS) || defined(CAM_DEBUG_TARGET) \ - || defined(CAM_DEBUG_LUN) -#ifdef CAMDEBUG -#if !defined(CAM_DEBUG_BUS) || !defined(CAM_DEBUG_TARGET) \ - || !defined(CAM_DEBUG_LUN) -#error "You must define all or none of CAM_DEBUG_BUS, CAM_DEBUG_TARGET \ - and CAM_DEBUG_LUN" -#endif /* !CAM_DEBUG_BUS || !CAM_DEBUG_TARGET || !CAM_DEBUG_LUN */ -#else /* !CAMDEBUG */ -#error "You must use options CAMDEBUG if you use the CAM_DEBUG_* options" -#endif /* CAMDEBUG */ -#endif /* CAM_DEBUG_BUS || CAM_DEBUG_TARGET || CAM_DEBUG_LUN */ - /* Our boot-time initialization hook */ static int cam_module_event_handler(module_t, int /*modeventtype_t*/, void *); @@ -742,30 +201,14 @@ DECLARE_MODULE(cam, cam_moduledata, SI_SUB_CONFIGURE, SI_ORDER_SECOND); MODULE_VERSION(cam, 1); -static cam_status xpt_compile_path(struct cam_path *new_path, - struct cam_periph *perph, - path_id_t path_id, - target_id_t target_id, - lun_id_t lun_id); - -static void xpt_release_path(struct cam_path *path); - static void xpt_async_bcast(struct async_list *async_head, u_int32_t async_code, struct cam_path *path, void *async_arg); -static void xpt_dev_async(u_int32_t async_code, - struct cam_eb *bus, - struct cam_et *target, - struct cam_ed *device, - void *async_arg); static path_id_t xptnextfreepathid(void); static path_id_t xptpathid(const char *sim_name, int sim_unit, int sim_bus); static union ccb *xpt_get_ccb(struct cam_ed *device); -static int xpt_schedule_dev(struct camq *queue, cam_pinfo *dev_pinfo, - u_int32_t new_priority); static void xpt_run_dev_allocq(struct cam_eb *bus); -static void xpt_run_dev_sendq(struct cam_eb *bus); static timeout_t xpt_release_devq_timeout; static void xpt_release_simq_timeout(void *arg) __unused; static void xpt_release_bus(struct cam_eb *bus); @@ -774,23 +217,14 @@ static void xpt_release_devq_device(struct cam_ed *dev, u_int count, static struct cam_et* xpt_alloc_target(struct cam_eb *bus, target_id_t target_id); static void xpt_release_target(struct cam_eb *bus, struct cam_et *target); -static struct cam_ed* - xpt_alloc_device(struct cam_eb *bus, struct cam_et *target, - lun_id_t lun_id); static void xpt_release_device(struct cam_eb *bus, struct cam_et *target, struct cam_ed *device); -static u_int32_t xpt_dev_ccbq_resize(struct cam_path *path, int newopenings); static struct cam_eb* xpt_find_bus(path_id_t path_id); static struct cam_et* xpt_find_target(struct cam_eb *bus, target_id_t target_id); static struct cam_ed* xpt_find_device(struct cam_et *target, lun_id_t lun_id); -static void xpt_scan_bus(struct cam_periph *periph, union ccb *ccb); -static void xpt_scan_lun(struct cam_periph *periph, - struct cam_path *path, cam_flags flags, - union ccb *ccb); -static void xptscandone(struct cam_periph *periph, union ccb *done_ccb); static xpt_busfunc_t xptconfigbuscountfunc; static xpt_busfunc_t xptconfigfunc; static void xpt_config(void *arg); @@ -840,30 +274,21 @@ static xpt_periphfunc_t xptdefperiphfunc; static int xpt_for_all_busses(xpt_busfunc_t *tr_func, void *arg); static int xpt_for_all_devices(xpt_devicefunc_t *tr_func, void *arg); +static void xpt_dev_async_default(u_int32_t async_code, + struct cam_eb *bus, + struct cam_et *target, + struct cam_ed *device, + void *async_arg); +static struct cam_ed * xpt_alloc_device_default(struct cam_eb *bus, + struct cam_et *target, + lun_id_t lun_id); static xpt_devicefunc_t xptsetasyncfunc; static xpt_busfunc_t xptsetasyncbusfunc; static cam_status xptregister(struct cam_periph *periph, void *arg); -static cam_status proberegister(struct cam_periph *periph, - void *arg); -static void probeschedule(struct cam_periph *probe_periph); -static void probestart(struct cam_periph *periph, union ccb *start_ccb); -static void proberequestdefaultnegotiation(struct cam_periph *periph); -static int proberequestbackoff(struct cam_periph *periph, - struct cam_ed *device); -static void probedone(struct cam_periph *periph, union ccb *done_ccb); -static void probecleanup(struct cam_periph *periph); -static void xpt_find_quirk(struct cam_ed *device); -static void xpt_devise_transport(struct cam_path *path); -static void xpt_set_transfer_settings(struct ccb_trans_settings *cts, - struct cam_ed *device, - int async_update); -static void xpt_toggle_tags(struct cam_path *path); static void xpt_start_tags(struct cam_path *path); static __inline int xpt_schedule_dev_allocq(struct cam_eb *bus, struct cam_ed *dev); -static __inline int xpt_schedule_dev_sendq(struct cam_eb *bus, - struct cam_ed *dev); static __inline int periph_is_queued(struct cam_periph *periph); static __inline int device_is_alloc_queued(struct cam_ed *device); static __inline int device_is_send_queued(struct cam_ed *device); @@ -897,27 +322,6 @@ xpt_schedule_dev_allocq(struct cam_eb *bus, struct cam_ed *dev) } static __inline int -xpt_schedule_dev_sendq(struct cam_eb *bus, struct cam_ed *dev) -{ - int retval; - - if (dev->ccbq.dev_openings > 0) { - /* - * The priority of a device waiting for controller - * resources is that of the the highest priority CCB - * enqueued. - */ - retval = - xpt_schedule_dev(&bus->sim->devq->send_queue, - &dev->send_ccb_entry.pinfo, - CAMQ_GET_HEAD(&dev->ccbq.queue)->priority); - } else { - retval = 0; - } - return (retval); -} - -static __inline int periph_is_queued(struct cam_periph *periph) { return (periph->pinfo.index != CAM_UNQUEUED_INDEX); @@ -955,12 +359,6 @@ xpt_periph_init() } static void -probe_periph_init() -{ -} - - -static void xptdone(struct cam_periph *periph, union ccb *done_ccb) { /* Caller will release the CCB */ @@ -1643,7 +1041,13 @@ xpt_announce_periph(struct cam_periph *periph, char *announce_string) path->target->target_id, path->device->lun_id); printf("%s%d: ", periph->periph_name, periph->unit_number); - scsi_print_inquiry(&path->device->inq_data); + if (path->device->protocol == PROTO_SCSI) + scsi_print_inquiry(&path->device->inq_data); + else if (path->device->protocol == PROTO_ATA || + path->device->protocol == PROTO_SATAPM) + ata_print_ident(&path->device->ident_data); + else + printf("Unknown protocol device\n"); if (bootverbose && path->device->serial_num_len > 0) { /* Don't wrap the screen - print only the first 60 chars */ printf("%s%d: Serial Number %.60s\n", periph->periph_name, @@ -1677,19 +1081,20 @@ xpt_announce_periph(struct cam_periph *periph, char *announce_string) if ((spi->valid & CTS_SPI_VALID_BUS_WIDTH) != 0) speed *= (0x01 << spi->bus_width); } - if (cts.ccb_h.status == CAM_REQ_CMP && cts.transport == XPORT_FC) { struct ccb_trans_settings_fc *fc = &cts.xport_specific.fc; - if (fc->valid & CTS_FC_VALID_SPEED) { + if (fc->valid & CTS_FC_VALID_SPEED) speed = fc->bitrate; - } } - if (cts.ccb_h.status == CAM_REQ_CMP && cts.transport == XPORT_SAS) { struct ccb_trans_settings_sas *sas = &cts.xport_specific.sas; - if (sas->valid & CTS_SAS_VALID_SPEED) { + if (sas->valid & CTS_SAS_VALID_SPEED) speed = sas->bitrate; - } + } + if (cts.ccb_h.status == CAM_REQ_CMP && cts.transport == XPORT_SATA) { + struct ccb_trans_settings_sata *sata = &cts.xport_specific.sata; + if (sata->valid & CTS_SATA_VALID_SPEED) + speed = sata->bitrate; } mb = speed / 1000; @@ -1738,7 +1143,7 @@ xpt_announce_periph(struct cam_periph *periph, char *announce_string) if (path->device->inq_flags & SID_CmdQue || path->device->flags & CAM_DEV_TAG_AFTER_COUNT) { - printf("\n%s%d: Command Queueing Enabled", + printf("\n%s%d: Command Queueing enabled", periph->periph_name, periph->unit_number); } printf("\n"); @@ -2288,9 +1693,14 @@ xptedtdevicefunc(struct cam_ed *device, void *arg) device->target->target_id; cdm->matches[j].result.device_result.target_lun = device->lun_id; + cdm->matches[j].result.device_result.protocol = + device->protocol; bcopy(&device->inq_data, &cdm->matches[j].result.device_result.inq_data, sizeof(struct scsi_inquiry_data)); + bcopy(&device->ident_data, + &cdm->matches[j].result.device_result.ident_data, + sizeof(struct ata_params)); /* Let the user know whether this device is unconfigured */ if (device->flags & CAM_DEV_UNCONFIGURED) @@ -2990,6 +2400,15 @@ xpt_action(union ccb *start_ccb) CAM_DEBUG(start_ccb->ccb_h.path, CAM_DEBUG_TRACE, ("xpt_action\n")); start_ccb->ccb_h.status = CAM_REQ_INPROG; + (*(start_ccb->ccb_h.path->bus->xport->action))(start_ccb); +} + +void +xpt_action_default(union ccb *start_ccb) +{ + + CAM_DEBUG(start_ccb->ccb_h.path, CAM_DEBUG_TRACE, ("xpt_action_default\n")); + switch (start_ccb->ccb_h.func_code) { case XPT_SCSI_IO: @@ -3039,6 +2458,10 @@ xpt_action(union ccb *start_ccb) start_ccb->csio.sense_resid = 0; start_ccb->csio.resid = 0; /* FALLTHROUGH */ + case XPT_ATA_IO: + if (start_ccb->ccb_h.func_code == XPT_ATA_IO) { + start_ccb->ataio.resid = 0; + } case XPT_RESET_DEV: case XPT_ENG_EXEC: { @@ -3056,13 +2479,6 @@ xpt_action(union ccb *start_ccb) xpt_run_dev_sendq(path->bus); break; } - case XPT_SET_TRAN_SETTINGS: - { - xpt_set_transfer_settings(&start_ccb->cts, - start_ccb->ccb_h.path->device, - /*async_update*/FALSE); - break; - } case XPT_CALC_GEOMETRY: { struct cam_sim *sim; @@ -3148,7 +2564,6 @@ xpt_action(union ccb *start_ccb) case XPT_EN_LUN: case XPT_IMMED_NOTIFY: case XPT_NOTIFY_ACK: - case XPT_GET_TRAN_SETTINGS: case XPT_RESET_BUS: { struct cam_sim *sim; @@ -3185,7 +2600,9 @@ xpt_action(union ccb *start_ccb) cgd = &start_ccb->cgd; bus = cgd->ccb_h.path->bus; tar = cgd->ccb_h.path->target; + cgd->protocol = dev->protocol; cgd->inq_data = dev->inq_data; + cgd->ident_data = dev->ident_data; cgd->ccb_h.status = CAM_REQ_CMP; cgd->serial_num_len = dev->serial_num_len; if ((dev->serial_num_len > 0) @@ -3216,8 +2633,8 @@ xpt_action(union ccb *start_ccb) cgds->devq_queued = dev->ccbq.queue.entries; cgds->held = dev->ccbq.held; cgds->last_reset = tar->last_reset; - cgds->maxtags = dev->quirk->maxtags; - cgds->mintags = dev->quirk->mintags; + cgds->maxtags = dev->maxtags; + cgds->mintags = dev->mintags; if (timevalcmp(&tar->last_reset, &bus->last_reset, <)) cgds->last_reset = bus->last_reset; cgds->ccb_h.status = CAM_REQ_CMP; @@ -3513,14 +2930,6 @@ xpt_action(union ccb *start_ccb) start_ccb->ccb_h.status = CAM_REQ_CMP; break; } - case XPT_SCAN_BUS: - xpt_scan_bus(start_ccb->ccb_h.path->periph, start_ccb); - break; - case XPT_SCAN_LUN: - xpt_scan_lun(start_ccb->ccb_h.path->periph, - start_ccb->ccb_h.path, start_ccb->crcn.flags, - start_ccb); - break; case XPT_DEBUG: { #ifdef CAMDEBUG #ifdef CAM_DEBUG_DELAY @@ -3675,7 +3084,7 @@ xpt_schedule(struct cam_periph *perph, u_int32_t new_priority) * started the queue, return 0 so the caller doesn't attempt * to run the queue. */ -static int +int xpt_schedule_dev(struct camq *queue, cam_pinfo *pinfo, u_int32_t new_priority) { @@ -3784,7 +3193,7 @@ xpt_run_dev_allocq(struct cam_eb *bus) devq->alloc_queue.qfrozen_cnt--; } -static void +void xpt_run_dev_sendq(struct cam_eb *bus) { struct cam_devq *devq; @@ -3993,7 +3402,7 @@ xpt_create_path_unlocked(struct cam_path **new_path_ptr, return (status); } -static cam_status +cam_status xpt_compile_path(struct cam_path *new_path, struct cam_periph *perph, path_id_t path_id, target_id_t target_id, lun_id_t lun_id) { @@ -4032,9 +3441,10 @@ xpt_compile_path(struct cam_path *new_path, struct cam_periph *perph, /* Create one */ struct cam_ed *new_device; - new_device = xpt_alloc_device(bus, - target, - lun_id); + new_device = + (*(bus->xport->alloc_device))(bus, + target, + lun_id); if (new_device == NULL) { status = CAM_RESRC_UNAVAIL; } else { @@ -4064,7 +3474,7 @@ xpt_compile_path(struct cam_path *new_path, struct cam_periph *perph, return (status); } -static void +void xpt_release_path(struct cam_path *path) { CAM_DEBUG(path, CAM_DEBUG_TRACE, ("xpt_release_path\n")); @@ -4306,6 +3716,12 @@ xpt_release_ccb(union ccb *free_ccb) /* Functions accessed by SIM drivers */ +static struct xpt_xport xport_default = { + .alloc_device = xpt_alloc_device_default, + .action = xpt_action_default, + .async = xpt_dev_async_default, +}; + /* * A sim structure, listing the SIM entry points and instance * identification info is passed to xpt_bus_register to hook the SIM @@ -4321,6 +3737,8 @@ xpt_bus_register(struct cam_sim *sim, device_t parent, u_int32_t bus) struct cam_eb *new_bus; struct cam_eb *old_bus; struct ccb_pathinq cpi; + struct cam_path path; + cam_status status; mtx_assert(sim->mtx, MA_OWNED); @@ -4333,7 +3751,6 @@ xpt_bus_register(struct cam_sim *sim, device_t parent, u_int32_t bus) } if (strcmp(sim->sim_name, "xpt") != 0) { - sim->path_id = xptpathid(sim->sim_name, sim->unit_number, sim->bus_id); } @@ -4346,6 +3763,7 @@ xpt_bus_register(struct cam_sim *sim, device_t parent, u_int32_t bus) new_bus->flags = 0; new_bus->refcount = 1; /* Held until a bus_deregister event */ new_bus->generation = 0; + mtx_lock(&xsoftc.xpt_topo_lock); old_bus = TAILQ_FIRST(&xsoftc.xpt_busses); while (old_bus != NULL @@ -4358,18 +3776,46 @@ xpt_bus_register(struct cam_sim *sim, device_t parent, u_int32_t bus) xsoftc.bus_generation++; mtx_unlock(&xsoftc.xpt_topo_lock); + /* + * Set a default transport so that a PATH_INQ can be issued to + * the SIM. This will then allow for probing and attaching of + * a more appropriate transport. + */ + new_bus->xport = &xport_default; + + bzero(&path, sizeof(path)); + status = xpt_compile_path(&path, /*periph*/NULL, sim->path_id, + CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD); + if (status != CAM_REQ_CMP) + printf("xpt_compile_path returned %d\n", status); + + xpt_setup_ccb(&cpi.ccb_h, &path, /*priority*/1); + cpi.ccb_h.func_code = XPT_PATH_INQ; + xpt_action((union ccb *)&cpi); + + if (cpi.ccb_h.status == CAM_REQ_CMP) { + switch (cpi.transport) { + case XPORT_SPI: + case XPORT_SAS: + case XPORT_FC: + case XPORT_USB: + new_bus->xport = scsi_get_xport(); + break; + case XPORT_ATA: + case XPORT_SATA: + new_bus->xport = ata_get_xport(); + break; + default: + new_bus->xport = &xport_default; + break; + } + } + /* Notify interested parties */ if (sim->path_id != CAM_XPT_PATH_ID) { - struct cam_path path; - - xpt_compile_path(&path, /*periph*/NULL, sim->path_id, - CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD); - xpt_setup_ccb(&cpi.ccb_h, &path, /*priority*/1); - cpi.ccb_h.func_code = XPT_PATH_INQ; - xpt_action((union ccb *)&cpi); xpt_async(AC_PATH_REGISTERED, &path, &cpi); - xpt_release_path(&path); } + xpt_release_path(&path); return (CAM_SUCCESS); } @@ -4521,8 +3967,9 @@ xpt_async(u_int32_t async_code, struct cam_path *path, void *async_arg) && device->lun_id != CAM_LUN_WILDCARD) continue; - xpt_dev_async(async_code, bus, target, - device, async_arg); + (*(bus->xport->async))(async_code, bus, + target, device, + async_arg); xpt_async_bcast(&device->asyncs, async_code, path, async_arg); @@ -4562,68 +4009,12 @@ xpt_async_bcast(struct async_list *async_head, } } -/* - * Handle any per-device event notifications that require action by the XPT. - */ static void -xpt_dev_async(u_int32_t async_code, struct cam_eb *bus, struct cam_et *target, - struct cam_ed *device, void *async_arg) +xpt_dev_async_default(u_int32_t async_code, struct cam_eb *bus, + struct cam_et *target, struct cam_ed *device, + void *async_arg) { - cam_status status; - struct cam_path newpath; - - /* - * We only need to handle events for real devices. - */ - if (target->target_id == CAM_TARGET_WILDCARD - || device->lun_id == CAM_LUN_WILDCARD) - return; - - /* - * We need our own path with wildcards expanded to - * handle certain types of events. - */ - if ((async_code == AC_SENT_BDR) - || (async_code == AC_BUS_RESET) - || (async_code == AC_INQ_CHANGED)) - status = xpt_compile_path(&newpath, NULL, - bus->path_id, - target->target_id, - device->lun_id); - else - status = CAM_REQ_CMP_ERR; - - if (status == CAM_REQ_CMP) { - - /* - * Allow transfer negotiation to occur in a - * tag free environment. - */ - if (async_code == AC_SENT_BDR - || async_code == AC_BUS_RESET) - xpt_toggle_tags(&newpath); - - if (async_code == AC_INQ_CHANGED) { - /* - * We've sent a start unit command, or - * something similar to a device that - * may have caused its inquiry data to - * change. So we re-scan the device to - * refresh the inquiry data for it. - */ - xpt_scan_lun(newpath.periph, &newpath, - CAM_EXPECT_INQ_CHANGE, NULL); - } - xpt_release_path(&newpath); - } else if (async_code == AC_LOST_DEVICE) { - device->flags |= CAM_DEV_UNCONFIGURED; - } else if (async_code == AC_TRANSFER_NEG) { - struct ccb_trans_settings *settings; - - settings = (struct ccb_trans_settings *)async_arg; - xpt_set_transfer_settings(settings, device, - /*async_update*/TRUE); - } + printf("xpt_dev_async called\n"); } u_int32_t @@ -4938,9 +4329,34 @@ xpt_release_target(struct cam_eb *bus, struct cam_et *target) } static struct cam_ed * +xpt_alloc_device_default(struct cam_eb *bus, struct cam_et *target, + lun_id_t lun_id) +{ + struct cam_ed *device, *cur_device; + + device = xpt_alloc_device(bus, target, lun_id); + if (device == NULL) + return (NULL); + + device->mintags = 1; + device->maxtags = 1; + bus->sim->max_ccbs = device->ccbq.devq_openings; + cur_device = TAILQ_FIRST(&target->ed_entries); + while (cur_device != NULL && cur_device->lun_id < lun_id) + cur_device = TAILQ_NEXT(cur_device, links); + if (cur_device != NULL) { + TAILQ_INSERT_BEFORE(cur_device, device, links); + } else { + TAILQ_INSERT_TAIL(&target->ed_entries, device, links); + } + target->generation++; + + return (device); +} + +struct cam_ed * xpt_alloc_device(struct cam_eb *bus, struct cam_et *target, lun_id_t lun_id) { - struct cam_path path; struct cam_ed *device; struct cam_devq *devq; cam_status status; @@ -4957,8 +4373,6 @@ xpt_alloc_device(struct cam_eb *bus, struct cam_et *target, lun_id_t lun_id) } if (device != NULL) { - struct cam_ed *cur_device; - cam_init_pinfo(&device->alloc_ccb_entry.pinfo); device->alloc_ccb_entry.device = device; cam_init_pinfo(&device->send_ccb_entry.pinfo); @@ -4981,16 +4395,6 @@ xpt_alloc_device(struct cam_eb *bus, struct cam_et *target, lun_id_t lun_id) SLIST_INIT(&device->periphs); device->generation = 0; device->owner = NULL; - /* - * Take the default quirk entry until we have inquiry - * data and can determine a better quirk to use. - */ - device->quirk = &xpt_quirk_table[xpt_quirk_table_size - 1]; - bzero(&device->inq_data, sizeof(device->inq_data)); - device->inq_flags = 0; - device->queue_flags = 0; - device->serial_num = NULL; - device->serial_num_len = 0; device->qfrozen_cnt = 0; device->flags = CAM_DEV_UNCONFIGURED; device->tag_delay_count = 0; @@ -5007,30 +4411,6 @@ xpt_alloc_device(struct cam_eb *bus, struct cam_et *target, lun_id_t lun_id) */ target->refcount++; - /* - * XXX should be limited by number of CCBs this bus can - * do. - */ - bus->sim->max_ccbs += device->ccbq.devq_openings; - /* Insertion sort into our target's device list */ - cur_device = TAILQ_FIRST(&target->ed_entries); - while (cur_device != NULL && cur_device->lun_id < lun_id) - cur_device = TAILQ_NEXT(cur_device, links); - if (cur_device != NULL) { - TAILQ_INSERT_BEFORE(cur_device, device, links); - } else { - TAILQ_INSERT_TAIL(&target->ed_entries, device, links); - } - target->generation++; - if (lun_id != CAM_LUN_WILDCARD) { - xpt_compile_path(&path, - NULL, - bus->path_id, - target->target_id, - lun_id); - xpt_devise_transport(&path); - xpt_release_path(&path); - } } return (device); } @@ -5064,7 +4444,7 @@ xpt_release_device(struct cam_eb *bus, struct cam_et *target, } } -static u_int32_t +u_int32_t xpt_dev_ccbq_resize(struct cam_path *path, int newopenings) { int diff; @@ -5136,1715 +4516,6 @@ xpt_find_device(struct cam_et *target, lun_id_t lun_id) return (device); } -typedef struct { - union ccb *request_ccb; - struct ccb_pathinq *cpi; - int counter; -} xpt_scan_bus_info; - -/* - * To start a scan, request_ccb is an XPT_SCAN_BUS ccb. - * As the scan progresses, xpt_scan_bus is used as the - * callback on completion function. - */ -static void -xpt_scan_bus(struct cam_periph *periph, union ccb *request_ccb) -{ - CAM_DEBUG(request_ccb->ccb_h.path, CAM_DEBUG_TRACE, - ("xpt_scan_bus\n")); - switch (request_ccb->ccb_h.func_code) { - case XPT_SCAN_BUS: - { - xpt_scan_bus_info *scan_info; - union ccb *work_ccb; - struct cam_path *path; - u_int i; - u_int max_target; - u_int initiator_id; - - /* Find out the characteristics of the bus */ - work_ccb = xpt_alloc_ccb_nowait(); - if (work_ccb == NULL) { - request_ccb->ccb_h.status = CAM_RESRC_UNAVAIL; - xpt_done(request_ccb); - return; - } - xpt_setup_ccb(&work_ccb->ccb_h, request_ccb->ccb_h.path, - request_ccb->ccb_h.pinfo.priority); - work_ccb->ccb_h.func_code = XPT_PATH_INQ; - xpt_action(work_ccb); - if (work_ccb->ccb_h.status != CAM_REQ_CMP) { - request_ccb->ccb_h.status = work_ccb->ccb_h.status; - xpt_free_ccb(work_ccb); - xpt_done(request_ccb); - return; - } - - if ((work_ccb->cpi.hba_misc & PIM_NOINITIATOR) != 0) { - /* - * Can't scan the bus on an adapter that - * cannot perform the initiator role. - */ - request_ccb->ccb_h.status = CAM_REQ_CMP; - xpt_free_ccb(work_ccb); - xpt_done(request_ccb); - return; - } - - /* Save some state for use while we probe for devices */ - scan_info = (xpt_scan_bus_info *) - malloc(sizeof(xpt_scan_bus_info), M_CAMXPT, M_NOWAIT); - if (scan_info == NULL) { - request_ccb->ccb_h.status = CAM_RESRC_UNAVAIL; - xpt_done(request_ccb); - return; - } - scan_info->request_ccb = request_ccb; - scan_info->cpi = &work_ccb->cpi; - - /* Cache on our stack so we can work asynchronously */ - max_target = scan_info->cpi->max_target; - initiator_id = scan_info->cpi->initiator_id; - - - /* - * We can scan all targets in parallel, or do it sequentially. - */ - if (scan_info->cpi->hba_misc & PIM_SEQSCAN) { - max_target = 0; - scan_info->counter = 0; - } else { - scan_info->counter = scan_info->cpi->max_target + 1; - if (scan_info->cpi->initiator_id < scan_info->counter) { - scan_info->counter--; - } - } - - for (i = 0; i <= max_target; i++) { - cam_status status; - if (i == initiator_id) - continue; - - status = xpt_create_path(&path, xpt_periph, - request_ccb->ccb_h.path_id, - i, 0); - if (status != CAM_REQ_CMP) { - printf("xpt_scan_bus: xpt_create_path failed" - " with status %#x, bus scan halted\n", - status); - free(scan_info, M_CAMXPT); - request_ccb->ccb_h.status = status; - xpt_free_ccb(work_ccb); - xpt_done(request_ccb); - break; - } - work_ccb = xpt_alloc_ccb_nowait(); - if (work_ccb == NULL) { - free(scan_info, M_CAMXPT); - xpt_free_path(path); - request_ccb->ccb_h.status = CAM_RESRC_UNAVAIL; - xpt_done(request_ccb); - break; - } - xpt_setup_ccb(&work_ccb->ccb_h, path, - request_ccb->ccb_h.pinfo.priority); - work_ccb->ccb_h.func_code = XPT_SCAN_LUN; - work_ccb->ccb_h.cbfcnp = xpt_scan_bus; - work_ccb->ccb_h.ppriv_ptr0 = scan_info; - work_ccb->crcn.flags = request_ccb->crcn.flags; - xpt_action(work_ccb); - } - break; - } - case XPT_SCAN_LUN: - { - cam_status status; - struct cam_path *path; - xpt_scan_bus_info *scan_info; - path_id_t path_id; - target_id_t target_id; - lun_id_t lun_id; - - /* Reuse the same CCB to query if a device was really found */ - scan_info = (xpt_scan_bus_info *)request_ccb->ccb_h.ppriv_ptr0; - xpt_setup_ccb(&request_ccb->ccb_h, request_ccb->ccb_h.path, - request_ccb->ccb_h.pinfo.priority); - request_ccb->ccb_h.func_code = XPT_GDEV_TYPE; - - path_id = request_ccb->ccb_h.path_id; - target_id = request_ccb->ccb_h.target_id; - lun_id = request_ccb->ccb_h.target_lun; - xpt_action(request_ccb); - - if (request_ccb->ccb_h.status != CAM_REQ_CMP) { - struct cam_ed *device; - struct cam_et *target; - int phl; - - /* - * If we already probed lun 0 successfully, or - * we have additional configured luns on this - * target that might have "gone away", go onto - * the next lun. - */ - target = request_ccb->ccb_h.path->target; - /* - * We may touch devices that we don't - * hold references too, so ensure they - * don't disappear out from under us. - * The target above is referenced by the - * path in the request ccb. - */ - phl = 0; - device = TAILQ_FIRST(&target->ed_entries); - if (device != NULL) { - phl = CAN_SRCH_HI_SPARSE(device); - if (device->lun_id == 0) - device = TAILQ_NEXT(device, links); - } - if ((lun_id != 0) || (device != NULL)) { - if (lun_id < (CAM_SCSI2_MAXLUN-1) || phl) - lun_id++; - } - } else { - struct cam_ed *device; - - device = request_ccb->ccb_h.path->device; - - if ((device->quirk->quirks & CAM_QUIRK_NOLUNS) == 0) { - /* Try the next lun */ - if (lun_id < (CAM_SCSI2_MAXLUN-1) - || CAN_SRCH_HI_DENSE(device)) - lun_id++; - } - } - - /* - * Free the current request path- we're done with it. - */ - xpt_free_path(request_ccb->ccb_h.path); - - /* - * Check to see if we scan any further luns. - */ - if (lun_id == request_ccb->ccb_h.target_lun - || lun_id > scan_info->cpi->max_lun) { - int done; - - hop_again: - done = 0; - if (scan_info->cpi->hba_misc & PIM_SEQSCAN) { - scan_info->counter++; - if (scan_info->counter == - scan_info->cpi->initiator_id) { - scan_info->counter++; - } - if (scan_info->counter >= - scan_info->cpi->max_target+1) { - done = 1; - } - } else { - scan_info->counter--; - if (scan_info->counter == 0) { - done = 1; - } - } - if (done) { - xpt_free_ccb(request_ccb); - xpt_free_ccb((union ccb *)scan_info->cpi); - request_ccb = scan_info->request_ccb; - free(scan_info, M_CAMXPT); - request_ccb->ccb_h.status = CAM_REQ_CMP; - xpt_done(request_ccb); - break; - } - - if ((scan_info->cpi->hba_misc & PIM_SEQSCAN) == 0) { - break; - } - status = xpt_create_path(&path, xpt_periph, - scan_info->request_ccb->ccb_h.path_id, - scan_info->counter, 0); - if (status != CAM_REQ_CMP) { - printf("xpt_scan_bus: xpt_create_path failed" - " with status %#x, bus scan halted\n", - status); - xpt_free_ccb(request_ccb); - xpt_free_ccb((union ccb *)scan_info->cpi); - request_ccb = scan_info->request_ccb; - free(scan_info, M_CAMXPT); - request_ccb->ccb_h.status = status; - xpt_done(request_ccb); - break; - } - xpt_setup_ccb(&request_ccb->ccb_h, path, - request_ccb->ccb_h.pinfo.priority); - request_ccb->ccb_h.func_code = XPT_SCAN_LUN; - request_ccb->ccb_h.cbfcnp = xpt_scan_bus; - request_ccb->ccb_h.ppriv_ptr0 = scan_info; - request_ccb->crcn.flags = - scan_info->request_ccb->crcn.flags; - } else { - status = xpt_create_path(&path, xpt_periph, - path_id, target_id, lun_id); - if (status != CAM_REQ_CMP) { - printf("xpt_scan_bus: xpt_create_path failed " - "with status %#x, halting LUN scan\n", - status); - goto hop_again; - } - xpt_setup_ccb(&request_ccb->ccb_h, path, - request_ccb->ccb_h.pinfo.priority); - request_ccb->ccb_h.func_code = XPT_SCAN_LUN; - request_ccb->ccb_h.cbfcnp = xpt_scan_bus; - request_ccb->ccb_h.ppriv_ptr0 = scan_info; - request_ccb->crcn.flags = - scan_info->request_ccb->crcn.flags; - } - xpt_action(request_ccb); - break; - } - default: - break; - } -} - -typedef enum { - PROBE_TUR, - PROBE_INQUIRY, /* this counts as DV0 for Basic Domain Validation */ - PROBE_FULL_INQUIRY, - PROBE_MODE_SENSE, - PROBE_SERIAL_NUM_0, - PROBE_SERIAL_NUM_1, - PROBE_TUR_FOR_NEGOTIATION, - PROBE_INQUIRY_BASIC_DV1, - PROBE_INQUIRY_BASIC_DV2, - PROBE_DV_EXIT, - PROBE_INVALID -} probe_action; - -static char *probe_action_text[] = { - "PROBE_TUR", - "PROBE_INQUIRY", - "PROBE_FULL_INQUIRY", - "PROBE_MODE_SENSE", - "PROBE_SERIAL_NUM_0", - "PROBE_SERIAL_NUM_1", - "PROBE_TUR_FOR_NEGOTIATION", - "PROBE_INQUIRY_BASIC_DV1", - "PROBE_INQUIRY_BASIC_DV2", - "PROBE_DV_EXIT", - "PROBE_INVALID" -}; - -#define PROBE_SET_ACTION(softc, newaction) \ -do { \ - char **text; \ - text = probe_action_text; \ - CAM_DEBUG((softc)->periph->path, CAM_DEBUG_INFO, \ - ("Probe %s to %s\n", text[(softc)->action], \ - text[(newaction)])); \ - (softc)->action = (newaction); \ -} while(0) - -typedef enum { - PROBE_INQUIRY_CKSUM = 0x01, - PROBE_SERIAL_CKSUM = 0x02, - PROBE_NO_ANNOUNCE = 0x04 -} probe_flags; - -typedef struct { - TAILQ_HEAD(, ccb_hdr) request_ccbs; - probe_action action; - union ccb saved_ccb; - probe_flags flags; - MD5_CTX context; - u_int8_t digest[16]; - struct cam_periph *periph; -} probe_softc; - -static void -xpt_scan_lun(struct cam_periph *periph, struct cam_path *path, - cam_flags flags, union ccb *request_ccb) -{ - struct ccb_pathinq cpi; - cam_status status; - struct cam_path *new_path; - struct cam_periph *old_periph; - - CAM_DEBUG(request_ccb->ccb_h.path, CAM_DEBUG_TRACE, - ("xpt_scan_lun\n")); - - xpt_setup_ccb(&cpi.ccb_h, path, /*priority*/1); - cpi.ccb_h.func_code = XPT_PATH_INQ; - xpt_action((union ccb *)&cpi); - - if (cpi.ccb_h.status != CAM_REQ_CMP) { - if (request_ccb != NULL) { - request_ccb->ccb_h.status = cpi.ccb_h.status; - xpt_done(request_ccb); - } - return; - } - - if ((cpi.hba_misc & PIM_NOINITIATOR) != 0) { - /* - * Can't scan the bus on an adapter that - * cannot perform the initiator role. - */ - if (request_ccb != NULL) { - request_ccb->ccb_h.status = CAM_REQ_CMP; - xpt_done(request_ccb); - } - return; - } - - if (request_ccb == NULL) { - request_ccb = malloc(sizeof(union ccb), M_CAMXPT, M_NOWAIT); - if (request_ccb == NULL) { - xpt_print(path, "xpt_scan_lun: can't allocate CCB, " - "can't continue\n"); - return; - } - new_path = malloc(sizeof(*new_path), M_CAMXPT, M_NOWAIT); - if (new_path == NULL) { - xpt_print(path, "xpt_scan_lun: can't allocate path, " - "can't continue\n"); - free(request_ccb, M_CAMXPT); - return; - } - status = xpt_compile_path(new_path, xpt_periph, - path->bus->path_id, - path->target->target_id, - path->device->lun_id); - - if (status != CAM_REQ_CMP) { - xpt_print(path, "xpt_scan_lun: can't compile path, " - "can't continue\n"); - free(request_ccb, M_CAMXPT); - free(new_path, M_CAMXPT); - return; - } - xpt_setup_ccb(&request_ccb->ccb_h, new_path, /*priority*/ 1); - request_ccb->ccb_h.cbfcnp = xptscandone; - request_ccb->ccb_h.func_code = XPT_SCAN_LUN; - request_ccb->crcn.flags = flags; - } - - if ((old_periph = cam_periph_find(path, "probe")) != NULL) { - probe_softc *softc; - - softc = (probe_softc *)old_periph->softc; - TAILQ_INSERT_TAIL(&softc->request_ccbs, &request_ccb->ccb_h, - periph_links.tqe); - } else { - status = cam_periph_alloc(proberegister, NULL, probecleanup, - probestart, "probe", - CAM_PERIPH_BIO, - request_ccb->ccb_h.path, NULL, 0, - request_ccb); - - if (status != CAM_REQ_CMP) { - xpt_print(path, "xpt_scan_lun: cam_alloc_periph " - "returned an error, can't continue probe\n"); - request_ccb->ccb_h.status = status; - xpt_done(request_ccb); - } - } -} - -static void -xptscandone(struct cam_periph *periph, union ccb *done_ccb) -{ - xpt_release_path(done_ccb->ccb_h.path); - free(done_ccb->ccb_h.path, M_CAMXPT); - free(done_ccb, M_CAMXPT); -} - -static cam_status -proberegister(struct cam_periph *periph, void *arg) -{ - union ccb *request_ccb; /* CCB representing the probe request */ - cam_status status; - probe_softc *softc; - - request_ccb = (union ccb *)arg; - if (periph == NULL) { - printf("proberegister: periph was NULL!!\n"); - return(CAM_REQ_CMP_ERR); - } - - if (request_ccb == NULL) { - printf("proberegister: no probe CCB, " - "can't register device\n"); - return(CAM_REQ_CMP_ERR); - } - - softc = (probe_softc *)malloc(sizeof(*softc), M_CAMXPT, M_NOWAIT); - - if (softc == NULL) { - printf("proberegister: Unable to probe new device. " - "Unable to allocate softc\n"); - return(CAM_REQ_CMP_ERR); - } - TAILQ_INIT(&softc->request_ccbs); - TAILQ_INSERT_TAIL(&softc->request_ccbs, &request_ccb->ccb_h, - periph_links.tqe); - softc->flags = 0; - periph->softc = softc; - softc->periph = periph; - softc->action = PROBE_INVALID; - status = cam_periph_acquire(periph); - if (status != CAM_REQ_CMP) { - return (status); - } - - - /* - * Ensure we've waited at least a bus settle - * delay before attempting to probe the device. - * For HBAs that don't do bus resets, this won't make a difference. - */ - cam_periph_freeze_after_event(periph, &periph->path->bus->last_reset, - scsi_delay); - probeschedule(periph); - return(CAM_REQ_CMP); -} - -static void -probeschedule(struct cam_periph *periph) -{ - struct ccb_pathinq cpi; - union ccb *ccb; - probe_softc *softc; - - softc = (probe_softc *)periph->softc; - ccb = (union ccb *)TAILQ_FIRST(&softc->request_ccbs); - - xpt_setup_ccb(&cpi.ccb_h, periph->path, /*priority*/1); - cpi.ccb_h.func_code = XPT_PATH_INQ; - xpt_action((union ccb *)&cpi); - - /* - * If a device has gone away and another device, or the same one, - * is back in the same place, it should have a unit attention - * condition pending. It will not report the unit attention in - * response to an inquiry, which may leave invalid transfer - * negotiations in effect. The TUR will reveal the unit attention - * condition. Only send the TUR for lun 0, since some devices - * will get confused by commands other than inquiry to non-existent - * luns. If you think a device has gone away start your scan from - * lun 0. This will insure that any bogus transfer settings are - * invalidated. - * - * If we haven't seen the device before and the controller supports - * some kind of transfer negotiation, negotiate with the first - * sent command if no bus reset was performed at startup. This - * ensures that the device is not confused by transfer negotiation - * settings left over by loader or BIOS action. - */ - if (((ccb->ccb_h.path->device->flags & CAM_DEV_UNCONFIGURED) == 0) - && (ccb->ccb_h.target_lun == 0)) { - PROBE_SET_ACTION(softc, PROBE_TUR); - } else if ((cpi.hba_inquiry & (PI_WIDE_32|PI_WIDE_16|PI_SDTR_ABLE)) != 0 - && (cpi.hba_misc & PIM_NOBUSRESET) != 0) { - proberequestdefaultnegotiation(periph); - PROBE_SET_ACTION(softc, PROBE_INQUIRY); - } else { - PROBE_SET_ACTION(softc, PROBE_INQUIRY); - } - - if (ccb->crcn.flags & CAM_EXPECT_INQ_CHANGE) - softc->flags |= PROBE_NO_ANNOUNCE; - else - softc->flags &= ~PROBE_NO_ANNOUNCE; - - xpt_schedule(periph, ccb->ccb_h.pinfo.priority); -} - -static void -probestart(struct cam_periph *periph, union ccb *start_ccb) -{ - /* Probe the device that our peripheral driver points to */ - struct ccb_scsiio *csio; - probe_softc *softc; - - CAM_DEBUG(start_ccb->ccb_h.path, CAM_DEBUG_TRACE, ("probestart\n")); - - softc = (probe_softc *)periph->softc; - csio = &start_ccb->csio; - - switch (softc->action) { - case PROBE_TUR: - case PROBE_TUR_FOR_NEGOTIATION: - case PROBE_DV_EXIT: - { - scsi_test_unit_ready(csio, - /*retries*/10, - probedone, - MSG_SIMPLE_Q_TAG, - SSD_FULL_SIZE, - /*timeout*/60000); - break; - } - case PROBE_INQUIRY: - case PROBE_FULL_INQUIRY: - case PROBE_INQUIRY_BASIC_DV1: - case PROBE_INQUIRY_BASIC_DV2: - { - u_int inquiry_len; - struct scsi_inquiry_data *inq_buf; - - inq_buf = &periph->path->device->inq_data; - - /* - * If the device is currently configured, we calculate an - * MD5 checksum of the inquiry data, and if the serial number - * length is greater than 0, add the serial number data - * into the checksum as well. Once the inquiry and the - * serial number check finish, we attempt to figure out - * whether we still have the same device. - */ - if ((periph->path->device->flags & CAM_DEV_UNCONFIGURED) == 0) { - - MD5Init(&softc->context); - MD5Update(&softc->context, (unsigned char *)inq_buf, - sizeof(struct scsi_inquiry_data)); - softc->flags |= PROBE_INQUIRY_CKSUM; - if (periph->path->device->serial_num_len > 0) { - MD5Update(&softc->context, - periph->path->device->serial_num, - periph->path->device->serial_num_len); - softc->flags |= PROBE_SERIAL_CKSUM; - } - MD5Final(softc->digest, &softc->context); - } - - if (softc->action == PROBE_INQUIRY) - inquiry_len = SHORT_INQUIRY_LENGTH; - else - inquiry_len = SID_ADDITIONAL_LENGTH(inq_buf); - - /* - * Some parallel SCSI devices fail to send an - * ignore wide residue message when dealing with - * odd length inquiry requests. Round up to be - * safe. - */ - inquiry_len = roundup2(inquiry_len, 2); - - if (softc->action == PROBE_INQUIRY_BASIC_DV1 - || softc->action == PROBE_INQUIRY_BASIC_DV2) { - inq_buf = malloc(inquiry_len, M_CAMXPT, M_NOWAIT); - } - if (inq_buf == NULL) { - xpt_print(periph->path, "malloc failure- skipping Basic" - "Domain Validation\n"); - PROBE_SET_ACTION(softc, PROBE_DV_EXIT); - scsi_test_unit_ready(csio, - /*retries*/4, - probedone, - MSG_SIMPLE_Q_TAG, - SSD_FULL_SIZE, - /*timeout*/60000); - break; - } - scsi_inquiry(csio, - /*retries*/4, - probedone, - MSG_SIMPLE_Q_TAG, - (u_int8_t *)inq_buf, - inquiry_len, - /*evpd*/FALSE, - /*page_code*/0, - SSD_MIN_SIZE, - /*timeout*/60 * 1000); - break; - } - case PROBE_MODE_SENSE: - { - void *mode_buf; - int mode_buf_len; - - mode_buf_len = sizeof(struct scsi_mode_header_6) - + sizeof(struct scsi_mode_blk_desc) - + sizeof(struct scsi_control_page); - mode_buf = malloc(mode_buf_len, M_CAMXPT, M_NOWAIT); - if (mode_buf != NULL) { - scsi_mode_sense(csio, - /*retries*/4, - probedone, - MSG_SIMPLE_Q_TAG, - /*dbd*/FALSE, - SMS_PAGE_CTRL_CURRENT, - SMS_CONTROL_MODE_PAGE, - mode_buf, - mode_buf_len, - SSD_FULL_SIZE, - /*timeout*/60000); - break; - } - xpt_print(periph->path, "Unable to mode sense control page - " - "malloc failure\n"); - PROBE_SET_ACTION(softc, PROBE_SERIAL_NUM_0); - } - /* FALLTHROUGH */ - case PROBE_SERIAL_NUM_0: - { - struct scsi_vpd_supported_page_list *vpd_list = NULL; - struct cam_ed *device; - - device = periph->path->device; - if ((device->quirk->quirks & CAM_QUIRK_NOSERIAL) == 0) { - vpd_list = malloc(sizeof(*vpd_list), M_CAMXPT, - M_NOWAIT | M_ZERO); - } - - if (vpd_list != NULL) { - scsi_inquiry(csio, - /*retries*/4, - probedone, - MSG_SIMPLE_Q_TAG, - (u_int8_t *)vpd_list, - sizeof(*vpd_list), - /*evpd*/TRUE, - SVPD_SUPPORTED_PAGE_LIST, - SSD_MIN_SIZE, - /*timeout*/60 * 1000); - break; - } - /* - * We'll have to do without, let our probedone - * routine finish up for us. - */ - start_ccb->csio.data_ptr = NULL; - probedone(periph, start_ccb); - return; - } - case PROBE_SERIAL_NUM_1: - { - struct scsi_vpd_unit_serial_number *serial_buf; - struct cam_ed* device; - - serial_buf = NULL; - device = periph->path->device; - device->serial_num = NULL; - device->serial_num_len = 0; - - serial_buf = (struct scsi_vpd_unit_serial_number *) - malloc(sizeof(*serial_buf), M_CAMXPT, M_NOWAIT|M_ZERO); - - if (serial_buf != NULL) { - scsi_inquiry(csio, - /*retries*/4, - probedone, - MSG_SIMPLE_Q_TAG, - (u_int8_t *)serial_buf, - sizeof(*serial_buf), - /*evpd*/TRUE, - SVPD_UNIT_SERIAL_NUMBER, - SSD_MIN_SIZE, - /*timeout*/60 * 1000); - break; - } - /* - * We'll have to do without, let our probedone - * routine finish up for us. - */ - start_ccb->csio.data_ptr = NULL; - probedone(periph, start_ccb); - return; - } - case PROBE_INVALID: - CAM_DEBUG(start_ccb->ccb_h.path, CAM_DEBUG_INFO, - ("probestart: invalid action state\n")); - default: - break; - } - xpt_action(start_ccb); -} - -static void -proberequestdefaultnegotiation(struct cam_periph *periph) -{ - struct ccb_trans_settings cts; - - xpt_setup_ccb(&cts.ccb_h, periph->path, /*priority*/1); - cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS; - cts.type = CTS_TYPE_USER_SETTINGS; - xpt_action((union ccb *)&cts); - if ((cts.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { - return; - } - cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS; - cts.type = CTS_TYPE_CURRENT_SETTINGS; - xpt_action((union ccb *)&cts); -} - -/* - * Backoff Negotiation Code- only pertinent for SPI devices. - */ -static int -proberequestbackoff(struct cam_periph *periph, struct cam_ed *device) -{ - struct ccb_trans_settings cts; - struct ccb_trans_settings_spi *spi; - - memset(&cts, 0, sizeof (cts)); - xpt_setup_ccb(&cts.ccb_h, periph->path, /*priority*/1); - cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS; - cts.type = CTS_TYPE_CURRENT_SETTINGS; - xpt_action((union ccb *)&cts); - if ((cts.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { - if (bootverbose) { - xpt_print(periph->path, - "failed to get current device settings\n"); - } - return (0); - } - if (cts.transport != XPORT_SPI) { - if (bootverbose) { - xpt_print(periph->path, "not SPI transport\n"); - } - return (0); - } - spi = &cts.xport_specific.spi; - - /* - * We cannot renegotiate sync rate if we don't have one. - */ - if ((spi->valid & CTS_SPI_VALID_SYNC_RATE) == 0) { - if (bootverbose) { - xpt_print(periph->path, "no sync rate known\n"); - } - return (0); - } - - /* - * We'll assert that we don't have to touch PPR options- the - * SIM will see what we do with period and offset and adjust - * the PPR options as appropriate. - */ - - /* - * A sync rate with unknown or zero offset is nonsensical. - * A sync period of zero means Async. - */ - if ((spi->valid & CTS_SPI_VALID_SYNC_OFFSET) == 0 - || spi->sync_offset == 0 || spi->sync_period == 0) { - if (bootverbose) { - xpt_print(periph->path, "no sync rate available\n"); - } - return (0); - } - - if (device->flags & CAM_DEV_DV_HIT_BOTTOM) { - CAM_DEBUG(periph->path, CAM_DEBUG_INFO, - ("hit async: giving up on DV\n")); - return (0); - } - - - /* - * Jump sync_period up by one, but stop at 5MHz and fall back to Async. - * We don't try to remember 'last' settings to see if the SIM actually - * gets into the speed we want to set. We check on the SIM telling - * us that a requested speed is bad, but otherwise don't try and - * check the speed due to the asynchronous and handshake nature - * of speed setting. - */ - spi->valid = CTS_SPI_VALID_SYNC_RATE | CTS_SPI_VALID_SYNC_OFFSET; - for (;;) { - spi->sync_period++; - if (spi->sync_period >= 0xf) { - spi->sync_period = 0; - spi->sync_offset = 0; - CAM_DEBUG(periph->path, CAM_DEBUG_INFO, - ("setting to async for DV\n")); - /* - * Once we hit async, we don't want to try - * any more settings. - */ - device->flags |= CAM_DEV_DV_HIT_BOTTOM; - } else if (bootverbose) { - CAM_DEBUG(periph->path, CAM_DEBUG_INFO, - ("DV: period 0x%x\n", spi->sync_period)); - printf("setting period to 0x%x\n", spi->sync_period); - } - cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS; - cts.type = CTS_TYPE_CURRENT_SETTINGS; - xpt_action((union ccb *)&cts); - if ((cts.ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) { - break; - } - CAM_DEBUG(periph->path, CAM_DEBUG_INFO, - ("DV: failed to set period 0x%x\n", spi->sync_period)); - if (spi->sync_period == 0) { - return (0); - } - } - return (1); -} - -static void -probedone(struct cam_periph *periph, union ccb *done_ccb) -{ - probe_softc *softc; - struct cam_path *path; - u_int32_t priority; - - CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_TRACE, ("probedone\n")); - - softc = (probe_softc *)periph->softc; - path = done_ccb->ccb_h.path; - priority = done_ccb->ccb_h.pinfo.priority; - - switch (softc->action) { - case PROBE_TUR: - { - if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { - - if (cam_periph_error(done_ccb, 0, - SF_NO_PRINT, NULL) == ERESTART) - return; - else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) - /* Don't wedge the queue */ - xpt_release_devq(done_ccb->ccb_h.path, - /*count*/1, - /*run_queue*/TRUE); - } - PROBE_SET_ACTION(softc, PROBE_INQUIRY); - xpt_release_ccb(done_ccb); - xpt_schedule(periph, priority); - return; - } - case PROBE_INQUIRY: - case PROBE_FULL_INQUIRY: - { - if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) { - struct scsi_inquiry_data *inq_buf; - u_int8_t periph_qual; - - path->device->flags |= CAM_DEV_INQUIRY_DATA_VALID; - inq_buf = &path->device->inq_data; - - periph_qual = SID_QUAL(inq_buf); - - switch(periph_qual) { - case SID_QUAL_LU_CONNECTED: - { - u_int8_t len; - - /* - * We conservatively request only - * SHORT_INQUIRY_LEN bytes of inquiry - * information during our first try - * at sending an INQUIRY. If the device - * has more information to give, - * perform a second request specifying - * the amount of information the device - * is willing to give. - */ - len = inq_buf->additional_length - + offsetof(struct scsi_inquiry_data, - additional_length) + 1; - if (softc->action == PROBE_INQUIRY - && len > SHORT_INQUIRY_LENGTH) { - PROBE_SET_ACTION(softc, PROBE_FULL_INQUIRY); - xpt_release_ccb(done_ccb); - xpt_schedule(periph, priority); - return; - } - - xpt_find_quirk(path->device); - - xpt_devise_transport(path); - if (INQ_DATA_TQ_ENABLED(inq_buf)) - PROBE_SET_ACTION(softc, PROBE_MODE_SENSE); - else - PROBE_SET_ACTION(softc, PROBE_SERIAL_NUM_0); - - path->device->flags &= ~CAM_DEV_UNCONFIGURED; - - xpt_release_ccb(done_ccb); - xpt_schedule(periph, priority); - return; - } - default: - break; - } - } else if (cam_periph_error(done_ccb, 0, - done_ccb->ccb_h.target_lun > 0 - ? SF_RETRY_UA|SF_QUIET_IR - : SF_RETRY_UA, - &softc->saved_ccb) == ERESTART) { - return; - } else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) { - /* Don't wedge the queue */ - xpt_release_devq(done_ccb->ccb_h.path, /*count*/1, - /*run_queue*/TRUE); - } - /* - * If we get to this point, we got an error status back - * from the inquiry and the error status doesn't require - * automatically retrying the command. Therefore, the - * inquiry failed. If we had inquiry information before - * for this device, but this latest inquiry command failed, - * the device has probably gone away. If this device isn't - * already marked unconfigured, notify the peripheral - * drivers that this device is no more. - */ - if ((path->device->flags & CAM_DEV_UNCONFIGURED) == 0) - /* Send the async notification. */ - xpt_async(AC_LOST_DEVICE, path, NULL); - - xpt_release_ccb(done_ccb); - break; - } - case PROBE_MODE_SENSE: - { - struct ccb_scsiio *csio; - struct scsi_mode_header_6 *mode_hdr; - - csio = &done_ccb->csio; - mode_hdr = (struct scsi_mode_header_6 *)csio->data_ptr; - if ((csio->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) { - struct scsi_control_page *page; - u_int8_t *offset; - - offset = ((u_int8_t *)&mode_hdr[1]) - + mode_hdr->blk_desc_len; - page = (struct scsi_control_page *)offset; - path->device->queue_flags = page->queue_flags; - } else if (cam_periph_error(done_ccb, 0, - SF_RETRY_UA|SF_NO_PRINT, - &softc->saved_ccb) == ERESTART) { - return; - } else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) { - /* Don't wedge the queue */ - xpt_release_devq(done_ccb->ccb_h.path, - /*count*/1, /*run_queue*/TRUE); - } - xpt_release_ccb(done_ccb); - free(mode_hdr, M_CAMXPT); - PROBE_SET_ACTION(softc, PROBE_SERIAL_NUM_0); - xpt_schedule(periph, priority); - return; - } - case PROBE_SERIAL_NUM_0: - { - struct ccb_scsiio *csio; - struct scsi_vpd_supported_page_list *page_list; - int length, serialnum_supported, i; - - serialnum_supported = 0; - csio = &done_ccb->csio; - page_list = - (struct scsi_vpd_supported_page_list *)csio->data_ptr; - - if (page_list == NULL) { - /* - * Don't process the command as it was never sent - */ - } else if ((csio->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP - && (page_list->length > 0)) { - length = min(page_list->length, - SVPD_SUPPORTED_PAGES_SIZE); - for (i = 0; i < length; i++) { - if (page_list->list[i] == - SVPD_UNIT_SERIAL_NUMBER) { - serialnum_supported = 1; - break; - } - } - } else if (cam_periph_error(done_ccb, 0, - SF_RETRY_UA|SF_NO_PRINT, - &softc->saved_ccb) == ERESTART) { - return; - } else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) { - /* Don't wedge the queue */ - xpt_release_devq(done_ccb->ccb_h.path, /*count*/1, - /*run_queue*/TRUE); - } - - if (page_list != NULL) - free(page_list, M_DEVBUF); - - if (serialnum_supported) { - xpt_release_ccb(done_ccb); - PROBE_SET_ACTION(softc, PROBE_SERIAL_NUM_1); - xpt_schedule(periph, priority); - return; - } - - csio->data_ptr = NULL; - /* FALLTHROUGH */ - } - - case PROBE_SERIAL_NUM_1: - { - struct ccb_scsiio *csio; - struct scsi_vpd_unit_serial_number *serial_buf; - u_int32_t priority; - int changed; - int have_serialnum; - - changed = 1; - have_serialnum = 0; - csio = &done_ccb->csio; - priority = done_ccb->ccb_h.pinfo.priority; - serial_buf = - (struct scsi_vpd_unit_serial_number *)csio->data_ptr; - - /* Clean up from previous instance of this device */ - if (path->device->serial_num != NULL) { - free(path->device->serial_num, M_CAMXPT); - path->device->serial_num = NULL; - path->device->serial_num_len = 0; - } - - if (serial_buf == NULL) { - /* - * Don't process the command as it was never sent - */ - } else if ((csio->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP - && (serial_buf->length > 0)) { - - have_serialnum = 1; - path->device->serial_num = - (u_int8_t *)malloc((serial_buf->length + 1), - M_CAMXPT, M_NOWAIT); - if (path->device->serial_num != NULL) { - bcopy(serial_buf->serial_num, - path->device->serial_num, - serial_buf->length); - path->device->serial_num_len = - serial_buf->length; - path->device->serial_num[serial_buf->length] - = '\0'; - } - } else if (cam_periph_error(done_ccb, 0, - SF_RETRY_UA|SF_NO_PRINT, - &softc->saved_ccb) == ERESTART) { - return; - } else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) { - /* Don't wedge the queue */ - xpt_release_devq(done_ccb->ccb_h.path, /*count*/1, - /*run_queue*/TRUE); - } - - /* - * Let's see if we have seen this device before. - */ - if ((softc->flags & PROBE_INQUIRY_CKSUM) != 0) { - MD5_CTX context; - u_int8_t digest[16]; - - MD5Init(&context); - - MD5Update(&context, - (unsigned char *)&path->device->inq_data, - sizeof(struct scsi_inquiry_data)); - - if (have_serialnum) - MD5Update(&context, serial_buf->serial_num, - serial_buf->length); - - MD5Final(digest, &context); - if (bcmp(softc->digest, digest, 16) == 0) - changed = 0; - - /* - * XXX Do we need to do a TUR in order to ensure - * that the device really hasn't changed??? - */ - if ((changed != 0) - && ((softc->flags & PROBE_NO_ANNOUNCE) == 0)) - xpt_async(AC_LOST_DEVICE, path, NULL); - } - if (serial_buf != NULL) - free(serial_buf, M_CAMXPT); - - if (changed != 0) { - /* - * Now that we have all the necessary - * information to safely perform transfer - * negotiations... Controllers don't perform - * any negotiation or tagged queuing until - * after the first XPT_SET_TRAN_SETTINGS ccb is - * received. So, on a new device, just retrieve - * the user settings, and set them as the current - * settings to set the device up. - */ - proberequestdefaultnegotiation(periph); - xpt_release_ccb(done_ccb); - - /* - * Perform a TUR to allow the controller to - * perform any necessary transfer negotiation. - */ - PROBE_SET_ACTION(softc, PROBE_TUR_FOR_NEGOTIATION); - xpt_schedule(periph, priority); - return; - } - xpt_release_ccb(done_ccb); - break; - } - case PROBE_TUR_FOR_NEGOTIATION: - if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { - DELAY(500000); - if (cam_periph_error(done_ccb, 0, SF_RETRY_UA, - NULL) == ERESTART) - return; - } - /* FALLTHROUGH */ - case PROBE_DV_EXIT: - if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) { - /* Don't wedge the queue */ - xpt_release_devq(done_ccb->ccb_h.path, /*count*/1, - /*run_queue*/TRUE); - } - /* - * Do Domain Validation for lun 0 on devices that claim - * to support Synchronous Transfer modes. - */ - if (softc->action == PROBE_TUR_FOR_NEGOTIATION - && done_ccb->ccb_h.target_lun == 0 - && (path->device->inq_data.flags & SID_Sync) != 0 - && (path->device->flags & CAM_DEV_IN_DV) == 0) { - CAM_DEBUG(periph->path, CAM_DEBUG_INFO, - ("Begin Domain Validation\n")); - path->device->flags |= CAM_DEV_IN_DV; - xpt_release_ccb(done_ccb); - PROBE_SET_ACTION(softc, PROBE_INQUIRY_BASIC_DV1); - xpt_schedule(periph, priority); - return; - } - if (softc->action == PROBE_DV_EXIT) { - CAM_DEBUG(periph->path, CAM_DEBUG_INFO, - ("Leave Domain Validation\n")); - } - path->device->flags &= - ~(CAM_DEV_UNCONFIGURED|CAM_DEV_IN_DV|CAM_DEV_DV_HIT_BOTTOM); - if ((softc->flags & PROBE_NO_ANNOUNCE) == 0) { - /* Inform the XPT that a new device has been found */ - done_ccb->ccb_h.func_code = XPT_GDEV_TYPE; - xpt_action(done_ccb); - xpt_async(AC_FOUND_DEVICE, done_ccb->ccb_h.path, - done_ccb); - } - xpt_release_ccb(done_ccb); - break; - case PROBE_INQUIRY_BASIC_DV1: - case PROBE_INQUIRY_BASIC_DV2: - { - struct scsi_inquiry_data *nbuf; - struct ccb_scsiio *csio; - - if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) { - /* Don't wedge the queue */ - xpt_release_devq(done_ccb->ccb_h.path, /*count*/1, - /*run_queue*/TRUE); - } - csio = &done_ccb->csio; - nbuf = (struct scsi_inquiry_data *)csio->data_ptr; - if (bcmp(nbuf, &path->device->inq_data, SHORT_INQUIRY_LENGTH)) { - xpt_print(path, - "inquiry data fails comparison at DV%d step\n", - softc->action == PROBE_INQUIRY_BASIC_DV1 ? 1 : 2); - if (proberequestbackoff(periph, path->device)) { - path->device->flags &= ~CAM_DEV_IN_DV; - PROBE_SET_ACTION(softc, PROBE_TUR_FOR_NEGOTIATION); - } else { - /* give up */ - PROBE_SET_ACTION(softc, PROBE_DV_EXIT); - } - free(nbuf, M_CAMXPT); - xpt_release_ccb(done_ccb); - xpt_schedule(periph, priority); - return; - } - free(nbuf, M_CAMXPT); - if (softc->action == PROBE_INQUIRY_BASIC_DV1) { - PROBE_SET_ACTION(softc, PROBE_INQUIRY_BASIC_DV2); - xpt_release_ccb(done_ccb); - xpt_schedule(periph, priority); - return; - } - if (softc->action == PROBE_INQUIRY_BASIC_DV2) { - CAM_DEBUG(periph->path, CAM_DEBUG_INFO, - ("Leave Domain Validation Successfully\n")); - } - path->device->flags &= - ~(CAM_DEV_UNCONFIGURED|CAM_DEV_IN_DV|CAM_DEV_DV_HIT_BOTTOM); - if ((softc->flags & PROBE_NO_ANNOUNCE) == 0) { - /* Inform the XPT that a new device has been found */ - done_ccb->ccb_h.func_code = XPT_GDEV_TYPE; - xpt_action(done_ccb); - xpt_async(AC_FOUND_DEVICE, done_ccb->ccb_h.path, - done_ccb); - } - xpt_release_ccb(done_ccb); - break; - } - case PROBE_INVALID: - CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_INFO, - ("probedone: invalid action state\n")); - default: - break; - } - done_ccb = (union ccb *)TAILQ_FIRST(&softc->request_ccbs); - TAILQ_REMOVE(&softc->request_ccbs, &done_ccb->ccb_h, periph_links.tqe); - done_ccb->ccb_h.status = CAM_REQ_CMP; - xpt_done(done_ccb); - if (TAILQ_FIRST(&softc->request_ccbs) == NULL) { - cam_periph_invalidate(periph); - cam_periph_release_locked(periph); - } else { - probeschedule(periph); - } -} - -static void -probecleanup(struct cam_periph *periph) -{ - free(periph->softc, M_CAMXPT); -} - -static void -xpt_find_quirk(struct cam_ed *device) -{ - caddr_t match; - - match = cam_quirkmatch((caddr_t)&device->inq_data, - (caddr_t)xpt_quirk_table, - sizeof(xpt_quirk_table)/sizeof(*xpt_quirk_table), - sizeof(*xpt_quirk_table), scsi_inquiry_match); - - if (match == NULL) - panic("xpt_find_quirk: device didn't match wildcard entry!!"); - - device->quirk = (struct xpt_quirk_entry *)match; -} - -static int -sysctl_cam_search_luns(SYSCTL_HANDLER_ARGS) -{ - int error, bool; - - bool = cam_srch_hi; - error = sysctl_handle_int(oidp, &bool, 0, req); - if (error != 0 || req->newptr == NULL) - return (error); - if (bool == 0 || bool == 1) { - cam_srch_hi = bool; - return (0); - } else { - return (EINVAL); - } -} - - -static void -xpt_devise_transport(struct cam_path *path) -{ - struct ccb_pathinq cpi; - struct ccb_trans_settings cts; - struct scsi_inquiry_data *inq_buf; - - /* Get transport information from the SIM */ - xpt_setup_ccb(&cpi.ccb_h, path, /*priority*/1); - cpi.ccb_h.func_code = XPT_PATH_INQ; - xpt_action((union ccb *)&cpi); - - inq_buf = NULL; - if ((path->device->flags & CAM_DEV_INQUIRY_DATA_VALID) != 0) - inq_buf = &path->device->inq_data; - path->device->protocol = PROTO_SCSI; - path->device->protocol_version = - inq_buf != NULL ? SID_ANSI_REV(inq_buf) : cpi.protocol_version; - path->device->transport = cpi.transport; - path->device->transport_version = cpi.transport_version; - - /* - * Any device not using SPI3 features should - * be considered SPI2 or lower. - */ - if (inq_buf != NULL) { - if (path->device->transport == XPORT_SPI - && (inq_buf->spi3data & SID_SPI_MASK) == 0 - && path->device->transport_version > 2) - path->device->transport_version = 2; - } else { - struct cam_ed* otherdev; - - for (otherdev = TAILQ_FIRST(&path->target->ed_entries); - otherdev != NULL; - otherdev = TAILQ_NEXT(otherdev, links)) { - if (otherdev != path->device) - break; - } - - if (otherdev != NULL) { - /* - * Initially assume the same versioning as - * prior luns for this target. - */ - path->device->protocol_version = - otherdev->protocol_version; - path->device->transport_version = - otherdev->transport_version; - } else { - /* Until we know better, opt for safty */ - path->device->protocol_version = 2; - if (path->device->transport == XPORT_SPI) - path->device->transport_version = 2; - else - path->device->transport_version = 0; - } - } - - /* - * XXX - * For a device compliant with SPC-2 we should be able - * to determine the transport version supported by - * scrutinizing the version descriptors in the - * inquiry buffer. - */ - - /* Tell the controller what we think */ - xpt_setup_ccb(&cts.ccb_h, path, /*priority*/1); - cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS; - cts.type = CTS_TYPE_CURRENT_SETTINGS; - cts.transport = path->device->transport; - cts.transport_version = path->device->transport_version; - cts.protocol = path->device->protocol; - cts.protocol_version = path->device->protocol_version; - cts.proto_specific.valid = 0; - cts.xport_specific.valid = 0; - xpt_action((union ccb *)&cts); -} - -static void -xpt_set_transfer_settings(struct ccb_trans_settings *cts, struct cam_ed *device, - int async_update) -{ - struct ccb_pathinq cpi; - struct ccb_trans_settings cur_cts; - struct ccb_trans_settings_scsi *scsi; - struct ccb_trans_settings_scsi *cur_scsi; - struct cam_sim *sim; - struct scsi_inquiry_data *inq_data; - - if (device == NULL) { - cts->ccb_h.status = CAM_PATH_INVALID; - xpt_done((union ccb *)cts); - return; - } - - if (cts->protocol == PROTO_UNKNOWN - || cts->protocol == PROTO_UNSPECIFIED) { - cts->protocol = device->protocol; - cts->protocol_version = device->protocol_version; - } - - if (cts->protocol_version == PROTO_VERSION_UNKNOWN - || cts->protocol_version == PROTO_VERSION_UNSPECIFIED) - cts->protocol_version = device->protocol_version; - - if (cts->protocol != device->protocol) { - xpt_print(cts->ccb_h.path, "Uninitialized Protocol %x:%x?\n", - cts->protocol, device->protocol); - cts->protocol = device->protocol; - } - - if (cts->protocol_version > device->protocol_version) { - if (bootverbose) { - xpt_print(cts->ccb_h.path, "Down reving Protocol " - "Version from %d to %d?\n", cts->protocol_version, - device->protocol_version); - } - cts->protocol_version = device->protocol_version; - } - - if (cts->transport == XPORT_UNKNOWN - || cts->transport == XPORT_UNSPECIFIED) { - cts->transport = device->transport; - cts->transport_version = device->transport_version; - } - - if (cts->transport_version == XPORT_VERSION_UNKNOWN - || cts->transport_version == XPORT_VERSION_UNSPECIFIED) - cts->transport_version = device->transport_version; - - if (cts->transport != device->transport) { - xpt_print(cts->ccb_h.path, "Uninitialized Transport %x:%x?\n", - cts->transport, device->transport); - cts->transport = device->transport; - } - - if (cts->transport_version > device->transport_version) { - if (bootverbose) { - xpt_print(cts->ccb_h.path, "Down reving Transport " - "Version from %d to %d?\n", cts->transport_version, - device->transport_version); - } - cts->transport_version = device->transport_version; - } - - sim = cts->ccb_h.path->bus->sim; - - /* - * Nothing more of interest to do unless - * this is a device connected via the - * SCSI protocol. - */ - if (cts->protocol != PROTO_SCSI) { - if (async_update == FALSE) - (*(sim->sim_action))(sim, (union ccb *)cts); - return; - } - - inq_data = &device->inq_data; - scsi = &cts->proto_specific.scsi; - xpt_setup_ccb(&cpi.ccb_h, cts->ccb_h.path, /*priority*/1); - cpi.ccb_h.func_code = XPT_PATH_INQ; - xpt_action((union ccb *)&cpi); - - /* SCSI specific sanity checking */ - if ((cpi.hba_inquiry & PI_TAG_ABLE) == 0 - || (INQ_DATA_TQ_ENABLED(inq_data)) == 0 - || (device->queue_flags & SCP_QUEUE_DQUE) != 0 - || (device->quirk->mintags == 0)) { - /* - * Can't tag on hardware that doesn't support tags, - * doesn't have it enabled, or has broken tag support. - */ - scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB; - } - - if (async_update == FALSE) { - /* - * Perform sanity checking against what the - * controller and device can do. - */ - xpt_setup_ccb(&cur_cts.ccb_h, cts->ccb_h.path, /*priority*/1); - cur_cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS; - cur_cts.type = cts->type; - xpt_action((union ccb *)&cur_cts); - if ((cur_cts.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { - return; - } - cur_scsi = &cur_cts.proto_specific.scsi; - if ((scsi->valid & CTS_SCSI_VALID_TQ) == 0) { - scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB; - scsi->flags |= cur_scsi->flags & CTS_SCSI_FLAGS_TAG_ENB; - } - if ((cur_scsi->valid & CTS_SCSI_VALID_TQ) == 0) - scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB; - } - - /* SPI specific sanity checking */ - if (cts->transport == XPORT_SPI && async_update == FALSE) { - u_int spi3caps; - struct ccb_trans_settings_spi *spi; - struct ccb_trans_settings_spi *cur_spi; - - spi = &cts->xport_specific.spi; - - cur_spi = &cur_cts.xport_specific.spi; - - /* Fill in any gaps in what the user gave us */ - if ((spi->valid & CTS_SPI_VALID_SYNC_RATE) == 0) - spi->sync_period = cur_spi->sync_period; - if ((cur_spi->valid & CTS_SPI_VALID_SYNC_RATE) == 0) - spi->sync_period = 0; - if ((spi->valid & CTS_SPI_VALID_SYNC_OFFSET) == 0) - spi->sync_offset = cur_spi->sync_offset; - if ((cur_spi->valid & CTS_SPI_VALID_SYNC_OFFSET) == 0) - spi->sync_offset = 0; - if ((spi->valid & CTS_SPI_VALID_PPR_OPTIONS) == 0) - spi->ppr_options = cur_spi->ppr_options; - if ((cur_spi->valid & CTS_SPI_VALID_PPR_OPTIONS) == 0) - spi->ppr_options = 0; - if ((spi->valid & CTS_SPI_VALID_BUS_WIDTH) == 0) - spi->bus_width = cur_spi->bus_width; - if ((cur_spi->valid & CTS_SPI_VALID_BUS_WIDTH) == 0) - spi->bus_width = 0; - if ((spi->valid & CTS_SPI_VALID_DISC) == 0) { - spi->flags &= ~CTS_SPI_FLAGS_DISC_ENB; - spi->flags |= cur_spi->flags & CTS_SPI_FLAGS_DISC_ENB; - } - if ((cur_spi->valid & CTS_SPI_VALID_DISC) == 0) - spi->flags &= ~CTS_SPI_FLAGS_DISC_ENB; - if (((device->flags & CAM_DEV_INQUIRY_DATA_VALID) != 0 - && (inq_data->flags & SID_Sync) == 0 - && cts->type == CTS_TYPE_CURRENT_SETTINGS) - || ((cpi.hba_inquiry & PI_SDTR_ABLE) == 0)) { - /* Force async */ - spi->sync_period = 0; - spi->sync_offset = 0; - } - - switch (spi->bus_width) { - case MSG_EXT_WDTR_BUS_32_BIT: - if (((device->flags & CAM_DEV_INQUIRY_DATA_VALID) == 0 - || (inq_data->flags & SID_WBus32) != 0 - || cts->type == CTS_TYPE_USER_SETTINGS) - && (cpi.hba_inquiry & PI_WIDE_32) != 0) - break; - /* Fall Through to 16-bit */ - case MSG_EXT_WDTR_BUS_16_BIT: - if (((device->flags & CAM_DEV_INQUIRY_DATA_VALID) == 0 - || (inq_data->flags & SID_WBus16) != 0 - || cts->type == CTS_TYPE_USER_SETTINGS) - && (cpi.hba_inquiry & PI_WIDE_16) != 0) { - spi->bus_width = MSG_EXT_WDTR_BUS_16_BIT; - break; - } - /* Fall Through to 8-bit */ - default: /* New bus width?? */ - case MSG_EXT_WDTR_BUS_8_BIT: - /* All targets can do this */ - spi->bus_width = MSG_EXT_WDTR_BUS_8_BIT; - break; - } - - spi3caps = cpi.xport_specific.spi.ppr_options; - if ((device->flags & CAM_DEV_INQUIRY_DATA_VALID) != 0 - && cts->type == CTS_TYPE_CURRENT_SETTINGS) - spi3caps &= inq_data->spi3data; - - if ((spi3caps & SID_SPI_CLOCK_DT) == 0) - spi->ppr_options &= ~MSG_EXT_PPR_DT_REQ; - - if ((spi3caps & SID_SPI_IUS) == 0) - spi->ppr_options &= ~MSG_EXT_PPR_IU_REQ; - - if ((spi3caps & SID_SPI_QAS) == 0) - spi->ppr_options &= ~MSG_EXT_PPR_QAS_REQ; - - /* No SPI Transfer settings are allowed unless we are wide */ - if (spi->bus_width == 0) - spi->ppr_options = 0; - - if ((spi->valid & CTS_SPI_VALID_DISC) - && ((spi->flags & CTS_SPI_FLAGS_DISC_ENB) == 0)) { - /* - * Can't tag queue without disconnection. - */ - scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB; - scsi->valid |= CTS_SCSI_VALID_TQ; - } - - /* - * If we are currently performing tagged transactions to - * this device and want to change its negotiation parameters, - * go non-tagged for a bit to give the controller a chance to - * negotiate unhampered by tag messages. - */ - if (cts->type == CTS_TYPE_CURRENT_SETTINGS - && (device->inq_flags & SID_CmdQue) != 0 - && (scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) != 0 - && (spi->flags & (CTS_SPI_VALID_SYNC_RATE| - CTS_SPI_VALID_SYNC_OFFSET| - CTS_SPI_VALID_BUS_WIDTH)) != 0) - xpt_toggle_tags(cts->ccb_h.path); - } - - if (cts->type == CTS_TYPE_CURRENT_SETTINGS - && (scsi->valid & CTS_SCSI_VALID_TQ) != 0) { - int device_tagenb; - - /* - * If we are transitioning from tags to no-tags or - * vice-versa, we need to carefully freeze and restart - * the queue so that we don't overlap tagged and non-tagged - * commands. We also temporarily stop tags if there is - * a change in transfer negotiation settings to allow - * "tag-less" negotiation. - */ - if ((device->flags & CAM_DEV_TAG_AFTER_COUNT) != 0 - || (device->inq_flags & SID_CmdQue) != 0) - device_tagenb = TRUE; - else - device_tagenb = FALSE; - - if (((scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) != 0 - && device_tagenb == FALSE) - || ((scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) == 0 - && device_tagenb == TRUE)) { - - if ((scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) != 0) { - /* - * Delay change to use tags until after a - * few commands have gone to this device so - * the controller has time to perform transfer - * negotiations without tagged messages getting - * in the way. - */ - device->tag_delay_count = CAM_TAG_DELAY_COUNT; - device->flags |= CAM_DEV_TAG_AFTER_COUNT; - } else { - struct ccb_relsim crs; - - xpt_freeze_devq(cts->ccb_h.path, /*count*/1); - device->inq_flags &= ~SID_CmdQue; - xpt_dev_ccbq_resize(cts->ccb_h.path, - sim->max_dev_openings); - device->flags &= ~CAM_DEV_TAG_AFTER_COUNT; - device->tag_delay_count = 0; - - xpt_setup_ccb(&crs.ccb_h, cts->ccb_h.path, - /*priority*/1); - crs.ccb_h.func_code = XPT_REL_SIMQ; - crs.release_flags = RELSIM_RELEASE_AFTER_QEMPTY; - crs.openings - = crs.release_timeout - = crs.qfrozen_cnt - = 0; - xpt_action((union ccb *)&crs); - } - } - } - if (async_update == FALSE) - (*(sim->sim_action))(sim, (union ccb *)cts); -} - - -static void -xpt_toggle_tags(struct cam_path *path) -{ - struct cam_ed *dev; - - /* - * Give controllers a chance to renegotiate - * before starting tag operations. We - * "toggle" tagged queuing off then on - * which causes the tag enable command delay - * counter to come into effect. - */ - dev = path->device; - if ((dev->flags & CAM_DEV_TAG_AFTER_COUNT) != 0 - || ((dev->inq_flags & SID_CmdQue) != 0 - && (dev->inq_flags & (SID_Sync|SID_WBus16|SID_WBus32)) != 0)) { - struct ccb_trans_settings cts; - - xpt_setup_ccb(&cts.ccb_h, path, 1); - cts.protocol = PROTO_SCSI; - cts.protocol_version = PROTO_VERSION_UNSPECIFIED; - cts.transport = XPORT_UNSPECIFIED; - cts.transport_version = XPORT_VERSION_UNSPECIFIED; - cts.proto_specific.scsi.flags = 0; - cts.proto_specific.scsi.valid = CTS_SCSI_VALID_TQ; - xpt_set_transfer_settings(&cts, path->device, - /*async_update*/TRUE); - cts.proto_specific.scsi.flags = CTS_SCSI_FLAGS_TAG_ENB; - xpt_set_transfer_settings(&cts, path->device, - /*async_update*/TRUE); - } -} - static void xpt_start_tags(struct cam_path *path) { @@ -6861,7 +4532,7 @@ xpt_start_tags(struct cam_path *path) if (device->tag_saved_openings != 0) newopenings = device->tag_saved_openings; else - newopenings = min(device->quirk->maxtags, + newopenings = min(device->maxtags, sim->max_tagged_dev_openings); xpt_dev_ccbq_resize(path, newopenings); xpt_setup_ccb(&crs.ccb_h, path, /*priority*/1); |