From owner-svn-src-all@FreeBSD.ORG Tue Jun 8 16:17:26 2010 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 336AE1065698; Tue, 8 Jun 2010 16:17:26 +0000 (UTC) (envelope-from mjacob@FreeBSD.org) Received: from svn.freebsd.org (unknown [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id 219E78FC16; Tue, 8 Jun 2010 16:17:26 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.3/8.14.3) with ESMTP id o58GHQt3050031; Tue, 8 Jun 2010 16:17:26 GMT (envelope-from mjacob@svn.freebsd.org) Received: (from mjacob@localhost) by svn.freebsd.org (8.14.3/8.14.3/Submit) id o58GHQIE050026; Tue, 8 Jun 2010 16:17:26 GMT (envelope-from mjacob@svn.freebsd.org) Message-Id: <201006081617.o58GHQIE050026@svn.freebsd.org> From: Matt Jacob Date: Tue, 8 Jun 2010 16:17:26 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r208911 - in head/sys/cam: . scsi X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 08 Jun 2010 16:17:26 -0000 Author: mjacob Date: Tue Jun 8 16:17:25 2010 New Revision: 208911 URL: http://svn.freebsd.org/changeset/base/208911 Log: Implement the usage of Report Luns as part of SCSI probing for SCP3 or better devices. This can be disabled on a per-device basis using quirks as well. This also handles the case where there is actually no connected LUN 0 (which can definitely be the case for storage arrays). Reviewed by: scsi@ MFC after: 1 month Modified: head/sys/cam/cam_debug.h head/sys/cam/cam_xpt.c head/sys/cam/cam_xpt_internal.h head/sys/cam/scsi/scsi_xpt.c Modified: head/sys/cam/cam_debug.h ============================================================================== --- head/sys/cam/cam_debug.h Tue Jun 8 15:45:38 2010 (r208910) +++ head/sys/cam/cam_debug.h Tue Jun 8 16:17:25 2010 (r208911) @@ -40,7 +40,8 @@ typedef enum { CAM_DEBUG_SUBTRACE = 0x04, /* internal to routine flows */ CAM_DEBUG_CDB = 0x08, /* print out SCSI CDBs only */ CAM_DEBUG_XPT = 0x10, /* print out xpt scheduling */ - CAM_DEBUG_PERIPH = 0x20 /* print out peripheral calls */ + CAM_DEBUG_PERIPH = 0x20, /* print out peripheral calls */ + CAM_DEBUG_PROBE = 0x40 /* print out probe actions */ } cam_debug_flags; #if defined(CAMDEBUG) && defined(_KERNEL) @@ -58,6 +59,7 @@ extern u_int32_t cam_debug_delay; && (cam_dpath != NULL) \ && (xpt_path_comp(cam_dpath, path) >= 0) \ && (xpt_path_comp(cam_dpath, path) < 2)) + #define CAM_DEBUG(path, flag, printfargs) \ if ((cam_dflags & (flag)) \ && (cam_dpath != NULL) \ @@ -68,6 +70,7 @@ extern u_int32_t cam_debug_delay; if (cam_debug_delay != 0) \ DELAY(cam_debug_delay); \ } + #define CAM_DEBUG_PRINT(flag, printfargs) \ if (cam_dflags & (flag)) { \ printf("cam_debug: "); \ @@ -76,11 +79,20 @@ extern u_int32_t cam_debug_delay; DELAY(cam_debug_delay); \ } +#define CAM_DEBUG_PATH_PRINT(flag, path, printfargs) \ + if (cam_dflags & (flag)) { \ + xpt_print(path, "cam_debug: "); \ + printf printfargs; \ + if (cam_debug_delay != 0) \ + DELAY(cam_debug_delay); \ + } + #else /* !CAMDEBUG || !_KERNEL */ #define CAM_DEBUGGED(A, B) 0 #define CAM_DEBUG(A, B, C) #define CAM_DEBUG_PRINT(A, B) +#define CAM_DEBUG_PATH_PRINT(A, B, C) #endif /* CAMDEBUG && _KERNEL */ Modified: head/sys/cam/cam_xpt.c ============================================================================== --- head/sys/cam/cam_xpt.c Tue Jun 8 15:45:38 2010 (r208910) +++ head/sys/cam/cam_xpt.c Tue Jun 8 16:17:25 2010 (r208911) @@ -196,8 +196,18 @@ static struct cdevsw xpt_cdevsw = { /* Storage for debugging datastructures */ #ifdef CAMDEBUG struct cam_path *cam_dpath; -u_int32_t cam_dflags; +#ifdef CAM_DEBUG_FLAGS +u_int32_t cam_dflags = CAM_DEBUG_FLAGS; +#else +u_int32_t cam_dflags = CAM_DEBUG_NONE; +#endif +TUNABLE_INT("kern.cam.dflags", &cam_dflags); +SYSCTL_INT(_kern_cam, OID_AUTO, dflags, CTLFLAG_RW, + &cam_dflags, 0, "Cam Debug Flags"); u_int32_t cam_debug_delay; +TUNABLE_INT("kern.cam.debug_delay", &cam_debug_delay); +SYSCTL_INT(_kern_cam, OID_AUTO, debug_delay, CTLFLAG_RW, + &cam_debug_delay, 0, "Cam Debug Flags"); #endif /* Our boot-time initialization hook */ @@ -4212,6 +4222,7 @@ xpt_alloc_target(struct cam_eb *bus, tar target->target_id = target_id; target->refcount = 1; target->generation = 0; + target->luns = NULL; timevalclear(&target->last_reset); /* * Hold a reference to our parent bus so it @@ -4243,6 +4254,8 @@ xpt_release_target(struct cam_et *target TAILQ_REMOVE(&target->bus->et_entries, target, links); target->bus->generation++; xpt_release_bus(target->bus); + if (target->luns) + free(target->luns, M_CAMXPT); free(target, M_CAMXPT); } } @@ -4505,11 +4518,6 @@ xpt_config(void *arg) #ifdef CAMDEBUG /* Setup debugging flags and path */ -#ifdef CAM_DEBUG_FLAGS - cam_dflags = CAM_DEBUG_FLAGS; -#else /* !CAM_DEBUG_FLAGS */ - cam_dflags = CAM_DEBUG_NONE; -#endif /* CAM_DEBUG_FLAGS */ #ifdef CAM_DEBUG_BUS if (cam_dflags != CAM_DEBUG_NONE) { /* Modified: head/sys/cam/cam_xpt_internal.h ============================================================================== --- head/sys/cam/cam_xpt_internal.h Tue Jun 8 15:45:38 2010 (r208910) +++ head/sys/cam/cam_xpt_internal.h Tue Jun 8 16:17:25 2010 (r208911) @@ -135,6 +135,8 @@ struct cam_et { u_int32_t refcount; u_int generation; struct timeval last_reset; + u_int rpl_size; + struct scsi_report_luns_data *luns; }; /* Modified: head/sys/cam/scsi/scsi_xpt.c ============================================================================== --- head/sys/cam/scsi/scsi_xpt.c Tue Jun 8 15:45:38 2010 (r208910) +++ head/sys/cam/scsi/scsi_xpt.c Tue Jun 8 16:17:25 2010 (r208911) @@ -71,6 +71,7 @@ struct scsi_quirk_entry { #define CAM_QUIRK_NOSERIAL 0x02 #define CAM_QUIRK_HILUNS 0x04 #define CAM_QUIRK_NOHILUNS 0x08 +#define CAM_QUIRK_NORPTLUNS 0x10 u_int mintags; u_int maxtags; }; @@ -84,6 +85,21 @@ SYSCTL_PROC(_kern_cam, OID_AUTO, cam_src "allow search above LUN 7 for SCSI3 and greater devices"); #define CAM_SCSI2_MAXLUN 8 +#define CAM_CAN_GET_SIMPLE_LUN(x, i) \ + ((((x)->luns[i].lundata[0] & RPL_LUNDATA_ATYP_MASK) == \ + RPL_LUNDATA_ATYP_PERIPH) || \ + (((x)->luns[i].lundata[0] & RPL_LUNDATA_ATYP_MASK) == \ + RPL_LUNDATA_ATYP_FLAT)) +#define CAM_GET_SIMPLE_LUN(lp, i, lval) \ + if (((lp)->luns[(i)].lundata[0] & RPL_LUNDATA_ATYP_MASK) == \ + RPL_LUNDATA_ATYP_PERIPH) { \ + (lval) = (lp)->luns[(i)].lundata[1]; \ + } else { \ + (lval) = (lp)->luns[(i)].lundata[0]; \ + (lval) &= RPL_LUNDATA_FLAT_LUN_MASK; \ + (lval) <<= 8; \ + (lval) |= (lp)->luns[(i)].lundata[1]; \ + } /* * If we're not quirked to search <= the first 8 luns * and we are either quirked to search above lun 8, @@ -116,6 +132,7 @@ typedef enum { PROBE_TUR, PROBE_INQUIRY, /* this counts as DV0 for Basic Domain Validation */ PROBE_FULL_INQUIRY, + PROBE_REPORT_LUNS, PROBE_MODE_SENSE, PROBE_SERIAL_NUM_0, PROBE_SERIAL_NUM_1, @@ -130,6 +147,7 @@ static char *probe_action_text[] = { "PROBE_TUR", "PROBE_INQUIRY", "PROBE_FULL_INQUIRY", + "PROBE_REPORT_LUNS", "PROBE_MODE_SENSE", "PROBE_SERIAL_NUM_0", "PROBE_SERIAL_NUM_1", @@ -527,6 +545,10 @@ static void proberequestdefaultnegotiat static int proberequestbackoff(struct cam_periph *periph, struct cam_ed *device); static void probedone(struct cam_periph *periph, union ccb *done_ccb); +static int probe_strange_rpl_data(struct scsi_report_luns_data *rp, + uint32_t maxlun); +static void probe_purge_old(struct cam_path *path, + struct scsi_report_luns_data *new); static void probecleanup(struct cam_periph *periph); static void scsi_find_quirk(struct cam_ed *device); static void scsi_scan_bus(struct cam_periph *periph, union ccb *ccb); @@ -685,6 +707,7 @@ probestart(struct cam_periph *periph, un softc = (probe_softc *)periph->softc; csio = &start_ccb->csio; +again: switch (softc->action) { case PROBE_TUR: @@ -773,6 +796,28 @@ probestart(struct cam_periph *periph, un /*timeout*/60 * 1000); break; } + case PROBE_REPORT_LUNS: + { + void *rp; + + rp = malloc(periph->path->target->rpl_size, + M_CAMXPT, M_NOWAIT | M_ZERO); + if (rp == NULL) { + struct scsi_inquiry_data *inq_buf; + inq_buf = &periph->path->device->inq_data; + xpt_print(periph->path, + "Unable to alloc report luns storage\n"); + if (INQ_DATA_TQ_ENABLED(inq_buf)) + PROBE_SET_ACTION(softc, PROBE_MODE_SENSE); + else + PROBE_SET_ACTION(softc, PROBE_SERIAL_NUM_0); + goto again; + } + scsi_report_luns(csio, 5, probedone, MSG_SIMPLE_Q_TAG, + RPL_REPORT_DEFAULT, rp, periph->path->target->rpl_size, + SSD_FULL_SIZE, 60000); break; + break; + } case PROBE_MODE_SENSE: { void *mode_buf; @@ -1045,9 +1090,7 @@ probedone(struct cam_periph *periph, uni periph_qual = SID_QUAL(inq_buf); - switch(periph_qual) { - case SID_QUAL_LU_CONNECTED: - { + if (periph_qual == SID_QUAL_LU_CONNECTED) { u_int8_t len; /* @@ -1074,10 +1117,23 @@ probedone(struct cam_periph *periph, uni scsi_find_quirk(path->device); scsi_devise_transport(path); - if (INQ_DATA_TQ_ENABLED(inq_buf)) - PROBE_SET_ACTION(softc, PROBE_MODE_SENSE); + + if (path->device->lun_id == 0 && + SID_ANSI_REV(inq_buf) > SCSI_REV_SPC2 && + (SCSI_QUIRK(path->device)->quirks & + CAM_QUIRK_NORPTLUNS) == 0) { + PROBE_SET_ACTION(softc, + PROBE_REPORT_LUNS); + /* + * Start with room for *one* lun. + */ + periph->path->target->rpl_size = 16; + } else if (INQ_DATA_TQ_ENABLED(inq_buf)) + PROBE_SET_ACTION(softc, + PROBE_MODE_SENSE); else - PROBE_SET_ACTION(softc, PROBE_SERIAL_NUM_0); + PROBE_SET_ACTION(softc, + PROBE_SERIAL_NUM_0); if (path->device->flags & CAM_DEV_UNCONFIGURED) { path->device->flags &= ~CAM_DEV_UNCONFIGURED; @@ -1086,9 +1142,21 @@ probedone(struct cam_periph *periph, uni xpt_release_ccb(done_ccb); xpt_schedule(periph, priority); return; - } - default: - break; + } else if (path->device->lun_id == 0 && + SID_ANSI_REV(inq_buf) > SCSI_REV_SPC2 && + (SCSI_QUIRK(path->device)->quirks & + CAM_QUIRK_NORPTLUNS) == 0) { + if (path->device->flags & + CAM_DEV_UNCONFIGURED) { + path->device->flags &= + ~CAM_DEV_UNCONFIGURED; + xpt_acquire_device(path->device); + } + PROBE_SET_ACTION(softc, PROBE_REPORT_LUNS); + periph->path->target->rpl_size = 16; + xpt_release_ccb(done_ccb); + xpt_schedule(periph, priority); + return; } } else if (cam_periph_error(done_ccb, 0, done_ccb->ccb_h.target_lun > 0 @@ -1118,6 +1186,120 @@ probedone(struct cam_periph *periph, uni xpt_release_ccb(done_ccb); break; } + case PROBE_REPORT_LUNS: + { + struct ccb_scsiio *csio; + struct scsi_report_luns_data *lp; + u_int nlun, maxlun; + + csio = &done_ccb->csio; + + lp = (struct scsi_report_luns_data *)csio->data_ptr; + nlun = scsi_4btoul(lp->length) / 8; + maxlun = (csio->dxfer_len / 8) - 1; + + if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { + 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; + } + if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) { + xpt_release_devq(done_ccb->ccb_h.path, 1, + TRUE); + } + free(lp, M_CAMXPT); + lp = NULL; + } else if (nlun > maxlun) { + /* + * Reallocate and retry to cover all luns + */ + CAM_DEBUG_PATH_PRINT(CAM_DEBUG_PROBE, path, + ("reallocating REPORT_LUNS for %u luns\n", nlun)); + free(lp, M_CAMXPT); + path->target->rpl_size = (nlun << 3) + 8; + xpt_release_ccb(done_ccb); + xpt_schedule(periph, priority); + return; + } else if (nlun == 0) { + /* + * If there don't appear to be any luns, bail. + */ + free(lp, M_CAMXPT); + lp = NULL; + } else if (probe_strange_rpl_data(lp, maxlun)) { + /* + * If we can't understand the lun format + * of any entry, bail. + */ + free(lp, M_CAMXPT); + lp = NULL; + } else { + lun_id_t lun; + int idx; + + CAM_DEBUG_PATH_PRINT(CAM_DEBUG_PROBE, path, + ("%u luns reported\n", nlun)); + + CAM_GET_SIMPLE_LUN(lp, 0, lun); + /* + * If the first lun is not lun 0, then either there + * is no lun 0 in the list, or the list is unsorted. + */ + if (lun != 0) { + for (idx = 0; idx < nlun; idx++) { + CAM_GET_SIMPLE_LUN(lp, idx, lun); + if (lun == 0) { + break; + } + } + if (idx != nlun) { + uint8_t tlun[8]; + memcpy(tlun, + lp->luns[0].lundata, 8); + memcpy(lp->luns[0].lundata, + lp->luns[idx].lundata, 8); + memcpy(lp->luns[idx].lundata, + tlun, 8); + CAM_DEBUG_PATH_PRINT(CAM_DEBUG_PROBE, + path, ("lun 0 in position %u\n", idx)); + } else { + /* + * There is no lun 0 in our list. Destroy + * the validity of the inquiry data so we + * bail here and now. + */ + path->device->flags &= + ~CAM_DEV_INQUIRY_DATA_VALID; + } + } + /* + * If we have an old lun list, We can either + * retest luns that appear to have been dropped, + * or just nuke them. We'll opt for the latter. + * This function will also install the new list + * in the target structure. + */ + probe_purge_old(path, lp); + lp = NULL; + } + if (path->device->flags & CAM_DEV_INQUIRY_DATA_VALID) { + struct scsi_inquiry_data *inq_buf; + inq_buf = &path->device->inq_data; + if (INQ_DATA_TQ_ENABLED(inq_buf)) + PROBE_SET_ACTION(softc, PROBE_MODE_SENSE); + else + PROBE_SET_ACTION(softc, PROBE_SERIAL_NUM_0); + xpt_release_ccb(done_ccb); + xpt_schedule(periph, priority); + return; + } + if (lp) { + free(lp, M_CAMXPT); + } + break; + } case PROBE_MODE_SENSE: { struct ccb_scsiio *csio; @@ -1432,6 +1614,80 @@ probedone(struct cam_periph *periph, uni } } +static int +probe_strange_rpl_data(struct scsi_report_luns_data *rp, uint32_t maxlun) +{ + uint32_t idx; + uint32_t nlun = MIN(maxlun, (scsi_4btoul(rp->length) / 8)); + + for (idx = 0; idx < nlun; idx++) { + if (!CAM_CAN_GET_SIMPLE_LUN(rp, idx)) { + return (-1); + } + } + return (0); +} + +static void +probe_purge_old(struct cam_path *path, struct scsi_report_luns_data *new) +{ + struct cam_path *tp; + struct scsi_report_luns_data *old; + u_int idx1, idx2, nlun_old, nlun_new, this_lun; + u_int8_t *ol, *nl; + + if (path->target == NULL) { + return; + } + if (path->target->luns == NULL) { + path->target->luns = new; + return; + } + old = path->target->luns; + nlun_old = scsi_4btoul(old->length) / 8; + nlun_new = scsi_4btoul(new->length) / 8; + + /* + * We are not going to assume sorted lists. Deal. + */ + for (idx1 = 0; idx1 < nlun_old; idx1++) { + ol = old->luns[idx1].lundata; + for (idx2 = 0; idx2 < nlun_new; idx2++) { + nl = new->luns[idx2].lundata; + if (memcmp(nl, ol, 8) == 0) { + break; + } + } + if (idx2 < nlun_new) { + continue; + } + /* + * An 'old' item not in the 'new' list. + * Nuke it. Except that if it is lun 0, + * that would be what the probe state + * machine is currently working on, + * so we won't do that. + * + * We also cannot nuke it if it is + * not in a lun format we understand. + */ + if (!CAM_CAN_GET_SIMPLE_LUN(old, idx1)) { + continue; + } + CAM_GET_SIMPLE_LUN(old, idx1, this_lun); + if (this_lun == 0) { + continue; + } + if (xpt_create_path(&tp, NULL, xpt_path_path_id(path), + xpt_path_target_id(path), this_lun) == CAM_REQ_CMP) { + xpt_async(AC_LOST_DEVICE, tp, NULL); + xpt_free_path(tp); + } + } + free(old, M_CAMXPT); + path->target->luns = new; +} + static void probecleanup(struct cam_periph *periph) { @@ -1480,6 +1736,7 @@ typedef struct { union ccb *request_ccb; struct ccb_pathinq *cpi; int counter; + int lunindex[0]; } scsi_scan_bus_info; /* @@ -1553,13 +1810,15 @@ scsi_scan_bus(struct cam_periph *periph, } /* Save some state for use while we probe for devices */ - scan_info = (scsi_scan_bus_info *) - malloc(sizeof(scsi_scan_bus_info), M_CAMXPT, M_NOWAIT); + scan_info = (scsi_scan_bus_info *) malloc(sizeof(scsi_scan_bus_info) + + (work_ccb->cpi.max_target * sizeof (u_int)), M_CAMXPT, M_ZERO|M_NOWAIT); if (scan_info == NULL) { request_ccb->ccb_h.status = CAM_RESRC_UNAVAIL; xpt_done(request_ccb); return; } + CAM_DEBUG_PATH_PRINT(CAM_DEBUG_PROBE, request_ccb->ccb_h.path, + ("SCAN start for %p\n", scan_info)); scan_info->request_ccb = request_ccb; scan_info->cpi = &work_ccb->cpi; @@ -1626,26 +1885,76 @@ scsi_scan_bus(struct cam_periph *periph, case XPT_SCAN_LUN: { cam_status status; - struct cam_path *path; + struct cam_path *path, *oldpath; scsi_scan_bus_info *scan_info; + struct cam_et *target; + struct cam_ed *device; + int next_target; path_id_t path_id; target_id_t target_id; lun_id_t lun_id; + oldpath = request_ccb->ccb_h.path; + + status = request_ccb->ccb_h.status & CAM_STATUS_MASK; /* Reuse the same CCB to query if a device was really found */ scan_info = (scsi_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; + target = request_ccb->ccb_h.path->target; + next_target = 1; + + if (target->luns) { + uint32_t first; + u_int nluns = scsi_4btoul(target->luns->length) / 8; + + /* + * Make sure we skip over lun 0 if it's the first member + * of the list as we've actually just finished probing + * it. + */ + CAM_GET_SIMPLE_LUN(target->luns, 0, first); + if (first == 0 && scan_info->lunindex[target_id] == 0) { + scan_info->lunindex[target_id]++; + } + + if (scan_info->lunindex[target_id] < nluns) { + CAM_GET_SIMPLE_LUN(target->luns, + scan_info->lunindex[target_id], lun_id); + next_target = 0; + CAM_DEBUG_PATH_PRINT(CAM_DEBUG_PROBE, + request_ccb->ccb_h.path, + ("next lun to try at index %u is %u\n", + scan_info->lunindex[target_id], lun_id)); + scan_info->lunindex[target_id]++; + } else { + /* + * We're done with scanning all luns. + * + * Nuke the bogus device for lun 0 if lun 0 + * wasn't on the list. + */ + if (first != 0) { + TAILQ_FOREACH(device, + &target->ed_entries, links) { + if (device->lun_id == 0) { + break; + } + } + if (device) { + xpt_release_device(device); + } + } + } + } else if (request_ccb->ccb_h.status != CAM_REQ_CMP) { int phl; /* @@ -1654,7 +1963,6 @@ scsi_scan_bus(struct cam_periph *periph, * 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 @@ -1670,11 +1978,15 @@ scsi_scan_bus(struct cam_periph *periph, device = TAILQ_NEXT(device, links); } if ((lun_id != 0) || (device != NULL)) { - if (lun_id < (CAM_SCSI2_MAXLUN-1) || phl) + if (lun_id < (CAM_SCSI2_MAXLUN-1) || phl) { lun_id++; + next_target = 0; + } } + if (lun_id == request_ccb->ccb_h.target_lun + || lun_id > scan_info->cpi->max_lun) + next_target = 1; } else { - struct cam_ed *device; device = request_ccb->ccb_h.path->device; @@ -1682,23 +1994,26 @@ scsi_scan_bus(struct cam_periph *periph, CAM_QUIRK_NOLUNS) == 0) { /* Try the next lun */ if (lun_id < (CAM_SCSI2_MAXLUN-1) - || CAN_SRCH_HI_DENSE(device)) + || CAN_SRCH_HI_DENSE(device)) { lun_id++; + next_target = 0; + } } + if (lun_id == request_ccb->ccb_h.target_lun + || lun_id > scan_info->cpi->max_lun) + next_target = 1; } /* - * 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) { + if (next_target) { int done; + /* + * Free the current request path- we're done with it. + */ + xpt_free_path(oldpath); hop_again: done = 0; if (scan_info->request_ccb->ccb_h.func_code == XPT_SCAN_TGT) { @@ -1723,6 +2038,9 @@ scsi_scan_bus(struct cam_periph *periph, xpt_free_ccb(request_ccb); xpt_free_ccb((union ccb *)scan_info->cpi); request_ccb = scan_info->request_ccb; + CAM_DEBUG_PATH_PRINT(CAM_DEBUG_PROBE, + request_ccb->ccb_h.path, + ("SCAN done for %p\n", scan_info)); free(scan_info, M_CAMXPT); request_ccb->ccb_h.status = CAM_REQ_CMP; xpt_done(request_ccb); @@ -1758,6 +2076,13 @@ scsi_scan_bus(struct cam_periph *periph, } else { status = xpt_create_path(&path, xpt_periph, path_id, target_id, lun_id); + /* + * Free the old request path- we're done with it. We + * do this *after* creating the new path so that + * we don't remove a target that has our lun list + * in the case that lun 0 is not present. + */ + xpt_free_path(oldpath); if (status != CAM_REQ_CMP) { printf("scsi_scan_bus: xpt_create_path failed " "with status %#x, halting LUN scan\n",