summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/cam/cam_xpt.c119
1 files changed, 111 insertions, 8 deletions
diff --git a/sys/cam/cam_xpt.c b/sys/cam/cam_xpt.c
index 28bcd8e..2d887bb 100644
--- a/sys/cam/cam_xpt.c
+++ b/sys/cam/cam_xpt.c
@@ -682,6 +682,18 @@ static struct cdevsw xpt_cdevsw = {
static struct intr_config_hook *xpt_config_hook;
+static void dead_sim_action(struct cam_sim *sim, union ccb *ccb);
+static void dead_sim_poll(struct cam_sim *sim);
+
+/* Dummy SIM that is used when the real one has gone. */
+static struct cam_sim cam_dead_sim = {
+ .sim_action = dead_sim_action,
+ .sim_poll = dead_sim_poll,
+ .sim_name = "dead_sim",
+};
+
+#define SIM_DEAD(sim) ((sim) == &cam_dead_sim)
+
/* Registered busses */
static TAILQ_HEAD(,cam_eb) xpt_busses;
static u_int bus_generation;
@@ -3055,12 +3067,22 @@ xpt_action(union ccb *start_ccb)
case XPT_ENG_EXEC:
{
struct cam_path *path;
+ struct cam_sim *sim;
int s;
int runq;
path = start_ccb->ccb_h.path;
s = splsoftcam();
+ sim = path->bus->sim;
+ if (SIM_DEAD(sim)) {
+ /* The SIM has gone; just execute the CCB directly. */
+ cam_ccbq_send_ccb(&path->device->ccbq, start_ccb);
+ (*(sim->sim_action))(sim, start_ccb);
+ splx(s);
+ break;
+ }
+
cam_ccbq_insert_ccb(&path->device->ccbq, start_ccb);
if (path->device->qfrozen_cnt == 0)
runq = xpt_schedule_dev_sendq(path->bus, path->device);
@@ -3641,8 +3663,8 @@ xpt_polled_action(union ccb *start_ccb)
dev->ccbq.devq_openings--;
dev->ccbq.dev_openings--;
- while((devq->send_openings <= 0 || dev->ccbq.dev_openings < 0)
- && (--timeout > 0)) {
+ while(((devq != NULL && devq->send_openings <= 0) ||
+ dev->ccbq.dev_openings < 0) && (--timeout > 0)) {
DELAY(1000);
(*(sim->sim_poll))(sim);
camisr(&cam_bioq);
@@ -3684,6 +3706,7 @@ void
xpt_schedule(struct cam_periph *perph, u_int32_t new_priority)
{
struct cam_ed *device;
+ union ccb *work_ccb;
int s;
int runq;
@@ -3702,6 +3725,16 @@ xpt_schedule(struct cam_periph *perph, u_int32_t new_priority)
new_priority);
}
runq = 0;
+ } else if (SIM_DEAD(perph->path->bus->sim)) {
+ /* The SIM is gone so just call periph_start directly. */
+ work_ccb = xpt_get_ccb(perph->path->device);
+ splx(s);
+ if (work_ccb == NULL)
+ return; /* XXX */
+ xpt_setup_ccb(&work_ccb->ccb_h, perph->path, new_priority);
+ perph->pinfo.priority = new_priority;
+ perph->periph_start(perph, work_ccb);
+ return;
} else {
/* New entry on the queue */
CAM_DEBUG(perph->path, CAM_DEBUG_SUBTRACE,
@@ -4337,6 +4370,10 @@ xpt_release_ccb(union ccb *free_ccb)
} else {
SLIST_INSERT_HEAD(&ccb_freeq, &free_ccb->ccb_h, xpt_links.sle);
}
+ if (bus->sim->devq == NULL) {
+ splx(s);
+ return;
+ }
bus->sim->devq->alloc_openings++;
bus->sim->devq->alloc_active--;
/* XXX Turn this into an inline function - xpt_run_device?? */
@@ -4422,6 +4459,12 @@ int32_t
xpt_bus_deregister(path_id_t pathid)
{
struct cam_path bus_path;
+ struct cam_ed *device;
+ struct cam_ed_qinfo *qinfo;
+ struct cam_devq *devq;
+ struct cam_periph *periph;
+ struct cam_sim *ccbsim;
+ union ccb *work_ccb;
cam_status status;
GIANT_REQUIRED;
@@ -4433,11 +4476,51 @@ xpt_bus_deregister(path_id_t pathid)
xpt_async(AC_LOST_DEVICE, &bus_path, NULL);
xpt_async(AC_PATH_DEREGISTERED, &bus_path, NULL);
-
+
+ /* The SIM may be gone, so use a dummy SIM for any stray operations. */
+ devq = bus_path.bus->sim->devq;
+ bus_path.bus->sim = &cam_dead_sim;
+
+ /* Execute any pending operations now. */
+ while ((qinfo = (struct cam_ed_qinfo *)camq_remove(&devq->send_queue,
+ CAMQ_HEAD)) != NULL ||
+ (qinfo = (struct cam_ed_qinfo *)camq_remove(&devq->alloc_queue,
+ CAMQ_HEAD)) != NULL) {
+ do {
+ device = qinfo->device;
+ work_ccb = cam_ccbq_peek_ccb(&device->ccbq, CAMQ_HEAD);
+ if (work_ccb != NULL) {
+ devq->active_dev = device;
+ cam_ccbq_remove_ccb(&device->ccbq, work_ccb);
+ cam_ccbq_send_ccb(&device->ccbq, work_ccb);
+ ccbsim = work_ccb->ccb_h.path->bus->sim;
+ (*(ccbsim->sim_action))(ccbsim, work_ccb);
+ }
+
+ periph = (struct cam_periph *)camq_remove(&device->drvq,
+ CAMQ_HEAD);
+ if (periph != NULL)
+ xpt_schedule(periph, periph->pinfo.priority);
+ } while (work_ccb != NULL || periph != NULL);
+ }
+
+ /* Make sure all completed CCBs are processed. */
+ while (!TAILQ_EMPTY(&cam_bioq)) {
+ camisr(&cam_bioq);
+
+ /* Repeat the async's for the benefit of any new devices. */
+ xpt_async(AC_LOST_DEVICE, &bus_path, NULL);
+ xpt_async(AC_PATH_DEREGISTERED, &bus_path, NULL);
+ }
+
/* Release the reference count held while registered. */
xpt_release_bus(bus_path.bus);
xpt_release_path(&bus_path);
+ /* Recheck for more completed CCBs. */
+ while (!TAILQ_EMPTY(&cam_bioq))
+ camisr(&cam_bioq);
+
return (CAM_REQ_CMP);
}
@@ -5021,6 +5104,9 @@ xpt_alloc_device(struct cam_eb *bus, struct cam_et *target, lun_id_t lun_id)
struct cam_devq *devq;
cam_status status;
+ if (SIM_DEAD(bus->sim))
+ return (NULL);
+
/* Make space for us in the device queue on our bus */
devq = bus->sim->devq;
status = cam_devq_resize(devq, devq->alloc_queue.array_size + 1);
@@ -5131,9 +5217,11 @@ xpt_release_device(struct cam_eb *bus, struct cam_et *target,
TAILQ_REMOVE(&target->ed_entries, device,links);
target->generation++;
xpt_max_ccbs -= device->ccbq.devq_openings;
- /* Release our slot in the devq */
- devq = bus->sim->devq;
- cam_devq_resize(devq, devq->alloc_queue.array_size - 1);
+ if (!SIM_DEAD(bus->sim)) {
+ /* Release our slot in the devq */
+ devq = bus->sim->devq;
+ cam_devq_resize(devq, devq->alloc_queue.array_size - 1);
+ }
splx(s);
camq_fini(&device->drvq);
camq_fini(&device->ccbq.queue);
@@ -7096,8 +7184,10 @@ camisr(void *V_queue)
s = splcam();
cam_ccbq_ccb_done(&dev->ccbq, (union ccb *)ccb_h);
- ccb_h->path->bus->sim->devq->send_active--;
- ccb_h->path->bus->sim->devq->send_openings++;
+ if (!SIM_DEAD(ccb_h->path->bus->sim)) {
+ ccb_h->path->bus->sim->devq->send_active--;
+ ccb_h->path->bus->sim->devq->send_openings++;
+ }
splx(s);
if (((dev->flags & CAM_DEV_REL_ON_COMPLETE) != 0
@@ -7145,3 +7235,16 @@ camisr(void *V_queue)
}
splx(s);
}
+
+static void
+dead_sim_action(struct cam_sim *sim, union ccb *ccb)
+{
+
+ ccb->ccb_h.status = CAM_DEV_NOT_THERE;
+ xpt_done(ccb);
+}
+
+static void
+dead_sim_poll(struct cam_sim *sim)
+{
+}
OpenPOWER on IntegriCloud