diff --git a/sys/cam/cam_ccb.h b/sys/cam/cam_ccb.h index 67b5934e0c68..a45d62ab4152 100644 --- a/sys/cam/cam_ccb.h +++ b/sys/cam/cam_ccb.h @@ -25,7 +25,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: cam_ccb.h,v 1.4 1999/03/05 23:13:20 gibbs Exp $ + * $Id: cam_ccb.h,v 1.5 1999/05/06 20:15:57 ken Exp $ */ #ifndef _CAM_CAM_CCB_H @@ -33,6 +33,7 @@ #include #include +#include #ifndef KERNEL #include #endif @@ -128,6 +129,10 @@ typedef enum { /* Get EDT entries matching the given pattern */ XPT_DEBUG = 0x0a, /* Turn on debugging for a bus, target or lun */ + XPT_PATH_STATS = 0x0b, + /* Path statistics (error counts, etc.) */ + XPT_GDEV_STATS = 0x0c, + /* Device statistics (error counts, etc.) */ /* SCSI Control Functions: 0x10->0x1F */ XPT_ABORT = 0x10, /* Abort the specified CCB */ @@ -243,6 +248,11 @@ struct ccb_getdev { u_int8_t serial_num[252]; u_int8_t serial_num_len; u_int8_t pd_type; /* returned peripheral device type */ +/* + * GARBAGE COLLECT + * Moved to ccb_getdevstats but left here for binary compatibility. + * Remove in next rev of CAM version. + */ int dev_openings; /* Space left for more work on device*/ int dev_active; /* Transactions running on the device */ int devq_openings;/* Space left for more queued work */ @@ -258,6 +268,19 @@ struct ccb_getdev { int mintags; }; +/* Device Statistics CCB */ +struct ccb_getdevstats { + struct ccb_hdr ccb_h; + int dev_openings; /* Space left for more work on device*/ + int dev_active; /* Transactions running on the device */ + int devq_openings; /* Space left for more queued work */ + int devq_queued; /* Transactions queued to be sent */ + int held; /* + * CCBs held by peripheral drivers + * for this device + */ + struct timeval last_reset; /* Time of last bus reset/loop init */ +}; typedef enum { CAM_GDEVLIST_LAST_DEVICE, @@ -488,6 +511,12 @@ struct ccb_pathinq { u_int32_t base_transfer_speed;/* Base bus speed in KB/sec */ }; +/* Path Statistics CCB */ +struct ccb_pathstats { + struct ccb_hdr ccb_h; + struct timeval last_reset; /* Time of last bus reset/loop init */ +}; + typedef union { u_int8_t *sense_ptr; /* * Pointer to storage @@ -757,6 +786,8 @@ union ccb { struct ccb_relsim crs; struct ccb_setasync csa; struct ccb_setdev csd; + struct ccb_pathstats cpis; + struct ccb_getdevstats cgds; struct ccb_dev_match cdm; struct ccb_trans_settings cts; struct ccb_calc_geometry ccg; diff --git a/sys/cam/cam_periph.c b/sys/cam/cam_periph.c index d365a125b873..f88373b8ec7b 100644 --- a/sys/cam/cam_periph.c +++ b/sys/cam/cam_periph.c @@ -26,7 +26,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: cam_periph.c,v 1.12 1999/04/19 21:26:07 gibbs Exp $ + * $Id: cam_periph.c,v 1.13 1999/05/09 01:25:04 ken Exp $ */ #include @@ -519,6 +519,7 @@ cam_periph_mapmem(union ccb *ccb, struct cam_periph_map_info *mapinfo) } break; case XPT_SCSI_IO: + case XPT_CONT_TARGET_IO: if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_NONE) return(0); @@ -834,6 +835,17 @@ cam_periph_runccb(union ccb *ccb, return(error); } +void +cam_freeze_devq(struct cam_path *path) +{ + struct ccb_hdr ccb_h; + + xpt_setup_ccb(&ccb_h, path, /*priority*/1); + ccb_h.func_code = XPT_NOOP; + ccb_h.flags = CAM_DEV_QFREEZE; + xpt_action((union ccb *)&ccb_h); +} + u_int32_t cam_release_devq(struct cam_path *path, u_int32_t relsim_flags, u_int32_t openings, u_int32_t timeout, @@ -1014,6 +1026,70 @@ camperiphdone(struct cam_periph *periph, union ccb *done_ccb) /*getcount_only*/0); } +/* + * Generic Async Event handler. Peripheral drivers usually + * filter out the events that require personal attention, + * and leave the rest to this function. + */ +void +cam_periph_async(struct cam_periph *periph, u_int32_t code, + struct cam_path *path, void *arg) +{ + switch (code) { + case AC_LOST_DEVICE: + cam_periph_invalidate(periph); + break; + case AC_SENT_BDR: + case AC_BUS_RESET: + { + cam_periph_bus_settle(periph, SCSI_DELAY); + break; + } + default: + break; + } +} + +void +cam_periph_bus_settle(struct cam_periph *periph, u_int bus_settle) +{ + struct ccb_getdevstats cgds; + + xpt_setup_ccb(&cgds.ccb_h, periph->path, /*priority*/1); + cgds.ccb_h.func_code = XPT_GDEV_STATS; + xpt_action((union ccb *)&cgds); + cam_periph_freeze_after_event(periph, &cgds.last_reset, bus_settle); +} + +void +cam_periph_freeze_after_event(struct cam_periph *periph, + struct timeval* event_time, u_int duration_ms) +{ + struct timeval delta; + struct timeval duration_tv; + int s; + + s = splclock(); + microtime(&delta); + splx(s); + timevalsub(&delta, event_time); + duration_tv.tv_sec = duration_ms / 1000; + duration_tv.tv_usec = (duration_ms % 1000) * 1000; + if (timevalcmp(&delta, &duration_tv, <)) { + timevalsub(&duration_tv, &delta); + + duration_ms = duration_tv.tv_sec * 1000; + duration_ms += duration_tv.tv_usec / 1000; + cam_freeze_devq(periph->path); + cam_release_devq(periph->path, + RELSIM_RELEASE_AFTER_TIMEOUT, + /*reduction*/0, + /*timeout*/duration_ms, + /*getcount_only*/0); + } + +} + /* * Generic error handler. Peripheral drivers usually filter * out the errors that they handle in a unique mannor, then diff --git a/sys/cam/cam_periph.h b/sys/cam/cam_periph.h index 9bad491f14a1..2efee41c4461 100644 --- a/sys/cam/cam_periph.h +++ b/sys/cam/cam_periph.h @@ -25,7 +25,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: cam_periph.h,v 1.2 1998/10/13 21:41:32 ken Exp $ + * $Id: cam_periph.h,v 1.3 1998/10/22 22:16:48 ken Exp $ */ #ifndef _CAM_CAM_PERIPH_H @@ -130,9 +130,17 @@ int cam_periph_ioctl(struct cam_periph *periph, int cmd, int (*error_routine)(union ccb *ccb, cam_flags camflags, u_int32_t sense_flags)); +void cam_freeze_devq(struct cam_path *path); u_int32_t cam_release_devq(struct cam_path *path, u_int32_t relsim_flags, u_int32_t opening_reduction, u_int32_t timeout, int getcount_only); +void cam_periph_async(struct cam_periph *periph, u_int32_t code, + struct cam_path *path, void *arg); +void cam_periph_bus_settle(struct cam_periph *periph, + u_int bus_settle_ms); +void cam_periph_freeze_after_event(struct cam_periph *periph, + struct timeval* event_time, + u_int duration_ms); int cam_periph_error(union ccb *ccb, cam_flags camflags, u_int32_t sense_flags, union ccb *save_ccb); diff --git a/sys/cam/cam_xpt.c b/sys/cam/cam_xpt.c index 4f277247d855..abd91fafccaf 100644 --- a/sys/cam/cam_xpt.c +++ b/sys/cam/cam_xpt.c @@ -26,7 +26,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: cam_xpt.c,v 1.57 1999/05/11 15:44:39 mjacob Exp $ + * $Id: cam_xpt.c,v 1.58 1999/05/18 00:41:05 gibbs Exp $ */ #include #include @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include @@ -61,7 +62,6 @@ #include #include #include "opt_cam.h" -#include "opt_scsi.h" /* Datastructures internal to the xpt layer */ @@ -89,30 +89,6 @@ static STAILQ_HEAD(highpowerlist, ccb_hdr) highpowerq; #define CAM_MAX_HIGHPOWER 4 #endif -/* - * This is the number of seconds we wait for devices to settle after a SCSI - * bus reset. - */ -#ifndef SCSI_DELAY -#define SCSI_DELAY 2000 -#endif -/* - * If someone sets this to 0, we assume that they want the minimum - * allowable bus settle delay. All devices need _some_ sort of bus settle - * delay, so we'll set it to a minimum value of 100ms. - */ -#if (SCSI_DELAY == 0) -#undef SCSI_DELAY -#define SCSI_DELAY 100 -#endif - -/* - * Make sure the user isn't using seconds instead of milliseconds. - */ -#if (SCSI_DELAY < 100) -#error "SCSI_DELAY is in milliseconds, not seconds! Please use a larger value" -#endif - /* number of high powered commands that can go through right now */ static int num_highpower = CAM_MAX_HIGHPOWER; @@ -166,6 +142,7 @@ struct cam_ed { #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 u_int32_t tag_delay_count; #define CAM_TAG_DELAY_COUNT 5 u_int32_t refcount; @@ -185,6 +162,7 @@ struct cam_et { target_id_t target_id; u_int32_t refcount; u_int generation; + struct timeval last_reset; }; /* @@ -197,6 +175,7 @@ struct cam_eb { 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; @@ -498,6 +477,9 @@ static struct xpt_quirk_entry xpt_quirk_table[] = }, }; +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, @@ -744,6 +726,7 @@ 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 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); @@ -2843,7 +2826,6 @@ xpt_action(union ccb *start_ccb) case XPT_IMMED_NOTIFY: case XPT_NOTIFY_ACK: case XPT_GET_TRAN_SETTINGS: - case XPT_PATH_INQ: case XPT_RESET_BUS: { struct cam_sim *sim; @@ -2852,21 +2834,36 @@ xpt_action(union ccb *start_ccb) (*(sim->sim_action))(sim, start_ccb); break; } + case XPT_PATH_INQ: + { + struct cam_sim *sim; + + sim = start_ccb->ccb_h.path->bus->sim; + (*(sim->sim_action))(sim, start_ccb); + break; + } + case XPT_PATH_STATS: + start_ccb->cpis.last_reset = + start_ccb->ccb_h.path->bus->last_reset; + start_ccb->ccb_h.status = CAM_REQ_CMP; + break; case XPT_GDEV_TYPE: { + struct cam_ed *dev; int s; + dev = start_ccb->ccb_h.path->device; s = splcam(); - if ((start_ccb->ccb_h.path->device->flags & CAM_DEV_UNCONFIGURED) != 0) { + if ((dev->flags & CAM_DEV_UNCONFIGURED) != 0) { start_ccb->ccb_h.status = CAM_DEV_NOT_THERE; } else { struct ccb_getdev *cgd; + struct cam_eb *bus; struct cam_et *tar; - struct cam_ed *dev; cgd = &start_ccb->cgd; + bus = cgd->ccb_h.path->bus; tar = cgd->ccb_h.path->target; - dev = cgd->ccb_h.path->device; cgd->inq_data = dev->inq_data; cgd->pd_type = SID_TYPE(&dev->inq_data); cgd->dev_openings = dev->ccbq.dev_openings; @@ -2886,6 +2883,36 @@ xpt_action(union ccb *start_ccb) splx(s); break; } + case XPT_GDEV_STATS: + { + struct cam_ed *dev; + int s; + + dev = start_ccb->ccb_h.path->device; + s = splcam(); + if ((dev->flags & CAM_DEV_UNCONFIGURED) != 0) { + start_ccb->ccb_h.status = CAM_DEV_NOT_THERE; + } else { + struct ccb_getdevstats *cgds; + struct cam_eb *bus; + struct cam_et *tar; + + cgds = &start_ccb->cgds; + bus = cgds->ccb_h.path->bus; + tar = cgds->ccb_h.path->target; + cgds->dev_openings = dev->ccbq.dev_openings; + cgds->dev_active = dev->ccbq.dev_active; + cgds->devq_openings = dev->ccbq.devq_openings; + cgds->devq_queued = dev->ccbq.queue.entries; + cgds->held = dev->ccbq.held; + cgds->last_reset = tar->last_reset; + if (timevalcmp(&tar->last_reset, &bus->last_reset, <)) + cgds->last_reset = bus->last_reset; + cgds->ccb_h.status = CAM_REQ_CMP; + } + splx(s); + break; + } case XPT_GDEVLIST: { struct cam_periph *nperiph; @@ -3237,6 +3264,8 @@ xpt_action(union ccb *start_ccb) break; } case XPT_NOOP: + if ((start_ccb->ccb_h.flags & CAM_DEV_QFREEZE) != 0) + xpt_freeze_devq(start_ccb->ccb_h.path, 1); start_ccb->ccb_h.status = CAM_REQ_CMP; break; default: @@ -3944,6 +3973,7 @@ xpt_bus_register(struct cam_sim *sim, u_int32_t bus) new_bus->path_id = sim->path_id; new_bus->sim = sim; TAILQ_INIT(&new_bus->et_entries); + timevalclear(&new_bus->last_reset); new_bus->refcount = 1; /* Held until a bus_deregister event */ s = splcam(); TAILQ_INSERT_TAIL(&xpt_busses, new_bus, links); @@ -4059,30 +4089,13 @@ xpt_async(u_int32_t async_code, struct cam_path *path, void *async_arg) bus = path->bus; - /* - * Freeze the SIM queue for SCSI_DELAY ms to - * allow the bus to settle. - */ if (async_code == AC_BUS_RESET) { - struct cam_sim *sim; + int s; - sim = bus->sim; - - /* - * If there isn't already another timeout pending, go ahead - * and freeze the simq and set the timeout flag. If there - * is another timeout pending, replace it with this - * timeout. There could be two bus reset async broadcasts - * sent for some dual-channel controllers. - */ - if ((sim->flags & CAM_SIM_REL_TIMEOUT_PENDING) == 0) { - xpt_freeze_simq(sim, 1); - sim->flags |= CAM_SIM_REL_TIMEOUT_PENDING; - } else - untimeout(xpt_release_simq_timeout, sim, sim->c_handle); - - sim->c_handle = timeout(xpt_release_simq_timeout, - sim, (SCSI_DELAY * hz) / 1000); + s = splclock(); + /* Update our notion of when the last reset occurred */ + microtime(&bus->last_reset); + splx(s); } for (target = TAILQ_FIRST(&bus->et_entries); @@ -4092,9 +4105,18 @@ xpt_async(u_int32_t async_code, struct cam_path *path, void *async_arg) next_target = TAILQ_NEXT(target, links); if (path->target != target - && path->target != NULL) + && path->target->target_id != CAM_TARGET_WILDCARD) continue; + if (async_code == AC_SENT_BDR) { + int s; + + /* Update our notion of when the last reset occurred */ + s = splclock(); + microtime(&path->target->last_reset); + splx(s); + } + for (device = TAILQ_FIRST(&target->ed_entries); device != NULL; device = next_device) { @@ -4104,7 +4126,7 @@ xpt_async(u_int32_t async_code, struct cam_path *path, void *async_arg) next_device = TAILQ_NEXT(device, links); if (path->device != device - && path->device != NULL) + && path->device->lun_id != CAM_LUN_WILDCARD) continue; /* @@ -4131,38 +4153,7 @@ xpt_async(u_int32_t async_code, struct cam_path *path, void *async_arg) || async_code == AC_BUS_RESET) xpt_toggle_tags(&newpath); - /* - * If we send a BDR, freeze the device queue - * for SCSI_DELAY ms to allow it to settle - * down. - */ - if (async_code == AC_SENT_BDR) { - xpt_freeze_devq(&newpath, 1); - /* - * Although this looks bad, it - * isn't as bad as it seems. We're - * passing in a stack-allocated path - * that we then immediately release - * after scheduling a timeout to - * release the device queue. So - * the path won't be around when - * the timeout fires, right? Right. - * But it doesn't matter, since - * xpt_release_devq and its timeout - * function both take the device as - * an argument. Theoretically, the - * device will still be there when - * the timeout fires, even though - * the path will be gone. - */ - cam_release_devq( - &newpath, - /*relsim_flags*/ - RELSIM_RELEASE_AFTER_TIMEOUT, - /*reduction*/0, - /*timeout*/SCSI_DELAY, - /*getcount_only*/0); - } else if (async_code == AC_INQ_CHANGED) { + if (async_code == AC_INQ_CHANGED) { /* * We've sent a start unit command, or * something similar to a device that @@ -4491,6 +4482,7 @@ xpt_alloc_target(struct cam_eb *bus, target_id_t target_id) */ bus->refcount++; TAILQ_INIT(&target->ed_entries); + timevalclear(&target->last_reset); /* Insertion sort into our bus's target list */ cur_target = TAILQ_FIRST(&bus->et_entries); @@ -4552,6 +4544,7 @@ xpt_alloc_device(struct cam_eb *bus, struct cam_et *target, lun_id_t lun_id) callout_handle_init(&device->c_handle); device->refcount = 1; device->flags |= CAM_DEV_UNCONFIGURED; + device->quirk = &xpt_quirk_table[xpt_quirk_table_size - 1]; cam_init_pinfo(&device->alloc_ccb_entry.pinfo); device->alloc_ccb_entry.device = device; @@ -5038,18 +5031,17 @@ xptscandone(struct cam_periph *periph, union ccb *done_ccb) static cam_status proberegister(struct cam_periph *periph, void *arg) { - struct ccb_getdev *cgd; + union ccb *request_ccb; /* CCB representing the probe request */ probe_softc *softc; - union ccb *ccb; - cgd = (struct ccb_getdev *)arg; + request_ccb = (union ccb *)arg; if (periph == NULL) { printf("proberegister: periph was NULL!!\n"); return(CAM_REQ_CMP_ERR); } - if (cgd == NULL) { - printf("proberegister: no getdev CCB, can't register device\n"); + if (request_ccb == NULL) { + printf("proberegister: no probe CCB, can't register device\n"); return(CAM_REQ_CMP_ERR); } @@ -5060,12 +5052,18 @@ proberegister(struct cam_periph *periph, void *arg) "Unable to allocate softc\n"); return(CAM_REQ_CMP_ERR); } - ccb = (union ccb *)cgd; TAILQ_INIT(&softc->request_ccbs); - TAILQ_INSERT_TAIL(&softc->request_ccbs, &ccb->ccb_h, periph_links.tqe); + TAILQ_INSERT_TAIL(&softc->request_ccbs, &request_ccb->ccb_h, + periph_links.tqe); softc->flags = 0; periph->softc = softc; cam_periph_acquire(periph); + /* + * Ensure we've waited at least a bus settle + * delay before attempting to probe the device. + */ + cam_periph_freeze_after_event(periph, &periph->path->bus->last_reset, + SCSI_DELAY); probeschedule(periph); return(CAM_REQ_CMP); } @@ -5073,12 +5071,17 @@ proberegister(struct cam_periph *periph, void *arg) 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 @@ -5090,12 +5093,23 @@ probeschedule(struct cam_periph *periph) * 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)) + && (ccb->ccb_h.target_lun == 0)) { softc->action = PROBE_TUR; - else + } else if ((cpi.hba_inquiry & (PI_WIDE_32|PI_WIDE_16|PI_SDTR_ABLE)) != 0 + && (cpi.hba_misc & PIM_NOBUSRESET) != 0) { + proberequestdefaultnegotiation(periph); softc->action = PROBE_INQUIRY; + } else { + softc->action = PROBE_INQUIRY; + } if (ccb->crcn.flags & CAM_EXPECT_INQ_CHANGE) softc->flags |= PROBE_NO_ANNOUNCE; @@ -5237,6 +5251,21 @@ probestart(struct cam_periph *periph, union ccb *start_ccb) 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.flags = CCB_TRANS_USER_SETTINGS; + xpt_action((union ccb *)&cts); + cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS; + cts.flags &= ~CCB_TRANS_USER_SETTINGS; + cts.flags |= CCB_TRANS_CURRENT_SETTINGS; + xpt_action((union ccb *)&cts); +} + static void probedone(struct cam_periph *periph, union ccb *done_ccb) { @@ -5275,6 +5304,7 @@ probedone(struct cam_periph *periph, union ccb *done_ccb) u_int8_t periph_qual; u_int8_t periph_dtype; + path->device->flags |= CAM_DEV_INQUIRY_DATA_VALID; inq_buf = &path->device->inq_data; periph_qual = SID_QUAL(inq_buf); @@ -5456,13 +5486,7 @@ probedone(struct cam_periph *periph, union ccb *done_ccb) * the user settings, and set them as the current * settings to set the device up. */ - done_ccb->ccb_h.func_code = XPT_GET_TRAN_SETTINGS; - done_ccb->cts.flags = CCB_TRANS_USER_SETTINGS; - xpt_action(done_ccb); - done_ccb->ccb_h.func_code = XPT_SET_TRAN_SETTINGS; - done_ccb->cts.flags &= ~CCB_TRANS_USER_SETTINGS; - done_ccb->cts.flags |= CCB_TRANS_CURRENT_SETTINGS; - xpt_action(done_ccb); + proberequestdefaultnegotiation(periph); xpt_release_ccb(done_ccb); /* @@ -5576,8 +5600,8 @@ xpt_set_transfer_settings(struct ccb_trans_settings *cts, struct cam_ed *device, cts->flags &= ~CCB_TRANS_TAG_ENB; cts->flags |= cur_cts.flags & CCB_TRANS_TAG_ENB; } - - if ((inq_data->flags & SID_Sync) == 0 + if (((device->flags & CAM_DEV_INQUIRY_DATA_VALID) != 0 + && (inq_data->flags & SID_Sync) == 0) || (cpi.hba_inquiry & PI_SDTR_ABLE) == 0) { /* Force async */ cts->sync_period = 0; @@ -5586,12 +5610,14 @@ xpt_set_transfer_settings(struct ccb_trans_settings *cts, struct cam_ed *device, switch (cts->bus_width) { case MSG_EXT_WDTR_BUS_32_BIT: - if ((inq_data->flags & SID_WBus32) != 0 + if (((device->flags & CAM_DEV_INQUIRY_DATA_VALID) == 0 + || (inq_data->flags & SID_WBus32) != 0) && (cpi.hba_inquiry & PI_WIDE_32) != 0) break; /* Fall Through to 16-bit */ case MSG_EXT_WDTR_BUS_16_BIT: - if ((inq_data->flags & SID_WBus16) != 0 + if (((device->flags & CAM_DEV_INQUIRY_DATA_VALID) == 0 + || (inq_data->flags & SID_WBus16) != 0) && (cpi.hba_inquiry & PI_WIDE_16) != 0) { cts->bus_width = MSG_EXT_WDTR_BUS_16_BIT; break; @@ -5704,6 +5730,8 @@ xpt_set_transfer_settings(struct ccb_trans_settings *cts, struct cam_ed *device, static void xpt_toggle_tags(struct cam_path *path) { + struct cam_ed *dev; + /* * Give controllers a chance to renegotiate * before starting tag operations. We @@ -5711,8 +5739,10 @@ xpt_toggle_tags(struct cam_path *path) * which causes the tag enable command delay * counter to come into effect. */ - if ((path->device->flags & CAM_DEV_TAG_AFTER_COUNT) != 0 - || (path->device->inq_flags & SID_CmdQue) != 0) { + 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); @@ -5752,12 +5782,29 @@ xpt_start_tags(struct cam_path *path) } static int busses_to_config; +static int busses_to_reset; static int xptconfigbuscountfunc(struct cam_eb *bus, void *arg) { - if (bus->path_id != CAM_XPT_PATH_ID) + if (bus->path_id != CAM_XPT_PATH_ID) { + struct cam_path path; + struct ccb_pathinq cpi; + int can_negotiate; + busses_to_config++; + xpt_compile_path(&path, NULL, bus->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); + can_negotiate = cpi.hba_inquiry; + can_negotiate &= (PI_WIDE_32|PI_WIDE_16|PI_SDTR_ABLE); + if ((cpi.hba_misc & PIM_NOBUSRESET) == 0 + && can_negotiate) + busses_to_reset++; + xpt_release_path(&path); + } return(1); } @@ -5770,6 +5817,7 @@ xptconfigfunc(struct cam_eb *bus, void *arg) if (bus->path_id != CAM_XPT_PATH_ID) { cam_status status; + int can_negotiate; work_ccb = xpt_alloc_ccb(); if ((status = xpt_create_path(&path, xpt_periph, bus->path_id, @@ -5794,7 +5842,10 @@ xptconfigfunc(struct cam_eb *bus, void *arg) return(1); } - if ((work_ccb->cpi.hba_misc & PIM_NOBUSRESET) == 0) { + can_negotiate = work_ccb->cpi.hba_inquiry; + can_negotiate &= (PI_WIDE_32|PI_WIDE_16|PI_SDTR_ABLE); + if ((work_ccb->cpi.hba_misc & PIM_NOBUSRESET) == 0 + && (can_negotiate != 0)) { xpt_setup_ccb(&work_ccb->ccb_h, path, /*priority*/1); work_ccb->ccb_h.func_code = XPT_RESET_BUS; work_ccb->ccb_h.cbfcnp = NULL; @@ -5850,7 +5901,7 @@ xpt_config(void *arg) /* Call manually because we don't have any busses */ xpt_finishconfig(xpt_periph, NULL); } else { - if (SCSI_DELAY >= 2000) { + if (busses_to_reset > 0 && SCSI_DELAY >= 2000) { printf("Waiting %d seconds for SCSI " "devices to settle\n", SCSI_DELAY/1000); }