summaryrefslogtreecommitdiffstats
path: root/sys/cam
diff options
context:
space:
mode:
authormav <mav@FreeBSD.org>2010-01-28 08:41:30 +0000
committermav <mav@FreeBSD.org>2010-01-28 08:41:30 +0000
commit72062fdcece91a123423691068781de9366fbfaa (patch)
treed7388e60da90bf39b478369ea46d12722c323f78 /sys/cam
parent973b5fa5f2d400701ce9699f4118bd6ccc5a418c (diff)
downloadFreeBSD-src-72062fdcece91a123423691068781de9366fbfaa.zip
FreeBSD-src-72062fdcece91a123423691068781de9366fbfaa.tar.gz
MFp4: Large set of CAM inprovements.
- Unify bus reset/probe sequence. Whenever bus attached at boot or later, CAM will automatically reset and scan it. It allows to remove duplicate code from many drivers. - Any bus, attached before CAM completed it's boot-time initialization, will equally join to the process, delaying boot if needed. - New kern.cam.boot_delay loader tunable should help controllers that are still unable to register their buses in time (such as slow USB/ PCCard/ CardBus devices), by adding one more event to wait on boot. - To allow synchronization between different CAM levels, concept of requests priorities was extended. Priorities now split between several "run levels". Device can be freezed at specified level, allowing higher priority requests to pass. For example, no payload requests allowed, until PMP driver enable port. ATA XPT negotiate transfer parameters, periph driver configure caching and so on. - Frozen requests are no more counted by request allocation scheduler. It fixes deadlocks, when frozen low priority payload requests occupying slots, required by higher levels to manage theit execution. - Two last changes were holding proper ATA reinitialization and error recovery implementation. Now it is done: SATA controllers and Port Multipliers now implement automatic hot-plug and should correctly recover from timeouts and bus resets. - Improve SCSI error recovery for devices on buses without automatic sense reporting, such as ATAPI or USB. For example, it allows CAM to wait, while CD drive loads disk, instead of immediately return error status. - Decapitalize diagnostic messages and make them more readable and sensible. - Teach PMP driver to limit maximum speed on fan-out ports. - Make boot wait for PMP scan completes, and make rescan more reliable. - Fix pass driver, to return CCB to user level in case of error. - Increase number of retries in cd driver, as device may return several UAs.
Diffstat (limited to 'sys/cam')
-rw-r--r--sys/cam/ata/ata_all.c6
-rw-r--r--sys/cam/ata/ata_da.c2
-rw-r--r--sys/cam/ata/ata_pmp.c150
-rw-r--r--sys/cam/ata/ata_xpt.c121
-rw-r--r--sys/cam/cam.c6
-rw-r--r--sys/cam/cam.h25
-rw-r--r--sys/cam/cam_ccb.h7
-rw-r--r--sys/cam/cam_periph.c389
-rw-r--r--sys/cam/cam_periph.h6
-rw-r--r--sys/cam/cam_queue.h105
-rw-r--r--sys/cam/cam_sim.c3
-rw-r--r--sys/cam/cam_xpt.c660
-rw-r--r--sys/cam/cam_xpt.h5
-rw-r--r--sys/cam/cam_xpt_internal.h1
-rw-r--r--sys/cam/cam_xpt_periph.h3
-rw-r--r--sys/cam/cam_xpt_sim.h8
-rw-r--r--sys/cam/scsi/scsi_all.c59
-rw-r--r--sys/cam/scsi/scsi_cd.c48
-rw-r--r--sys/cam/scsi/scsi_ch.c2
-rw-r--r--sys/cam/scsi/scsi_da.c2
-rw-r--r--sys/cam/scsi/scsi_low.c36
-rw-r--r--sys/cam/scsi/scsi_pass.c12
-rw-r--r--sys/cam/scsi/scsi_xpt.c65
23 files changed, 909 insertions, 812 deletions
diff --git a/sys/cam/ata/ata_all.c b/sys/cam/ata/ata_all.c
index 25daea4..b2db7a0 100644
--- a/sys/cam/ata/ata_all.c
+++ b/sys/cam/ata/ata_all.c
@@ -198,7 +198,7 @@ ata_command_sbuf(struct ccb_ataio *ataio, struct sbuf *sb)
{
char cmd_str[(12 * 3) + 1];
- sbuf_printf(sb, "CMD: %s: %s",
+ sbuf_printf(sb, "%s. ACB: %s",
ata_op_string(&ataio->cmd),
ata_cmd_string(&ataio->cmd, cmd_str, sizeof(cmd_str)));
@@ -212,7 +212,7 @@ int
ata_status_sbuf(struct ccb_ataio *ataio, struct sbuf *sb)
{
- sbuf_printf(sb, "ATA Status: %02x (%s%s%s%s%s%s%s%s)",
+ sbuf_printf(sb, "ATA status: %02x (%s%s%s%s%s%s%s%s)",
ataio->res.status,
(ataio->res.status & 0x80) ? "BSY " : "",
(ataio->res.status & 0x40) ? "DRDY " : "",
@@ -223,7 +223,7 @@ ata_status_sbuf(struct ccb_ataio *ataio, struct sbuf *sb)
(ataio->res.status & 0x02) ? "IDX " : "",
(ataio->res.status & 0x01) ? "ERR" : "");
if (ataio->res.status & 1) {
- sbuf_printf(sb, ", Error: %02x (%s%s%s%s%s%s%s%s)",
+ sbuf_printf(sb, ", error: %02x (%s%s%s%s%s%s%s%s)",
ataio->res.error,
(ataio->res.error & 0x80) ? "ICRC " : "",
(ataio->res.error & 0x40) ? "UNC " : "",
diff --git a/sys/cam/ata/ata_da.c b/sys/cam/ata/ata_da.c
index 8d49309..3408b4f 100644
--- a/sys/cam/ata/ata_da.c
+++ b/sys/cam/ata/ata_da.c
@@ -689,7 +689,7 @@ adaregister(struct cam_periph *periph, void *arg)
/* Check if the SIM does not want queued commands */
bzero(&cpi, sizeof(cpi));
- xpt_setup_ccb(&cpi.ccb_h, periph->path, CAM_PRIORITY_NORMAL);
+ xpt_setup_ccb(&cpi.ccb_h, periph->path, CAM_PRIORITY_NONE);
cpi.ccb_h.func_code = XPT_PATH_INQ;
xpt_action((union ccb *)&cpi);
if (cpi.ccb_h.status != CAM_REQ_CMP ||
diff --git a/sys/cam/ata/ata_pmp.c b/sys/cam/ata/ata_pmp.c
index 8c2e1bf..1b8d9d5 100644
--- a/sys/cam/ata/ata_pmp.c
+++ b/sys/cam/ata/ata_pmp.c
@@ -98,6 +98,9 @@ struct pmp_softc {
int reset;
int frozen;
int restart;
+ int events;
+#define PMP_EV_RESET 1
+#define PMP_EV_RESCAN 2
union ccb saved_ccb;
struct task sysctl_task;
struct sysctl_ctx_list sysctl_ctx;
@@ -179,7 +182,8 @@ pmpfreeze(struct cam_periph *periph, int mask)
i, 0) == CAM_REQ_CMP) {
softc->frozen |= (1 << i);
xpt_acquire_device(dpath->device);
- cam_freeze_devq(dpath);
+ cam_freeze_devq_arg(dpath,
+ RELSIM_RELEASE_RUNLEVEL, CAM_RL_BUS + 1);
xpt_free_path(dpath);
}
}
@@ -200,7 +204,8 @@ pmprelease(struct cam_periph *periph, int mask)
xpt_path_path_id(periph->path),
i, 0) == CAM_REQ_CMP) {
softc->frozen &= ~(1 << i);
- cam_release_devq(dpath, 0, 0, 0, FALSE);
+ cam_release_devq(dpath,
+ RELSIM_RELEASE_RUNLEVEL, 0, CAM_RL_BUS + 1, FALSE);
xpt_release_device(dpath->device);
xpt_free_path(dpath);
}
@@ -298,19 +303,20 @@ pmpasync(void *callback_arg, u_int32_t code,
case AC_BUS_RESET:
softc = (struct pmp_softc *)periph->softc;
cam_periph_async(periph, code, path, arg);
- if (code == AC_SCSI_AEN && softc->state != PMP_STATE_NORMAL &&
- softc->state != PMP_STATE_SCAN)
- break;
- if (softc->state != PMP_STATE_SCAN)
- pmpfreeze(periph, softc->found);
+ if (code == AC_SCSI_AEN)
+ softc->events |= PMP_EV_RESCAN;
else
- pmpfreeze(periph, softc->found & ~(1 << softc->pm_step));
+ softc->events |= PMP_EV_RESET;
+ if (code == AC_SCSI_AEN && softc->state != PMP_STATE_NORMAL)
+ break;
+ xpt_hold_boot();
+ pmpfreeze(periph, softc->found);
if (code == AC_SENT_BDR || code == AC_BUS_RESET)
softc->found = 0; /* We have to reset everything. */
if (softc->state == PMP_STATE_NORMAL) {
- softc->state = PMP_STATE_PORTS;
+ softc->state = PMP_STATE_PRECONFIG;
cam_periph_acquire(periph);
- xpt_schedule(periph, CAM_PRIORITY_BUS);
+ xpt_schedule(periph, CAM_PRIORITY_DEV);
} else
softc->restart = 1;
break;
@@ -353,7 +359,6 @@ static cam_status
pmpregister(struct cam_periph *periph, void *arg)
{
struct pmp_softc *softc;
- struct ccb_pathinq cpi;
struct ccb_getdev *cgd;
cgd = (struct ccb_getdev *)arg;
@@ -377,16 +382,8 @@ pmpregister(struct cam_periph *periph, void *arg)
}
periph->softc = softc;
- softc->state = PMP_STATE_PORTS;
softc->pm_pid = ((uint32_t *)&cgd->ident_data)[0];
softc->pm_prv = ((uint32_t *)&cgd->ident_data)[1];
-
- /* Check if the SIM does not want queued commands */
- bzero(&cpi, sizeof(cpi));
- xpt_setup_ccb(&cpi.ccb_h, periph->path, CAM_PRIORITY_NORMAL);
- cpi.ccb_h.func_code = XPT_PATH_INQ;
- xpt_action((union ccb *)&cpi);
-
TASK_INIT(&softc->sysctl_task, 0, pmpsysctlinit, periph);
xpt_announce_periph(periph, NULL);
@@ -408,7 +405,10 @@ pmpregister(struct cam_periph *periph, void *arg)
* the end of probe.
*/
(void)cam_periph_acquire(periph);
- xpt_schedule(periph, CAM_PRIORITY_BUS);
+ xpt_hold_boot();
+ softc->state = PMP_STATE_PORTS;
+ softc->events = PMP_EV_RESCAN;
+ xpt_schedule(periph, CAM_PRIORITY_DEV);
return(CAM_REQ_CMP);
}
@@ -416,17 +416,35 @@ pmpregister(struct cam_periph *periph, void *arg)
static void
pmpstart(struct cam_periph *periph, union ccb *start_ccb)
{
+ struct ccb_trans_settings cts;
struct ccb_ataio *ataio;
struct pmp_softc *softc;
+ struct cam_path *dpath;
+ int revision = 0;
softc = (struct pmp_softc *)periph->softc;
ataio = &start_ccb->ataio;
if (softc->restart) {
softc->restart = 0;
- softc->state = PMP_STATE_PORTS;
+ softc->state = min(softc->state, PMP_STATE_PRECONFIG);
+ }
+ /* Fetch user wanted device speed. */
+ if (softc->state == PMP_STATE_RESET ||
+ softc->state == PMP_STATE_CONNECT) {
+ if (xpt_create_path(&dpath, periph,
+ xpt_path_path_id(periph->path),
+ softc->pm_step, 0) == CAM_REQ_CMP) {
+ bzero(&cts, sizeof(cts));
+ xpt_setup_ccb(&cts.ccb_h, dpath, CAM_PRIORITY_NONE);
+ cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
+ cts.type = CTS_TYPE_USER_SETTINGS;
+ xpt_action((union ccb *)&cts);
+ if (cts.xport_specific.sata.valid & CTS_SATA_VALID_REVISION)
+ revision = cts.xport_specific.sata.revision;
+ xpt_free_path(dpath);
+ }
}
-
switch (softc->state) {
case PMP_STATE_PORTS:
cam_fill_ataio(ataio,
@@ -460,7 +478,8 @@ pmpstart(struct cam_periph *periph, union ccb *start_ccb)
/*dxfer_len*/0,
pmp_default_timeout * 1000);
ata_pm_write_cmd(ataio, 2, softc->pm_step,
- (softc->found & (1 << softc->pm_step)) ? 0 : 1);
+ (revision << 4) |
+ ((softc->found & (1 << softc->pm_step)) ? 0 : 1));
break;
case PMP_STATE_CONNECT:
cam_fill_ataio(ataio,
@@ -471,7 +490,8 @@ pmpstart(struct cam_periph *periph, union ccb *start_ccb)
/*data_ptr*/NULL,
/*dxfer_len*/0,
pmp_default_timeout * 1000);
- ata_pm_write_cmd(ataio, 2, softc->pm_step, 0);
+ ata_pm_write_cmd(ataio, 2, softc->pm_step,
+ (revision << 4));
break;
case PMP_STATE_CHECK:
cam_fill_ataio(ataio,
@@ -519,9 +539,9 @@ pmpdone(struct cam_periph *periph, union ccb *done_ccb)
struct ccb_trans_settings cts;
struct pmp_softc *softc;
struct ccb_ataio *ataio;
- union ccb *work_ccb;
struct cam_path *path, *dpath;
u_int32_t priority, res;
+ int i;
softc = (struct pmp_softc *)periph->softc;
ataio = &done_ccb->ataio;
@@ -547,16 +567,8 @@ pmpdone(struct cam_periph *periph, union ccb *done_ccb)
if (softc->restart) {
softc->restart = 0;
- if (softc->state == PMP_STATE_SCAN) {
- pmpfreeze(periph, 1 << softc->pm_step);
- work_ccb = done_ccb;
- done_ccb = (union ccb*)work_ccb->ccb_h.ppriv_ptr0;
- /* Free the current request path- we're done with it. */
- xpt_free_path(work_ccb->ccb_h.path);
- xpt_free_ccb(work_ccb);
- }
xpt_release_ccb(done_ccb);
- softc->state = PMP_STATE_PORTS;
+ softc->state = min(softc->state, PMP_STATE_PRECONFIG);
xpt_schedule(periph, priority);
return;
}
@@ -645,7 +657,7 @@ pmpdone(struct cam_periph *periph, union ccb *done_ccb)
xpt_path_path_id(periph->path),
softc->pm_step, 0) == CAM_REQ_CMP) {
bzero(&cts, sizeof(cts));
- xpt_setup_ccb(&cts.ccb_h, dpath, CAM_PRIORITY_NORMAL);
+ xpt_setup_ccb(&cts.ccb_h, dpath, CAM_PRIORITY_NONE);
cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS;
cts.type = CTS_TYPE_CURRENT_SETTINGS;
cts.xport_specific.sata.revision = (res & 0x0f0) >> 4;
@@ -705,53 +717,43 @@ pmpdone(struct cam_periph *periph, union ccb *done_ccb)
xpt_schedule(periph, priority);
return;
case PMP_STATE_CONFIG:
- if (softc->found) {
- softc->pm_step = 0;
- softc->state = PMP_STATE_SCAN;
- work_ccb = xpt_alloc_ccb_nowait();
- if (work_ccb != NULL)
- goto do_scan;
- xpt_release_ccb(done_ccb);
+ for (i = 0; i < softc->pm_ports; i++) {
+ union ccb *ccb;
+
+ if ((softc->found & (1 << i)) == 0)
+ continue;
+ if (xpt_create_path(&dpath, periph,
+ xpt_path_path_id(periph->path),
+ i, 0) != CAM_REQ_CMP) {
+ printf("pmpdone: xpt_create_path failed"
+ ", bus scan halted\n");
+ xpt_free_ccb(done_ccb);
+ goto done;
+ }
+ /* If we did hard reset to this device, inform XPT. */
+ if ((softc->reset & softc->found & (1 << i)) != 0)
+ xpt_async(AC_SENT_BDR, dpath, NULL);
+ /* If rescan requested, scan this device. */
+ if (softc->events & PMP_EV_RESCAN) {
+ ccb = xpt_alloc_ccb_nowait();
+ if (ccb == NULL) {
+ xpt_free_path(dpath);
+ goto done;
+ }
+ xpt_setup_ccb(&ccb->ccb_h, dpath, CAM_PRIORITY_XPT);
+ xpt_rescan(ccb);
+ } else
+ xpt_free_path(dpath);
}
break;
- case PMP_STATE_SCAN:
- work_ccb = done_ccb;
- done_ccb = (union ccb*)work_ccb->ccb_h.ppriv_ptr0;
- /* Free the current request path- we're done with it. */
- xpt_free_path(work_ccb->ccb_h.path);
- softc->pm_step++;
-do_scan:
- while (softc->pm_step < softc->pm_ports &&
- (softc->found & (1 << softc->pm_step)) == 0) {
- softc->pm_step++;
- }
- if (softc->pm_step >= softc->pm_ports) {
- xpt_free_ccb(work_ccb);
- break;
- }
- if (xpt_create_path(&dpath, periph,
- done_ccb->ccb_h.path_id,
- softc->pm_step, 0) != CAM_REQ_CMP) {
- printf("pmpdone: xpt_create_path failed"
- ", bus scan halted\n");
- xpt_free_ccb(work_ccb);
- break;
- }
- xpt_setup_ccb(&work_ccb->ccb_h, dpath,
- done_ccb->ccb_h.pinfo.priority);
- work_ccb->ccb_h.func_code = XPT_SCAN_LUN;
- work_ccb->ccb_h.cbfcnp = pmpdone;
- work_ccb->ccb_h.ppriv_ptr0 = done_ccb;
- work_ccb->crcn.flags = done_ccb->crcn.flags;
- xpt_action(work_ccb);
- pmprelease(periph, 1 << softc->pm_step);
- return;
default:
break;
}
done:
xpt_release_ccb(done_ccb);
softc->state = PMP_STATE_NORMAL;
+ softc->events = 0;
+ xpt_release_boot();
pmprelease(periph, -1);
cam_periph_release_locked(periph);
}
diff --git a/sys/cam/ata/ata_xpt.c b/sys/cam/ata/ata_xpt.c
index 99cf314..bff0340 100644
--- a/sys/cam/ata/ata_xpt.c
+++ b/sys/cam/ata/ata_xpt.c
@@ -130,6 +130,7 @@ typedef struct {
u_int8_t digest[16];
uint32_t pm_pid;
uint32_t pm_prv;
+ int restart;
struct cam_periph *periph;
} probe_softc;
@@ -231,15 +232,11 @@ proberegister(struct cam_periph *periph, void *arg)
if (status != CAM_REQ_CMP) {
return (status);
}
-
-
/*
- * Ensure we've waited at least a bus settle
- * delay before attempting to probe the device.
- * For HBAs that don't do bus resets, this won't make a difference.
+ * Ensure nobody slip in until probe finish.
*/
- cam_periph_freeze_after_event(periph, &periph->path->bus->last_reset,
- scsi_delay);
+ cam_freeze_devq_arg(periph->path,
+ RELSIM_RELEASE_RUNLEVEL, CAM_RL_XPT + 1);
probeschedule(periph);
return(CAM_REQ_CMP);
}
@@ -247,17 +244,12 @@ 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, CAM_PRIORITY_NORMAL);
- cpi.ccb_h.func_code = XPT_PATH_INQ;
- xpt_action((union ccb *)&cpi);
-
if ((periph->path->device->flags & CAM_DEV_UNCONFIGURED) ||
periph->path->device->protocol == PROTO_SATAPM)
PROBE_SET_ACTION(softc, PROBE_RESET);
@@ -269,7 +261,7 @@ probeschedule(struct cam_periph *periph)
else
softc->flags &= ~PROBE_NO_ANNOUNCE;
- xpt_schedule(periph, ccb->ccb_h.pinfo.priority);
+ xpt_schedule(periph, CAM_PRIORITY_XPT);
}
static void
@@ -290,6 +282,14 @@ probestart(struct cam_periph *periph, union ccb *start_ccb)
csio = &start_ccb->csio;
ident_buf = &periph->path->device->ident_data;
+ if (softc->restart) {
+ softc->restart = 0;
+ if ((path->device->flags & CAM_DEV_UNCONFIGURED) ||
+ path->device->protocol == PROTO_SATAPM)
+ softc->action = PROBE_RESET;
+ else
+ softc->action = PROBE_IDENTIFY;
+ }
switch (softc->action) {
case PROBE_RESET:
cam_fill_ataio(ataio,
@@ -299,7 +299,7 @@ probestart(struct cam_periph *periph, union ccb *start_ccb)
0,
/*data_ptr*/NULL,
/*dxfer_len*/0,
- (start_ccb->ccb_h.target_id == 15 ? 3 : 15) * 1000);
+ 15 * 1000);
ata_reset_cmd(ataio);
break;
case PROBE_IDENTIFY:
@@ -339,7 +339,7 @@ probestart(struct cam_periph *periph, union ccb *start_ccb)
mode = 0;
/* Fetch user modes from SIM. */
bzero(&cts, sizeof(cts));
- xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NORMAL);
+ xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE);
cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
cts.type = CTS_TYPE_USER_SETTINGS;
xpt_action((union ccb *)&cts);
@@ -355,7 +355,7 @@ negotiate:
wantmode = mode = ata_max_mode(ident_buf, mode);
/* Report modes to SIM. */
bzero(&cts, sizeof(cts));
- xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NORMAL);
+ xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE);
cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS;
cts.type = CTS_TYPE_CURRENT_SETTINGS;
if (path->device->transport == XPORT_ATA) {
@@ -368,7 +368,7 @@ negotiate:
xpt_action((union ccb *)&cts);
/* Fetch current modes from SIM. */
bzero(&cts, sizeof(cts));
- xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NORMAL);
+ xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE);
cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
cts.type = CTS_TYPE_CURRENT_SETTINGS;
xpt_action((union ccb *)&cts);
@@ -400,7 +400,7 @@ negotiate:
bytecount = 8192; /* SATA maximum */
/* Fetch user bytecount from SIM. */
bzero(&cts, sizeof(cts));
- xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NORMAL);
+ xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE);
cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
cts.type = CTS_TYPE_USER_SETTINGS;
xpt_action((union ccb *)&cts);
@@ -416,7 +416,7 @@ negotiate:
bytecount / ata_logical_sector_size(ident_buf)));
/* Report bytecount to SIM. */
bzero(&cts, sizeof(cts));
- xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NORMAL);
+ xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE);
cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS;
cts.type = CTS_TYPE_CURRENT_SETTINGS;
if (path->device->transport == XPORT_ATA) {
@@ -431,7 +431,7 @@ negotiate:
xpt_action((union ccb *)&cts);
/* Fetch current bytecount from SIM. */
bzero(&cts, sizeof(cts));
- xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NORMAL);
+ xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE);
cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
cts.type = CTS_TYPE_CURRENT_SETTINGS;
xpt_action((union ccb *)&cts);
@@ -462,7 +462,7 @@ negotiate:
bytecount = 8192; /* SATA maximum */
/* Fetch user bytecount from SIM. */
bzero(&cts, sizeof(cts));
- xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NORMAL);
+ xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE);
cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
cts.type = CTS_TYPE_USER_SETTINGS;
xpt_action((union ccb *)&cts);
@@ -482,7 +482,7 @@ negotiate:
}
/* Report bytecount to SIM. */
bzero(&cts, sizeof(cts));
- xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NORMAL);
+ xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE);
cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS;
cts.type = CTS_TYPE_CURRENT_SETTINGS;
if (path->device->transport == XPORT_ATA) {
@@ -560,7 +560,7 @@ proberequestdefaultnegotiation(struct cam_periph *periph)
{
struct ccb_trans_settings cts;
- xpt_setup_ccb(&cts.ccb_h, periph->path, CAM_PRIORITY_NORMAL);
+ xpt_setup_ccb(&cts.ccb_h, periph->path, CAM_PRIORITY_NONE);
cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
cts.type = CTS_TYPE_USER_SETTINGS;
xpt_action((union ccb *)&cts);
@@ -582,7 +582,7 @@ proberequestbackoff(struct cam_periph *periph, struct cam_ed *device)
struct ccb_trans_settings_spi *spi;
memset(&cts, 0, sizeof (cts));
- xpt_setup_ccb(&cts.ccb_h, periph->path, CAM_PRIORITY_NORMAL);
+ xpt_setup_ccb(&cts.ccb_h, periph->path, CAM_PRIORITY_NONE);
cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
cts.type = CTS_TYPE_CURRENT_SETTINGS;
xpt_action((union ccb *)&cts);
@@ -739,7 +739,7 @@ noerror:
done_ccb->ccb_h.target_id == 15) {
/* Report SIM that PM is present. */
bzero(&cts, sizeof(cts));
- xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NORMAL);
+ xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE);
cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS;
cts.type = CTS_TYPE_CURRENT_SETTINGS;
cts.xport_specific.sata.pm_present = 1;
@@ -836,7 +836,7 @@ noerror:
path->bus->sim->max_tagged_dev_openings != 0) {
/* Report SIM which tags are allowed. */
bzero(&cts, sizeof(cts));
- xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NORMAL);
+ xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE);
cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS;
cts.type = CTS_TYPE_CURRENT_SETTINGS;
cts.xport_specific.sata.tags = path->device->maxtags;
@@ -957,18 +957,23 @@ noerror:
break;
}
done:
- xpt_release_ccb(done_ccb);
- done_ccb = (union ccb *)TAILQ_FIRST(&softc->request_ccbs);
- TAILQ_REMOVE(&softc->request_ccbs, &done_ccb->ccb_h, periph_links.tqe);
- done_ccb->ccb_h.status = CAM_REQ_CMP;
- done_ccb->ccb_h.ppriv_field1 = found;
- xpt_done(done_ccb);
- if (TAILQ_FIRST(&softc->request_ccbs) == NULL) {
- cam_periph_invalidate(periph);
- cam_periph_release_locked(periph);
- } else {
+ if (softc->restart) {
+ softc->restart = 0;
+ xpt_release_ccb(done_ccb);
probeschedule(periph);
+ return;
}
+ xpt_release_ccb(done_ccb);
+ while ((done_ccb = (union ccb *)TAILQ_FIRST(&softc->request_ccbs))) {
+ TAILQ_REMOVE(&softc->request_ccbs,
+ &done_ccb->ccb_h, periph_links.tqe);
+ done_ccb->ccb_h.status = found ? CAM_REQ_CMP : CAM_REQ_CMP_ERR;
+ xpt_done(done_ccb);
+ }
+ cam_release_devq(periph->path,
+ RELSIM_RELEASE_RUNLEVEL, 0, CAM_RL_XPT + 1, FALSE);
+ cam_periph_invalidate(periph);
+ cam_periph_release_locked(periph);
}
static void
@@ -1013,7 +1018,7 @@ ata_scan_bus(struct cam_periph *periph, union ccb *request_ccb)
{
struct cam_path *path;
ata_scan_bus_info *scan_info;
- union ccb *work_ccb;
+ union ccb *work_ccb, *reset_ccb;
cam_status status;
CAM_DEBUG(request_ccb->ccb_h.path, CAM_DEBUG_TRACE,
@@ -1038,6 +1043,26 @@ ata_scan_bus(struct cam_periph *periph, union ccb *request_ccb)
return;
}
+ /* We may need to reset bus first, if we haven't done it yet. */
+ if ((work_ccb->cpi.hba_inquiry &
+ (PI_WIDE_32|PI_WIDE_16|PI_SDTR_ABLE)) &&
+ !(work_ccb->cpi.hba_misc & PIM_NOBUSRESET) &&
+ !timevalisset(&request_ccb->ccb_h.path->bus->last_reset)) {
+ reset_ccb = xpt_alloc_ccb_nowait();
+ xpt_setup_ccb(&reset_ccb->ccb_h, request_ccb->ccb_h.path,
+ CAM_PRIORITY_NONE);
+ reset_ccb->ccb_h.func_code = XPT_RESET_BUS;
+ xpt_action(reset_ccb);
+ if (reset_ccb->ccb_h.status != CAM_REQ_CMP) {
+ request_ccb->ccb_h.status = reset_ccb->ccb_h.status;
+ xpt_free_ccb(reset_ccb);
+ xpt_free_ccb(work_ccb);
+ xpt_done(request_ccb);
+ return;
+ }
+ xpt_free_ccb(reset_ccb);
+ }
+
/* Save some state for use while we probe for devices */
scan_info = (ata_scan_bus_info *)
malloc(sizeof(ata_scan_bus_info), M_CAMXPT, M_NOWAIT);
@@ -1071,7 +1096,7 @@ ata_scan_bus(struct cam_periph *periph, union ccb *request_ccb)
/* If there is PMP... */
if ((scan_info->cpi->hba_inquiry & PI_SATAPM) &&
(scan_info->counter == scan_info->cpi->max_target)) {
- if (work_ccb->ccb_h.ppriv_field1 != 0) {
+ if (work_ccb->ccb_h.status == CAM_REQ_CMP) {
/* everything else willbe probed by it */
goto done;
} else {
@@ -1141,10 +1166,9 @@ ata_scan_lun(struct cam_periph *periph, struct cam_path *path,
struct cam_path *new_path;
struct cam_periph *old_periph;
- CAM_DEBUG(request_ccb->ccb_h.path, CAM_DEBUG_TRACE,
- ("xpt_scan_lun\n"));
+ CAM_DEBUG(path, CAM_DEBUG_TRACE, ("xpt_scan_lun\n"));
- xpt_setup_ccb(&cpi.ccb_h, path, CAM_PRIORITY_NORMAL);
+ xpt_setup_ccb(&cpi.ccb_h, path, CAM_PRIORITY_NONE);
cpi.ccb_h.func_code = XPT_PATH_INQ;
xpt_action((union ccb *)&cpi);
@@ -1182,7 +1206,7 @@ ata_scan_lun(struct cam_periph *periph, struct cam_path *path,
free(new_path, M_CAMXPT);
return;
}
- xpt_setup_ccb(&request_ccb->ccb_h, new_path, CAM_PRIORITY_NORMAL);
+ xpt_setup_ccb(&request_ccb->ccb_h, new_path, CAM_PRIORITY_XPT);
request_ccb->ccb_h.cbfcnp = xptscandone;
request_ccb->ccb_h.func_code = XPT_SCAN_LUN;
request_ccb->crcn.flags = flags;
@@ -1194,6 +1218,7 @@ ata_scan_lun(struct cam_periph *periph, struct cam_path *path,
softc = (probe_softc *)old_periph->softc;
TAILQ_INSERT_TAIL(&softc->request_ccbs, &request_ccb->ccb_h,
periph_links.tqe);
+ softc->restart = 1;
} else {
status = cam_periph_alloc(proberegister, NULL, probecleanup,
probestart, "aprobe",
@@ -1281,7 +1306,7 @@ ata_device_transport(struct cam_path *path)
struct ata_params *ident_buf = NULL;
/* Get transport information from the SIM */
- xpt_setup_ccb(&cpi.ccb_h, path, CAM_PRIORITY_NORMAL);
+ xpt_setup_ccb(&cpi.ccb_h, path, CAM_PRIORITY_NONE);
cpi.ccb_h.func_code = XPT_PATH_INQ;
xpt_action((union ccb *)&cpi);
@@ -1301,7 +1326,7 @@ ata_device_transport(struct cam_path *path)
ata_version(ident_buf->version_major) : cpi.transport_version;
/* Tell the controller what we think */
- xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NORMAL);
+ xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE);
cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS;
cts.type = CTS_TYPE_CURRENT_SETTINGS;
cts.transport = path->device->transport;
@@ -1429,7 +1454,7 @@ ata_set_transfer_settings(struct ccb_trans_settings *cts, struct cam_ed *device,
inq_data = &device->inq_data;
scsi = &cts->proto_specific.scsi;
- xpt_setup_ccb(&cpi.ccb_h, cts->ccb_h.path, CAM_PRIORITY_NORMAL);
+ xpt_setup_ccb(&cpi.ccb_h, cts->ccb_h.path, CAM_PRIORITY_NONE);
cpi.ccb_h.func_code = XPT_PATH_INQ;
xpt_action((union ccb *)&cpi);
@@ -1450,7 +1475,7 @@ ata_set_transfer_settings(struct ccb_trans_settings *cts, struct cam_ed *device,
* Perform sanity checking against what the
* controller and device can do.
*/
- xpt_setup_ccb(&cur_cts.ccb_h, cts->ccb_h.path, CAM_PRIORITY_NORMAL);
+ xpt_setup_ccb(&cur_cts.ccb_h, cts->ccb_h.path, CAM_PRIORITY_NONE);
cur_cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
cur_cts.type = cts->type;
xpt_action((union ccb *)&cur_cts);
@@ -1550,6 +1575,10 @@ ata_dev_async(u_int32_t async_code, struct cam_eb *bus, struct cam_et *target,
*/
ata_scan_lun(newpath.periph, &newpath,
CAM_EXPECT_INQ_CHANGE, NULL);
+ } else {
+ /* We need to reinitialize device after reset. */
+ ata_scan_lun(newpath.periph, &newpath,
+ 0, NULL);
}
xpt_release_path(&newpath);
} else if (async_code == AC_LOST_DEVICE &&
diff --git a/sys/cam/cam.c b/sys/cam/cam.c
index 85b02fb..88271b0 100644
--- a/sys/cam/cam.c
+++ b/sys/cam/cam.c
@@ -305,10 +305,10 @@ cam_error_string(struct cam_device *device, union ccb *ccb, char *str,
entry = cam_fetch_status_entry(status);
if (entry == NULL)
- sbuf_printf(&sb, "CAM Status: Unknown (%#x)\n",
+ sbuf_printf(&sb, "CAM status: Unknown (%#x)\n",
ccb->ccb_h.status);
else
- sbuf_printf(&sb, "CAM Status: %s\n",
+ sbuf_printf(&sb, "CAM status: %s\n",
entry->status_text);
}
@@ -338,7 +338,7 @@ cam_error_string(struct cam_device *device, union ccb *ccb, char *str,
if (proto_flags & CAM_ESF_PRINT_STATUS) {
sbuf_cat(&sb, path_str);
- sbuf_printf(&sb, "SCSI Status: %s\n",
+ sbuf_printf(&sb, "SCSI status: %s\n",
scsi_status_string(&ccb->csio));
}
diff --git a/sys/cam/cam.h b/sys/cam/cam.h
index 3d85264..2b3b98c 100644
--- a/sys/cam/cam.h
+++ b/sys/cam/cam.h
@@ -60,16 +60,29 @@ typedef u_int lun_id_t;
struct cam_periph;
/*
- * Priority information for a CAM structure. The generation number is
- * incremented everytime a new entry is entered into the queue giving round
- * robin per priority level scheduling.
+ * Priority information for a CAM structure.
+ */
+typedef enum {
+ CAM_RL_HOST,
+ CAM_RL_BUS,
+ CAM_RL_XPT,
+ CAM_RL_DEV,
+ CAM_RL_NORMAL,
+ CAM_RL_VALUES
+} cam_rl;
+/*
+ * The generation number is incremented everytime a new entry is entered into
+ * the queue giving round robin per priority level scheduling.
*/
typedef struct {
u_int32_t priority;
-#define CAM_PRIORITY_BUS 0
-#define CAM_PRIORITY_DEV 0
-#define CAM_PRIORITY_NORMAL 1
+#define CAM_PRIORITY_HOST ((CAM_RL_HOST << 8) + 0x80)
+#define CAM_PRIORITY_BUS ((CAM_RL_BUS << 8) + 0x80)
+#define CAM_PRIORITY_XPT ((CAM_RL_XPT << 8) + 0x80)
+#define CAM_PRIORITY_DEV ((CAM_RL_DEV << 8) + 0x80)
+#define CAM_PRIORITY_NORMAL ((CAM_RL_NORMAL << 8) + 0x80)
#define CAM_PRIORITY_NONE (u_int32_t)-1
+#define CAM_PRIORITY_TO_RL(x) ((x) >> 8)
u_int32_t generation;
int index;
#define CAM_UNQUEUED_INDEX -1
diff --git a/sys/cam/cam_ccb.h b/sys/cam/cam_ccb.h
index 72de564..4c5adba 100644
--- a/sys/cam/cam_ccb.h
+++ b/sys/cam/cam_ccb.h
@@ -126,7 +126,7 @@ typedef enum {
XPT_PATH_INQ = 0x04,
/* Path routing inquiry */
XPT_REL_SIMQ = 0x05,
- /* Release a frozen SIM queue */
+ /* Release a frozen device queue */
XPT_SASYNC_CB = 0x06,
/* Set Asynchronous Callback Parameters */
XPT_SDEV_TYPE = 0x07,
@@ -142,6 +142,8 @@ typedef enum {
/* Path statistics (error counts, etc.) */
XPT_GDEV_STATS = 0x0c,
/* Device statistics (error counts, etc.) */
+ XPT_FREEZE_QUEUE = 0x0d,
+ /* Freeze device queue */
/* SCSI Control Functions: 0x10->0x1F */
XPT_ABORT = 0x10,
/* Abort the specified CCB */
@@ -685,8 +687,9 @@ struct ccb_relsim {
#define RELSIM_RELEASE_AFTER_TIMEOUT 0x02
#define RELSIM_RELEASE_AFTER_CMDCMPLT 0x04
#define RELSIM_RELEASE_AFTER_QEMPTY 0x08
+#define RELSIM_RELEASE_RUNLEVEL 0x10
u_int32_t openings;
- u_int32_t release_timeout;
+ u_int32_t release_timeout; /* Abstract argument. */
u_int32_t qfrozen_cnt;
};
diff --git a/sys/cam/cam_periph.c b/sys/cam/cam_periph.c
index 9bac0f5..4c7502a 100644
--- a/sys/cam/cam_periph.c
+++ b/sys/cam/cam_periph.c
@@ -71,19 +71,20 @@ static void camperiphfree(struct cam_periph *periph);
static int camperiphscsistatuserror(union ccb *ccb,
cam_flags camflags,
u_int32_t sense_flags,
- union ccb *save_ccb,
int *openings,
u_int32_t *relsim_flags,
- u_int32_t *timeout);
+ u_int32_t *timeout,
+ const char **action_string);
static int camperiphscsisenseerror(union ccb *ccb,
cam_flags camflags,
u_int32_t sense_flags,
- union ccb *save_ccb,
int *openings,
u_int32_t *relsim_flags,
- u_int32_t *timeout);
+ u_int32_t *timeout,
+ const char **action_string);
static int nperiph_drivers;
+static int initialized = 0;
struct periph_driver **periph_drivers;
MALLOC_DEFINE(M_CAMPERIPH, "CAM periph", "CAM peripheral buffers");
@@ -99,6 +100,7 @@ TUNABLE_INT("kern.cam.periph_busy_delay", &periph_busy_delay);
void
periphdriver_register(void *data)
{
+ struct periph_driver *drv = (struct periph_driver *)data;
struct periph_driver **newdrivers, **old;
int ndrivers;
@@ -108,13 +110,30 @@ periphdriver_register(void *data)
if (periph_drivers)
bcopy(periph_drivers, newdrivers,
sizeof(*newdrivers) * nperiph_drivers);
- newdrivers[nperiph_drivers] = (struct periph_driver *)data;
+ newdrivers[nperiph_drivers] = drv;
newdrivers[nperiph_drivers + 1] = NULL;
old = periph_drivers;
periph_drivers = newdrivers;
if (old)
free(old, M_CAMPERIPH);
nperiph_drivers++;
+ /* If driver marked as early or it is late now, initialize it. */
+ if (((drv->flags & CAM_PERIPH_DRV_EARLY) != 0 && initialized > 0) ||
+ initialized > 1)
+ (*drv->init)();
+}
+
+void
+periphdriver_init(int level)
+{
+ int i, early;
+
+ initialized = max(initialized, level);
+ for (i = 0; periph_drivers[i] != NULL; i++) {
+ early = (periph_drivers[i]->flags & CAM_PERIPH_DRV_EARLY) ? 1 : 2;
+ if (early == initialized)
+ (*periph_drivers[i]->init)();
+ }
}
cam_status
@@ -915,12 +934,14 @@ cam_periph_runccb(union ccb *ccb,
} while (error == ERESTART);
- if ((ccb->ccb_h.status & CAM_DEV_QFRZN) != 0)
+ if ((ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) {
cam_release_devq(ccb->ccb_h.path,
/* relsim_flags */0,
/* openings */0,
/* timeout */0,
/* getcount_only */ FALSE);
+ ccb->ccb_h.status &= ~CAM_DEV_QFRZN;
+ }
if (ds != NULL) {
if (ccb->ccb_h.func_code == XPT_SCSI_IO) {
@@ -950,17 +971,26 @@ cam_periph_runccb(union ccb *ccb,
void
cam_freeze_devq(struct cam_path *path)
{
- struct ccb_hdr ccb_h;
- xpt_setup_ccb(&ccb_h, path, CAM_PRIORITY_NORMAL);
- ccb_h.func_code = XPT_NOOP;
- ccb_h.flags = CAM_DEV_QFREEZE;
- xpt_action((union ccb *)&ccb_h);
+ cam_freeze_devq_arg(path, 0, 0);
+}
+
+void
+cam_freeze_devq_arg(struct cam_path *path, uint32_t flags, uint32_t arg)
+{
+ struct ccb_relsim crs;
+
+ xpt_setup_ccb(&crs.ccb_h, path, CAM_PRIORITY_NONE);
+ crs.ccb_h.func_code = XPT_FREEZE_QUEUE;
+ crs.release_flags = flags;
+ crs.openings = arg;
+ crs.release_timeout = arg;
+ xpt_action((union ccb *)&crs);
}
u_int32_t
cam_release_devq(struct cam_path *path, u_int32_t relsim_flags,
- u_int32_t openings, u_int32_t timeout,
+ u_int32_t openings, u_int32_t arg,
int getcount_only)
{
struct ccb_relsim crs;
@@ -970,22 +1000,92 @@ cam_release_devq(struct cam_path *path, u_int32_t relsim_flags,
crs.ccb_h.flags = getcount_only ? CAM_DEV_QFREEZE : 0;
crs.release_flags = relsim_flags;
crs.openings = openings;
- crs.release_timeout = timeout;
+ crs.release_timeout = arg;
xpt_action((union ccb *)&crs);
return (crs.qfrozen_cnt);
}
#define saved_ccb_ptr ppriv_ptr0
+#define recovery_depth ppriv_field1
+static void
+camperiphsensedone(struct cam_periph *periph, union ccb *done_ccb)
+{
+ union ccb *saved_ccb = (union ccb *)done_ccb->ccb_h.saved_ccb_ptr;
+ cam_status status;
+ int frozen = 0;
+ u_int sense_key;
+ int depth = done_ccb->ccb_h.recovery_depth;
+
+ status = done_ccb->ccb_h.status;
+ if (status & CAM_DEV_QFRZN) {
+ frozen = 1;
+ /*
+ * Clear freeze flag now for case of retry,
+ * freeze will be dropped later.
+ */
+ done_ccb->ccb_h.status &= ~CAM_DEV_QFRZN;
+ }
+ status &= CAM_STATUS_MASK;
+ switch (status) {
+ case CAM_REQ_CMP:
+ {
+ /*
+ * If we manually retrieved sense into a CCB and got
+ * something other than "NO SENSE" send the updated CCB
+ * back to the client via xpt_done() to be processed via
+ * the error recovery code again.
+ */
+ sense_key = saved_ccb->csio.sense_data.flags;
+ sense_key &= SSD_KEY;
+ if (sense_key != SSD_KEY_NO_SENSE) {
+ saved_ccb->ccb_h.status |=
+ CAM_AUTOSNS_VALID;
+ } else {
+ saved_ccb->ccb_h.status &=
+ ~CAM_STATUS_MASK;
+ saved_ccb->ccb_h.status |=
+ CAM_AUTOSENSE_FAIL;
+ }
+ bcopy(saved_ccb, done_ccb, sizeof(union ccb));
+ xpt_free_ccb(saved_ccb);
+ break;
+ }
+ default:
+ bcopy(saved_ccb, done_ccb, sizeof(union ccb));
+ xpt_free_ccb(saved_ccb);
+ done_ccb->ccb_h.status &= ~CAM_STATUS_MASK;
+ done_ccb->ccb_h.status |= CAM_AUTOSENSE_FAIL;
+ break;
+ }
+ periph->flags &= ~CAM_PERIPH_SENSE_INPROG;
+ /*
+ * If it is the end of recovery, drop freeze, taken due to
+ * CAM_DEV_QFREEZE flag, set on recovery request.
+ */
+ if (depth == 0) {
+ cam_release_devq(done_ccb->ccb_h.path,
+ /*relsim_flags*/0,
+ /*openings*/0,
+ /*timeout*/0,
+ /*getcount_only*/0);
+ }
+ /*
+ * Copy frozen flag from recovery request if it is set there
+ * for some reason.
+ */
+ if (frozen != 0)
+ done_ccb->ccb_h.status |= CAM_DEV_QFRZN;
+ (*done_ccb->ccb_h.cbfcnp)(periph, done_ccb);
+}
+
static void
camperiphdone(struct cam_periph *periph, union ccb *done_ccb)
{
- union ccb *saved_ccb;
+ union ccb *saved_ccb, *save_ccb;
cam_status status;
int frozen = 0;
- int sense;
struct scsi_start_stop_unit *scsi_cmd;
u_int32_t relsim_flags, timeout;
- int xpt_done_ccb = FALSE;
status = done_ccb->ccb_h.status;
if (status & CAM_DEV_QFRZN) {
@@ -996,14 +1096,12 @@ camperiphdone(struct cam_periph *periph, union ccb *done_ccb)
*/
done_ccb->ccb_h.status &= ~CAM_DEV_QFRZN;
}
- sense = (status & CAM_AUTOSNS_VALID) != 0;
- status &= CAM_STATUS_MASK;
timeout = 0;
relsim_flags = 0;
saved_ccb = (union ccb *)done_ccb->ccb_h.saved_ccb_ptr;
- switch (status) {
+ switch (status & CAM_STATUS_MASK) {
case CAM_REQ_CMP:
{
/*
@@ -1012,57 +1110,19 @@ camperiphdone(struct cam_periph *periph, union ccb *done_ccb)
* the inquiry information. Many devices (mostly disks)
* don't properly report their inquiry information unless
* they are spun up.
- *
- * If we manually retrieved sense into a CCB and got
- * something other than "NO SENSE" send the updated CCB
- * back to the client via xpt_done() to be processed via
- * the error recovery code again.
*/
- if (done_ccb->ccb_h.func_code == XPT_SCSI_IO) {
- scsi_cmd = (struct scsi_start_stop_unit *)
- &done_ccb->csio.cdb_io.cdb_bytes;
-
- if (scsi_cmd->opcode == START_STOP_UNIT)
- xpt_async(AC_INQ_CHANGED,
- done_ccb->ccb_h.path, NULL);
- if (scsi_cmd->opcode == REQUEST_SENSE) {
- u_int sense_key;
-
- sense_key = saved_ccb->csio.sense_data.flags;
- sense_key &= SSD_KEY;
- if (sense_key != SSD_KEY_NO_SENSE) {
- saved_ccb->ccb_h.status |=
- CAM_AUTOSNS_VALID;
-#if 0
- xpt_print(saved_ccb->ccb_h.path,
- "Recovered Sense\n");
- scsi_sense_print(&saved_ccb->csio);
- cam_error_print(saved_ccb, CAM_ESF_ALL,
- CAM_EPF_ALL);
-#endif
- } else {
- saved_ccb->ccb_h.status &=
- ~CAM_STATUS_MASK;
- saved_ccb->ccb_h.status |=
- CAM_AUTOSENSE_FAIL;
- }
- xpt_done_ccb = TRUE;
- }
- }
- bcopy(done_ccb->ccb_h.saved_ccb_ptr, done_ccb,
- sizeof(union ccb));
-
- periph->flags &= ~CAM_PERIPH_RECOVERY_INPROG;
-
- if (xpt_done_ccb == FALSE)
- xpt_action(done_ccb);
+ scsi_cmd = (struct scsi_start_stop_unit *)
+ &done_ccb->csio.cdb_io.cdb_bytes;
- break;
+ if (scsi_cmd->opcode == START_STOP_UNIT)
+ xpt_async(AC_INQ_CHANGED,
+ done_ccb->ccb_h.path, NULL);
+ goto final;
}
case CAM_SCSI_STATUS_ERROR:
scsi_cmd = (struct scsi_start_stop_unit *)
&done_ccb->csio.cdb_io.cdb_bytes;
- if (sense != 0) {
+ if (status & CAM_AUTOSNS_VALID) {
struct ccb_getdev cgd;
struct scsi_sense_data *sense;
int error_code, sense_key, asc, ascq;
@@ -1071,7 +1131,6 @@ camperiphdone(struct cam_periph *periph, union ccb *done_ccb)
sense = &done_ccb->csio.sense_data;
scsi_extract_sense(sense, &error_code,
&sense_key, &asc, &ascq);
-
/*
* Grab the inquiry data for this device.
*/
@@ -1081,7 +1140,6 @@ camperiphdone(struct cam_periph *periph, union ccb *done_ccb)
xpt_action((union ccb *)&cgd);
err_action = scsi_error_action(&done_ccb->csio,
&cgd.inq_data, 0);
-
/*
* If the error is "invalid field in CDB",
* and the load/eject flag is set, turn the
@@ -1091,7 +1149,6 @@ camperiphdone(struct cam_periph *periph, union ccb *done_ccb)
* the load/eject flag by default for
* removable media.
*/
-
/* XXX KDM
* Should we check to see what the specific
* scsi status is?? Or does it not matter
@@ -1106,9 +1163,7 @@ camperiphdone(struct cam_periph *periph, union ccb *done_ccb)
(done_ccb->ccb_h.retry_count > 0)) {
scsi_cmd->how &= ~SSS_LOEJ;
-
xpt_action(done_ccb);
-
} else if ((done_ccb->ccb_h.retry_count > 1)
&& ((err_action & SS_MASK) != SS_FAIL)) {
@@ -1119,53 +1174,51 @@ camperiphdone(struct cam_periph *periph, union ccb *done_ccb)
* it another try unless this is an
* unretryable error.
*/
-
/* set the timeout to .5 sec */
relsim_flags =
RELSIM_RELEASE_AFTER_TIMEOUT;
timeout = 500;
-
xpt_action(done_ccb);
-
break;
-
} else {
/*
* Perform the final retry with the original
* CCB so that final error processing is
* performed by the owner of the CCB.
*/
- bcopy(done_ccb->ccb_h.saved_ccb_ptr,
- done_ccb, sizeof(union ccb));
-
- periph->flags &= ~CAM_PERIPH_RECOVERY_INPROG;
-
- xpt_action(done_ccb);
+ goto final;
}
} else {
+ save_ccb = xpt_alloc_ccb_nowait();
+ if (save_ccb == NULL)
+ goto final;
+ bcopy(done_ccb, save_ccb, sizeof(*save_ccb));
+ periph->flags |= CAM_PERIPH_SENSE_INPROG;
/*
- * Eh?? The command failed, but we don't
- * have any sense. What's up with that?
- * Fire the CCB again to return it to the
- * caller.
+ * Send a Request Sense to the device. We
+ * assume that we are in a contingent allegiance
+ * condition so we do not tag this request.
*/
- bcopy(done_ccb->ccb_h.saved_ccb_ptr,
- done_ccb, sizeof(union ccb));
-
- periph->flags &= ~CAM_PERIPH_RECOVERY_INPROG;
-
+ scsi_request_sense(&done_ccb->csio, /*retries*/1,
+ camperiphsensedone,
+ &save_ccb->csio.sense_data,
+ sizeof(save_ccb->csio.sense_data),
+ CAM_TAG_ACTION_NONE,
+ /*sense_len*/SSD_FULL_SIZE,
+ /*timeout*/5000);
+ done_ccb->ccb_h.pinfo.priority--;
+ done_ccb->ccb_h.flags |= CAM_DEV_QFREEZE;
+ done_ccb->ccb_h.saved_ccb_ptr = save_ccb;
+ done_ccb->ccb_h.recovery_depth++;
xpt_action(done_ccb);
-
}
break;
default:
- bcopy(done_ccb->ccb_h.saved_ccb_ptr, done_ccb,
- sizeof(union ccb));
-
+final:
+ bcopy(saved_ccb, done_ccb, sizeof(*done_ccb));
+ xpt_free_ccb(saved_ccb);
periph->flags &= ~CAM_PERIPH_RECOVERY_INPROG;
-
xpt_action(done_ccb);
-
break;
}
@@ -1188,23 +1241,13 @@ camperiphdone(struct cam_periph *periph, union ccb *done_ccb)
/*openings*/0,
/*timeout*/timeout,
/*getcount_only*/0);
- if (xpt_done_ccb == TRUE) {
- /*
- * Copy frozen flag from recovery request if it is set there
- * for some reason.
- */
- if (frozen != 0)
- done_ccb->ccb_h.status |= CAM_DEV_QFRZN;
- (*done_ccb->ccb_h.cbfcnp)(periph, done_ccb);
- } else {
- /* Drop freeze taken, if this recovery request got error. */
- if (frozen != 0) {
- cam_release_devq(done_ccb->ccb_h.path,
- /*relsim_flags*/0,
- /*openings*/0,
- /*timeout*/0,
- /*getcount_only*/0);
- }
+ /* Drop freeze taken, if this recovery request got error. */
+ if (frozen != 0) {
+ cam_release_devq(done_ccb->ccb_h.path,
+ /*relsim_flags*/0,
+ /*openings*/0,
+ /*timeout*/0,
+ /*getcount_only*/0);
}
}
@@ -1221,12 +1264,6 @@ cam_periph_async(struct cam_periph *periph, u_int32_t 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;
}
@@ -1271,9 +1308,9 @@ cam_periph_freeze_after_event(struct cam_periph *periph,
static int
camperiphscsistatuserror(union ccb *ccb, cam_flags camflags,
- u_int32_t sense_flags, union ccb *save_ccb,
+ u_int32_t sense_flags,
int *openings, u_int32_t *relsim_flags,
- u_int32_t *timeout)
+ u_int32_t *timeout, const char **action_string)
{
int error;
@@ -1286,13 +1323,15 @@ camperiphscsistatuserror(union ccb *ccb, cam_flags camflags,
break;
case SCSI_STATUS_CMD_TERMINATED:
case SCSI_STATUS_CHECK_COND:
+ if (bootverbose)
+ xpt_print(ccb->ccb_h.path, "SCSI status error\n");
error = camperiphscsisenseerror(ccb,
camflags,
sense_flags,
- save_ccb,
openings,
relsim_flags,
- timeout);
+ timeout,
+ action_string);
break;
case SCSI_STATUS_QUEUE_FULL:
{
@@ -1347,7 +1386,7 @@ camperiphscsistatuserror(union ccb *ccb, cam_flags camflags,
*timeout = 0;
error = ERESTART;
if (bootverbose) {
- xpt_print(ccb->ccb_h.path, "Queue Full\n");
+ xpt_print(ccb->ccb_h.path, "Queue full\n");
}
break;
}
@@ -1359,7 +1398,7 @@ camperiphscsistatuserror(union ccb *ccb, cam_flags camflags,
* command completes or a 1 second timeout.
*/
if (bootverbose) {
- xpt_print(ccb->ccb_h.path, "Device Busy\n");
+ xpt_print(ccb->ccb_h.path, "Device busy\n");
}
if (ccb->ccb_h.retry_count > 0) {
ccb->ccb_h.retry_count--;
@@ -1372,11 +1411,11 @@ camperiphscsistatuserror(union ccb *ccb, cam_flags camflags,
}
break;
case SCSI_STATUS_RESERV_CONFLICT:
- xpt_print(ccb->ccb_h.path, "Reservation Conflict\n");
+ xpt_print(ccb->ccb_h.path, "Reservation conflict\n");
error = EIO;
break;
default:
- xpt_print(ccb->ccb_h.path, "SCSI Status 0x%x\n",
+ xpt_print(ccb->ccb_h.path, "SCSI status 0x%x\n",
ccb->csio.scsi_status);
error = EIO;
break;
@@ -1386,16 +1425,17 @@ camperiphscsistatuserror(union ccb *ccb, cam_flags camflags,
static int
camperiphscsisenseerror(union ccb *ccb, cam_flags camflags,
- u_int32_t sense_flags, union ccb *save_ccb,
+ u_int32_t sense_flags,
int *openings, u_int32_t *relsim_flags,
- u_int32_t *timeout)
+ u_int32_t *timeout, const char **action_string)
{
struct cam_periph *periph;
+ union ccb *orig_ccb = ccb;
int error;
periph = xpt_path_periph(ccb->ccb_h.path);
- if (periph->flags & CAM_PERIPH_RECOVERY_INPROG) {
-
+ if (periph->flags &
+ (CAM_PERIPH_RECOVERY_INPROG | CAM_PERIPH_SENSE_INPROG)) {
/*
* If error recovery is already in progress, don't attempt
* to process this error, but requeue it unconditionally
@@ -1413,17 +1453,6 @@ camperiphscsisenseerror(union ccb *ccb, cam_flags camflags,
} else {
scsi_sense_action err_action;
struct ccb_getdev cgd;
- const char *action_string;
- union ccb* print_ccb;
-
- /* A description of the error recovery action performed */
- action_string = NULL;
-
- /*
- * The location of the orignal ccb
- * for sense printing purposes.
- */
- print_ccb = ccb;
/*
* Grab the inquiry data for this device.
@@ -1451,7 +1480,7 @@ camperiphscsisenseerror(union ccb *ccb, cam_flags camflags,
if (ccb->ccb_h.retry_count > 0)
ccb->ccb_h.retry_count--;
else {
- action_string = "Retries Exhausted";
+ *action_string = "Retries exhausted";
goto sense_error_done;
}
}
@@ -1461,8 +1490,9 @@ camperiphscsisenseerror(union ccb *ccb, cam_flags camflags,
* Do common portions of commands that
* use recovery CCBs.
*/
- if (save_ccb == NULL) {
- action_string = "No recovery CCB supplied";
+ orig_ccb = xpt_alloc_ccb_nowait();
+ if (orig_ccb == NULL) {
+ *action_string = "Can't allocate recovery CCB";
goto sense_error_done;
}
/*
@@ -1470,22 +1500,20 @@ camperiphscsisenseerror(union ccb *ccb, cam_flags camflags,
* this freeze will be dropped as part of ERESTART.
*/
ccb->ccb_h.status &= ~CAM_DEV_QFRZN;
- bcopy(ccb, save_ccb, sizeof(*save_ccb));
- print_ccb = save_ccb;
- periph->flags |= CAM_PERIPH_RECOVERY_INPROG;
+ bcopy(ccb, orig_ccb, sizeof(*orig_ccb));
}
switch (err_action & SS_MASK) {
case SS_NOP:
- action_string = "No Recovery Action Needed";
+ *action_string = "No recovery action needed";
error = 0;
break;
case SS_RETRY:
- action_string = "Retrying Command (per Sense Data)";
+ *action_string = "Retrying command (per sense data)";
error = ERESTART;
break;
case SS_FAIL:
- action_string = "Unretryable error";
+ *action_string = "Unretryable error";
break;
case SS_START:
{
@@ -1495,7 +1523,8 @@ camperiphscsisenseerror(union ccb *ccb, cam_flags camflags,
* Send a start unit command to the device, and
* then retry the command.
*/
- action_string = "Attempting to Start Unit";
+ *action_string = "Attempting to start unit";
+ periph->flags |= CAM_PERIPH_RECOVERY_INPROG;
/*
* Check for removable media and set
@@ -1530,12 +1559,13 @@ camperiphscsisenseerror(union ccb *ccb, cam_flags camflags,
int retries;
if ((err_action & SSQ_MANY) != 0) {
- action_string = "Polling device for readiness";
+ *action_string = "Polling device for readiness";
retries = 120;
} else {
- action_string = "Testing device for readiness";
+ *action_string = "Testing device for readiness";
retries = 1;
}
+ periph->flags |= CAM_PERIPH_RECOVERY_INPROG;
scsi_test_unit_ready(&ccb->csio,
retries,
camperiphdone,
@@ -1553,15 +1583,17 @@ camperiphscsisenseerror(union ccb *ccb, cam_flags camflags,
}
case SS_REQSENSE:
{
+ *action_string = "Requesting SCSI sense data";
+ periph->flags |= CAM_PERIPH_SENSE_INPROG;
/*
* Send a Request Sense to the device. We
* assume that we are in a contingent allegiance
* condition so we do not tag this request.
*/
scsi_request_sense(&ccb->csio, /*retries*/1,
- camperiphdone,
- &save_ccb->csio.sense_data,
- sizeof(save_ccb->csio.sense_data),
+ camperiphsensedone,
+ &orig_ccb->csio.sense_data,
+ sizeof(orig_ccb->csio.sense_data),
CAM_TAG_ACTION_NONE,
/*sense_len*/SSD_FULL_SIZE,
/*timeout*/5000);
@@ -1580,21 +1612,17 @@ camperiphscsisenseerror(union ccb *ccb, cam_flags camflags,
* the proper order before we release normal
* transactions to the device.
*/
- ccb->ccb_h.pinfo.priority = CAM_PRIORITY_DEV;
+ ccb->ccb_h.pinfo.priority--;
ccb->ccb_h.flags |= CAM_DEV_QFREEZE;
- ccb->ccb_h.saved_ccb_ptr = save_ccb;
+ ccb->ccb_h.saved_ccb_ptr = orig_ccb;
+ ccb->ccb_h.recovery_depth = 0;
error = ERESTART;
}
sense_error_done:
if ((err_action & SSQ_PRINT_SENSE) != 0
- && (ccb->ccb_h.status & CAM_AUTOSNS_VALID) != 0) {
- cam_error_print(print_ccb, CAM_ESF_ALL, CAM_EPF_ALL);
- xpt_print_path(ccb->ccb_h.path);
- if (bootverbose)
- scsi_sense_print(&print_ccb->csio);
- printf("%s\n", action_string);
- }
+ && (ccb->ccb_h.status & CAM_AUTOSNS_VALID) != 0)
+ cam_error_print(orig_ccb, CAM_ESF_ALL, CAM_EPF_ALL);
}
return (error);
}
@@ -1630,19 +1658,18 @@ cam_periph_error(union ccb *ccb, cam_flags camflags,
error = camperiphscsistatuserror(ccb,
camflags,
sense_flags,
- save_ccb,
&openings,
&relsim_flags,
- &timeout);
+ &timeout,
+ &action_string);
break;
case CAM_AUTOSENSE_FAIL:
- xpt_print(ccb->ccb_h.path, "AutoSense Failed\n");
+ xpt_print(ccb->ccb_h.path, "AutoSense failed\n");
error = EIO; /* we have to kill the command */
break;
case CAM_ATA_STATUS_ERROR:
if (bootverbose && printed == 0) {
- xpt_print(ccb->ccb_h.path,
- "Request completed with CAM_ATA_STATUS_ERROR\n");
+ xpt_print(ccb->ccb_h.path, "ATA status error\n");
cam_error_print(ccb, CAM_ESF_ALL, CAM_EPF_ALL);
printed++;
}
@@ -1669,13 +1696,13 @@ cam_periph_error(union ccb *ccb, cam_flags camflags,
case CAM_UNCOR_PARITY:
if (bootverbose && printed == 0) {
xpt_print(ccb->ccb_h.path,
- "Uncorrected Parity Error\n");
+ "Uncorrected parity error\n");
printed++;
}
/* FALLTHROUGH */
case CAM_DATA_RUN_ERR:
if (bootverbose && printed == 0) {
- xpt_print(ccb->ccb_h.path, "Data Overrun\n");
+ xpt_print(ccb->ccb_h.path, "Data overrun\n");
printed++;
}
error = EIO; /* we have to kill the command */
@@ -1684,7 +1711,7 @@ cam_periph_error(union ccb *ccb, cam_flags camflags,
ccb->ccb_h.retry_count--;
error = ERESTART;
} else {
- action_string = "Retries Exhausted";
+ action_string = "Retries exhausted";
error = EIO;
}
break;
@@ -1705,7 +1732,7 @@ cam_periph_error(union ccb *ccb, cam_flags camflags,
error = ERESTART;
if (bootverbose && printed == 0) {
xpt_print(ccb->ccb_h.path,
- "Selection Timeout\n");
+ "Selection timeout\n");
printed++;
}
@@ -1767,7 +1794,7 @@ cam_periph_error(union ccb *ccb, cam_flags camflags,
/* Unconditional requeue */
error = ERESTART;
if (bootverbose && printed == 0) {
- xpt_print(ccb->ccb_h.path, "Request Requeued\n");
+ xpt_print(ccb->ccb_h.path, "Request requeued\n");
printed++;
}
break;
@@ -1788,13 +1815,13 @@ cam_periph_error(union ccb *ccb, cam_flags camflags,
ccb->ccb_h.retry_count--;
error = ERESTART;
if (bootverbose && printed == 0) {
- xpt_print(ccb->ccb_h.path, "CAM Status 0x%x\n",
+ xpt_print(ccb->ccb_h.path, "CAM status 0x%x\n",
status);
printed++;
}
} else {
error = EIO;
- action_string = "Retries Exhausted";
+ action_string = "Retries exhausted";
}
break;
}
@@ -1807,11 +1834,13 @@ cam_periph_error(union ccb *ccb, cam_flags camflags,
!(status == CAM_SEL_TIMEOUT && (camflags & CAM_RETRY_SELTO) == 0)) {
if (error != ERESTART) {
if (action_string == NULL)
- action_string = "Unretryable Error";
- xpt_print(ccb->ccb_h.path, "error %d\n", error);
+ action_string = "Unretryable error";
+ xpt_print(ccb->ccb_h.path, "Error %d, %s\n",
+ error, action_string);
+ } else if (action_string != NULL)
xpt_print(ccb->ccb_h.path, "%s\n", action_string);
- } else
- xpt_print(ccb->ccb_h.path, "Retrying Command\n");
+ else
+ xpt_print(ccb->ccb_h.path, "Retrying command\n");
}
/* Attempt a retry */
diff --git a/sys/cam/cam_periph.h b/sys/cam/cam_periph.h
index e207b19..33e9f75 100644
--- a/sys/cam/cam_periph.h
+++ b/sys/cam/cam_periph.h
@@ -42,6 +42,7 @@ extern struct cam_periph *xpt_periph;
extern struct periph_driver **periph_drivers;
void periphdriver_register(void *);
+void periphdriver_init(int level);
#include <sys/module.h>
#define PERIPHDRIVER_DECLARE(name, driver) \
@@ -117,6 +118,7 @@ struct cam_periph {
#define CAM_PERIPH_INVALID 0x08
#define CAM_PERIPH_NEW_DEV_FOUND 0x10
#define CAM_PERIPH_RECOVERY_INPROG 0x20
+#define CAM_PERIPH_SENSE_INPROG 0x40
u_int32_t immediate_priority;
u_int32_t refcount;
SLIST_HEAD(, ccb_hdr) ccb_list; /* For "immediate" requests */
@@ -165,8 +167,10 @@ int cam_periph_ioctl(struct cam_periph *periph, u_long cmd,
cam_flags camflags,
u_int32_t sense_flags));
void cam_freeze_devq(struct cam_path *path);
+void cam_freeze_devq_arg(struct cam_path *path, u_int32_t flags,
+ uint32_t arg);
u_int32_t cam_release_devq(struct cam_path *path, u_int32_t relsim_flags,
- u_int32_t opening_reduction, u_int32_t timeout,
+ u_int32_t opening_reduction, u_int32_t arg,
int getcount_only);
void cam_periph_async(struct cam_periph *periph, u_int32_t code,
struct cam_path *path, void *arg);
diff --git a/sys/cam/cam_queue.h b/sys/cam/cam_queue.h
index 31f9bc2..dd9f9a7 100644
--- a/sys/cam/cam_queue.h
+++ b/sys/cam/cam_queue.h
@@ -34,6 +34,7 @@
#ifdef _KERNEL
#include <sys/queue.h>
+#include <cam/cam.h>
/*
* This structure implements a heap based priority queue. The queue
@@ -47,7 +48,7 @@ struct camq {
int array_size;
int entries;
u_int32_t generation;
- u_int32_t qfrozen_cnt;
+ u_int32_t qfrozen_cnt[CAM_RL_VALUES];
};
TAILQ_HEAD(ccb_hdr_tailq, ccb_hdr);
@@ -140,6 +141,10 @@ cam_pinfo *camq_remove(struct camq *queue, int index);
/* Index the first element in the heap */
#define CAMQ_GET_HEAD(camq) ((camq)->queue_array[CAMQ_HEAD])
+/* Get the first element priority. */
+#define CAMQ_GET_PRIO(camq) (((camq)->entries > 0) ? \
+ ((camq)->queue_array[CAMQ_HEAD]->priority) : 0)
+
/*
* camq_change_priority: Raise or lower the priority of an entry
* maintaining queue order.
@@ -153,10 +158,10 @@ cam_ccbq_pending_ccb_count(struct cam_ccbq *ccbq);
static __inline void
cam_ccbq_take_opening(struct cam_ccbq *ccbq);
-static __inline void
+static __inline int
cam_ccbq_insert_ccb(struct cam_ccbq *ccbq, union ccb *new_ccb);
-static __inline void
+static __inline int
cam_ccbq_remove_ccb(struct cam_ccbq *ccbq, union ccb *ccb);
static __inline union ccb *
@@ -185,17 +190,31 @@ cam_ccbq_take_opening(struct cam_ccbq *ccbq)
ccbq->held++;
}
-static __inline void
+static __inline int
cam_ccbq_insert_ccb(struct cam_ccbq *ccbq, union ccb *new_ccb)
{
ccbq->held--;
camq_insert(&ccbq->queue, &new_ccb->ccb_h.pinfo);
+ if (ccbq->queue.qfrozen_cnt[CAM_PRIORITY_TO_RL(
+ new_ccb->ccb_h.pinfo.priority)] > 0) {
+ ccbq->devq_openings++;
+ ccbq->held++;
+ return (1);
+ } else
+ return (0);
}
-static __inline void
+static __inline int
cam_ccbq_remove_ccb(struct cam_ccbq *ccbq, union ccb *ccb)
{
camq_remove(&ccbq->queue, ccb->ccb_h.pinfo.index);
+ if (ccbq->queue.qfrozen_cnt[CAM_PRIORITY_TO_RL(
+ ccb->ccb_h.pinfo.priority)] > 0) {
+ ccbq->devq_openings--;
+ ccbq->held--;
+ return (1);
+ } else
+ return (0);
}
static __inline union ccb *
@@ -229,5 +248,81 @@ cam_ccbq_release_opening(struct cam_ccbq *ccbq)
ccbq->devq_openings++;
}
+static __inline int
+cam_ccbq_freeze(struct cam_ccbq *ccbq, cam_rl rl, u_int32_t cnt)
+{
+ int i, frozen = 0;
+ cam_rl p, n;
+
+ /* Find pevious run level. */
+ for (p = 0; p < CAM_RL_VALUES && ccbq->queue.qfrozen_cnt[p] == 0; p++);
+ /* Find new run level. */
+ n = min(rl, p);
+ /* Apply new run level. */
+ for (i = rl; i < CAM_RL_VALUES; i++)
+ ccbq->queue.qfrozen_cnt[i] += cnt;
+ /* Update ccbq statistics. */
+ if (n == p)
+ return (0);
+ for (i = CAMQ_HEAD; i <= ccbq->queue.entries; i++) {
+ cam_rl rrl =
+ CAM_PRIORITY_TO_RL(ccbq->queue.queue_array[i]->priority);
+ if (rrl < n)
+ continue;
+ if (rrl >= p)
+ break;
+ ccbq->devq_openings++;
+ ccbq->held++;
+ frozen++;
+ }
+ return (frozen);
+}
+
+static __inline int
+cam_ccbq_release(struct cam_ccbq *ccbq, cam_rl rl, u_int32_t cnt)
+{
+ int i, released = 0;
+ cam_rl p, n;
+
+ /* Apply new run level. */
+ for (i = rl; i < CAM_RL_VALUES; i++)
+ ccbq->queue.qfrozen_cnt[i] -= cnt;
+ /* Find new run level. */
+ for (n = 0; n < CAM_RL_VALUES && ccbq->queue.qfrozen_cnt[n] == 0; n++);
+ /* Find previous run level. */
+ p = min(rl, n);
+ /* Update ccbq statistics. */
+ if (n == p)
+ return (0);
+ for (i = CAMQ_HEAD; i <= ccbq->queue.entries; i++) {
+ cam_rl rrl =
+ CAM_PRIORITY_TO_RL(ccbq->queue.queue_array[i]->priority);
+ if (rrl < p)
+ continue;
+ if (rrl >= n)
+ break;
+ ccbq->devq_openings--;
+ ccbq->held--;
+ released++;
+ }
+ return (released);
+}
+
+static __inline u_int32_t
+cam_ccbq_frozen(struct cam_ccbq *ccbq, cam_rl rl)
+{
+
+ return (ccbq->queue.qfrozen_cnt[rl]);
+}
+
+static __inline u_int32_t
+cam_ccbq_frozen_top(struct cam_ccbq *ccbq)
+{
+ cam_rl rl;
+
+ rl = CAM_PRIORITY_TO_RL(CAMQ_GET_PRIO(&ccbq->queue));
+ return (ccbq->queue.qfrozen_cnt[rl]);
+}
+
#endif /* _KERNEL */
#endif /* _CAM_CAM_QUEUE_H */
diff --git a/sys/cam/cam_sim.c b/sys/cam/cam_sim.c
index adccfa8..59148a9 100644
--- a/sys/cam/cam_sim.c
+++ b/sys/cam/cam_sim.c
@@ -69,7 +69,7 @@ cam_sim_alloc(sim_action_func sim_action, sim_poll_func sim_poll,
return (NULL);
sim = (struct cam_sim *)malloc(sizeof(struct cam_sim),
- M_CAMSIM, M_NOWAIT);
+ M_CAMSIM, M_ZERO | M_NOWAIT);
if (sim == NULL)
return (NULL);
@@ -86,6 +86,7 @@ cam_sim_alloc(sim_action_func sim_action, sim_poll_func sim_poll,
sim->flags = 0;
sim->refcount = 1;
sim->devq = queue;
+ sim->max_ccbs = 8; /* Reserve for management purposes. */
sim->mtx = mtx;
if (mtx == &Giant) {
sim->flags |= 0;
diff --git a/sys/cam/cam_xpt.c b/sys/cam/cam_xpt.c
index 88ee309..d966a9f 100644
--- a/sys/cam/cam_xpt.c
+++ b/sys/cam/cam_xpt.c
@@ -102,6 +102,8 @@ struct xpt_softc {
/* queue for handling async rescan requests. */
TAILQ_HEAD(, ccb_hdr) ccb_scanq;
+ int buses_to_config;
+ int buses_config_done;
/* Registered busses */
TAILQ_HEAD(,cam_eb) xpt_busses;
@@ -109,6 +111,9 @@ struct xpt_softc {
struct intr_config_hook *xpt_config_hook;
+ int boot_delay;
+ struct callout boot_callout;
+
struct mtx xpt_topo_lock;
struct mtx xpt_lock;
};
@@ -145,6 +150,10 @@ typedef int xpt_pdrvfunc_t (struct periph_driver **pdrv, void *arg);
/* Transport layer configuration information */
static struct xpt_softc xsoftc;
+TUNABLE_INT("kern.cam.boot_delay", &xsoftc.boot_delay);
+SYSCTL_INT(_kern_cam, OID_AUTO, boot_delay, CTLFLAG_RDTUN,
+ &xsoftc.boot_delay, 0, "Bus registration wait time");
+
/* Queues for our software interrupt handler */
typedef TAILQ_HEAD(cam_isrq, ccb_hdr) cam_isrq_t;
typedef TAILQ_HEAD(cam_simq, cam_sim) cam_simq_t;
@@ -210,11 +219,12 @@ static path_id_t xptnextfreepathid(void);
static path_id_t xptpathid(const char *sim_name, int sim_unit, int sim_bus);
static union ccb *xpt_get_ccb(struct cam_ed *device);
static void xpt_run_dev_allocq(struct cam_eb *bus);
+static void xpt_run_dev_sendq(struct cam_eb *bus);
static timeout_t xpt_release_devq_timeout;
static void xpt_release_simq_timeout(void *arg) __unused;
static void xpt_release_bus(struct cam_eb *bus);
-static void xpt_release_devq_device(struct cam_ed *dev, u_int count,
- int run_queue);
+static void xpt_release_devq_device(struct cam_ed *dev, cam_rl rl,
+ u_int count, int run_queue);
static struct cam_et*
xpt_alloc_target(struct cam_eb *bus, target_id_t target_id);
static void xpt_release_target(struct cam_et *target);
@@ -224,11 +234,8 @@ static struct cam_et*
xpt_find_target(struct cam_eb *bus, target_id_t target_id);
static struct cam_ed*
xpt_find_device(struct cam_et *target, lun_id_t lun_id);
-static xpt_busfunc_t xptconfigbuscountfunc;
-static xpt_busfunc_t xptconfigfunc;
static void xpt_config(void *arg);
static xpt_devicefunc_t xptpassannouncefunc;
-static void xpt_finishconfig(struct cam_periph *periph, union ccb *ccb);
static void xptaction(struct cam_sim *sim, union ccb *work_ccb);
static void xptpoll(struct cam_sim *sim);
static void camisr(void *);
@@ -270,6 +277,7 @@ static xpt_busfunc_t xptdefbusfunc;
static xpt_targetfunc_t xptdeftargetfunc;
static xpt_devicefunc_t xptdefdevicefunc;
static xpt_periphfunc_t xptdefperiphfunc;
+static void xpt_finishconfig_task(void *context, int pending);
static int xpt_for_all_busses(xpt_busfunc_t *tr_func, void *arg);
static int xpt_for_all_devices(xpt_devicefunc_t *tr_func,
void *arg);
@@ -285,19 +293,19 @@ static xpt_devicefunc_t xptsetasyncfunc;
static xpt_busfunc_t xptsetasyncbusfunc;
static cam_status xptregister(struct cam_periph *periph,
void *arg);
-static __inline int xpt_schedule_dev_allocq(struct cam_eb *bus,
- struct cam_ed *dev);
static __inline int periph_is_queued(struct cam_periph *periph);
static __inline int device_is_alloc_queued(struct cam_ed *device);
static __inline int device_is_send_queued(struct cam_ed *device);
-static __inline int dev_allocq_is_runnable(struct cam_devq *devq);
static __inline int
xpt_schedule_dev_allocq(struct cam_eb *bus, struct cam_ed *dev)
{
int retval;
- if (dev->ccbq.devq_openings > 0) {
+ if ((dev->drvq.entries > 0) &&
+ (dev->ccbq.devq_openings > 0) &&
+ (cam_ccbq_frozen(&dev->ccbq, CAM_PRIORITY_TO_RL(
+ CAMQ_GET_PRIO(&dev->drvq))) == 0)) {
/*
* The priority of a device waiting for CCB resources
* is that of the the highest priority peripheral driver
@@ -305,7 +313,7 @@ xpt_schedule_dev_allocq(struct cam_eb *bus, struct cam_ed *dev)
*/
retval = xpt_schedule_dev(&bus->sim->devq->alloc_queue,
&dev->alloc_ccb_entry.pinfo,
- CAMQ_GET_HEAD(&dev->drvq)->priority);
+ CAMQ_GET_PRIO(&dev->drvq));
} else {
retval = 0;
}
@@ -318,7 +326,9 @@ xpt_schedule_dev_sendq(struct cam_eb *bus, struct cam_ed *dev)
{
int retval;
- if (dev->ccbq.dev_openings > 0) {
+ if ((dev->ccbq.queue.entries > 0) &&
+ (dev->ccbq.dev_openings > 0) &&
+ (cam_ccbq_frozen_top(&dev->ccbq) == 0)) {
/*
* The priority of a device waiting for controller
* resources is that of the the highest priority CCB
@@ -327,7 +337,7 @@ xpt_schedule_dev_sendq(struct cam_eb *bus, struct cam_ed *dev)
retval =
xpt_schedule_dev(&bus->sim->devq->send_queue,
&dev->send_ccb_entry.pinfo,
- CAMQ_GET_HEAD(&dev->ccbq.queue)->priority);
+ CAMQ_GET_PRIO(&dev->ccbq.queue));
} else {
retval = 0;
}
@@ -352,19 +362,6 @@ device_is_send_queued(struct cam_ed *device)
return (device->send_ccb_entry.pinfo.index != CAM_UNQUEUED_INDEX);
}
-static __inline int
-dev_allocq_is_runnable(struct cam_devq *devq)
-{
- /*
- * Have work to do.
- * Have space to do more work.
- * Allowed to do work.
- */
- return ((devq->alloc_queue.qfrozen_cnt == 0)
- && (devq->alloc_queue.entries > 0)
- && (devq->alloc_openings > 0));
-}
-
static void
xpt_periph_init()
{
@@ -818,45 +815,42 @@ cam_module_event_handler(module_t mod, int what, void *arg)
return 0;
}
+static void
+xpt_rescan_done(struct cam_periph *periph, union ccb *done_ccb)
+{
+
+ if (done_ccb->ccb_h.ppriv_ptr1 == NULL) {
+ xpt_free_path(done_ccb->ccb_h.path);
+ xpt_free_ccb(done_ccb);
+ } else {
+ done_ccb->ccb_h.cbfcnp = done_ccb->ccb_h.ppriv_ptr1;
+ (*done_ccb->ccb_h.cbfcnp)(periph, done_ccb);
+ }
+ xpt_release_boot();
+}
+
/* thread to handle bus rescans */
static void
xpt_scanner_thread(void *dummy)
{
- cam_isrq_t queue;
union ccb *ccb;
struct cam_sim *sim;
+ xpt_lock_buses();
for (;;) {
- /*
- * Wait for a rescan request to come in. When it does, splice
- * it onto a queue from local storage so that the xpt lock
- * doesn't need to be held while the requests are being
- * processed.
- */
- xpt_lock_buses();
if (TAILQ_EMPTY(&xsoftc.ccb_scanq))
msleep(&xsoftc.ccb_scanq, &xsoftc.xpt_topo_lock, PRIBIO,
"ccb_scanq", 0);
- TAILQ_INIT(&queue);
- TAILQ_CONCAT(&queue, &xsoftc.ccb_scanq, sim_links.tqe);
- xpt_unlock_buses();
-
- while ((ccb = (union ccb *)TAILQ_FIRST(&queue)) != NULL) {
- TAILQ_REMOVE(&queue, &ccb->ccb_h, sim_links.tqe);
+ if ((ccb = (union ccb *)TAILQ_FIRST(&xsoftc.ccb_scanq)) != NULL) {
+ TAILQ_REMOVE(&xsoftc.ccb_scanq, &ccb->ccb_h, sim_links.tqe);
+ xpt_unlock_buses();
sim = ccb->ccb_h.path->bus->sim;
CAM_SIM_LOCK(sim);
-
- if( ccb->ccb_h.path->target->target_id == CAM_TARGET_WILDCARD )
- ccb->ccb_h.func_code = XPT_SCAN_BUS;
- else
- ccb->ccb_h.func_code = XPT_SCAN_LUN;
- ccb->ccb_h.cbfcnp = xptdone;
- xpt_setup_ccb(&ccb->ccb_h, ccb->ccb_h.path, CAM_PRIORITY_NORMAL);
- cam_periph_runccb(ccb, NULL, 0, 0, NULL);
- xpt_free_path(ccb->ccb_h.path);
- xpt_free_ccb(ccb);
+ xpt_action(ccb);
CAM_SIM_UNLOCK(sim);
+
+ xpt_lock_buses();
}
}
}
@@ -866,21 +860,30 @@ xpt_rescan(union ccb *ccb)
{
struct ccb_hdr *hdr;
- /*
- * Don't make duplicate entries for the same paths.
- */
+ /* Prepare request */
+ if(ccb->ccb_h.path->target->target_id == CAM_TARGET_WILDCARD)
+ ccb->ccb_h.func_code = XPT_SCAN_BUS;
+ else
+ ccb->ccb_h.func_code = XPT_SCAN_LUN;
+ ccb->ccb_h.ppriv_ptr1 = ccb->ccb_h.cbfcnp;
+ ccb->ccb_h.cbfcnp = xpt_rescan_done;
+ xpt_setup_ccb(&ccb->ccb_h, ccb->ccb_h.path, CAM_PRIORITY_XPT);
+ /* Don't make duplicate entries for the same paths. */
xpt_lock_buses();
- TAILQ_FOREACH(hdr, &xsoftc.ccb_scanq, sim_links.tqe) {
- if (xpt_path_comp(hdr->path, ccb->ccb_h.path) == 0) {
- wakeup(&xsoftc.ccb_scanq);
- xpt_unlock_buses();
- xpt_print(ccb->ccb_h.path, "rescan already queued\n");
- xpt_free_path(ccb->ccb_h.path);
- xpt_free_ccb(ccb);
- return;
+ if (ccb->ccb_h.ppriv_ptr1 == NULL) {
+ TAILQ_FOREACH(hdr, &xsoftc.ccb_scanq, sim_links.tqe) {
+ if (xpt_path_comp(hdr->path, ccb->ccb_h.path) == 0) {
+ wakeup(&xsoftc.ccb_scanq);
+ xpt_unlock_buses();
+ xpt_print(ccb->ccb_h.path, "rescan already queued\n");
+ xpt_free_path(ccb->ccb_h.path);
+ xpt_free_ccb(ccb);
+ return;
+ }
}
}
TAILQ_INSERT_TAIL(&xsoftc.ccb_scanq, &ccb->ccb_h, sim_links.tqe);
+ xsoftc.buses_to_config++;
wakeup(&xsoftc.ccb_scanq);
xpt_unlock_buses();
}
@@ -923,10 +926,9 @@ xpt_init(void *dummy)
if (xpt_sim == NULL)
return (ENOMEM);
- xpt_sim->max_ccbs = 16;
-
mtx_lock(&xsoftc.xpt_lock);
if ((status = xpt_bus_register(xpt_sim, NULL, 0)) != CAM_SUCCESS) {
+ mtx_unlock(&xsoftc.xpt_lock);
printf("xpt_init: xpt_bus_register failed with status %#x,"
" failing attach\n", status);
return (EINVAL);
@@ -940,6 +942,7 @@ xpt_init(void *dummy)
if ((status = xpt_create_path(&path, NULL, CAM_XPT_PATH_ID,
CAM_TARGET_WILDCARD,
CAM_LUN_WILDCARD)) != CAM_REQ_CMP) {
+ mtx_unlock(&xsoftc.xpt_lock);
printf("xpt_init: xpt_create_path failed with status %#x,"
" failing attach\n", status);
return (EINVAL);
@@ -949,7 +952,8 @@ xpt_init(void *dummy)
path, NULL, 0, xpt_sim);
xpt_free_path(path);
mtx_unlock(&xsoftc.xpt_lock);
-
+ /* Install our software interrupt handlers */
+ swi_add(NULL, "cambio", camisr, NULL, SWI_CAMBIO, INTR_MPSAFE, &cambio_ih);
/*
* Register a callback for when interrupts are enabled.
*/
@@ -961,7 +965,6 @@ xpt_init(void *dummy)
"- failing attach\n");
return (ENOMEM);
}
-
xsoftc.xpt_config_hook->ich_func = xpt_config;
if (config_intrhook_establish(xsoftc.xpt_config_hook) != 0) {
free (xsoftc.xpt_config_hook, M_CAMXPT);
@@ -969,13 +972,6 @@ xpt_init(void *dummy)
"- failing attach\n");
}
- /* fire up rescan thread */
- if (kproc_create(xpt_scanner_thread, NULL, NULL, 0, 0, "xpt_thrd")) {
- printf("xpt_init: failed to create rescan thread\n");
- }
- /* Install our software interrupt handlers */
- swi_add(NULL, "cambio", camisr, NULL, SWI_CAMBIO, INTR_MPSAFE, &cambio_ih);
-
return (0);
}
@@ -2481,6 +2477,9 @@ xpt_action(union ccb *start_ccb)
CAM_DEBUG(start_ccb->ccb_h.path, CAM_DEBUG_TRACE, ("xpt_action\n"));
start_ccb->ccb_h.status = CAM_REQ_INPROG;
+ /* Compatibility for RL-unaware code. */
+ if (CAM_PRIORITY_TO_RL(start_ccb->ccb_h.pinfo.priority) == 0)
+ start_ccb->ccb_h.pinfo.priority += CAM_PRIORITY_NORMAL - 1;
(*(start_ccb->ccb_h.path->bus->xport->action))(start_ccb);
}
@@ -2546,17 +2545,14 @@ xpt_action_default(union ccb *start_ccb)
case XPT_RESET_DEV:
case XPT_ENG_EXEC:
{
- struct cam_path *path;
- int runq;
-
- path = start_ccb->ccb_h.path;
-
- cam_ccbq_insert_ccb(&path->device->ccbq, start_ccb);
- if (path->device->ccbq.queue.qfrozen_cnt == 0)
- runq = xpt_schedule_dev_sendq(path->bus, path->device);
- else
- runq = 0;
- if (runq != 0)
+ struct cam_path *path = start_ccb->ccb_h.path;
+ int frozen;
+
+ frozen = cam_ccbq_insert_ccb(&path->device->ccbq, start_ccb);
+ path->device->sim->devq->alloc_openings += frozen;
+ if (frozen > 0)
+ xpt_run_dev_allocq(path->bus);
+ if (xpt_schedule_dev_sendq(path->bus, path->device))
xpt_run_dev_sendq(path->bus);
break;
}
@@ -2601,9 +2597,12 @@ xpt_action_default(union ccb *start_ccb)
if (abort_ccb->ccb_h.pinfo.index >= 0) {
struct cam_ccbq *ccbq;
+ struct cam_ed *device;
- ccbq = &abort_ccb->ccb_h.path->device->ccbq;
- cam_ccbq_remove_ccb(ccbq, abort_ccb);
+ device = abort_ccb->ccb_h.path->device;
+ ccbq = &device->ccbq;
+ device->sim->devq->alloc_openings -=
+ cam_ccbq_remove_ccb(ccbq, abort_ccb);
abort_ccb->ccb_h.status =
CAM_REQ_ABORTED|CAM_DEV_QFRZN;
xpt_freeze_devq(abort_ccb->ccb_h.path, 1);
@@ -3008,11 +3007,12 @@ xpt_action_default(union ccb *start_ccb)
}
if ((start_ccb->ccb_h.flags & CAM_DEV_QFREEZE) == 0) {
-
- xpt_release_devq(crs->ccb_h.path, /*count*/1,
- /*run_queue*/TRUE);
+ xpt_release_devq_rl(crs->ccb_h.path, /*runlevel*/
+ (crs->release_flags & RELSIM_RELEASE_RUNLEVEL) ?
+ crs->release_timeout : 0,
+ /*count*/1, /*run_queue*/TRUE);
}
- start_ccb->crs.qfrozen_cnt = dev->ccbq.queue.qfrozen_cnt;
+ start_ccb->crs.qfrozen_cnt = dev->ccbq.queue.qfrozen_cnt[0];
start_ccb->ccb_h.status = CAM_REQ_CMP;
break;
}
@@ -3049,6 +3049,16 @@ xpt_action_default(union ccb *start_ccb)
#endif /* CAMDEBUG */
break;
}
+ case XPT_FREEZE_QUEUE:
+ {
+ struct ccb_relsim *crs = &start_ccb->crs;
+
+ xpt_freeze_devq_rl(crs->ccb_h.path, /*runlevel*/
+ (crs->release_flags & RELSIM_RELEASE_RUNLEVEL) ?
+ crs->release_timeout : 0, /*count*/1);
+ start_ccb->ccb_h.status = CAM_REQ_CMP;
+ break;
+ }
case XPT_NOOP:
if ((start_ccb->ccb_h.flags & CAM_DEV_QFREEZE) != 0)
xpt_freeze_devq(start_ccb->ccb_h.path, 1);
@@ -3129,7 +3139,7 @@ void
xpt_schedule(struct cam_periph *perph, u_int32_t new_priority)
{
struct cam_ed *device;
- int runq;
+ int runq = 0;
mtx_assert(perph->sim->mtx, MA_OWNED);
@@ -3143,8 +3153,8 @@ xpt_schedule(struct cam_periph *perph, u_int32_t new_priority)
camq_change_priority(&device->drvq,
perph->pinfo.index,
new_priority);
+ runq = xpt_schedule_dev_allocq(perph->path->bus, device);
}
- runq = 0;
} else {
/* New entry on the queue */
CAM_DEBUG(perph->path, CAM_DEBUG_SUBTRACE,
@@ -3192,8 +3202,9 @@ xpt_schedule_dev(struct camq *queue, cam_pinfo *pinfo,
CAM_DEBUG_PRINT(CAM_DEBUG_XPT,
("changed priority to %d\n",
new_priority));
- }
- retval = 0;
+ retval = 1;
+ } else
+ retval = 0;
} else {
/* New entry on the queue */
if (new_priority < old_priority)
@@ -3219,15 +3230,15 @@ xpt_run_dev_allocq(struct cam_eb *bus)
CAM_DEBUG_PRINT(CAM_DEBUG_XPT,
(" qfrozen_cnt == 0x%x, entries == %d, "
"openings == %d, active == %d\n",
- devq->alloc_queue.qfrozen_cnt,
+ devq->alloc_queue.qfrozen_cnt[0],
devq->alloc_queue.entries,
devq->alloc_openings,
devq->alloc_active));
- devq->alloc_queue.qfrozen_cnt++;
+ devq->alloc_queue.qfrozen_cnt[0]++;
while ((devq->alloc_queue.entries > 0)
&& (devq->alloc_openings > 0)
- && (devq->alloc_queue.qfrozen_cnt <= 1)) {
+ && (devq->alloc_queue.qfrozen_cnt[0] <= 1)) {
struct cam_ed_qinfo *qinfo;
struct cam_ed *device;
union ccb *work_ccb;
@@ -3237,7 +3248,6 @@ xpt_run_dev_allocq(struct cam_eb *bus)
qinfo = (struct cam_ed_qinfo *)camq_remove(&devq->alloc_queue,
CAMQ_HEAD);
device = qinfo->device;
-
CAM_DEBUG_PRINT(CAM_DEBUG_XPT,
("running device %p\n", device));
@@ -3271,15 +3281,13 @@ xpt_run_dev_allocq(struct cam_eb *bus)
break;
}
- if (drvq->entries > 0) {
- /* We have more work. Attempt to reschedule */
- xpt_schedule_dev_allocq(bus, device);
- }
+ /* We may have more work. Attempt to reschedule. */
+ xpt_schedule_dev_allocq(bus, device);
}
- devq->alloc_queue.qfrozen_cnt--;
+ devq->alloc_queue.qfrozen_cnt[0]--;
}
-void
+static void
xpt_run_dev_sendq(struct cam_eb *bus)
{
struct cam_devq *devq;
@@ -3288,10 +3296,10 @@ xpt_run_dev_sendq(struct cam_eb *bus)
devq = bus->sim->devq;
- devq->send_queue.qfrozen_cnt++;
+ devq->send_queue.qfrozen_cnt[0]++;
while ((devq->send_queue.entries > 0)
&& (devq->send_openings > 0)
- && (devq->send_queue.qfrozen_cnt <= 1)) {
+ && (devq->send_queue.qfrozen_cnt[0] <= 1)) {
struct cam_ed_qinfo *qinfo;
struct cam_ed *device;
union ccb *work_ccb;
@@ -3300,15 +3308,6 @@ xpt_run_dev_sendq(struct cam_eb *bus)
qinfo = (struct cam_ed_qinfo *)camq_remove(&devq->send_queue,
CAMQ_HEAD);
device = qinfo->device;
-
- /*
- * If the device has been "frozen", don't attempt
- * to run it.
- */
- if (device->ccbq.queue.qfrozen_cnt > 0) {
- continue;
- }
-
CAM_DEBUG_PRINT(CAM_DEBUG_XPT,
("running device %p\n", device));
@@ -3328,7 +3327,7 @@ xpt_run_dev_sendq(struct cam_eb *bus)
* the device queue until we have a slot
* available.
*/
- device->ccbq.queue.qfrozen_cnt++;
+ xpt_freeze_devq(work_ccb->ccb_h.path, 1);
STAILQ_INSERT_TAIL(&xsoftc.highpowerq,
&work_ccb->ccb_h,
xpt_links.stqe);
@@ -3350,15 +3349,14 @@ xpt_run_dev_sendq(struct cam_eb *bus)
devq->send_openings--;
devq->send_active++;
- if (device->ccbq.queue.entries > 0)
- xpt_schedule_dev_sendq(bus, device);
+ xpt_schedule_dev_sendq(bus, device);
if (work_ccb && (work_ccb->ccb_h.flags & CAM_DEV_QFREEZE) != 0){
/*
* The client wants to freeze the queue
* after this CCB is sent.
*/
- device->ccbq.queue.qfrozen_cnt++;
+ xpt_freeze_devq(work_ccb->ccb_h.path, 1);
}
/* In Target mode, the peripheral driver knows best... */
@@ -3383,7 +3381,7 @@ xpt_run_dev_sendq(struct cam_eb *bus)
sim = work_ccb->ccb_h.path->bus->sim;
(*(sim->sim_action))(sim, work_ccb);
}
- devq->send_queue.qfrozen_cnt--;
+ devq->send_queue.qfrozen_cnt[0]--;
}
/*
@@ -3789,13 +3787,9 @@ xpt_release_ccb(union ccb *free_ccb)
}
sim->devq->alloc_openings++;
sim->devq->alloc_active--;
- /* XXX Turn this into an inline function - xpt_run_device?? */
- if ((device_is_alloc_queued(device) == 0)
- && (device->drvq.entries > 0)) {
+ if (device_is_alloc_queued(device) == 0)
xpt_schedule_dev_allocq(bus, device);
- }
- if (dev_allocq_is_runnable(sim->devq))
- xpt_run_dev_allocq(bus);
+ xpt_run_dev_allocq(bus);
}
/* Functions accessed by SIM drivers */
@@ -3821,7 +3815,7 @@ xpt_bus_register(struct cam_sim *sim, device_t parent, u_int32_t bus)
struct cam_eb *new_bus;
struct cam_eb *old_bus;
struct ccb_pathinq cpi;
- struct cam_path path;
+ struct cam_path *path;
cam_status status;
mtx_assert(sim->mtx, MA_OWNED);
@@ -3833,6 +3827,11 @@ xpt_bus_register(struct cam_sim *sim, device_t parent, u_int32_t bus)
/* Couldn't satisfy request */
return (CAM_RESRC_UNAVAIL);
}
+ path = (struct cam_path *)malloc(sizeof(*path), M_CAMXPT, M_NOWAIT);
+ if (path == NULL) {
+ free(new_bus, M_CAMXPT);
+ return (CAM_RESRC_UNAVAIL);
+ }
if (strcmp(sim->sim_name, "xpt") != 0) {
sim->path_id =
@@ -3867,13 +3866,12 @@ xpt_bus_register(struct cam_sim *sim, device_t parent, u_int32_t bus)
*/
new_bus->xport = &xport_default;
- bzero(&path, sizeof(path));
- status = xpt_compile_path(&path, /*periph*/NULL, sim->path_id,
+ status = xpt_compile_path(path, /*periph*/NULL, sim->path_id,
CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD);
if (status != CAM_REQ_CMP)
printf("xpt_compile_path returned %d\n", status);
- xpt_setup_ccb(&cpi.ccb_h, &path, CAM_PRIORITY_NORMAL);
+ xpt_setup_ccb(&cpi.ccb_h, path, CAM_PRIORITY_NORMAL);
cpi.ccb_h.func_code = XPT_PATH_INQ;
xpt_action((union ccb *)&cpi);
@@ -3899,9 +3897,17 @@ xpt_bus_register(struct cam_sim *sim, device_t parent, u_int32_t bus)
/* Notify interested parties */
if (sim->path_id != CAM_XPT_PATH_ID) {
- xpt_async(AC_PATH_REGISTERED, &path, &cpi);
- }
- xpt_release_path(&path);
+ union ccb *scan_ccb;
+
+ xpt_async(AC_PATH_REGISTERED, path, &cpi);
+ /* Initiate bus rescan. */
+ scan_ccb = xpt_alloc_ccb_nowait();
+ scan_ccb->ccb_h.path = path;
+ scan_ccb->ccb_h.func_code = XPT_SCAN_BUS;
+ scan_ccb->crcn.flags = 0;
+ xpt_rescan(scan_ccb);
+ } else
+ xpt_free_path(path);
return (CAM_SUCCESS);
}
@@ -4110,12 +4116,34 @@ xpt_dev_async_default(u_int32_t async_code, struct cam_eb *bus,
}
u_int32_t
-xpt_freeze_devq(struct cam_path *path, u_int count)
+xpt_freeze_devq_rl(struct cam_path *path, cam_rl rl, u_int count)
{
+ struct cam_ed *dev = path->device;
mtx_assert(path->bus->sim->mtx, MA_OWNED);
- path->device->ccbq.queue.qfrozen_cnt += count;
- return (path->device->ccbq.queue.qfrozen_cnt);
+ dev->sim->devq->alloc_openings +=
+ cam_ccbq_freeze(&dev->ccbq, rl, count);
+ /* Remove frozen device from allocq. */
+ if (device_is_alloc_queued(dev) &&
+ cam_ccbq_frozen(&dev->ccbq, CAM_PRIORITY_TO_RL(
+ CAMQ_GET_PRIO(&dev->drvq)))) {
+ camq_remove(&dev->sim->devq->alloc_queue,
+ dev->alloc_ccb_entry.pinfo.index);
+ }
+ /* Remove frozen device from sendq. */
+ if (device_is_send_queued(dev) &&
+ cam_ccbq_frozen_top(&dev->ccbq)) {
+ camq_remove(&dev->sim->devq->send_queue,
+ dev->send_ccb_entry.pinfo.index);
+ }
+ return (dev->ccbq.queue.qfrozen_cnt[rl]);
+}
+
+u_int32_t
+xpt_freeze_devq(struct cam_path *path, u_int count)
+{
+
+ return (xpt_freeze_devq_rl(path, 0, count));
}
u_int32_t
@@ -4123,8 +4151,8 @@ xpt_freeze_simq(struct cam_sim *sim, u_int count)
{
mtx_assert(sim->mtx, MA_OWNED);
- sim->devq->send_queue.qfrozen_cnt += count;
- return (sim->devq->send_queue.qfrozen_cnt);
+ sim->devq->send_queue.qfrozen_cnt[0] += count;
+ return (sim->devq->send_queue.qfrozen_cnt[0]);
}
static void
@@ -4134,7 +4162,7 @@ xpt_release_devq_timeout(void *arg)
device = (struct cam_ed *)arg;
- xpt_release_devq_device(device, /*count*/1, /*run_queue*/TRUE);
+ xpt_release_devq_device(device, /*rl*/0, /*count*/1, /*run_queue*/TRUE);
}
void
@@ -4142,51 +4170,59 @@ xpt_release_devq(struct cam_path *path, u_int count, int run_queue)
{
mtx_assert(path->bus->sim->mtx, MA_OWNED);
- xpt_release_devq_device(path->device, count, run_queue);
+ xpt_release_devq_device(path->device, /*rl*/0, count, run_queue);
}
-static void
-xpt_release_devq_device(struct cam_ed *dev, u_int count, int run_queue)
+void
+xpt_release_devq_rl(struct cam_path *path, cam_rl rl, u_int count, int run_queue)
{
- int rundevq;
-
- rundevq = 0;
- if (dev->ccbq.queue.qfrozen_cnt > 0) {
-
- count = (count > dev->ccbq.queue.qfrozen_cnt) ?
- dev->ccbq.queue.qfrozen_cnt : count;
- dev->ccbq.queue.qfrozen_cnt -= count;
- if (dev->ccbq.queue.qfrozen_cnt == 0) {
+ mtx_assert(path->bus->sim->mtx, MA_OWNED);
- /*
- * No longer need to wait for a successful
- * command completion.
- */
- dev->flags &= ~CAM_DEV_REL_ON_COMPLETE;
+ xpt_release_devq_device(path->device, rl, count, run_queue);
+}
- /*
- * Remove any timeouts that might be scheduled
- * to release this queue.
- */
- if ((dev->flags & CAM_DEV_REL_TIMEOUT_PENDING) != 0) {
- callout_stop(&dev->callout);
- dev->flags &= ~CAM_DEV_REL_TIMEOUT_PENDING;
- }
+static void
+xpt_release_devq_device(struct cam_ed *dev, cam_rl rl, u_int count, int run_queue)
+{
- /*
- * Now that we are unfrozen schedule the
- * device so any pending transactions are
- * run.
- */
- if ((dev->ccbq.queue.entries > 0)
- && (xpt_schedule_dev_sendq(dev->target->bus, dev))
- && (run_queue != 0)) {
- rundevq = 1;
- }
+ if (count > dev->ccbq.queue.qfrozen_cnt[rl]) {
+#ifdef INVARIANTS
+ printf("xpt_release_devq(%d): requested %u > present %u\n",
+ rl, count, dev->ccbq.queue.qfrozen_cnt[rl]);
+#endif
+ count = dev->ccbq.queue.qfrozen_cnt[rl];
+ }
+ dev->sim->devq->alloc_openings -=
+ cam_ccbq_release(&dev->ccbq, rl, count);
+ if (cam_ccbq_frozen(&dev->ccbq, CAM_PRIORITY_TO_RL(
+ CAMQ_GET_PRIO(&dev->drvq))) == 0) {
+ if (xpt_schedule_dev_allocq(dev->target->bus, dev))
+ xpt_run_dev_allocq(dev->target->bus);
+ }
+ if (cam_ccbq_frozen_top(&dev->ccbq) == 0) {
+ /*
+ * No longer need to wait for a successful
+ * command completion.
+ */
+ dev->flags &= ~CAM_DEV_REL_ON_COMPLETE;
+ /*
+ * Remove any timeouts that might be scheduled
+ * to release this queue.
+ */
+ if ((dev->flags & CAM_DEV_REL_TIMEOUT_PENDING) != 0) {
+ callout_stop(&dev->callout);
+ dev->flags &= ~CAM_DEV_REL_TIMEOUT_PENDING;
}
+ if (run_queue == 0)
+ return;
+ /*
+ * Now that we are unfrozen schedule the
+ * device so any pending transactions are
+ * run.
+ */
+ if (xpt_schedule_dev_sendq(dev->target->bus, dev))
+ xpt_run_dev_sendq(dev->target->bus);
}
- if (rundevq != 0)
- xpt_run_dev_sendq(dev->target->bus);
}
void
@@ -4195,32 +4231,33 @@ xpt_release_simq(struct cam_sim *sim, int run_queue)
struct camq *sendq;
mtx_assert(sim->mtx, MA_OWNED);
-
sendq = &(sim->devq->send_queue);
- if (sendq->qfrozen_cnt > 0) {
+ if (sendq->qfrozen_cnt[0] <= 0) {
+#ifdef INVARIANTS
+ printf("xpt_release_simq: requested 1 > present %u\n",
+ sendq->qfrozen_cnt[0]);
+#endif
+ } else
+ sendq->qfrozen_cnt[0]--;
+ if (sendq->qfrozen_cnt[0] == 0) {
+ /*
+ * If there is a timeout scheduled to release this
+ * sim queue, remove it. The queue frozen count is
+ * already at 0.
+ */
+ if ((sim->flags & CAM_SIM_REL_TIMEOUT_PENDING) != 0){
+ callout_stop(&sim->callout);
+ sim->flags &= ~CAM_SIM_REL_TIMEOUT_PENDING;
+ }
+ if (run_queue) {
+ struct cam_eb *bus;
- sendq->qfrozen_cnt--;
- if (sendq->qfrozen_cnt == 0) {
/*
- * If there is a timeout scheduled to release this
- * sim queue, remove it. The queue frozen count is
- * already at 0.
+ * Now that we are unfrozen run the send queue.
*/
- if ((sim->flags & CAM_SIM_REL_TIMEOUT_PENDING) != 0){
- callout_stop(&sim->callout);
- sim->flags &= ~CAM_SIM_REL_TIMEOUT_PENDING;
- }
-
- if (run_queue) {
- struct cam_eb *bus;
-
- /*
- * Now that we are unfrozen run the send queue.
- */
- bus = xpt_find_bus(sim->path_id);
- xpt_run_dev_sendq(bus);
- xpt_release_bus(bus);
- }
+ bus = xpt_find_bus(sim->path_id);
+ xpt_run_dev_sendq(bus);
+ xpt_release_bus(bus);
}
}
}
@@ -4399,7 +4436,7 @@ xpt_alloc_device_default(struct cam_eb *bus, struct cam_et *target,
device->mintags = 1;
device->maxtags = 1;
- bus->sim->max_ccbs = device->ccbq.devq_openings;
+ bus->sim->max_ccbs += device->ccbq.devq_openings;
cur_device = TAILQ_FIRST(&target->ed_entries);
while (cur_device != NULL && cur_device->lun_id < lun_id)
cur_device = TAILQ_NEXT(cur_device, links);
@@ -4629,104 +4666,16 @@ xpt_stop_tags(struct cam_path *path)
xpt_action((union ccb *)&crs);
}
-static int busses_to_config;
-static int busses_to_reset;
-
-static int
-xptconfigbuscountfunc(struct cam_eb *bus, void *arg)
-{
-
- mtx_assert(bus->sim->mtx, MA_OWNED);
-
- 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, CAM_PRIORITY_NORMAL);
- 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);
-}
-
-static int
-xptconfigfunc(struct cam_eb *bus, void *arg)
+static void
+xpt_boot_delay(void *arg)
{
- struct cam_path *path;
- union ccb *work_ccb;
- mtx_assert(bus->sim->mtx, MA_OWNED);
-
- if (bus->path_id != CAM_XPT_PATH_ID) {
- cam_status status;
- int can_negotiate;
-
- work_ccb = xpt_alloc_ccb_nowait();
- if (work_ccb == NULL) {
- busses_to_config--;
- xpt_finishconfig(xpt_periph, NULL);
- return(0);
- }
- if ((status = xpt_create_path(&path, xpt_periph, bus->path_id,
- CAM_TARGET_WILDCARD,
- CAM_LUN_WILDCARD)) !=CAM_REQ_CMP){
- printf("xptconfigfunc: xpt_create_path failed with "
- "status %#x for scbus%d\n", status, bus->path_id);
- printf("xptconfigfunc: halting bus configuration\n");
- xpt_free_ccb(work_ccb);
- busses_to_config--;
- xpt_finishconfig(xpt_periph, NULL);
- return(0);
- }
- xpt_setup_ccb(&work_ccb->ccb_h, path, CAM_PRIORITY_NORMAL);
- work_ccb->ccb_h.func_code = XPT_PATH_INQ;
- xpt_action(work_ccb);
- if (work_ccb->ccb_h.status != CAM_REQ_CMP) {
- printf("xptconfigfunc: CPI failed on scbus%d "
- "with status %d\n", bus->path_id,
- work_ccb->ccb_h.status);
- xpt_finishconfig(xpt_periph, work_ccb);
- return(1);
- }
-
- 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, CAM_PRIORITY_NORMAL);
- work_ccb->ccb_h.func_code = XPT_RESET_BUS;
- work_ccb->ccb_h.cbfcnp = NULL;
- CAM_DEBUG(path, CAM_DEBUG_SUBTRACE,
- ("Resetting Bus\n"));
- xpt_action(work_ccb);
- xpt_finishconfig(xpt_periph, work_ccb);
- } else {
- /* Act as though we performed a successful BUS RESET */
- work_ccb->ccb_h.func_code = XPT_RESET_BUS;
- xpt_finishconfig(xpt_periph, work_ccb);
- }
- }
-
- return(1);
+ xpt_release_boot();
}
static void
xpt_config(void *arg)
{
- struct periph_driver **p_drv;
- int i;
-
/*
* Now that interrupts are enabled, go find our devices
*/
@@ -4760,28 +4709,43 @@ xpt_config(void *arg)
#endif /* CAM_DEBUG_BUS */
#endif /* CAMDEBUG */
- /* Register early peripheral drivers */
- /* XXX This will have to change when we have loadable modules */
- p_drv = periph_drivers;
- for (i = 0; p_drv[i] != NULL; i++) {
- if ((p_drv[i]->flags & CAM_PERIPH_DRV_EARLY) != 0)
- (*p_drv[i]->init)();
+ periphdriver_init(1);
+ xpt_hold_boot();
+ callout_init(&xsoftc.boot_callout, 1);
+ callout_reset(&xsoftc.boot_callout, hz * xsoftc.boot_delay / 1000,
+ xpt_boot_delay, NULL);
+ /* Fire up rescan thread. */
+ if (kproc_create(xpt_scanner_thread, NULL, NULL, 0, 0, "xpt_thrd")) {
+ printf("xpt_init: failed to create rescan thread\n");
}
- /*
- * Scan all installed busses.
- */
- xpt_for_all_busses(xptconfigbuscountfunc, NULL);
+}
+
+void
+xpt_hold_boot(void)
+{
+ xpt_lock_buses();
+ xsoftc.buses_to_config++;
+ xpt_unlock_buses();
+}
+
+void
+xpt_release_boot(void)
+{
+ xpt_lock_buses();
+ xsoftc.buses_to_config--;
+ if (xsoftc.buses_to_config == 0 && xsoftc.buses_config_done == 0) {
+ struct xpt_task *task;
- if (busses_to_config == 0) {
+ xsoftc.buses_config_done = 1;
+ xpt_unlock_buses();
/* Call manually because we don't have any busses */
- xpt_finishconfig(xpt_periph, NULL);
- } else {
- if (busses_to_reset > 0 && scsi_delay >= 2000) {
- printf("Waiting %d seconds for SCSI "
- "devices to settle\n", scsi_delay/1000);
+ task = malloc(sizeof(struct xpt_task), M_CAMXPT, M_NOWAIT);
+ if (task != NULL) {
+ TASK_INIT(&task->task, 0, xpt_finishconfig_task, task);
+ taskqueue_enqueue(taskqueue_thread, &task->task);
}
- xpt_for_all_busses(xptconfigfunc, NULL);
- }
+ } else
+ xpt_unlock_buses();
}
/*
@@ -4809,72 +4773,23 @@ xptpassannouncefunc(struct cam_ed *device, void *arg)
static void
xpt_finishconfig_task(void *context, int pending)
{
- struct periph_driver **p_drv;
- int i;
-
- if (busses_to_config == 0) {
- /* Register all the peripheral drivers */
- /* XXX This will have to change when we have loadable modules */
- p_drv = periph_drivers;
- for (i = 0; p_drv[i] != NULL; i++) {
- if ((p_drv[i]->flags & CAM_PERIPH_DRV_EARLY) == 0)
- (*p_drv[i]->init)();
- }
- /*
- * Check for devices with no "standard" peripheral driver
- * attached. For any devices like that, announce the
- * passthrough driver so the user will see something.
- */
- xpt_for_all_devices(xptpassannouncefunc, NULL);
+ periphdriver_init(2);
+ /*
+ * Check for devices with no "standard" peripheral driver
+ * attached. For any devices like that, announce the
+ * passthrough driver so the user will see something.
+ */
+ xpt_for_all_devices(xptpassannouncefunc, NULL);
- /* Release our hook so that the boot can continue. */
- config_intrhook_disestablish(xsoftc.xpt_config_hook);
- free(xsoftc.xpt_config_hook, M_CAMXPT);
- xsoftc.xpt_config_hook = NULL;
- }
+ /* Release our hook so that the boot can continue. */
+ config_intrhook_disestablish(xsoftc.xpt_config_hook);
+ free(xsoftc.xpt_config_hook, M_CAMXPT);
+ xsoftc.xpt_config_hook = NULL;
free(context, M_CAMXPT);
}
-static void
-xpt_finishconfig(struct cam_periph *periph, union ccb *done_ccb)
-{
- struct xpt_task *task;
-
- if (done_ccb != NULL) {
- CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_TRACE,
- ("xpt_finishconfig\n"));
- switch(done_ccb->ccb_h.func_code) {
- case XPT_RESET_BUS:
- if (done_ccb->ccb_h.status == CAM_REQ_CMP) {
- done_ccb->ccb_h.func_code = XPT_SCAN_BUS;
- done_ccb->ccb_h.cbfcnp = xpt_finishconfig;
- done_ccb->crcn.flags = 0;
- xpt_action(done_ccb);
- return;
- }
- /* FALLTHROUGH */
- case XPT_SCAN_BUS:
- default:
- xpt_free_path(done_ccb->ccb_h.path);
- busses_to_config--;
- break;
- }
- }
-
- if (busses_to_config == 0) {
- task = malloc(sizeof(struct xpt_task), M_CAMXPT, M_NOWAIT);
- if (task != NULL) {
- TASK_INIT(&task->task, 0, xpt_finishconfig_task, task);
- taskqueue_enqueue(taskqueue_thread, &task->task);
- }
- }
-
- if (done_ccb != NULL)
- xpt_free_ccb(done_ccb);
-}
-
cam_status
xpt_register_async(int event, ac_callback_t *cbfunc, void *cbarg,
struct cam_path *path)
@@ -4894,7 +4809,7 @@ xpt_register_async(int event, ac_callback_t *cbfunc, void *cbarg,
xptpath = 1;
}
- xpt_setup_ccb(&csa.ccb_h, path, /*priority*/5);
+ xpt_setup_ccb(&csa.ccb_h, path, CAM_PRIORITY_NORMAL);
csa.ccb_h.func_code = XPT_SASYNC_CB;
csa.event_enable = event;
csa.callback = cbfunc;
@@ -5047,26 +4962,19 @@ camisr_runqueue(void *V_queue)
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++;
+ runq = TRUE;
if (((dev->flags & CAM_DEV_REL_ON_COMPLETE) != 0
&& (ccb_h->status&CAM_STATUS_MASK) != CAM_REQUEUE_REQ)
|| ((dev->flags & CAM_DEV_REL_ON_QUEUE_EMPTY) != 0
&& (dev->ccbq.dev_active == 0))) {
-
xpt_release_devq(ccb_h->path, /*count*/1,
- /*run_queue*/TRUE);
+ /*run_queue*/FALSE);
}
if ((dev->flags & CAM_DEV_TAG_AFTER_COUNT) != 0
&& (--dev->tag_delay_count == 0))
xpt_start_tags(ccb_h->path);
-
- if ((dev->ccbq.queue.entries > 0)
- && (dev->ccbq.queue.qfrozen_cnt == 0)
- && (device_is_send_queued(dev) == 0)) {
- runq = xpt_schedule_dev_sendq(ccb_h->path->bus,
- dev);
- }
}
if (ccb_h->status & CAM_RELEASE_SIMQ) {
diff --git a/sys/cam/cam_xpt.h b/sys/cam/cam_xpt.h
index 283cad1..61a7f3f 100644
--- a/sys/cam/cam_xpt.h
+++ b/sys/cam/cam_xpt.h
@@ -87,6 +87,9 @@ SLIST_HEAD(periph_list, cam_periph);
void xpt_action(union ccb *new_ccb);
void xpt_action_default(union ccb *new_ccb);
+union ccb *xpt_alloc_ccb(void);
+union ccb *xpt_alloc_ccb_nowait(void);
+void xpt_free_ccb(union ccb *free_ccb);
void xpt_setup_ccb(struct ccb_hdr *ccb_h,
struct cam_path *path,
u_int32_t priority);
@@ -115,6 +118,8 @@ struct cam_periph *xpt_path_periph(struct cam_path *path);
void xpt_async(u_int32_t async_code, struct cam_path *path,
void *async_arg);
void xpt_rescan(union ccb *ccb);
+void xpt_hold_boot(void);
+void xpt_release_boot(void);
void xpt_lock_buses(void);
void xpt_unlock_buses(void);
cam_status xpt_register_async(int event, ac_callback_t *cbfunc,
diff --git a/sys/cam/cam_xpt_internal.h b/sys/cam/cam_xpt_internal.h
index 146764e..b1fbaaf 100644
--- a/sys/cam/cam_xpt_internal.h
+++ b/sys/cam/cam_xpt_internal.h
@@ -172,7 +172,6 @@ struct cam_ed * xpt_alloc_device(struct cam_eb *bus,
lun_id_t lun_id);
void xpt_acquire_device(struct cam_ed *device);
void xpt_release_device(struct cam_ed *device);
-void xpt_run_dev_sendq(struct cam_eb *bus);
int xpt_schedule_dev(struct camq *queue, cam_pinfo *dev_pinfo,
u_int32_t new_priority);
u_int32_t xpt_dev_ccbq_resize(struct cam_path *path, int newopenings);
diff --git a/sys/cam/cam_xpt_periph.h b/sys/cam/cam_xpt_periph.h
index dbfb55e..867b1c1 100644
--- a/sys/cam/cam_xpt_periph.h
+++ b/sys/cam/cam_xpt_periph.h
@@ -39,9 +39,6 @@
/* Functions accessed by the peripheral drivers */
#ifdef _KERNEL
void xpt_polled_action(union ccb *ccb);
-union ccb *xpt_alloc_ccb(void);
-union ccb *xpt_alloc_ccb_nowait(void);
-void xpt_free_ccb(union ccb *free_ccb);
void xpt_release_ccb(union ccb *released_ccb);
void xpt_schedule(struct cam_periph *perph, u_int32_t new_priority);
int32_t xpt_add_periph(struct cam_periph *periph);
diff --git a/sys/cam/cam_xpt_sim.h b/sys/cam/cam_xpt_sim.h
index e64c67c..323f786 100644
--- a/sys/cam/cam_xpt_sim.h
+++ b/sys/cam/cam_xpt_sim.h
@@ -43,8 +43,12 @@ int32_t xpt_bus_deregister(path_id_t path_id);
u_int32_t xpt_freeze_simq(struct cam_sim *sim, u_int count);
void xpt_release_simq(struct cam_sim *sim, int run_queue);
u_int32_t xpt_freeze_devq(struct cam_path *path, u_int count);
-void xpt_release_devq(struct cam_path *path, u_int count,
- int run_queue);
+u_int32_t xpt_freeze_devq_rl(struct cam_path *path, cam_rl rl,
+ u_int count);
+void xpt_release_devq(struct cam_path *path,
+ u_int count, int run_queue);
+void xpt_release_devq_rl(struct cam_path *path, cam_rl rl,
+ u_int count, int run_queue);
int xpt_sim_opened(struct cam_sim *sim);
void xpt_done(union ccb *done_ccb);
#endif
diff --git a/sys/cam/scsi/scsi_all.c b/sys/cam/scsi/scsi_all.c
index e6f3a7c..d40a536 100644
--- a/sys/cam/scsi/scsi_all.c
+++ b/sys/cam/scsi/scsi_all.c
@@ -2880,7 +2880,7 @@ scsi_error_action(struct ccb_scsiio *csio, struct scsi_inquiry_data *inq_data,
}
}
}
-#ifdef KERNEL
+#ifdef _KERNEL
if (bootverbose)
sense_flags |= SF_PRINT_ALWAYS;
#endif
@@ -2995,27 +2995,29 @@ scsi_command_string(struct cam_device *device, struct ccb_scsiio *csio,
struct scsi_inquiry_data *inq_data;
char cdb_str[(SCSI_MAX_CDBLEN * 3) + 1];
#ifdef _KERNEL
- struct ccb_getdev cgd;
+ struct ccb_getdev *cgd;
#endif /* _KERNEL */
#ifdef _KERNEL
+ if ((cgd = (struct ccb_getdev*)xpt_alloc_ccb_nowait()) == NULL)
+ return(-1);
/*
* Get the device information.
*/
- xpt_setup_ccb(&cgd.ccb_h,
+ xpt_setup_ccb(&cgd->ccb_h,
csio->ccb_h.path,
CAM_PRIORITY_NORMAL);
- cgd.ccb_h.func_code = XPT_GDEV_TYPE;
- xpt_action((union ccb *)&cgd);
+ cgd->ccb_h.func_code = XPT_GDEV_TYPE;
+ xpt_action((union ccb *)cgd);
/*
* If the device is unconfigured, just pretend that it is a hard
* drive. scsi_op_desc() needs this.
*/
- if (cgd.ccb_h.status == CAM_DEV_NOT_THERE)
- cgd.inq_data.device = T_DIRECT;
+ if (cgd->ccb_h.status == CAM_DEV_NOT_THERE)
+ cgd->inq_data.device = T_DIRECT;
- inq_data = &cgd.inq_data;
+ inq_data = &cgd->inq_data;
#else /* !_KERNEL */
@@ -3055,7 +3057,7 @@ scsi_sense_sbuf(struct cam_device *device, struct ccb_scsiio *csio,
struct scsi_sense_data *sense;
struct scsi_inquiry_data *inq_data;
#ifdef _KERNEL
- struct ccb_getdev cgd;
+ struct ccb_getdev *cgd;
#endif /* _KERNEL */
u_int32_t info;
int error_code;
@@ -3083,23 +3085,25 @@ scsi_sense_sbuf(struct cam_device *device, struct ccb_scsiio *csio,
#endif /* _KERNEL/!_KERNEL */
#ifdef _KERNEL
+ if ((cgd = (struct ccb_getdev*)xpt_alloc_ccb_nowait()) == NULL)
+ return(-1);
/*
* Get the device information.
*/
- xpt_setup_ccb(&cgd.ccb_h,
+ xpt_setup_ccb(&cgd->ccb_h,
csio->ccb_h.path,
CAM_PRIORITY_NORMAL);
- cgd.ccb_h.func_code = XPT_GDEV_TYPE;
- xpt_action((union ccb *)&cgd);
+ cgd->ccb_h.func_code = XPT_GDEV_TYPE;
+ xpt_action((union ccb *)cgd);
/*
* If the device is unconfigured, just pretend that it is a hard
* drive. scsi_op_desc() needs this.
*/
- if (cgd.ccb_h.status == CAM_DEV_NOT_THERE)
- cgd.inq_data.device = T_DIRECT;
+ if (cgd->ccb_h.status == CAM_DEV_NOT_THERE)
+ cgd->inq_data.device = T_DIRECT;
- inq_data = &cgd.inq_data;
+ inq_data = &cgd->inq_data;
#else /* !_KERNEL */
@@ -3125,9 +3129,12 @@ scsi_sense_sbuf(struct cam_device *device, struct ccb_scsiio *csio,
* If the sense data is a physical pointer, forget it.
*/
if (csio->ccb_h.flags & CAM_SENSE_PTR) {
- if (csio->ccb_h.flags & CAM_SENSE_PHYS)
+ if (csio->ccb_h.flags & CAM_SENSE_PHYS) {
+#ifdef _KERNEL
+ xpt_free_ccb((union ccb*)cgd);
+#endif /* _KERNEL/!_KERNEL */
return(-1);
- else {
+ } else {
/*
* bcopy the pointer to avoid unaligned access
* errors on finicky architectures. We don't
@@ -3145,9 +3152,12 @@ scsi_sense_sbuf(struct cam_device *device, struct ccb_scsiio *csio,
* dumped on one of the bogus pointer deferences above
* already.)
*/
- if (csio->ccb_h.flags & CAM_SENSE_PHYS)
+ if (csio->ccb_h.flags & CAM_SENSE_PHYS) {
+#ifdef _KERNEL
+ xpt_free_ccb((union ccb*)cgd);
+#endif /* _KERNEL/!_KERNEL */
return(-1);
- else
+ } else
sense = &csio->sense_data;
}
@@ -3157,9 +3167,10 @@ scsi_sense_sbuf(struct cam_device *device, struct ccb_scsiio *csio,
error_code = sense->error_code & SSD_ERRCODE;
sense_key = sense->flags & SSD_KEY;
+ sbuf_printf(sb, "SCSI sense: ");
switch (error_code) {
case SSD_DEFERRED_ERROR:
- sbuf_printf(sb, "Deferred Error: ");
+ sbuf_printf(sb, "Deferred error: ");
/* FALLTHROUGH */
case SSD_CURRENT_ERROR:
@@ -3212,8 +3223,7 @@ scsi_sense_sbuf(struct cam_device *device, struct ccb_scsiio *csio,
}
}
- sbuf_printf(sb, " asc:%x,%x\n%s%s", asc, ascq,
- path_str, asc_desc);
+ sbuf_printf(sb, " asc:%x,%x (%s)", asc, ascq, asc_desc);
if (sense->extra_len >= 7 && sense->fru) {
sbuf_printf(sb, " field replaceable unit: %x",
@@ -3265,7 +3275,7 @@ scsi_sense_sbuf(struct cam_device *device, struct ccb_scsiio *csio,
}
default:
- sbuf_printf(sb, "Sense Error Code 0x%x", sense->error_code);
+ sbuf_printf(sb, "Error code 0x%x", sense->error_code);
if (sense->error_code & SSD_ERRCODE_VALID) {
sbuf_printf(sb, " at block no. %d (decimal)",
info = scsi_4btoul(sense->info));
@@ -3274,6 +3284,9 @@ scsi_sense_sbuf(struct cam_device *device, struct ccb_scsiio *csio,
sbuf_printf(sb, "\n");
+#ifdef _KERNEL
+ xpt_free_ccb((union ccb*)cgd);
+#endif /* _KERNEL/!_KERNEL */
return(0);
}
diff --git a/sys/cam/scsi/scsi_cd.c b/sys/cam/scsi/scsi_cd.c
index cf99eea..9d5dcf6 100644
--- a/sys/cam/scsi/scsi_cd.c
+++ b/sys/cam/scsi/scsi_cd.c
@@ -433,7 +433,7 @@ cdcleanup(struct cam_periph *periph)
callout_stop(&softc->changer->short_handle);
softc->changer->flags &= ~CHANGER_SHORT_TMOUT_SCHED;
}
- softc->changer->devq.qfrozen_cnt--;
+ softc->changer->devq.qfrozen_cnt[0]--;
softc->changer->flags |= CHANGER_MANUAL_CALL;
cdrunchangerqueue(softc->changer);
}
@@ -972,9 +972,9 @@ cdregisterexit:
(void)cam_periph_hold(periph, PRIBIO);
if ((softc->flags & CD_FLAG_CHANGER) == 0)
- xpt_schedule(periph, /*priority*/5);
+ xpt_schedule(periph, CAM_PRIORITY_DEV);
else
- cdschedule(periph, /*priority*/ 5);
+ cdschedule(periph, CAM_PRIORITY_DEV);
return(CAM_REQ_CMP);
}
@@ -1167,13 +1167,13 @@ cdrunchangerqueue(void *arg)
* If the changer queue is frozen, that means we have an active
* device.
*/
- if (changer->devq.qfrozen_cnt > 0) {
+ if (changer->devq.qfrozen_cnt[0] > 0) {
/*
* We always need to reset the frozen count and clear the
* active flag.
*/
- changer->devq.qfrozen_cnt--;
+ changer->devq.qfrozen_cnt[0]--;
changer->cur_device->flags &= ~CD_FLAG_ACTIVE;
changer->cur_device->flags &= ~CD_FLAG_SCHED_ON_COMP;
@@ -1208,7 +1208,7 @@ cdrunchangerqueue(void *arg)
changer->cur_device = softc;
- changer->devq.qfrozen_cnt++;
+ changer->devq.qfrozen_cnt[0]++;
softc->flags |= CD_FLAG_ACTIVE;
/* Just in case this device is waiting */
@@ -1465,7 +1465,7 @@ cdstart(struct cam_periph *periph, union ccb *start_ccb)
bioq_remove(&softc->bio_queue, bp);
scsi_read_write(&start_ccb->csio,
- /*retries*/cd_retry_count,
+ /*retries*/ cd_retry_count,
/* cbfcnp */ cddone,
MSG_SIMPLE_Q_TAG,
/* read */bp->bio_cmd == BIO_READ,
@@ -1516,7 +1516,7 @@ cdstart(struct cam_periph *periph, union ccb *start_ccb)
}
csio = &start_ccb->csio;
scsi_read_capacity(csio,
- /*retries*/1,
+ /*retries*/ cd_retry_count,
cddone,
MSG_SIMPLE_Q_TAG,
rcap,
@@ -2733,7 +2733,7 @@ cdprevent(struct cam_periph *periph, int action)
ccb = cdgetccb(periph, CAM_PRIORITY_NORMAL);
scsi_prevent(&ccb->csio,
- /*retries*/ 1,
+ /*retries*/ cd_retry_count,
cddone,
MSG_SIMPLE_Q_TAG,
action,
@@ -2911,7 +2911,7 @@ cdsize(struct cam_periph *periph, u_int32_t *size)
return (ENOMEM);
scsi_read_capacity(&ccb->csio,
- /*retries*/ 1,
+ /*retries*/ cd_retry_count,
cddone,
MSG_SIMPLE_Q_TAG,
rcap_buf,
@@ -3159,7 +3159,7 @@ cdreadtoc(struct cam_periph *periph, u_int32_t mode, u_int32_t start,
csio = &ccb->csio;
cam_fill_csio(csio,
- /* retries */ 1,
+ /* retries */ cd_retry_count,
/* cbfcnp */ cddone,
/* flags */ CAM_DIR_IN,
/* tag_action */ MSG_SIMPLE_Q_TAG,
@@ -3206,7 +3206,7 @@ cdreadsubchannel(struct cam_periph *periph, u_int32_t mode,
csio = &ccb->csio;
cam_fill_csio(csio,
- /* retries */ 1,
+ /* retries */ cd_retry_count,
/* cbfcnp */ cddone,
/* flags */ CAM_DIR_IN,
/* tag_action */ MSG_SIMPLE_Q_TAG,
@@ -3267,7 +3267,7 @@ cdgetmode(struct cam_periph *periph, struct cd_mode_params *data,
param_len = min(param_len, data->alloc_len);
scsi_mode_sense_len(csio,
- /* retries */ 1,
+ /* retries */ cd_retry_count,
/* cbfcnp */ cddone,
/* tag_action */ MSG_SIMPLE_Q_TAG,
/* dbd */ 0,
@@ -3410,7 +3410,7 @@ cdsetmode(struct cam_periph *periph, struct cd_mode_params *data)
param_len = min(param_len, data->alloc_len);
scsi_mode_select_len(csio,
- /* retries */ 1,
+ /* retries */ cd_retry_count,
/* cbfcnp */ cddone,
/* tag_action */ MSG_SIMPLE_Q_TAG,
/* scsi_page_fmt */ 1,
@@ -3472,7 +3472,7 @@ cdplay(struct cam_periph *periph, u_int32_t blk, u_int32_t len)
cdb_len = sizeof(*scsi_cmd);
}
cam_fill_csio(csio,
- /*retries*/2,
+ /*retries*/ cd_retry_count,
cddone,
/*flags*/CAM_DIR_NONE,
MSG_SIMPLE_Q_TAG,
@@ -3506,7 +3506,7 @@ cdplaymsf(struct cam_periph *periph, u_int32_t startm, u_int32_t starts,
csio = &ccb->csio;
cam_fill_csio(csio,
- /* retries */ 1,
+ /* retries */ cd_retry_count,
/* cbfcnp */ cddone,
/* flags */ CAM_DIR_NONE,
/* tag_action */ MSG_SIMPLE_Q_TAG,
@@ -3552,7 +3552,7 @@ cdplaytracks(struct cam_periph *periph, u_int32_t strack, u_int32_t sindex,
csio = &ccb->csio;
cam_fill_csio(csio,
- /* retries */ 1,
+ /* retries */ cd_retry_count,
/* cbfcnp */ cddone,
/* flags */ CAM_DIR_NONE,
/* tag_action */ MSG_SIMPLE_Q_TAG,
@@ -3594,7 +3594,7 @@ cdpause(struct cam_periph *periph, u_int32_t go)
csio = &ccb->csio;
cam_fill_csio(csio,
- /* retries */ 1,
+ /* retries */ cd_retry_count,
/* cbfcnp */ cddone,
/* flags */ CAM_DIR_NONE,
/* tag_action */ MSG_SIMPLE_Q_TAG,
@@ -3629,7 +3629,7 @@ cdstartunit(struct cam_periph *periph, int load)
ccb = cdgetccb(periph, CAM_PRIORITY_NORMAL);
scsi_start_stop(&ccb->csio,
- /* retries */ 1,
+ /* retries */ cd_retry_count,
/* cbfcnp */ cddone,
/* tag_action */ MSG_SIMPLE_Q_TAG,
/* start */ TRUE,
@@ -3657,7 +3657,7 @@ cdstopunit(struct cam_periph *periph, u_int32_t eject)
ccb = cdgetccb(periph, CAM_PRIORITY_NORMAL);
scsi_start_stop(&ccb->csio,
- /* retries */ 1,
+ /* retries */ cd_retry_count,
/* cbfcnp */ cddone,
/* tag_action */ MSG_SIMPLE_Q_TAG,
/* start */ FALSE,
@@ -3693,7 +3693,7 @@ cdsetspeed(struct cam_periph *periph, u_int32_t rdspeed, u_int32_t wrspeed)
wrspeed *= 177;
cam_fill_csio(csio,
- /* retries */ 1,
+ /* retries */ cd_retry_count,
/* cbfcnp */ cddone,
/* flags */ CAM_DIR_NONE,
/* tag_action */ MSG_SIMPLE_Q_TAG,
@@ -3768,7 +3768,7 @@ cdreportkey(struct cam_periph *periph, struct dvd_authinfo *authinfo)
ccb = cdgetccb(periph, CAM_PRIORITY_NORMAL);
scsi_report_key(&ccb->csio,
- /* retries */ 1,
+ /* retries */ cd_retry_count,
/* cbfcnp */ cddone,
/* tag_action */ MSG_SIMPLE_Q_TAG,
/* lba */ lba,
@@ -3946,7 +3946,7 @@ cdsendkey(struct cam_periph *periph, struct dvd_authinfo *authinfo)
ccb = cdgetccb(periph, CAM_PRIORITY_NORMAL);
scsi_send_key(&ccb->csio,
- /* retries */ 1,
+ /* retries */ cd_retry_count,
/* cbfcnp */ cddone,
/* tag_action */ MSG_SIMPLE_Q_TAG,
/* agid */ authinfo->agid,
@@ -4050,7 +4050,7 @@ cdreaddvdstructure(struct cam_periph *periph, struct dvd_struct *dvdstruct)
ccb = cdgetccb(periph, CAM_PRIORITY_NORMAL);
scsi_read_dvd_structure(&ccb->csio,
- /* retries */ 1,
+ /* retries */ cd_retry_count,
/* cbfcnp */ cddone,
/* tag_action */ MSG_SIMPLE_Q_TAG,
/* lba */ address,
diff --git a/sys/cam/scsi/scsi_ch.c b/sys/cam/scsi/scsi_ch.c
index 2829a15..107f22b 100644
--- a/sys/cam/scsi/scsi_ch.c
+++ b/sys/cam/scsi/scsi_ch.c
@@ -376,7 +376,7 @@ chregister(struct cam_periph *periph, void *arg)
* This first call can't block
*/
(void)cam_periph_hold(periph, PRIBIO);
- xpt_schedule(periph, /*priority*/5);
+ xpt_schedule(periph, CAM_PRIORITY_DEV);
return(CAM_REQ_CMP);
}
diff --git a/sys/cam/scsi/scsi_da.c b/sys/cam/scsi/scsi_da.c
index d05376e..77652b2 100644
--- a/sys/cam/scsi/scsi_da.c
+++ b/sys/cam/scsi/scsi_da.c
@@ -1272,7 +1272,7 @@ daregister(struct cam_periph *periph, void *arg)
* the end of probe.
*/
(void)cam_periph_hold(periph, PRIBIO);
- xpt_schedule(periph, /*priority*/5);
+ xpt_schedule(periph, CAM_PRIORITY_DEV);
/*
* Schedule a periodic event to occasionally send an
diff --git a/sys/cam/scsi/scsi_low.c b/sys/cam/scsi/scsi_low.c
index 1cee43d..1b2f4f6 100644
--- a/sys/cam/scsi/scsi_low.c
+++ b/sys/cam/scsi/scsi_low.c
@@ -895,8 +895,6 @@ scsi_low_target_open(link, cf)
#define SCSI_LOW_ALLOC_CCB(flags) scsi_low_get_ccb()
static void scsi_low_poll_cam(struct cam_sim *);
-static void scsi_low_cam_rescan_callback(struct cam_periph *, union ccb *);
-static void scsi_low_rescan_bus_cam(struct scsi_low_softc *);
void scsi_low_scsi_action_cam(struct cam_sim *, union ccb *);
static int scsi_low_attach_cam(struct scsi_low_softc *);
@@ -954,38 +952,6 @@ scsi_low_poll_cam(sim)
}
}
-static void
-scsi_low_cam_rescan_callback(periph, ccb)
- struct cam_periph *periph;
- union ccb *ccb;
-{
-
- xpt_free_path(ccb->ccb_h.path);
- xpt_free_ccb(ccb);
-}
-
-static void
-scsi_low_rescan_bus_cam(slp)
- struct scsi_low_softc *slp;
-{
- struct cam_path *path;
- union ccb *ccb;
- cam_status status;
-
- status = xpt_create_path(&path, xpt_periph,
- cam_sim_path(slp->sl_si.sim), -1, 0);
- if (status != CAM_REQ_CMP)
- return;
-
- ccb = xpt_alloc_ccb();
- bzero(ccb, sizeof(union ccb));
- xpt_setup_ccb(&ccb->ccb_h, path, 5);
- ccb->ccb_h.func_code = XPT_SCAN_BUS;
- ccb->ccb_h.cbfcnp = scsi_low_cam_rescan_callback;
- ccb->crcn.flags = CAM_FLAG_NONE;
- xpt_action(ccb);
-}
-
void
scsi_low_scsi_action_cam(sim, ccb)
struct cam_sim *sim;
@@ -1376,8 +1342,6 @@ scsi_low_world_start_cam(slp)
struct scsi_low_softc *slp;
{
- if (!cold)
- scsi_low_rescan_bus_cam(slp);
return 0;
}
diff --git a/sys/cam/scsi/scsi_pass.c b/sys/cam/scsi/scsi_pass.c
index 7551891..9464ca2 100644
--- a/sys/cam/scsi/scsi_pass.c
+++ b/sys/cam/scsi/scsi_pass.c
@@ -563,12 +563,10 @@ passsendccb(struct cam_periph *periph, union ccb *ccb, union ccb *inccb)
* that request. Otherwise, it's up to the user to perform any
* error recovery.
*/
- error = cam_periph_runccb(ccb,
- (ccb->ccb_h.flags & CAM_PASS_ERR_RECOVER) ?
- passerror : NULL,
- /* cam_flags */ CAM_RETRY_SELTO,
- /* sense_flags */SF_RETRY_UA,
- softc->device_stats);
+ cam_periph_runccb(ccb,
+ (ccb->ccb_h.flags & CAM_PASS_ERR_RECOVER) ? passerror : NULL,
+ /* cam_flags */ CAM_RETRY_SELTO, /* sense_flags */SF_RETRY_UA,
+ softc->device_stats);
if (need_unmap != 0)
cam_periph_unmapmem(ccb, &mapinfo);
@@ -577,7 +575,7 @@ passsendccb(struct cam_periph *periph, union ccb *ccb, union ccb *inccb)
ccb->ccb_h.periph_priv = inccb->ccb_h.periph_priv;
bcopy(ccb, inccb, sizeof(union ccb));
- return(error);
+ return(0);
}
static int
diff --git a/sys/cam/scsi/scsi_xpt.c b/sys/cam/scsi/scsi_xpt.c
index cae7be6..7639377 100644
--- a/sys/cam/scsi/scsi_xpt.c
+++ b/sys/cam/scsi/scsi_xpt.c
@@ -616,6 +616,11 @@ proberegister(struct cam_periph *periph, void *arg)
*/
cam_periph_freeze_after_event(periph, &periph->path->bus->last_reset,
scsi_delay);
+ /*
+ * Ensure nobody slip in until probe finish.
+ */
+ cam_freeze_devq_arg(periph->path,
+ RELSIM_RELEASE_RUNLEVEL, CAM_RL_XPT + 1);
probeschedule(periph);
return(CAM_REQ_CMP);
}
@@ -630,7 +635,7 @@ probeschedule(struct cam_periph *periph)
softc = (probe_softc *)periph->softc;
ccb = (union ccb *)TAILQ_FIRST(&softc->request_ccbs);
- xpt_setup_ccb(&cpi.ccb_h, periph->path, CAM_PRIORITY_NORMAL);
+ xpt_setup_ccb(&cpi.ccb_h, periph->path, CAM_PRIORITY_NONE);
cpi.ccb_h.func_code = XPT_PATH_INQ;
xpt_action((union ccb *)&cpi);
@@ -668,7 +673,7 @@ probeschedule(struct cam_periph *periph)
else
softc->flags &= ~PROBE_NO_ANNOUNCE;
- xpt_schedule(periph, ccb->ccb_h.pinfo.priority);
+ xpt_schedule(periph, CAM_PRIORITY_XPT);
}
static void
@@ -881,7 +886,7 @@ proberequestdefaultnegotiation(struct cam_periph *periph)
{
struct ccb_trans_settings cts;
- xpt_setup_ccb(&cts.ccb_h, periph->path, CAM_PRIORITY_NORMAL);
+ xpt_setup_ccb(&cts.ccb_h, periph->path, CAM_PRIORITY_NONE);
cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
cts.type = CTS_TYPE_USER_SETTINGS;
xpt_action((union ccb *)&cts);
@@ -903,7 +908,7 @@ proberequestbackoff(struct cam_periph *periph, struct cam_ed *device)
struct ccb_trans_settings_spi *spi;
memset(&cts, 0, sizeof (cts));
- xpt_setup_ccb(&cts.ccb_h, periph->path, CAM_PRIORITY_NORMAL);
+ xpt_setup_ccb(&cts.ccb_h, periph->path, CAM_PRIORITY_NONE);
cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
cts.type = CTS_TYPE_CURRENT_SETTINGS;
xpt_action((union ccb *)&cts);
@@ -1420,6 +1425,8 @@ probedone(struct cam_periph *periph, union ccb *done_ccb)
done_ccb->ccb_h.status = CAM_REQ_CMP;
xpt_done(done_ccb);
if (TAILQ_FIRST(&softc->request_ccbs) == NULL) {
+ cam_release_devq(periph->path,
+ RELSIM_RELEASE_RUNLEVEL, 0, CAM_RL_XPT + 1, FALSE);
cam_periph_invalidate(periph);
cam_periph_release_locked(periph);
} else {
@@ -1491,7 +1498,7 @@ scsi_scan_bus(struct cam_periph *periph, union ccb *request_ccb)
case XPT_SCAN_BUS:
{
scsi_scan_bus_info *scan_info;
- union ccb *work_ccb;
+ union ccb *work_ccb, *reset_ccb;
struct cam_path *path;
u_int i;
u_int max_target;
@@ -1526,6 +1533,26 @@ scsi_scan_bus(struct cam_periph *periph, union ccb *request_ccb)
return;
}
+ /* We may need to reset bus first, if we haven't done it yet. */
+ if ((work_ccb->cpi.hba_inquiry &
+ (PI_WIDE_32|PI_WIDE_16|PI_SDTR_ABLE)) &&
+ !(work_ccb->cpi.hba_misc & PIM_NOBUSRESET) &&
+ !timevalisset(&request_ccb->ccb_h.path->bus->last_reset)) {
+ reset_ccb = xpt_alloc_ccb_nowait();
+ xpt_setup_ccb(&reset_ccb->ccb_h, request_ccb->ccb_h.path,
+ CAM_PRIORITY_NONE);
+ reset_ccb->ccb_h.func_code = XPT_RESET_BUS;
+ xpt_action(reset_ccb);
+ if (reset_ccb->ccb_h.status != CAM_REQ_CMP) {
+ request_ccb->ccb_h.status = reset_ccb->ccb_h.status;
+ xpt_free_ccb(reset_ccb);
+ xpt_free_ccb(work_ccb);
+ xpt_done(request_ccb);
+ return;
+ }
+ xpt_free_ccb(reset_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);
@@ -1756,10 +1783,9 @@ scsi_scan_lun(struct cam_periph *periph, struct cam_path *path,
struct cam_path *new_path;
struct cam_periph *old_periph;
- CAM_DEBUG(request_ccb->ccb_h.path, CAM_DEBUG_TRACE,
- ("scsi_scan_lun\n"));
+ CAM_DEBUG(path, CAM_DEBUG_TRACE, ("scsi_scan_lun\n"));
- xpt_setup_ccb(&cpi.ccb_h, path, CAM_PRIORITY_NORMAL);
+ xpt_setup_ccb(&cpi.ccb_h, path, CAM_PRIORITY_NONE);
cpi.ccb_h.func_code = XPT_PATH_INQ;
xpt_action((union ccb *)&cpi);
@@ -1809,7 +1835,7 @@ scsi_scan_lun(struct cam_periph *periph, struct cam_path *path,
free(new_path, M_CAMXPT);
return;
}
- xpt_setup_ccb(&request_ccb->ccb_h, new_path, CAM_PRIORITY_NORMAL);
+ xpt_setup_ccb(&request_ccb->ccb_h, new_path, CAM_PRIORITY_XPT);
request_ccb->ccb_h.cbfcnp = xptscandone;
request_ccb->ccb_h.func_code = XPT_SCAN_LUN;
request_ccb->crcn.flags = flags;
@@ -1907,7 +1933,7 @@ scsi_devise_transport(struct cam_path *path)
struct scsi_inquiry_data *inq_buf;
/* Get transport information from the SIM */
- xpt_setup_ccb(&cpi.ccb_h, path, CAM_PRIORITY_NORMAL);
+ xpt_setup_ccb(&cpi.ccb_h, path, CAM_PRIORITY_NONE);
cpi.ccb_h.func_code = XPT_PATH_INQ;
xpt_action((union ccb *)&cpi);
@@ -1967,7 +1993,7 @@ scsi_devise_transport(struct cam_path *path)
*/
/* Tell the controller what we think */
- xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NORMAL);
+ xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE);
cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS;
cts.type = CTS_TYPE_CURRENT_SETTINGS;
cts.transport = path->device->transport;
@@ -2095,7 +2121,7 @@ scsi_set_transfer_settings(struct ccb_trans_settings *cts, struct cam_ed *device
inq_data = &device->inq_data;
scsi = &cts->proto_specific.scsi;
- xpt_setup_ccb(&cpi.ccb_h, cts->ccb_h.path, CAM_PRIORITY_NORMAL);
+ xpt_setup_ccb(&cpi.ccb_h, cts->ccb_h.path, CAM_PRIORITY_NONE);
cpi.ccb_h.func_code = XPT_PATH_INQ;
xpt_action((union ccb *)&cpi);
@@ -2116,7 +2142,7 @@ scsi_set_transfer_settings(struct ccb_trans_settings *cts, struct cam_ed *device
* Perform sanity checking against what the
* controller and device can do.
*/
- xpt_setup_ccb(&cur_cts.ccb_h, cts->ccb_h.path, CAM_PRIORITY_NORMAL);
+ xpt_setup_ccb(&cur_cts.ccb_h, cts->ccb_h.path, CAM_PRIORITY_NONE);
cur_cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
cur_cts.type = cts->type;
xpt_action((union ccb *)&cur_cts);
@@ -2300,7 +2326,7 @@ scsi_toggle_tags(struct cam_path *path)
&& (dev->inq_flags & (SID_Sync|SID_WBus16|SID_WBus32)) != 0)) {
struct ccb_trans_settings cts;
- xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NORMAL);
+ xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE);
cts.protocol = PROTO_SCSI;
cts.protocol_version = PROTO_VERSION_UNSPECIFIED;
cts.transport = XPORT_UNSPECIFIED;
@@ -2350,11 +2376,18 @@ scsi_dev_async(u_int32_t async_code, struct cam_eb *bus, struct cam_et *target,
/*
* Allow transfer negotiation to occur in a
- * tag free environment.
+ * tag free environment and after settle delay.
*/
if (async_code == AC_SENT_BDR
- || async_code == AC_BUS_RESET)
+ || async_code == AC_BUS_RESET) {
+ cam_freeze_devq(&newpath);
+ cam_release_devq(&newpath,
+ RELSIM_RELEASE_AFTER_TIMEOUT,
+ /*reduction*/0,
+ /*timeout*/scsi_delay,
+ /*getcount_only*/0);
scsi_toggle_tags(&newpath);
+ }
if (async_code == AC_INQ_CHANGED) {
/*
OpenPOWER on IntegriCloud