Changeset View
Changeset View
Standalone View
Standalone View
head/sys/cam/cam_periph.c
Show All 32 Lines | |||||
__FBSDID("$FreeBSD$"); | __FBSDID("$FreeBSD$"); | ||||
#include <sys/param.h> | #include <sys/param.h> | ||||
#include <sys/systm.h> | #include <sys/systm.h> | ||||
#include <sys/types.h> | #include <sys/types.h> | ||||
#include <sys/malloc.h> | #include <sys/malloc.h> | ||||
#include <sys/kernel.h> | #include <sys/kernel.h> | ||||
#include <sys/bio.h> | #include <sys/bio.h> | ||||
#include <sys/conf.h> | |||||
#include <sys/lock.h> | #include <sys/lock.h> | ||||
#include <sys/mutex.h> | #include <sys/mutex.h> | ||||
#include <sys/buf.h> | #include <sys/buf.h> | ||||
#include <sys/proc.h> | #include <sys/proc.h> | ||||
#include <sys/devicestat.h> | #include <sys/devicestat.h> | ||||
#include <sys/bus.h> | #include <sys/bus.h> | ||||
#include <sys/sbuf.h> | #include <sys/sbuf.h> | ||||
#include <vm/vm.h> | #include <vm/vm.h> | ||||
▲ Show 20 Lines • Show All 1,104 Lines • ▼ Show 20 Lines | cam_periph_runccb(union ccb *ccb, | ||||
cam_flags camflags, | cam_flags camflags, | ||||
u_int32_t sense_flags), | u_int32_t sense_flags), | ||||
cam_flags camflags, u_int32_t sense_flags, | cam_flags camflags, u_int32_t sense_flags, | ||||
struct devstat *ds) | struct devstat *ds) | ||||
{ | { | ||||
struct bintime *starttime; | struct bintime *starttime; | ||||
struct bintime ltime; | struct bintime ltime; | ||||
int error; | int error; | ||||
bool sched_stopped; | bool must_poll; | ||||
struct mtx *periph_mtx; | struct mtx *periph_mtx; | ||||
struct cam_periph *periph; | struct cam_periph *periph; | ||||
uint32_t timeout = 1; | uint32_t timeout = 1; | ||||
starttime = NULL; | starttime = NULL; | ||||
xpt_path_assert(ccb->ccb_h.path, MA_OWNED); | xpt_path_assert(ccb->ccb_h.path, MA_OWNED); | ||||
KASSERT((ccb->ccb_h.flags & CAM_UNLOCKED) == 0, | KASSERT((ccb->ccb_h.flags & CAM_UNLOCKED) == 0, | ||||
("%s: ccb=%p, func_code=%#x, flags=%#x", __func__, ccb, | ("%s: ccb=%p, func_code=%#x, flags=%#x", __func__, ccb, | ||||
ccb->ccb_h.func_code, ccb->ccb_h.flags)); | ccb->ccb_h.func_code, ccb->ccb_h.flags)); | ||||
/* | /* | ||||
* If the user has supplied a stats structure, and if we understand | * If the user has supplied a stats structure, and if we understand | ||||
* this particular type of ccb, record the transaction start. | * this particular type of ccb, record the transaction start. | ||||
*/ | */ | ||||
if (ds != NULL && | if (ds != NULL && | ||||
(ccb->ccb_h.func_code == XPT_SCSI_IO || | (ccb->ccb_h.func_code == XPT_SCSI_IO || | ||||
ccb->ccb_h.func_code == XPT_ATA_IO || | ccb->ccb_h.func_code == XPT_ATA_IO || | ||||
ccb->ccb_h.func_code == XPT_NVME_IO)) { | ccb->ccb_h.func_code == XPT_NVME_IO)) { | ||||
starttime = <ime; | starttime = <ime; | ||||
binuptime(starttime); | binuptime(starttime); | ||||
devstat_start_transaction(ds, starttime); | devstat_start_transaction(ds, starttime); | ||||
} | } | ||||
sched_stopped = SCHEDULER_STOPPED(); | /* | ||||
* We must poll the I/O while we're dumping. The scheduler is normally | |||||
* stopped for dumping, except when we call doadump from ddb. While the | |||||
* scheduler is running in this case, we still need to poll the I/O to | |||||
* avoid sleeping waiting for the ccb to complete. | |||||
*/ | |||||
must_poll = dumping; | |||||
ccb->ccb_h.cbfcnp = cam_periph_done; | ccb->ccb_h.cbfcnp = cam_periph_done; | ||||
periph = xpt_path_periph(ccb->ccb_h.path); | periph = xpt_path_periph(ccb->ccb_h.path); | ||||
periph_mtx = cam_periph_mtx(periph); | periph_mtx = cam_periph_mtx(periph); | ||||
/* | /* | ||||
* If we're polling, then we need to ensure that we have ample resources | * If we're polling, then we need to ensure that we have ample resources | ||||
* in the periph. We also need to drop the periph lock while we're polling. | * in the periph. We also need to drop the periph lock while we're polling. | ||||
* cam_periph_error can reschedule the ccb by calling xpt_action and returning | * cam_periph_error can reschedule the ccb by calling xpt_action and returning | ||||
* ERESTART, so we have to effect the polling in the do loop below. | * ERESTART, so we have to effect the polling in the do loop below. | ||||
*/ | */ | ||||
if (sched_stopped) { | if (must_poll) { | ||||
mtx_unlock(periph_mtx); | mtx_unlock(periph_mtx); | ||||
timeout = xpt_poll_setup(ccb); | timeout = xpt_poll_setup(ccb); | ||||
} | } | ||||
if (timeout == 0) { | if (timeout == 0) { | ||||
ccb->ccb_h.status = CAM_RESRC_UNAVAIL; | ccb->ccb_h.status = CAM_RESRC_UNAVAIL; | ||||
error = EBUSY; | error = EBUSY; | ||||
} else { | } else { | ||||
xpt_action(ccb); | xpt_action(ccb); | ||||
do { | do { | ||||
if (!sched_stopped) | if (must_poll) { | ||||
cam_periph_ccbwait(ccb); | |||||
else { | |||||
xpt_pollwait(ccb, timeout); | xpt_pollwait(ccb, timeout); | ||||
timeout = ccb->ccb_h.timeout * 10; | timeout = ccb->ccb_h.timeout * 10; | ||||
} else { | |||||
cam_periph_ccbwait(ccb); | |||||
} | } | ||||
if ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) | if ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) | ||||
error = 0; | error = 0; | ||||
else if (error_routine != NULL) { | else if (error_routine != NULL) { | ||||
ccb->ccb_h.cbfcnp = cam_periph_done; | ccb->ccb_h.cbfcnp = cam_periph_done; | ||||
error = (*error_routine)(ccb, camflags, sense_flags); | error = (*error_routine)(ccb, camflags, sense_flags); | ||||
} else | } else | ||||
error = 0; | error = 0; | ||||
} while (error == ERESTART); | } while (error == ERESTART); | ||||
} | } | ||||
if (sched_stopped) | if (must_poll) | ||||
mtx_lock(periph_mtx); | mtx_lock(periph_mtx); | ||||
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, | cam_release_devq(ccb->ccb_h.path, | ||||
/* relsim_flags */0, | /* relsim_flags */0, | ||||
/* openings */0, | /* openings */0, | ||||
/* timeout */0, | /* timeout */0, | ||||
/* getcount_only */ FALSE); | /* getcount_only */ FALSE); | ||||
▲ Show 20 Lines • Show All 826 Lines • Show Last 20 Lines |