Add SCSI passthrough support to CISS. This allows devices like tape drives
that are on a CISS bus to be exported up to CAM and made available as normal devices. This will typically add one or two buses to CAM, which will be numbered starting at 32 to allow room for CISS proxy buses. Also, the CISS firmware usually hides disk devices, but these can also be exposed as 'pass' devices if you set the hw.ciss.expose_hidden_physical tunable. Sponsored by: Tape Laboratories, Inc. MFC After: 3 days
This commit is contained in:
parent
4104a7f84f
commit
3eaa7bd6e0
@ -125,6 +125,7 @@ static void ciss_command_map_helper(void *arg, bus_dma_segment_t *segs,
|
||||
static int ciss_identify_adapter(struct ciss_softc *sc);
|
||||
static int ciss_init_logical(struct ciss_softc *sc);
|
||||
static int ciss_init_physical(struct ciss_softc *sc);
|
||||
static int ciss_filter_physical(struct ciss_softc *sc, struct ciss_lun_report *cll);
|
||||
static int ciss_identify_logical(struct ciss_softc *sc, struct ciss_ldrive *ld);
|
||||
static int ciss_get_ldrive_status(struct ciss_softc *sc, struct ciss_ldrive *ld);
|
||||
static int ciss_update_config(struct ciss_softc *sc);
|
||||
@ -187,6 +188,7 @@ static void ciss_notify_event(struct ciss_softc *sc);
|
||||
static void ciss_notify_complete(struct ciss_request *cr);
|
||||
static int ciss_notify_abort(struct ciss_softc *sc);
|
||||
static int ciss_notify_abort_bmic(struct ciss_softc *sc);
|
||||
static void ciss_notify_hotplug(struct ciss_softc *sc, struct ciss_notify *cn);
|
||||
static void ciss_notify_logical(struct ciss_softc *sc, struct ciss_notify *cn);
|
||||
static void ciss_notify_physical(struct ciss_softc *sc, struct ciss_notify *cn);
|
||||
|
||||
@ -235,6 +237,13 @@ static struct cdevsw ciss_cdevsw = {
|
||||
.d_name = "ciss",
|
||||
};
|
||||
|
||||
/*
|
||||
* This tunable can be set at boot time and controls whether physical devices
|
||||
* that are marked hidden by the firmware should be exposed anyways.
|
||||
*/
|
||||
static unsigned int ciss_expose_hidden_physical = 0;
|
||||
TUNABLE_INT("hw.ciss.expose_hidden_physical", &ciss_expose_hidden_physical);
|
||||
|
||||
/************************************************************************
|
||||
* CISS adapters amazingly don't have a defined programming interface
|
||||
* value. (One could say some very despairing things about PCI and
|
||||
@ -1067,14 +1076,14 @@ ciss_init_logical(struct ciss_softc *sc)
|
||||
}
|
||||
|
||||
sc->ciss_logical =
|
||||
malloc(sc->ciss_max_bus_number * sizeof(struct ciss_ldrive *),
|
||||
malloc(sc->ciss_max_logical_bus * sizeof(struct ciss_ldrive *),
|
||||
CISS_MALLOC_CLASS, M_NOWAIT | M_ZERO);
|
||||
if (sc->ciss_logical == NULL) {
|
||||
error = ENXIO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (i = 0; i <= sc->ciss_max_bus_number; i++) {
|
||||
for (i = 0; i <= sc->ciss_max_logical_bus; i++) {
|
||||
sc->ciss_logical[i] =
|
||||
malloc(CISS_MAX_LOGICAL * sizeof(struct ciss_ldrive),
|
||||
CISS_MALLOC_CLASS, M_NOWAIT | M_ZERO);
|
||||
@ -1122,9 +1131,13 @@ ciss_init_physical(struct ciss_softc *sc)
|
||||
struct ciss_lun_report *cll;
|
||||
int error = 0, i;
|
||||
int nphys;
|
||||
int bus, target;
|
||||
|
||||
debug_called(1);
|
||||
|
||||
bus = 0;
|
||||
target = 0;
|
||||
|
||||
cll = ciss_report_luns(sc, CISS_OPCODE_REPORT_PHYSICAL_LUNS,
|
||||
CISS_MAX_PHYSICAL);
|
||||
if (cll == NULL) {
|
||||
@ -1139,6 +1152,30 @@ ciss_init_physical(struct ciss_softc *sc)
|
||||
nphys, (nphys > 1 || nphys == 0) ? "s" : "");
|
||||
}
|
||||
|
||||
/*
|
||||
* Figure out the bus mapping.
|
||||
* Logical buses include both the local logical bus for local arrays and
|
||||
* proxy buses for remote arrays. Physical buses are numbered by the
|
||||
* controller and represent physical buses that hold physical devices.
|
||||
* We shift these bus numbers so that everything fits into a single flat
|
||||
* numbering space for CAM. Logical buses occupy the first 32 CAM bus
|
||||
* numbers, and the physical bus numbers are shifted to be above that.
|
||||
* This results in the various driver arrays being indexed as follows:
|
||||
*
|
||||
* ciss_controllers[] - indexed by logical bus
|
||||
* ciss_cam_sim[] - indexed by both logical and physical, with physical
|
||||
* being shifted by 32.
|
||||
* ciss_logical[][] - indexed by logical bus
|
||||
* ciss_physical[][] - indexed by physical bus
|
||||
*
|
||||
* XXX This is getting more and more hackish. CISS really doesn't play
|
||||
* well with a standard SCSI model; devices are addressed via magic
|
||||
* cookies, not via b/t/l addresses. Since there is no way to store
|
||||
* the cookie in the CAM device object, we have to keep these lookup
|
||||
* tables handy so that the devices can be found quickly at the cost
|
||||
* of wasting memory and having a convoluted lookup scheme. This
|
||||
* driver should probably be converted to block interface.
|
||||
*/
|
||||
/*
|
||||
* If the L2 and L3 SCSI addresses are 0, this signifies a proxy
|
||||
* controller. A proxy controller is another physical controller
|
||||
@ -1148,15 +1185,19 @@ ciss_init_physical(struct ciss_softc *sc)
|
||||
* find the highest numbered one so the array can be properly
|
||||
* sized.
|
||||
*/
|
||||
sc->ciss_max_bus_number = 1;
|
||||
sc->ciss_max_logical_bus = 1;
|
||||
for (i = 0; i < nphys; i++) {
|
||||
if (cll->lun[i].physical.extra_address == 0) {
|
||||
sc->ciss_max_bus_number = cll->lun[i].physical.bus + 1;
|
||||
bus = cll->lun[i].physical.bus;
|
||||
sc->ciss_max_logical_bus = max(sc->ciss_max_logical_bus, bus) + 1;
|
||||
} else {
|
||||
bus = CISS_EXTRA_BUS2(cll->lun[i].physical.extra_address);
|
||||
sc->ciss_max_physical_bus = max(sc->ciss_max_physical_bus, bus);
|
||||
}
|
||||
}
|
||||
|
||||
sc->ciss_controllers =
|
||||
malloc(sc->ciss_max_bus_number * sizeof (union ciss_device_address),
|
||||
malloc(sc->ciss_max_logical_bus * sizeof (union ciss_device_address),
|
||||
CISS_MALLOC_CLASS, M_NOWAIT | M_ZERO);
|
||||
|
||||
if (sc->ciss_controllers == NULL) {
|
||||
@ -1172,6 +1213,28 @@ ciss_init_physical(struct ciss_softc *sc)
|
||||
}
|
||||
}
|
||||
|
||||
sc->ciss_physical =
|
||||
malloc(sc->ciss_max_physical_bus * sizeof(struct ciss_pdrive *),
|
||||
CISS_MALLOC_CLASS, M_NOWAIT | M_ZERO);
|
||||
if (sc->ciss_physical == NULL) {
|
||||
ciss_printf(sc, "Could not allocate memory for physical device map\n");
|
||||
error = ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (i = 0; i < sc->ciss_max_physical_bus; i++) {
|
||||
sc->ciss_physical[i] =
|
||||
malloc(sizeof(struct ciss_pdrive) * CISS_MAX_PHYSTGT,
|
||||
CISS_MALLOC_CLASS, M_NOWAIT | M_ZERO);
|
||||
if (sc->ciss_physical[i] == NULL) {
|
||||
ciss_printf(sc, "Could not allocate memory for target map\n");
|
||||
error = ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
ciss_filter_physical(sc, cll);
|
||||
|
||||
out:
|
||||
if (cll != NULL)
|
||||
free(cll, CISS_MALLOC_CLASS);
|
||||
@ -1179,6 +1242,52 @@ ciss_init_physical(struct ciss_softc *sc)
|
||||
return(error);
|
||||
}
|
||||
|
||||
static int
|
||||
ciss_filter_physical(struct ciss_softc *sc, struct ciss_lun_report *cll)
|
||||
{
|
||||
u_int32_t ea;
|
||||
int i, nphys;
|
||||
int bus, target;
|
||||
|
||||
nphys = (ntohl(cll->list_size) / sizeof(union ciss_device_address));
|
||||
for (i = 0; i < nphys; i++) {
|
||||
if (cll->lun[i].physical.extra_address == 0)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Filter out devices that we don't want. Level 3 LUNs could
|
||||
* probably be supported, but the docs don't give enough of a
|
||||
* hint to know how.
|
||||
*
|
||||
* The mode field of the physical address is likely set to have
|
||||
* hard disks masked out. Honor it unless the user has overridden
|
||||
* us with the tunable. We also munge the inquiry data for these
|
||||
* disks so that they only show up as passthrough devices. Keeping
|
||||
* them visible in this fashion is useful for doing things like
|
||||
* flashing firmware.
|
||||
*/
|
||||
ea = cll->lun[i].physical.extra_address;
|
||||
if ((CISS_EXTRA_BUS3(ea) != 0) || (CISS_EXTRA_TARGET3(ea) != 0) ||
|
||||
(CISS_EXTRA_MODE2(ea) == 0x3))
|
||||
continue;
|
||||
if ((ciss_expose_hidden_physical == 0) &&
|
||||
(cll->lun[i].physical.mode == CISS_HDR_ADDRESS_MODE_MASK_PERIPHERAL))
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Note: CISS firmware numbers physical busses starting at '1', not
|
||||
* '0'. This numbering is internal to the firmware and is only
|
||||
* used as a hint here.
|
||||
*/
|
||||
bus = CISS_EXTRA_BUS2(ea) - 1;
|
||||
target = CISS_EXTRA_TARGET2(ea);
|
||||
sc->ciss_physical[bus][target].cp_address = cll->lun[i];
|
||||
sc->ciss_physical[bus][target].cp_online = 1;
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
ciss_inquiry_logical(struct ciss_softc *sc, struct ciss_ldrive *ld)
|
||||
{
|
||||
@ -1564,7 +1673,14 @@ ciss_free(struct ciss_softc *sc)
|
||||
|
||||
/* disconnect from CAM */
|
||||
if (sc->ciss_cam_sim) {
|
||||
for (i = 0; i < sc->ciss_max_bus_number; i++) {
|
||||
for (i = 0; i < sc->ciss_max_logical_bus; i++) {
|
||||
if (sc->ciss_cam_sim[i]) {
|
||||
xpt_bus_deregister(cam_sim_path(sc->ciss_cam_sim[i]));
|
||||
cam_sim_free(sc->ciss_cam_sim[i], 0);
|
||||
}
|
||||
}
|
||||
for (i = CISS_PHYSICAL_BASE; i < sc->ciss_max_physical_bus +
|
||||
CISS_PHYSICAL_BASE; i++) {
|
||||
if (sc->ciss_cam_sim[i]) {
|
||||
xpt_bus_deregister(cam_sim_path(sc->ciss_cam_sim[i]));
|
||||
cam_sim_free(sc->ciss_cam_sim[i], 0);
|
||||
@ -1576,11 +1692,17 @@ ciss_free(struct ciss_softc *sc)
|
||||
cam_simq_free(sc->ciss_cam_devq);
|
||||
|
||||
if (sc->ciss_logical) {
|
||||
for (i = 0; i < sc->ciss_max_bus_number; i++)
|
||||
for (i = 0; i < sc->ciss_max_logical_bus; i++)
|
||||
free(sc->ciss_logical[i], CISS_MALLOC_CLASS);
|
||||
free(sc->ciss_logical, CISS_MALLOC_CLASS);
|
||||
}
|
||||
|
||||
if (sc->ciss_physical) {
|
||||
for (i = 0; i < sc->ciss_max_physical_bus; i++)
|
||||
free(sc->ciss_physical[i], CISS_MALLOC_CLASS);
|
||||
free(sc->ciss_physical, CISS_MALLOC_CLASS);
|
||||
}
|
||||
|
||||
if (sc->ciss_controllers)
|
||||
free(sc->ciss_controllers, CISS_MALLOC_CLASS);
|
||||
}
|
||||
@ -2277,7 +2399,7 @@ ciss_unmap_request(struct ciss_request *cr)
|
||||
static int
|
||||
ciss_cam_init(struct ciss_softc *sc)
|
||||
{
|
||||
int i;
|
||||
int i, maxbus;
|
||||
|
||||
debug_called(1);
|
||||
|
||||
@ -2292,15 +2414,23 @@ ciss_cam_init(struct ciss_softc *sc)
|
||||
|
||||
/*
|
||||
* Create a SIM.
|
||||
*
|
||||
* This naturally wastes a bit of memory. The alternative is to allocate
|
||||
* and register each bus as it is found, and then track them on a linked
|
||||
* list. Unfortunately, the driver has a few places where it needs to
|
||||
* look up the SIM based solely on bus number, and it's unclear whether
|
||||
* a list traversal would work for these situations.
|
||||
*/
|
||||
sc->ciss_cam_sim = malloc(sc->ciss_max_bus_number * sizeof(struct cam_sim *),
|
||||
maxbus = max(sc->ciss_max_logical_bus, sc->ciss_max_physical_bus +
|
||||
CISS_PHYSICAL_BASE);
|
||||
sc->ciss_cam_sim = malloc(maxbus * sizeof(struct cam_sim*),
|
||||
CISS_MALLOC_CLASS, M_NOWAIT | M_ZERO);
|
||||
if (sc->ciss_cam_sim == NULL) {
|
||||
ciss_printf(sc, "can't allocate memory for controller SIM\n");
|
||||
return(ENOMEM);
|
||||
}
|
||||
|
||||
for (i = 0; i < sc->ciss_max_bus_number; i++) {
|
||||
for (i = 0; i < sc->ciss_max_logical_bus; i++) {
|
||||
if ((sc->ciss_cam_sim[i] = cam_sim_alloc(ciss_cam_action, ciss_cam_poll,
|
||||
"ciss", sc,
|
||||
device_get_unit(sc->ciss_dev),
|
||||
@ -2314,10 +2444,29 @@ ciss_cam_init(struct ciss_softc *sc)
|
||||
/*
|
||||
* Register bus with this SIM.
|
||||
*/
|
||||
if ((i == 0 || sc->ciss_controllers[i].physical.bus != 0) &&
|
||||
xpt_bus_register(sc->ciss_cam_sim[i], i) != 0) {
|
||||
if (i == 0 || sc->ciss_controllers[i].physical.bus != 0) {
|
||||
if (xpt_bus_register(sc->ciss_cam_sim[i], i) != 0) {
|
||||
ciss_printf(sc, "can't register SCSI bus %d\n", i);
|
||||
return(ENXIO);
|
||||
return (ENXIO);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (i = CISS_PHYSICAL_BASE; i < sc->ciss_max_physical_bus +
|
||||
CISS_PHYSICAL_BASE; i++) {
|
||||
if ((sc->ciss_cam_sim[i] = cam_sim_alloc(ciss_cam_action, ciss_cam_poll,
|
||||
"ciss", sc,
|
||||
device_get_unit(sc->ciss_dev),
|
||||
sc->ciss_max_requests - 2,
|
||||
1,
|
||||
sc->ciss_cam_devq)) == NULL) {
|
||||
ciss_printf(sc, "can't allocate CAM SIM for controller %d\n", i);
|
||||
return (ENOMEM);
|
||||
}
|
||||
|
||||
if (xpt_bus_register(sc->ciss_cam_sim[i], i) != 0) {
|
||||
ciss_printf(sc, "can't register SCSI bus %d\n", i);
|
||||
return (ENXIO);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2366,7 +2515,12 @@ ciss_cam_rescan_all(struct ciss_softc *sc)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < sc->ciss_max_bus_number; i++)
|
||||
/* Rescan the logical buses */
|
||||
for (i = 0; i < sc->ciss_max_logical_bus; i++)
|
||||
ciss_cam_rescan_target(sc, i, CAM_TARGET_WILDCARD);
|
||||
/* Rescan the physical buses */
|
||||
for (i = CISS_PHYSICAL_BASE; i < sc->ciss_max_logical_bus +
|
||||
CISS_PHYSICAL_BASE; i++)
|
||||
ciss_cam_rescan_target(sc, i, CAM_TARGET_WILDCARD);
|
||||
}
|
||||
|
||||
@ -2386,11 +2540,13 @@ ciss_cam_action(struct cam_sim *sim, union ccb *ccb)
|
||||
struct ciss_softc *sc;
|
||||
struct ccb_scsiio *csio;
|
||||
int bus, target;
|
||||
int physical;
|
||||
|
||||
sc = cam_sim_softc(sim);
|
||||
bus = cam_sim_bus(sim);
|
||||
csio = (struct ccb_scsiio *)&ccb->csio;
|
||||
target = csio->ccb_h.target_id;
|
||||
physical = CISS_IS_PHYSICAL(bus);
|
||||
|
||||
switch (ccb->ccb_h.func_code) {
|
||||
|
||||
@ -2404,15 +2560,19 @@ ciss_cam_action(struct cam_sim *sim, union ccb *ccb)
|
||||
case XPT_CALC_GEOMETRY:
|
||||
{
|
||||
struct ccb_calc_geometry *ccg = &ccb->ccg;
|
||||
struct ciss_ldrive *ld = &sc->ciss_logical[bus][target];
|
||||
struct ciss_ldrive *ld;
|
||||
|
||||
debug(1, "XPT_CALC_GEOMETRY %d:%d:%d", cam_sim_bus(sim), ccb->ccb_h.target_id, ccb->ccb_h.target_lun);
|
||||
|
||||
ld = NULL;
|
||||
if (!physical)
|
||||
ld = &sc->ciss_logical[bus][target];
|
||||
|
||||
/*
|
||||
* Use the cached geometry settings unless the fault tolerance
|
||||
* is invalid.
|
||||
*/
|
||||
if (ld->cl_geometry.fault_tolerance == 0xFF) {
|
||||
if (physical || ld->cl_geometry.fault_tolerance == 0xFF) {
|
||||
u_int32_t secs_per_cylinder;
|
||||
|
||||
ccg->heads = 255;
|
||||
@ -2538,7 +2698,7 @@ ciss_cam_action_io(struct cam_sim *sim, struct ccb_scsiio *csio)
|
||||
* request completes.
|
||||
*/
|
||||
if ((error = ciss_get_request(sc, &cr)) != 0) {
|
||||
xpt_freeze_simq(sc->ciss_cam_sim[bus], 1);
|
||||
xpt_freeze_simq(sim, 1);
|
||||
csio->ccb_h.status |= CAM_REQUEUE_REQ;
|
||||
return(error);
|
||||
}
|
||||
@ -2555,7 +2715,12 @@ ciss_cam_action_io(struct cam_sim *sim, struct ccb_scsiio *csio)
|
||||
/*
|
||||
* Target the right logical volume.
|
||||
*/
|
||||
cc->header.address = sc->ciss_logical[bus][target].cl_address;
|
||||
if (CISS_IS_PHYSICAL(bus))
|
||||
cc->header.address =
|
||||
sc->ciss_physical[CISS_CAM_TO_PBUS(bus)][target].cp_address;
|
||||
else
|
||||
cc->header.address =
|
||||
sc->ciss_logical[bus][target].cl_address;
|
||||
cc->cdb.cdb_length = csio->cdb_len;
|
||||
cc->cdb.type = CISS_CDB_TYPE_COMMAND;
|
||||
cc->cdb.attribute = CISS_CDB_ATTRIBUTE_SIMPLE; /* XXX ordered tags? */
|
||||
@ -2584,7 +2749,7 @@ ciss_cam_action_io(struct cam_sim *sim, struct ccb_scsiio *csio)
|
||||
* if the adapter rejects the command).
|
||||
*/
|
||||
if ((error = ciss_start(cr)) != 0) {
|
||||
xpt_freeze_simq(sc->ciss_cam_sim[bus], 1);
|
||||
xpt_freeze_simq(sim, 1);
|
||||
if (error == EINPROGRESS) {
|
||||
csio->ccb_h.status |= CAM_RELEASE_SIMQ;
|
||||
error = 0;
|
||||
@ -2612,6 +2777,15 @@ ciss_cam_emulate(struct ciss_softc *sc, struct ccb_scsiio *csio)
|
||||
opcode = (csio->ccb_h.flags & CAM_CDB_POINTER) ?
|
||||
*(u_int8_t *)csio->cdb_io.cdb_ptr : csio->cdb_io.cdb_bytes[0];
|
||||
|
||||
if (CISS_IS_PHYSICAL(bus)) {
|
||||
if (sc->ciss_physical[CISS_CAM_TO_PBUS(bus)][target].cp_online != 1) {
|
||||
csio->ccb_h.status = CAM_SEL_TIMEOUT;
|
||||
xpt_done((union ccb *)csio);
|
||||
return(1);
|
||||
} else
|
||||
return(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle requests for volumes that don't exist or are not online.
|
||||
* A selection timeout is slightly better than an illegal request.
|
||||
@ -2750,6 +2924,17 @@ ciss_cam_complete_fixup(struct ciss_softc *sc, struct ccb_scsiio *csio)
|
||||
inq = (struct scsi_inquiry_data *)csio->data_ptr;
|
||||
target = csio->ccb_h.target_id;
|
||||
bus = cam_sim_bus(xpt_path_sim(csio->ccb_h.path));
|
||||
|
||||
/*
|
||||
* Don't let hard drives be seen by the DA driver. They will still be
|
||||
* attached by the PASS driver.
|
||||
*/
|
||||
if (CISS_IS_PHYSICAL(bus)) {
|
||||
if (SID_TYPE(inq) == T_DIRECT)
|
||||
inq->device = (inq->device & 0xe0) | T_NODEVICE;
|
||||
return;
|
||||
}
|
||||
|
||||
cl = &sc->ciss_logical[bus][target];
|
||||
|
||||
padstr(inq->vendor, "COMPAQ", 8);
|
||||
@ -2790,8 +2975,11 @@ ciss_name_device(struct ciss_softc *sc, int bus, int target)
|
||||
{
|
||||
struct cam_periph *periph;
|
||||
|
||||
if (CISS_IS_PHYSICAL(bus) == 0)
|
||||
return (0);
|
||||
if ((periph = ciss_find_periph(sc, bus, target)) != NULL) {
|
||||
sprintf(sc->ciss_logical[bus][target].cl_name, "%s%d", periph->periph_name, periph->unit_number);
|
||||
sprintf(sc->ciss_logical[bus][target].cl_name, "%s%d",
|
||||
periph->periph_name, periph->unit_number);
|
||||
return(0);
|
||||
}
|
||||
sc->ciss_logical[bus][target].cl_name[0] = 0;
|
||||
@ -3218,7 +3406,7 @@ ciss_notify_rescan_logical(struct ciss_softc *sc)
|
||||
* Delete any of the drives which were destroyed by the
|
||||
* firmware.
|
||||
*/
|
||||
for (i = 0; i < sc->ciss_max_bus_number; i++) {
|
||||
for (i = 0; i < sc->ciss_max_logical_bus; i++) {
|
||||
for (j = 0; j < CISS_MAX_LOGICAL; j++) {
|
||||
ld = &sc->ciss_logical[i][j];
|
||||
|
||||
@ -3355,6 +3543,51 @@ ciss_notify_physical(struct ciss_softc *sc, struct ciss_notify *cn)
|
||||
{
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
* Handle a notify event relating to the status of a physical drive.
|
||||
*/
|
||||
static void
|
||||
ciss_notify_hotplug(struct ciss_softc *sc, struct ciss_notify *cn)
|
||||
{
|
||||
struct ciss_lun_report *cll;
|
||||
int bus, target;
|
||||
int s;
|
||||
|
||||
switch (cn->subclass) {
|
||||
case CISS_NOTIFY_HOTPLUG_PHYSICAL:
|
||||
case CISS_NOTIFY_HOTPLUG_NONDISK:
|
||||
bus = CISS_BIG_MAP_BUS(sc, cn->data.drive.big_physical_drive_number);
|
||||
target =
|
||||
CISS_BIG_MAP_TARGET(sc, cn->data.drive.big_physical_drive_number);
|
||||
|
||||
s = splcam();
|
||||
if (cn->detail == 0) {
|
||||
/*
|
||||
* Mark the device offline so that it'll start producing selection
|
||||
* timeouts to the upper layer.
|
||||
*/
|
||||
sc->ciss_physical[bus][target].cp_online = 0;
|
||||
} else {
|
||||
/*
|
||||
* Rescan the physical lun list for new items
|
||||
*/
|
||||
cll = ciss_report_luns(sc, CISS_OPCODE_REPORT_PHYSICAL_LUNS,
|
||||
CISS_MAX_PHYSICAL);
|
||||
if (cll == NULL) {
|
||||
ciss_printf(sc, "Warning, cannot get physical lun list\n");
|
||||
break;
|
||||
}
|
||||
ciss_filter_physical(sc, cll);
|
||||
}
|
||||
splx(s);
|
||||
break;
|
||||
|
||||
default:
|
||||
ciss_printf(sc, "Unknown hotplug event %d\n", cn->subclass);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
* Handle deferred processing of notify events. Notify events may need
|
||||
* sleep which is unsafe during an interrupt.
|
||||
@ -3390,6 +3623,9 @@ ciss_notify_thread(void *arg)
|
||||
cn = (struct ciss_notify *)cr->cr_data;
|
||||
|
||||
switch (cn->class) {
|
||||
case CISS_NOTIFY_HOTPLUG:
|
||||
ciss_notify_hotplug(sc, cn);
|
||||
break;
|
||||
case CISS_NOTIFY_LOGICAL:
|
||||
ciss_notify_logical(sc, cn);
|
||||
break;
|
||||
@ -3586,13 +3822,15 @@ ciss_print_adapter(struct ciss_softc *sc)
|
||||
ciss_printf(sc, "flags %b\n", sc->ciss_flags,
|
||||
"\20\1notify_ok\2control_open\3aborting\4running\21fake_synch\22bmic_abort\n");
|
||||
|
||||
for (i = 0; i < sc->ciss_max_bus_number; i++) {
|
||||
for (i = 0; i < sc->ciss_max_logical_bus; i++) {
|
||||
for (j = 0; j < CISS_MAX_LOGICAL; j++) {
|
||||
ciss_printf(sc, "LOGICAL DRIVE %d: ", i);
|
||||
ciss_print_ldrive(sc, &sc->ciss_logical[i][j]);
|
||||
}
|
||||
}
|
||||
|
||||
/* XXX Should physical drives be printed out here? */
|
||||
|
||||
for (i = 1; i < sc->ciss_max_requests; i++)
|
||||
ciss_print_request(sc->ciss_request + i);
|
||||
}
|
||||
|
@ -59,6 +59,13 @@ union ciss_device_address
|
||||
#define CISS_HDR_ADDRESS_MODE_LOGICAL 0x1
|
||||
#define CISS_HDR_ADDRESS_MODE_MASK_PERIPHERAL 0x3
|
||||
|
||||
#define CISS_EXTRA_MODE2(extra) ((extra & 0xc0000000) >> 30)
|
||||
#define CISS_EXTRA_BUS2(extra) ((extra & 0x3f000000) >> 24)
|
||||
#define CISS_EXTRA_TARGET2(extra) ((extra & 0x00ff0000) >> 16)
|
||||
#define CISS_EXTRA_MODE3(extra) ((extra & 0x0000c000) >> 14)
|
||||
#define CISS_EXTRA_BUS3(extra) ((extra & 0x00003f00) >> 8)
|
||||
#define CISS_EXTRA_TARGET3(extra) ((extra & 0x000000ff))
|
||||
|
||||
struct ciss_header
|
||||
{
|
||||
u_int8_t :8; /* reserved */
|
||||
|
@ -166,6 +166,22 @@ struct ciss_ldrive
|
||||
char cl_name[16]; /* device name */
|
||||
};
|
||||
|
||||
/*
|
||||
* Per-physical-drive data
|
||||
*/
|
||||
struct ciss_pdrive
|
||||
{
|
||||
union ciss_device_address cp_address;
|
||||
int cp_online;
|
||||
};
|
||||
|
||||
#define CISS_PHYSICAL_SHIFT 5
|
||||
#define CISS_PHYSICAL_BASE (1 << CISS_PHYSICAL_SHIFT)
|
||||
#define CISS_MAX_PHYSTGT 15
|
||||
|
||||
#define CISS_IS_PHYSICAL(bus) (bus >= CISS_PHYSICAL_BASE)
|
||||
#define CISS_CAM_TO_PBUS(bus) (bus - CISS_PHYSICAL_BASE)
|
||||
|
||||
/*
|
||||
* Per-adapter data
|
||||
*/
|
||||
@ -212,8 +228,11 @@ struct ciss_softc
|
||||
struct ciss_request *ciss_periodic_notify; /* notify callback request */
|
||||
|
||||
struct ciss_ldrive **ciss_logical;
|
||||
struct ciss_pdrive **ciss_physical;
|
||||
union ciss_device_address *ciss_controllers; /* controller address */
|
||||
int ciss_max_bus_number; /* maximum bus number */
|
||||
int ciss_max_logical_bus;
|
||||
int ciss_max_physical_bus;
|
||||
|
||||
struct cam_devq *ciss_cam_devq;
|
||||
struct cam_sim **ciss_cam_sim;
|
||||
|
Loading…
Reference in New Issue
Block a user