From owner-p4-projects@FreeBSD.ORG Wed Apr 8 14:13:11 2009 Return-Path: Delivered-To: p4-projects@freebsd.org Received: by hub.freebsd.org (Postfix, from userid 32767) id 066FE106566C; Wed, 8 Apr 2009 14:13:11 +0000 (UTC) Delivered-To: perforce@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id B42971065672 for ; Wed, 8 Apr 2009 14:13:10 +0000 (UTC) (envelope-from scottl@freebsd.org) Received: from repoman.freebsd.org (repoman.freebsd.org [IPv6:2001:4f8:fff6::29]) by mx1.freebsd.org (Postfix) with ESMTP id A11458FC15 for ; Wed, 8 Apr 2009 14:13:10 +0000 (UTC) (envelope-from scottl@freebsd.org) Received: from repoman.freebsd.org (localhost [127.0.0.1]) by repoman.freebsd.org (8.14.3/8.14.3) with ESMTP id n38EDA5T071704 for ; Wed, 8 Apr 2009 14:13:10 GMT (envelope-from scottl@freebsd.org) Received: (from perforce@localhost) by repoman.freebsd.org (8.14.3/8.14.3/Submit) id n38EDAbx071702 for perforce@freebsd.org; Wed, 8 Apr 2009 14:13:10 GMT (envelope-from scottl@freebsd.org) Date: Wed, 8 Apr 2009 14:13:10 GMT Message-Id: <200904081413.n38EDAbx071702@repoman.freebsd.org> X-Authentication-Warning: repoman.freebsd.org: perforce set sender to scottl@freebsd.org using -f From: Scott Long To: Perforce Change Reviews Cc: Subject: PERFORCE change 160378 for review X-BeenThere: p4-projects@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: p4 projects tree changes List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 08 Apr 2009 14:13:12 -0000 http://perforce.freebsd.org/chv.cgi?CH=160378 Change 160378 by scottl@scottl-deimos on 2009/04/08 14:13:08 Separate xpt_action into a transport-specific action, and bring some helper functions over with it. Also create a async notification vector. Affected files ... .. //depot/projects/scottl-camlock/src/sys/cam/cam_xpt.c#83 edit .. //depot/projects/scottl-camlock/src/sys/cam/cam_xpt.h#15 edit .. //depot/projects/scottl-camlock/src/sys/cam/scsi/scsi_xpt.c#9 edit Differences ... ==== //depot/projects/scottl-camlock/src/sys/cam/cam_xpt.c#83 (text+ko) ==== @@ -204,11 +204,6 @@ 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); @@ -286,10 +281,6 @@ static xpt_busfunc_t xptsetasyncbusfunc; static cam_status xptregister(struct cam_periph *periph, void *arg); -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); @@ -2415,49 +2406,17 @@ 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->xpt_action_func))(start_ccb); +} - switch (start_ccb->ccb_h.func_code) { - case XPT_SCSI_IO: - { - struct cam_ed *device; -#ifdef CAMDEBUG - char cdb_str[(SCSI_MAX_CDBLEN * 3) + 1]; - struct cam_path *path; +void +xpt_action_default(union ccb *start_ccb) +{ - path = start_ccb->ccb_h.path; -#endif + CAM_DEBUG(start_ccb->ccb_h.path, CAM_DEBUG_TRACE, ("xpt_action_default\n")); - /* - * For the sake of compatibility with SCSI-1 - * devices that may not understand the identify - * message, we include lun information in the - * second byte of all commands. SCSI-1 specifies - * that luns are a 3 bit value and reserves only 3 - * bits for lun information in the CDB. Later - * revisions of the SCSI spec allow for more than 8 - * luns, but have deprecated lun information in the - * CDB. So, if the lun won't fit, we must omit. - * - * Also be aware that during initial probing for devices, - * the inquiry information is unknown but initialized to 0. - * This means that this code will be exercised while probing - * devices with an ANSI revision greater than 2. - */ - device = start_ccb->ccb_h.path->device; - if (device->protocol_version <= SCSI_REV_2 - && start_ccb->ccb_h.target_lun < 8 - && (start_ccb->ccb_h.flags & CAM_CDB_POINTER) == 0) { - start_ccb->csio.cdb_io.cdb_bytes[1] |= - start_ccb->ccb_h.target_lun << 5; - } - start_ccb->csio.scsi_status = SCSI_STATUS_OK; - CAM_DEBUG(path, CAM_DEBUG_CDB,("%s. CDB: %s\n", - scsi_op_desc(start_ccb->csio.cdb_io.cdb_bytes[0], - &path->device->inq_data), - scsi_cdb_string(start_ccb->csio.cdb_io.cdb_bytes, - cdb_str, sizeof(cdb_str)))); - } + switch (start_ccb->ccb_h.func_code) { /* FALLTHROUGH */ case XPT_TARGET_IO: case XPT_CONT_TARGET_IO: @@ -2481,13 +2440,6 @@ 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; @@ -2573,7 +2525,6 @@ 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; @@ -2938,14 +2889,6 @@ 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 @@ -3947,8 +3890,9 @@ && device->lun_id != CAM_LUN_WILDCARD) continue; - xpt_dev_async(async_code, bus, target, - device, async_arg); + (*(bus->xport->xpt_dev_async_func))(async_code, bus, + target, device, + async_arg); xpt_async_bcast(&device->asyncs, async_code, path, async_arg); @@ -3988,70 +3932,6 @@ } } -/* - * 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) -{ - 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); - } -} - u_int32_t xpt_freeze_devq(struct cam_path *path, u_int count) { @@ -4526,326 +4406,6 @@ } 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->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) { struct ccb_relsim crs; ==== //depot/projects/scottl-camlock/src/sys/cam/cam_xpt.h#15 (text+ko) ==== @@ -173,6 +173,7 @@ typedef struct cam_ed * (*xpt_alloc_device_func)(struct cam_eb *bus, struct cam_et *target, lun_id_t lun_id); +typedef void (*xpt_action_func)(union ccb *start_ccb); #if defined(CAM_DEBUG_FLAGS) && !defined(CAMDEBUG) #error "You must have options CAMDEBUG to use options CAM_DEBUG_FLAGS" @@ -199,6 +200,7 @@ MALLOC_DECLARE(M_CAMXPT); void xpt_action(union ccb *new_ccb); +void xpt_action_default(union ccb *new_ccb); static struct cam_ed* xpt_alloc_device(struct cam_eb *bus, struct cam_et *target, lun_id_t lun_id); ==== //depot/projects/scottl-camlock/src/sys/cam/scsi/scsi_xpt.c#9 (text+ko) ==== @@ -540,6 +540,15 @@ scsi_alloc_device(struct cam_eb *bus, struct cam_et *target, lun_id_t lun_id); static void scsi_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_dev_async(u_int32_t async_code, + struct cam_eb *bus, + struct cam_et *target, + struct cam_ed *device, + void *async_arg); static void probe_periph_init() @@ -1938,3 +1947,476 @@ xpt_action((union ccb *)&cts); } +static void +scsi_action(union ccb *start_ccb) +{ + + switch (start_ccb->ccb_h.func_code) { + case XPT_SCSI_IO: + { + struct cam_ed *device; +#ifdef CAMDEBUG + char cdb_str[(SCSI_MAX_CDBLEN * 3) + 1]; + struct cam_path *path; + + path = start_ccb->ccb_h.path; +#endif + + /* + * For the sake of compatibility with SCSI-1 + * devices that may not understand the identify + * message, we include lun information in the + * second byte of all commands. SCSI-1 specifies + * that luns are a 3 bit value and reserves only 3 + * bits for lun information in the CDB. Later + * revisions of the SCSI spec allow for more than 8 + * luns, but have deprecated lun information in the + * CDB. So, if the lun won't fit, we must omit. + * + * Also be aware that during initial probing for devices, + * the inquiry information is unknown but initialized to 0. + * This means that this code will be exercised while probing + * devices with an ANSI revision greater than 2. + */ + device = start_ccb->ccb_h.path->device; + if (device->protocol_version <= SCSI_REV_2 + && start_ccb->ccb_h.target_lun < 8 + && (start_ccb->ccb_h.flags & CAM_CDB_POINTER) == 0) { + + start_ccb->csio.cdb_io.cdb_bytes[1] |= + start_ccb->ccb_h.target_lun << 5; + } + start_ccb->csio.scsi_status = SCSI_STATUS_OK; + CAM_DEBUG(path, CAM_DEBUG_CDB,("%s. CDB: %s\n", + scsi_op_desc(start_ccb->csio.cdb_io.cdb_bytes[0], + &path->device->inq_data), + scsi_cdb_string(start_ccb->csio.cdb_io.cdb_bytes, + cdb_str, sizeof(cdb_str)))); + } + { + struct cam_path *path; + int runq; + + path = start_ccb->ccb_h.path; + + cam_ccbq_insert_ccb(&path->device->ccbq, start_ccb); + if (path->device->qfrozen_cnt == 0) + runq = xpt_schedule_dev_sendq(path->bus, path->device); + else + runq = 0; + if (runq != 0) + 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_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_GET_TRAN_SETTINGS: + { + struct cam_sim *sim; + + sim = start_ccb->ccb_h.path->bus->sim; + (*(sim->sim_action))(sim, start_ccb); + break; + } + default: + xpt_action_default(start_ccb); + break; + } +} + +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->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); + } +} + +/* + * 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) >>> TRUNCATED FOR MAIL (1000 lines) <<<