From 72062fdcece91a123423691068781de9366fbfaa Mon Sep 17 00:00:00 2001 From: mav Date: Thu, 28 Jan 2010 08:41:30 +0000 Subject: [PATCH] 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. --- sys/cam/ata/ata_all.c | 6 +- sys/cam/ata/ata_da.c | 2 +- sys/cam/ata/ata_pmp.c | 150 ++++---- sys/cam/ata/ata_xpt.c | 121 ++++--- sys/cam/cam.c | 6 +- sys/cam/cam.h | 25 +- sys/cam/cam_ccb.h | 7 +- sys/cam/cam_periph.c | 393 ++++++++++---------- sys/cam/cam_periph.h | 6 +- sys/cam/cam_queue.h | 105 +++++- sys/cam/cam_sim.c | 3 +- sys/cam/cam_xpt.c | 662 +++++++++++++++------------------- sys/cam/cam_xpt.h | 5 + sys/cam/cam_xpt_internal.h | 1 - sys/cam/cam_xpt_periph.h | 3 - sys/cam/cam_xpt_sim.h | 8 +- sys/cam/scsi/scsi_all.c | 59 +-- sys/cam/scsi/scsi_cd.c | 48 +-- sys/cam/scsi/scsi_ch.c | 2 +- sys/cam/scsi/scsi_da.c | 2 +- sys/cam/scsi/scsi_low.c | 36 -- sys/cam/scsi/scsi_pass.c | 12 +- sys/cam/scsi/scsi_xpt.c | 65 +++- sys/dev/ahci/ahci.c | 55 ++- sys/dev/ahci/ahci.h | 15 + sys/dev/asr/asr.c | 1 - sys/dev/ata/ata-all.c | 27 +- sys/dev/ata/atapi-cam.c | 32 +- sys/dev/ciss/ciss.c | 48 +-- sys/dev/hptiop/hptiop.c | 31 +- sys/dev/hptrr/hptrr_osm_bsd.c | 32 +- sys/dev/hptrr/os_bsd.h | 1 - sys/dev/mly/mly.c | 22 +- sys/dev/mpt/mpt_cam.h | 1 - sys/dev/mpt/mpt_raid.c | 17 +- sys/dev/ppbus/vpo.c | 37 -- sys/dev/siis/siis.c | 35 +- sys/dev/trm/trm.c | 18 - sys/dev/twa/tw_osl_cam.c | 59 +-- sys/dev/usb/storage/umass.c | 77 ---- 40 files changed, 1051 insertions(+), 1184 deletions(-) diff --git a/sys/cam/ata/ata_all.c b/sys/cam/ata/ata_all.c index 25daea4eb7f6..b2db7a03ce1a 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 8d493096bffe..3408b4fa3bbc 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 8c2e1bff3a28..1b8d9d5129ff 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 99cf31410835..bff0340b6710 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 85b02fb9cfac..88271b0684bc 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 3d85264f4c59..2b3b98cba603 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 72de56467256..4c5adba54189 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 9bac0f5a82e2..4c7502ae877e 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,21 @@ 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 -camperiphdone(struct cam_periph *periph, union ccb *done_ccb) +camperiphsensedone(struct cam_periph *periph, union ccb *done_ccb) { - union ccb *saved_ccb; + union ccb *saved_ccb = (union ccb *)done_ccb->ccb_h.saved_ccb_ptr; 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; + u_int sense_key; + int depth = done_ccb->ccb_h.recovery_depth; status = done_ccb->ccb_h.status; if (status & CAM_DEV_QFRZN) { @@ -996,14 +1025,83 @@ 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; + 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, *save_ccb; + cam_status status; + int frozen = 0; + struct scsi_start_stop_unit *scsi_cmd; + u_int32_t relsim_flags, timeout; + + 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; + } 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; + 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); - - 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 e207b1925ab5..33e9f7584355 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 #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 31f9bc238bf7..dd9f9a7306e7 100644 --- a/sys/cam/cam_queue.h +++ b/sys/cam/cam_queue.h @@ -34,6 +34,7 @@ #ifdef _KERNEL #include +#include /* * 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 adccfa8593ec..59148a9a4267 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 88ee30916755..d966a9fb5bd4 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; + struct cam_path *path = start_ccb->ccb_h.path; + int frozen; - 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) + 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); } @@ -4109,13 +4115,35 @@ xpt_dev_async_default(u_int32_t async_code, struct cam_eb *bus, printf("xpt_dev_async called\n"); } +u_int32_t +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); + 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) { - mtx_assert(path->bus->sim->mtx, MA_OWNED); - path->device->ccbq.queue.qfrozen_cnt += count; - return (path->device->ccbq.queue.qfrozen_cnt); + 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); +} + +void +xpt_release_devq_rl(struct cam_path *path, cam_rl rl, u_int count, int run_queue) +{ + mtx_assert(path->bus->sim->mtx, MA_OWNED); + + xpt_release_devq_device(path->device, rl, count, run_queue); } static void -xpt_release_devq_device(struct cam_ed *dev, u_int count, int run_queue) +xpt_release_devq_device(struct cam_ed *dev, 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) { - - /* - * 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; - } - - /* - * 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) +static void +xpt_boot_delay(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) -{ - 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); +} - if (busses_to_config == 0) { +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; + + 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)(); - } + 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); - /* - * 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 283cad1c34e6..61a7f3f02d20 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 146764ef7634..b1fbaafb2212 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 dbfb55eb7576..867b1c1d3813 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 e64c67c16fa1..323f786c813f 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 e6f3a7c1005a..d40a53659ecd 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 cf99eea53592..9d5dcf6c8b8d 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 2829a155d9ad..107f22b2ed9f 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 d05376ee2959..77652b2dc949 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 1cee43dca297..1b2f4f601edb 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 755189183754..9464ca21ce38 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 cae7be61ac99..7639377052b4 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) { /* diff --git a/sys/dev/ahci/ahci.c b/sys/dev/ahci/ahci.c index 789a8aa717af..ecff8a02391b 100644 --- a/sys/dev/ahci/ahci.c +++ b/sys/dev/ahci/ahci.c @@ -52,7 +52,6 @@ __FBSDID("$FreeBSD$"); #include #include #include -#include #include /* local prototypes */ @@ -86,7 +85,7 @@ static void ahci_start_fr(device_t dev); static void ahci_stop_fr(device_t dev); static int ahci_sata_connect(struct ahci_channel *ch); -static int ahci_sata_phy_reset(device_t dev, int quick); +static int ahci_sata_phy_reset(device_t dev); static void ahci_issue_read_log(device_t dev); static void ahci_process_read_log(device_t dev, union ccb *ccb); @@ -348,6 +347,8 @@ ahci_attach(device_t dev) ctlr->caps = ATA_INL(ctlr->r_mem, AHCI_CAP); if (version >= 0x00010020) ctlr->caps2 = ATA_INL(ctlr->r_mem, AHCI_CAP2); + if (ctlr->caps & AHCI_CAP_EMS) + ctlr->capsem = ATA_INL(ctlr->r_mem, AHCI_EM_CTL); ctlr->ichannels = ATA_INL(ctlr->r_mem, AHCI_PI); if (ctlr->quirks & AHCI_Q_1CH) { ctlr->caps &= ~AHCI_CAP_NPMASK; @@ -417,6 +418,17 @@ ahci_attach(device_t dev) (ctlr->caps2 & AHCI_CAP2_NVMP) ? " NVMP":"", (ctlr->caps2 & AHCI_CAP2_BOH) ? " BOH":""); } + if (bootverbose && (ctlr->caps & AHCI_CAP_EMS)) { + device_printf(dev, "EM Caps: %s%s%s%s%s%s%s%s\n", + (ctlr->capsem & AHCI_EM_PM) ? " PM":"", + (ctlr->capsem & AHCI_EM_ALHD) ? " ALHD":"", + (ctlr->capsem & AHCI_EM_XMT) ? " XMT":"", + (ctlr->capsem & AHCI_EM_SMB) ? " SMB":"", + (ctlr->capsem & AHCI_EM_SGPIO) ? " SGPIO":"", + (ctlr->capsem & AHCI_EM_SES2) ? " SES-2":"", + (ctlr->capsem & AHCI_EM_SAFTE) ? " SAF-TE":"", + (ctlr->capsem & AHCI_EM_LED) ? " LED":""); + } /* Attach all channels on this controller */ for (unit = 0; unit < ctlr->channels; unit++) { if ((ctlr->ichannels & (1 << unit)) == 0) @@ -1131,6 +1143,8 @@ ahci_phy_check_events(device_t dev, u_int32_t serr) if ((serr & ATA_SE_PHY_CHANGED) && (ch->pm_level == 0)) { u_int32_t status = ATA_INL(ch->r_mem, AHCI_P_SSTS); + union ccb *ccb; + if (((status & ATA_SS_DET_MASK) == ATA_SS_DET_PHY_ONLINE) && ((status & ATA_SS_SPD_MASK) != ATA_SS_SPD_NO_SPEED) && ((status & ATA_SS_IPM_MASK) == ATA_SS_IPM_ACTIVE)) { @@ -1142,6 +1156,15 @@ ahci_phy_check_events(device_t dev, u_int32_t serr) device_printf(dev, "DISCONNECT requested\n"); ch->devices = 0; } + if ((ccb = xpt_alloc_ccb_nowait()) == NULL) + return; + if (xpt_create_path(&ccb->ccb_h.path, NULL, + cam_sim_path(ch->sim), + CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP) { + xpt_free_ccb(ccb); + return; + } + xpt_rescan(ccb); } } @@ -1511,6 +1534,13 @@ ahci_execute_transaction(struct ahci_slot *slot) if (timeout && (count >= timeout)) { device_printf(ch->dev, "Poll timeout on slot %d\n", slot->slot); + device_printf(dev, "is %08x cs %08x ss %08x " + "rs %08x tfd %02x serr %08x\n", + ATA_INL(ch->r_mem, AHCI_P_IS), + ATA_INL(ch->r_mem, AHCI_P_CI), + ATA_INL(ch->r_mem, AHCI_P_SACT), ch->rslots, + ATA_INL(ch->r_mem, AHCI_P_TFD), + ATA_INL(ch->r_mem, AHCI_P_SERR)); et = AHCI_ERR_TIMEOUT; } if (et != AHCI_ERR_NONE) { @@ -1935,7 +1965,7 @@ ahci_wait_ready(device_t dev, int t) (ATA_S_BUSY | ATA_S_DRQ)) { DELAY(1000); if (timeout++ > t) { - device_printf(dev, "port is not ready (timeout %dms) " + device_printf(dev, "device is not ready (timeout %dms) " "tfd = %08x\n", t, val); return (EBUSY); } @@ -1952,6 +1982,7 @@ ahci_reset(device_t dev) struct ahci_controller *ctlr = device_get_softc(device_get_parent(dev)); int i; + xpt_freeze_simq(ch->sim, 1); if (bootverbose) device_printf(dev, "AHCI reset...\n"); /* Requeue freezed command. */ @@ -1986,7 +2017,7 @@ ahci_reset(device_t dev) /* Disable port interrupts */ ATA_OUTL(ch->r_mem, AHCI_P_IE, 0); /* Reset and reconnect PHY, */ - if (!ahci_sata_phy_reset(dev, 0)) { + if (!ahci_sata_phy_reset(dev)) { if (bootverbose) device_printf(dev, "AHCI reset done: phy reset found no device\n"); @@ -1994,13 +2025,12 @@ ahci_reset(device_t dev) /* Enable wanted port interrupts */ ATA_OUTL(ch->r_mem, AHCI_P_IE, (AHCI_P_IX_CPD | AHCI_P_IX_PRC | AHCI_P_IX_PC)); + xpt_release_simq(ch->sim, TRUE); return; } /* Wait for clearing busy status. */ - if (ahci_wait_ready(dev, 10000)) { - device_printf(dev, "device ready timeout\n"); + if (ahci_wait_ready(dev, 15000)) ahci_clo(dev); - } ahci_start(dev); ch->devices = 1; /* Enable wanted port interrupts */ @@ -2012,6 +2042,7 @@ ahci_reset(device_t dev) AHCI_P_IX_DS | AHCI_P_IX_PS | (ctlr->ccc ? 0 : AHCI_P_IX_DHR))); if (bootverbose) device_printf(dev, "AHCI reset done: device found\n"); + xpt_release_simq(ch->sim, TRUE); } static int @@ -2104,20 +2135,12 @@ ahci_sata_connect(struct ahci_channel *ch) } static int -ahci_sata_phy_reset(device_t dev, int quick) +ahci_sata_phy_reset(device_t dev) { struct ahci_channel *ch = device_get_softc(dev); int sata_rev; uint32_t val; - if (quick) { - val = ATA_INL(ch->r_mem, AHCI_P_SCTL); - if ((val & ATA_SC_DET_MASK) == ATA_SC_DET_IDLE) - return (ahci_sata_connect(ch)); - } - - if (bootverbose) - device_printf(dev, "hardware reset ...\n"); sata_rev = ch->user[ch->pm_present ? 15 : 0].revision; if (sata_rev == 1) val = ATA_SC_SPD_SPEED_GEN1; diff --git a/sys/dev/ahci/ahci.h b/sys/dev/ahci/ahci.h index e11f84f489d3..d136d82b3265 100644 --- a/sys/dev/ahci/ahci.h +++ b/sys/dev/ahci/ahci.h @@ -186,6 +186,20 @@ #define AHCI_CCCC_EN 0x00000001 #define AHCI_CCCP 0x18 +#define AHCI_EM_LOC 0x1C +#define AHCI_EM_CTL 0x20 +#define AHCI_EM_MR 0x00000001 +#define AHCI_EM_TM 0x00000100 +#define AHCI_EM_RST 0x00000200 +#define AHCI_EM_LED 0x00010000 +#define AHCI_EM_SAFTE 0x00020000 +#define AHCI_EM_SES2 0x00040000 +#define AHCI_EM_SGPIO 0x00080000 +#define AHCI_EM_SMB 0x01000000 +#define AHCI_EM_XMT 0x02000000 +#define AHCI_EM_ALHD 0x04000000 +#define AHCI_EM_PM 0x08000000 + #define AHCI_CAP2 0x24 #define AHCI_CAP2_BOH 0x00000001 #define AHCI_CAP2_NVMP 0x00000002 @@ -402,6 +416,7 @@ struct ahci_controller { } irqs[16]; uint32_t caps; /* Controller capabilities */ uint32_t caps2; /* Controller capabilities */ + uint32_t capsem; /* Controller capabilities */ int quirks; int numirqs; int channels; diff --git a/sys/dev/asr/asr.c b/sys/dev/asr/asr.c index 2bc5e2277246..ae363d0045d4 100644 --- a/sys/dev/asr/asr.c +++ b/sys/dev/asr/asr.c @@ -130,7 +130,6 @@ #include #include #include -#include #include #include diff --git a/sys/dev/ata/ata-all.c b/sys/dev/ata/ata-all.c index f342c819ef13..1ad3c5117c16 100644 --- a/sys/dev/ata/ata-all.c +++ b/sys/dev/ata/ata-all.c @@ -55,7 +55,6 @@ __FBSDID("$FreeBSD$"); #include #include #include -#include #include #endif @@ -289,12 +288,26 @@ ata_detach(device_t dev) static void ata_conn_event(void *context, int dummy) { - device_t dev = (device_t)context; - struct ata_channel *ch = device_get_softc(dev); + device_t dev = (device_t)context; + struct ata_channel *ch = device_get_softc(dev); +#ifdef ATA_CAM + union ccb *ccb; +#endif - mtx_lock(&ch->state_mtx); - ata_reinit(dev); - mtx_unlock(&ch->state_mtx); + mtx_lock(&ch->state_mtx); + ata_reinit(dev); + mtx_unlock(&ch->state_mtx); +#ifdef ATA_CAM + if ((ccb = xpt_alloc_ccb()) == NULL) + return; + if (xpt_create_path(&ccb->ccb_h.path, NULL, + cam_sim_path(ch->sim), + CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP) { + xpt_free_ccb(ccb); + return; + } + xpt_rescan(ccb); +#endif } int @@ -390,6 +403,7 @@ ata_reinit(device_t dev) /* kick off requests on the queue */ ata_start(dev); #else + xpt_freeze_simq(ch->sim, 1); if ((request = ch->running)) { ch->running = NULL; if (ch->state == ATA_ACTIVE) @@ -404,6 +418,7 @@ ata_reinit(device_t dev) ATA_RESET(dev); /* Tell the XPT about the event */ xpt_async(AC_BUS_RESET, ch->path, NULL); + xpt_release_simq(ch->sim, TRUE); #endif return(0); } diff --git a/sys/dev/ata/atapi-cam.c b/sys/dev/ata/atapi-cam.c index 84b44c563993..3f8e650708c3 100644 --- a/sys/dev/ata/atapi-cam.c +++ b/sys/dev/ata/atapi-cam.c @@ -48,7 +48,6 @@ __FBSDID("$FreeBSD$"); #include #include #include -#include #include #include @@ -109,7 +108,6 @@ static int atapi_cam_event_handler(module_t mod, int what, void *arg); /* internal functions */ static void reinit_bus(struct atapi_xpt_softc *scp, enum reinit_reason reason); static void setup_async_cb(struct atapi_xpt_softc *, uint32_t); -static void cam_rescan_callback(struct cam_periph *, union ccb *); static void cam_rescan(struct cam_sim *); static void free_hcb_and_ccb_done(struct atapi_hcb *, u_int32_t); static struct atapi_hcb *allocate_hcb(struct atapi_xpt_softc *, int, int, union ccb *); @@ -315,6 +313,7 @@ reinit_bus(struct atapi_xpt_softc *scp, enum reinit_reason reason) { switch (reason) { case BOOT_ATTACH: + case ATTACH: break; case RESET: xpt_async(AC_BUS_RESET, scp->path, NULL); @@ -322,8 +321,6 @@ reinit_bus(struct atapi_xpt_softc *scp, enum reinit_reason reason) { if (!dev_changed) break; - /*FALLTHROUGH*/ - case ATTACH: cam_rescan(scp->sim); break; } @@ -821,42 +818,21 @@ atapi_async(void *callback_arg, u_int32_t code, } } -static void -cam_rescan_callback(struct cam_periph *periph, union ccb *ccb) -{ - if (ccb->ccb_h.status != CAM_REQ_CMP) { - CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE, - ("Rescan failed, 0x%04x\n", ccb->ccb_h.status)); - } else { - CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE, - ("Rescan succeeded\n")); - } - xpt_free_path(ccb->ccb_h.path); - xpt_free_ccb(ccb); -} - static void cam_rescan(struct cam_sim *sim) { - struct cam_path *path; union ccb *ccb; ccb = xpt_alloc_ccb_nowait(); if (ccb == NULL) return; - - if (xpt_create_path(&path, xpt_periph, cam_sim_path(sim), + if (xpt_create_path(&ccb->ccb_h.path, xpt_periph, cam_sim_path(sim), CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP) { xpt_free_ccb(ccb); return; } - - CAM_DEBUG(path, CAM_DEBUG_TRACE, ("Rescanning ATAPI bus.\n")); - xpt_setup_ccb(&ccb->ccb_h, path, 5/*priority (low)*/); - ccb->ccb_h.func_code = XPT_SCAN_BUS; - ccb->ccb_h.cbfcnp = cam_rescan_callback; - ccb->crcn.flags = CAM_FLAG_NONE; - xpt_action(ccb); + CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE, ("Rescanning ATAPI bus.\n")); + xpt_rescan(ccb); /* scan is in progress now */ } diff --git a/sys/dev/ciss/ciss.c b/sys/dev/ciss/ciss.c index c5ad417e70c8..4e336a94be28 100644 --- a/sys/dev/ciss/ciss.c +++ b/sys/dev/ciss/ciss.c @@ -173,8 +173,6 @@ static void ciss_unmap_request(struct ciss_request *cr); static int ciss_cam_init(struct ciss_softc *sc); static void ciss_cam_rescan_target(struct ciss_softc *sc, int bus, int target); -static void ciss_cam_rescan_all(struct ciss_softc *sc); -static void ciss_cam_rescan_callback(struct cam_periph *periph, union ccb *ccb); static void ciss_cam_action(struct cam_sim *sim, union ccb *ccb); static int ciss_cam_action_io(struct cam_sim *sim, struct ccb_scsiio *csio); static int ciss_cam_emulate(struct ciss_softc *sc, struct ccb_scsiio *csio); @@ -2863,13 +2861,6 @@ ciss_cam_init(struct ciss_softc *sc) mtx_unlock(&sc->ciss_mtx); } - /* - * Initiate a rescan of the bus. - */ - mtx_lock(&sc->ciss_mtx); - ciss_cam_rescan_all(sc); - mtx_unlock(&sc->ciss_mtx); - return(0); } @@ -2879,53 +2870,26 @@ ciss_cam_init(struct ciss_softc *sc) static void ciss_cam_rescan_target(struct ciss_softc *sc, int bus, int target) { - struct cam_path *path; union ccb *ccb; debug_called(1); - if ((ccb = malloc(sizeof(union ccb), CISS_MALLOC_CLASS, M_NOWAIT | M_ZERO)) == NULL) { + if ((ccb = xpt_alloc_ccb_nowait()) == NULL) { ciss_printf(sc, "rescan failed (can't allocate CCB)\n"); return; } - if (xpt_create_path(&path, xpt_periph, cam_sim_path(sc->ciss_cam_sim[bus]), - target, CAM_LUN_WILDCARD) != CAM_REQ_CMP) { + if (xpt_create_path(&ccb->ccb_h.path, xpt_periph, + cam_sim_path(sc->ciss_cam_sim[bus]), + target, CAM_LUN_WILDCARD) != CAM_REQ_CMP) { ciss_printf(sc, "rescan failed (can't create path)\n"); - free(ccb, CISS_MALLOC_CLASS); + xpt_free_ccb(ccb); return; } - - xpt_setup_ccb(&ccb->ccb_h, path, 5/*priority (low)*/); - ccb->ccb_h.func_code = XPT_SCAN_BUS; - ccb->ccb_h.cbfcnp = ciss_cam_rescan_callback; - ccb->crcn.flags = CAM_FLAG_NONE; - xpt_action(ccb); - + xpt_rescan(ccb); /* scan is now in progress */ } -static void -ciss_cam_rescan_all(struct ciss_softc *sc) -{ - int i; - - /* Rescan the logical buses */ - for (i = 0; i < sc->ciss_max_logical_bus; i++) - ciss_cam_rescan_target(sc, i, CAM_TARGET_WILDCARD); - /* Rescan the physical buses */ - for (i = CISS_PHYSICAL_BASE; i < sc->ciss_max_physical_bus + - CISS_PHYSICAL_BASE; i++) - ciss_cam_rescan_target(sc, i, CAM_TARGET_WILDCARD); -} - -static void -ciss_cam_rescan_callback(struct cam_periph *periph, union ccb *ccb) -{ - xpt_free_path(ccb->ccb_h.path); - free(ccb, CISS_MALLOC_CLASS); -} - /************************************************************************ * Handle requests coming from CAM */ diff --git a/sys/dev/hptiop/hptiop.c b/sys/dev/hptiop/hptiop.c index 7218bc504425..1ea257becc33 100644 --- a/sys/dev/hptiop/hptiop.c +++ b/sys/dev/hptiop/hptiop.c @@ -79,7 +79,6 @@ __FBSDID("$FreeBSD$"); #include #include #include -#include #include #include #include @@ -105,7 +104,6 @@ static int hptiop_do_ioctl_itl(struct hpt_iop_hba *hba, struct hpt_iop_ioctl_param *pParams); static int hptiop_do_ioctl_mv(struct hpt_iop_hba *hba, struct hpt_iop_ioctl_param *pParams); -static void hptiop_bus_scan_cb(struct cam_periph *periph, union ccb *ccb); static int hptiop_rescan_bus(struct hpt_iop_hba *hba); static int hptiop_alloc_pci_res_itl(struct hpt_iop_hba *hba); static int hptiop_alloc_pci_res_mv(struct hpt_iop_hba *hba); @@ -1035,26 +1033,17 @@ invalid: static int hptiop_rescan_bus(struct hpt_iop_hba * hba) { - struct cam_path *path; union ccb *ccb; - if (xpt_create_path(&path, xpt_periph, cam_sim_path(hba->sim), - CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP) - return(EIO); - if ((ccb = malloc(sizeof(union ccb), M_TEMP, M_WAITOK)) == NULL) - return(ENOMEM); - 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 = hptiop_bus_scan_cb; - ccb->crcn.flags = CAM_FLAG_NONE; - xpt_action(ccb); - return(0); -} -static void hptiop_bus_scan_cb(struct cam_periph *periph, union ccb *ccb) -{ - xpt_free_path(ccb->ccb_h.path); - free(ccb, M_TEMP); + if ((ccb = xpt_alloc_ccb()) == NULL) + return(ENOMEM); + if (xpt_create_path(&ccb->ccb_h.path, xpt_periph, cam_sim_path(hba->sim), + CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP) { + xpt_free_ccb(ccb); + return(EIO); + } + xpt_rescan(ccb); + return(0); } static bus_dmamap_callback_t hptiop_map_srb; @@ -1539,8 +1528,6 @@ static int hptiop_attach(device_t dev) hba->ioctl_dev->si_drv1 = hba; #endif - hptiop_rescan_bus(hba); - return 0; diff --git a/sys/dev/hptrr/hptrr_osm_bsd.c b/sys/dev/hptrr/hptrr_osm_bsd.c index 78c8b60fe2e1..6bc30c22b36f 100644 --- a/sys/dev/hptrr/hptrr_osm_bsd.c +++ b/sys/dev/hptrr/hptrr_osm_bsd.c @@ -989,7 +989,6 @@ static void hpt_stop_tasks(PVBUS_EXT vbus_ext) static d_open_t hpt_open; static d_close_t hpt_close; static d_ioctl_t hpt_ioctl; -static void hpt_bus_scan_cb(struct cam_periph *periph, union ccb *ccb); static int hpt_rescan_bus(void); static struct cdevsw hpt_cdevsw = { @@ -1381,7 +1380,6 @@ invalid: static int hpt_rescan_bus(void) { - struct cam_path *path; union ccb *ccb; PVBUS vbus; PVBUS_EXT vbus_ext; @@ -1391,17 +1389,15 @@ static int hpt_rescan_bus(void) #endif ldm_for_each_vbus(vbus, vbus_ext) { - if (xpt_create_path(&path, xpt_periph, cam_sim_path(vbus_ext->sim), - CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP) - return(EIO); - if ((ccb = malloc(sizeof(union ccb), M_TEMP, M_WAITOK)) == NULL) + if ((ccb = xpt_alloc_ccb()) == NULL) return(ENOMEM); - 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 = hpt_bus_scan_cb; - ccb->crcn.flags = CAM_FLAG_NONE; - xpt_action(ccb); + if (xpt_create_path(&ccb->ccb_h.path, xpt_periph, + cam_sim_path(vbus_ext->sim), + CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP) { + xpt_free_ccb(ccb); + return(EIO); + } + xpt_rescan(ccb); } #if (__FreeBSD_version >= 500000) @@ -1410,15 +1406,3 @@ static int hpt_rescan_bus(void) return(0); } - -static void hpt_bus_scan_cb(struct cam_periph *periph, union ccb *ccb) -{ - if (ccb->ccb_h.status != CAM_REQ_CMP) - KdPrint(("cam_scan_callback: failure status = %x",ccb->ccb_h.status)); - else - KdPrint(("Scan bus successfully!")); - - xpt_free_path(ccb->ccb_h.path); - free(ccb, M_TEMP); - return; -} diff --git a/sys/dev/hptrr/os_bsd.h b/sys/dev/hptrr/os_bsd.h index fb487e820b67..ec221f39b90a 100644 --- a/sys/dev/hptrr/os_bsd.h +++ b/sys/dev/hptrr/os_bsd.h @@ -91,7 +91,6 @@ #include #include #include -#include #include #include #include diff --git a/sys/dev/mly/mly.c b/sys/dev/mly/mly.c index 189f53991c96..90f2819ccbfd 100644 --- a/sys/dev/mly/mly.c +++ b/sys/dev/mly/mly.c @@ -101,7 +101,6 @@ static void mly_unmap_command(struct mly_command *mc); static int mly_cam_attach(struct mly_softc *sc); static void mly_cam_detach(struct mly_softc *sc); static void mly_cam_rescan_btl(struct mly_softc *sc, int bus, int target); -static void mly_cam_rescan_callback(struct cam_periph *periph, union ccb *ccb); static void mly_cam_action(struct cam_sim *sim, union ccb *ccb); static int mly_cam_action_io(struct cam_sim *sim, struct ccb_scsiio *csio); static void mly_cam_poll(struct cam_sim *sim); @@ -2017,29 +2016,18 @@ mly_cam_rescan_btl(struct mly_softc *sc, int bus, int target) debug_called(1); - if ((ccb = malloc(sizeof(union ccb), M_TEMP, M_WAITOK | M_ZERO)) == NULL) { + if ((ccb = xpt_alloc_ccb()) == NULL) { mly_printf(sc, "rescan failed (can't allocate CCB)\n"); return; } - - if (xpt_create_path(&sc->mly_cam_path, xpt_periph, - cam_sim_path(sc->mly_cam_sim[bus]), target, 0) != CAM_REQ_CMP) { + if (xpt_create_path(&ccb->ccb_h.path, xpt_periph, + cam_sim_path(sc->mly_cam_sim[bus]), target, 0) != CAM_REQ_CMP) { mly_printf(sc, "rescan failed (can't create path)\n"); - free(ccb, M_TEMP); + xpt_free_ccb(ccb); return; } - xpt_setup_ccb(&ccb->ccb_h, sc->mly_cam_path, 5/*priority (low)*/); - ccb->ccb_h.func_code = XPT_SCAN_LUN; - ccb->ccb_h.cbfcnp = mly_cam_rescan_callback; - ccb->crcn.flags = CAM_FLAG_NONE; debug(1, "rescan target %d:%d", bus, target); - xpt_action(ccb); -} - -static void -mly_cam_rescan_callback(struct cam_periph *periph, union ccb *ccb) -{ - free(ccb, M_TEMP); + xpt_rescan(ccb); } /******************************************************************************** diff --git a/sys/dev/mpt/mpt_cam.h b/sys/dev/mpt/mpt_cam.h index f2faa4abdff8..8a18934d6483 100644 --- a/sys/dev/mpt/mpt_cam.h +++ b/sys/dev/mpt/mpt_cam.h @@ -102,7 +102,6 @@ #include #include #include -#include #include #include #include diff --git a/sys/dev/mpt/mpt_raid.c b/sys/dev/mpt/mpt_raid.c index 5185ec0d7960..d313253fa9e9 100644 --- a/sys/dev/mpt/mpt_raid.c +++ b/sys/dev/mpt/mpt_raid.c @@ -52,7 +52,6 @@ __FBSDID("$FreeBSD$"); #include #include #include -#include #include #if __FreeBSD_version < 500000 @@ -655,14 +654,6 @@ mpt_terminate_raid_thread(struct mpt_softc *mpt) mpt_sleep(mpt, &mpt->raid_thread, PUSER, "thtrm", 0); } -static void -mpt_cam_rescan_callback(struct cam_periph *periph, union ccb *ccb) -{ - - xpt_free_path(ccb->ccb_h.path); - xpt_free_ccb(ccb); -} - static void mpt_raid_thread(void *arg) { @@ -715,13 +706,7 @@ mpt_raid_thread(void *arg) xpt_free_ccb(ccb); mpt_prt(mpt, "Unable to rescan RAID Bus!\n"); } else { - xpt_setup_ccb(&ccb->ccb_h, path, 5); - ccb->ccb_h.func_code = XPT_SCAN_BUS; - ccb->ccb_h.cbfcnp = mpt_cam_rescan_callback; - ccb->crcn.flags = CAM_FLAG_NONE; - MPTLOCK_2_CAMLOCK(mpt); - xpt_action(ccb); - CAMLOCK_2_MPTLOCK(mpt); + xpt_rescan(ccb); } } } diff --git a/sys/dev/ppbus/vpo.c b/sys/dev/ppbus/vpo.c index 673a7858d4da..02bc9b397b2e 100644 --- a/sys/dev/ppbus/vpo.c +++ b/sys/dev/ppbus/vpo.c @@ -83,9 +83,6 @@ struct vpo_data { /* cam related functions */ static void vpo_action(struct cam_sim *sim, union ccb *ccb); static void vpo_poll(struct cam_sim *sim); -static void vpo_cam_rescan_callback(struct cam_periph *periph, - union ccb *ccb); -static void vpo_cam_rescan(struct vpo_data *vpo); static void vpo_identify(driver_t *driver, device_t parent) @@ -176,44 +173,10 @@ vpo_attach(device_t dev) return (ENXIO); } ppb_unlock(ppbus); - vpo_cam_rescan(vpo); /* have CAM rescan the bus */ return (0); } -static void -vpo_cam_rescan_callback(struct cam_periph *periph, union ccb *ccb) -{ - - free(ccb, M_TEMP); -} - -static void -vpo_cam_rescan(struct vpo_data *vpo) -{ - device_t ppbus = device_get_parent(vpo->vpo_dev); - struct cam_path *path; - union ccb *ccb = malloc(sizeof(union ccb), M_TEMP, M_WAITOK | M_ZERO); - - ppb_lock(ppbus); - if (xpt_create_path(&path, xpt_periph, cam_sim_path(vpo->sim), 0, 0) - != CAM_REQ_CMP) { - /* A failure is benign as the user can do a manual rescan */ - ppb_unlock(ppbus); - free(ccb, M_TEMP); - return; - } - - xpt_setup_ccb(&ccb->ccb_h, path, 5/*priority (low)*/); - ccb->ccb_h.func_code = XPT_SCAN_BUS; - ccb->ccb_h.cbfcnp = vpo_cam_rescan_callback; - ccb->crcn.flags = CAM_FLAG_NONE; - xpt_action(ccb); - ppb_unlock(ppbus); - - /* The scan is in progress now. */ -} - /* * vpo_intr() */ diff --git a/sys/dev/siis/siis.c b/sys/dev/siis/siis.c index 6f693e4e8a2e..630ee7b44c97 100644 --- a/sys/dev/siis/siis.c +++ b/sys/dev/siis/siis.c @@ -52,7 +52,6 @@ __FBSDID("$FreeBSD$"); #include #include #include -#include #include /* local prototypes */ @@ -740,6 +739,8 @@ siis_phy_check_events(device_t dev) /* If we have a connection event, deal with it */ if (ch->pm_level == 0) { u_int32_t status = ATA_INL(ch->r_mem, SIIS_P_SSTS); + union ccb *ccb; + if (((status & ATA_SS_DET_MASK) == ATA_SS_DET_PHY_ONLINE) && ((status & ATA_SS_SPD_MASK) != ATA_SS_SPD_NO_SPEED) && ((status & ATA_SS_IPM_MASK) == ATA_SS_IPM_ACTIVE)) { @@ -751,6 +752,15 @@ siis_phy_check_events(device_t dev) device_printf(dev, "DISCONNECT requested\n"); ch->devices = 0; } + if ((ccb = xpt_alloc_ccb_nowait()) == NULL) + return; + if (xpt_create_path(&ccb->ccb_h.path, NULL, + cam_sim_path(ch->sim), + CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP) { + xpt_free_ccb(ccb); + return; + } + xpt_rescan(ccb); } } @@ -1025,6 +1035,13 @@ siis_execute_transaction(struct siis_slot *slot) if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_OUT) ctp->control |= htole16(SIIS_PRB_PACKET_WRITE); } + /* Special handling for Soft Reset command. */ + if ((ccb->ccb_h.func_code == XPT_ATA_IO) && + (ccb->ataio.cmd.flags & CAM_ATAIO_CONTROL) && + (ccb->ataio.cmd.control & ATA_A_RESET)) { + /* Kick controller into sane state */ + siis_portinit(dev); + } /* Setup the FIS for this request */ if (!siis_setup_fis(dev, ctp, ccb, slot->slot)) { device_printf(ch->dev, "Setting up SATA FIS failed\n"); @@ -1081,10 +1098,11 @@ siis_timeout(struct siis_slot *slot) if (slot->state < SIIS_SLOT_RUNNING) return; device_printf(dev, "Timeout on slot %d\n", slot->slot); -device_printf(dev, "%s is %08x ss %08x rs %08x es %08x sts %08x serr %08x\n", - __func__, ATA_INL(ch->r_mem, SIIS_P_IS), ATA_INL(ch->r_mem, SIIS_P_SS), ch->rslots, - ATA_INL(ch->r_mem, SIIS_P_CMDERR), ATA_INL(ch->r_mem, SIIS_P_STS), - ATA_INL(ch->r_mem, SIIS_P_SERR)); + device_printf(dev, "%s is %08x ss %08x rs %08x es %08x sts %08x serr %08x\n", + __func__, ATA_INL(ch->r_mem, SIIS_P_IS), + ATA_INL(ch->r_mem, SIIS_P_SS), ch->rslots, + ATA_INL(ch->r_mem, SIIS_P_CMDERR), ATA_INL(ch->r_mem, SIIS_P_STS), + ATA_INL(ch->r_mem, SIIS_P_SERR)); if (ch->toslots == 0) xpt_freeze_simq(ch->sim, 1); @@ -1368,8 +1386,6 @@ siis_devreset(device_t dev) return (EBUSY); } } - if (bootverbose) - device_printf(dev, "device reset time=%dms\n", timeout); return (0); } @@ -1389,8 +1405,6 @@ siis_wait_ready(device_t dev, int t) return (EBUSY); } } - if (bootverbose) - device_printf(dev, "ready wait time=%dms\n", timeout); return (0); } @@ -1401,6 +1415,7 @@ siis_reset(device_t dev) int i, retry = 0, sata_rev; uint32_t val; + xpt_freeze_simq(ch->sim, 1); if (bootverbose) device_printf(dev, "SIIS reset...\n"); if (!ch->readlog && !ch->recovery) @@ -1466,6 +1481,7 @@ retry: "SIIS reset done: phy reset found no device\n"); /* Tell the XPT about the event */ xpt_async(AC_BUS_RESET, ch->path, NULL); + xpt_release_simq(ch->sim, TRUE); return; } /* Wait for clearing busy status. */ @@ -1496,6 +1512,7 @@ retry: device_printf(dev, "SIIS reset done: devices=%08x\n", ch->devices); /* Tell the XPT about the event */ xpt_async(AC_BUS_RESET, ch->path, NULL); + xpt_release_simq(ch->sim, TRUE); } static int diff --git a/sys/dev/trm/trm.c b/sys/dev/trm/trm.c index 26ab35239e7f..e7d5aad6d77d 100644 --- a/sys/dev/trm/trm.c +++ b/sys/dev/trm/trm.c @@ -746,15 +746,6 @@ trm_action(struct cam_sim *psim, union ccb *pccb) pccb->ccb_h.status = CAM_REQ_INVALID; xpt_done(pccb); break; - /* - * (Re)Scan the SCSI Bus - * Rescan the given bus, or bus/target/lun - */ - case XPT_SCAN_BUS: - TRM_DPRINTF(" XPT_SCAN_BUS \n"); - pccb->ccb_h.status = CAM_REQ_INVALID; - xpt_done(pccb); - break; /* * Get EDT entries matching the given pattern */ @@ -818,15 +809,6 @@ trm_action(struct cam_sim *psim, union ccb *pccb) pccb->ccb_h.status = CAM_REQ_INVALID; xpt_done(pccb); break; - /* - * Scan Logical Unit - */ - case XPT_SCAN_LUN: - TRM_DPRINTF(" XPT_SCAN_LUN \n"); - pccb->ccb_h.status = CAM_REQ_INVALID; - xpt_done(pccb); - break; - /* * Get/Set transfer rate/width/disconnection/tag queueing * settings diff --git a/sys/dev/twa/tw_osl_cam.c b/sys/dev/twa/tw_osl_cam.c index b7a085f19789..1d22920f291b 100644 --- a/sys/dev/twa/tw_osl_cam.c +++ b/sys/dev/twa/tw_osl_cam.c @@ -56,7 +56,6 @@ static TW_VOID twa_action(struct cam_sim *sim, union ccb *ccb); static TW_VOID twa_poll(struct cam_sim *sim); static TW_VOID twa_timeout(TW_VOID *arg); -static TW_VOID twa_bus_scan_cb(struct cam_periph *periph, union ccb *ccb); static TW_INT32 tw_osli_execute_scsi(struct tw_osli_req_context *req, union ccb *ccb); @@ -76,7 +75,6 @@ TW_INT32 tw_osli_cam_attach(struct twa_softc *sc) { struct cam_devq *devq; - TW_INT32 error; tw_osli_dbg_dprintf(3, sc, "entered"); @@ -149,23 +147,8 @@ tw_osli_cam_attach(struct twa_softc *sc) mtx_unlock(sc->sim_lock); return(ENXIO); } - - tw_osli_dbg_dprintf(3, sc, "Calling xpt_setup_ccb"); mtx_unlock(sc->sim_lock); - tw_osli_dbg_dprintf(3, sc, "Calling tw_osli_request_bus_scan"); - /* - * Request a bus scan, so that CAM gets to know of - * the logical units that we control. - */ - if ((error = tw_osli_request_bus_scan(sc))) - tw_osli_printf(sc, "error = %d", - TW_CL_SEVERITY_ERROR_STRING, - TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER, - 0x2104, - "Bus scan request to CAM failed", - error); - tw_osli_dbg_dprintf(3, sc, "exiting"); return(0); } @@ -561,7 +544,6 @@ twa_timeout(TW_VOID *arg) TW_INT32 tw_osli_request_bus_scan(struct twa_softc *sc) { - struct cam_path *path; union ccb *ccb; tw_osli_dbg_dprintf(3, sc, "entering"); @@ -569,13 +551,12 @@ tw_osli_request_bus_scan(struct twa_softc *sc) /* If we get here before sc->sim is initialized, return an error. */ if (!(sc->sim)) return(ENXIO); - if ((ccb = malloc(sizeof(union ccb), M_TEMP, M_WAITOK)) == NULL) + if ((ccb = xpt_alloc_ccb()) == NULL) return(ENOMEM); - bzero(ccb, sizeof(union ccb)); mtx_lock(sc->sim_lock); - if (xpt_create_path(&path, xpt_periph, cam_sim_path(sc->sim), - CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP) { - free(ccb, M_TEMP); + if (xpt_create_path(&ccb->ccb_h.path, xpt_periph, cam_sim_path(sc->sim), + CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP) { + xpt_free_ccb(ccb); mtx_unlock(sc->sim_lock); return(EIO); } @@ -586,43 +567,13 @@ tw_osli_request_bus_scan(struct twa_softc *sc) sc->state &= ~TW_OSLI_CTLR_STATE_SIMQ_FROZEN; } - xpt_setup_ccb(&ccb->ccb_h, path, 5); - ccb->ccb_h.func_code = XPT_SCAN_BUS; - ccb->ccb_h.cbfcnp = twa_bus_scan_cb; - ccb->crcn.flags = CAM_FLAG_NONE; - xpt_action(ccb); + xpt_rescan(ccb); mtx_unlock(sc->sim_lock); return(0); } -/* - * Function name: twa_bus_scan_cb - * Description: Callback from CAM on a bus scan request. - * - * Input: periph -- we don't use this - * ccb -- bus scan request ccb that we sent to CAM - * Output: None - * Return value: None - */ -static TW_VOID -twa_bus_scan_cb(struct cam_periph *periph, union ccb *ccb) -{ - tw_osli_dbg_printf(3, "entering"); - - if (ccb->ccb_h.status != CAM_REQ_CMP) - printf("cam_scan_callback: failure status = %x\n", - ccb->ccb_h.status); - else - tw_osli_dbg_printf(3, "success"); - - xpt_free_path(ccb->ccb_h.path); - free(ccb, M_TEMP); -} - - - /* * Function name: tw_osli_allow_new_requests * Description: Sets the appropriate status bits in a ccb such that, diff --git a/sys/dev/usb/storage/umass.c b/sys/dev/usb/storage/umass.c index 4e57d82a1fdc..e41e55b7f909 100644 --- a/sys/dev/usb/storage/umass.c +++ b/sys/dev/usb/storage/umass.c @@ -469,8 +469,6 @@ static void umass_cbi_start_status(struct umass_softc *); static void umass_t_cbi_data_clear_stall_callback(struct usb_xfer *, uint8_t, uint8_t, usb_error_t); static int umass_cam_attach_sim(struct umass_softc *); -static void umass_cam_rescan_callback(struct cam_periph *, union ccb *); -static void umass_cam_rescan(struct umass_softc *); static void umass_cam_attach(struct umass_softc *); static void umass_cam_detach_sim(struct umass_softc *); static void umass_cam_action(struct cam_sim *, union ccb *); @@ -2144,68 +2142,6 @@ umass_cam_attach_sim(struct umass_softc *sc) return (0); } -static void -umass_cam_rescan_callback(struct cam_periph *periph, union ccb *ccb) -{ -#if USB_DEBUG - struct umass_softc *sc = NULL; - - if (ccb->ccb_h.status != CAM_REQ_CMP) { - DPRINTF(sc, UDMASS_SCSI, "%s:%d Rescan failed, 0x%04x\n", - periph->periph_name, periph->unit_number, - ccb->ccb_h.status); - } else { - DPRINTF(sc, UDMASS_SCSI, "%s%d: Rescan succeeded\n", - periph->periph_name, periph->unit_number); - } -#endif - - xpt_free_path(ccb->ccb_h.path); - free(ccb, M_USBDEV); -} - -static void -umass_cam_rescan(struct umass_softc *sc) -{ - struct cam_path *path; - union ccb *ccb; - - DPRINTF(sc, UDMASS_SCSI, "scbus%d: scanning for %d:%d:%d\n", - cam_sim_path(sc->sc_sim), - cam_sim_path(sc->sc_sim), - sc->sc_unit, CAM_LUN_WILDCARD); - - ccb = malloc(sizeof(*ccb), M_USBDEV, M_WAITOK | M_ZERO); - - if (ccb == NULL) { - return; - } -#if (__FreeBSD_version >= 700037) - mtx_lock(&sc->sc_mtx); -#endif - - if (xpt_create_path(&path, xpt_periph, cam_sim_path(sc->sc_sim), - CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) - != CAM_REQ_CMP) { -#if (__FreeBSD_version >= 700037) - mtx_unlock(&sc->sc_mtx); -#endif - free(ccb, M_USBDEV); - return; - } - xpt_setup_ccb(&ccb->ccb_h, path, 5 /* priority (low) */ ); - ccb->ccb_h.func_code = XPT_SCAN_BUS; - ccb->ccb_h.cbfcnp = &umass_cam_rescan_callback; - ccb->crcn.flags = CAM_FLAG_NONE; - xpt_action(ccb); - -#if (__FreeBSD_version >= 700037) - mtx_unlock(&sc->sc_mtx); -#endif - - /* The scan is in progress now. */ -} - static void umass_cam_attach(struct umass_softc *sc) { @@ -2216,19 +2152,6 @@ umass_cam_attach(struct umass_softc *sc) sc->sc_name, cam_sim_path(sc->sc_sim), sc->sc_unit, CAM_LUN_WILDCARD, cam_sim_path(sc->sc_sim)); - - if (!cold) { - /* - * Notify CAM of the new device after a short delay. Any - * failure is benign, as the user can still do it by hand - * (camcontrol rescan ). Only do this if we are not - * booting, because CAM does a scan after booting has - * completed, when interrupts have been enabled. - */ - - /* scan the new sim */ - umass_cam_rescan(sc); - } } /* umass_cam_detach