mirror of
https://git.FreeBSD.org/src.git
synced 2025-01-12 14:29:28 +00:00
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
This commit is contained in:
parent
a47eae85b4
commit
82b361b11b
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=208911
@ -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 */
|
||||
|
||||
|
@ -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, target_id_t target_id)
|
||||
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) {
|
||||
/*
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -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_srch_hi, CTLTYPE_INT|CTLFLAG_RW, 0, 0,
|
||||
"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 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 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, union ccb *start_ccb)
|
||||
|
||||
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, union ccb *start_ccb)
|
||||
/*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, union ccb *done_ccb)
|
||||
|
||||
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, union ccb *done_ccb)
|
||||
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, union ccb *done_ccb)
|
||||
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, union ccb *done_ccb)
|
||||
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, union ccb *done_ccb)
|
||||
}
|
||||
}
|
||||
|
||||
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, union ccb *request_ccb)
|
||||
}
|
||||
|
||||
/* 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, union ccb *request_ccb)
|
||||
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, union ccb *request_ccb)
|
||||
* 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, union ccb *request_ccb)
|
||||
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, union ccb *request_ccb)
|
||||
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, union ccb *request_ccb)
|
||||
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, union ccb *request_ccb)
|
||||
} 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",
|
||||
|
Loading…
Reference in New Issue
Block a user