Changeset View
Changeset View
Standalone View
Standalone View
sys/cam/scsi/scsi_da.c
Context not available. | |||||
} da_state; | } da_state; | ||||
typedef enum { | typedef enum { | ||||
DA_REF_NONE = 0x000, | |||||
DA_REF_OPEN = 0x001, | |||||
DA_REF_ALLOC = 0x002, | |||||
DA_REF_OTAG = 0x004, | |||||
DA_REF_GEOM = 0x008, | |||||
DA_REF_MEDIA = 0x010, | |||||
DA_REF_TUR = 0x020, | |||||
DA_REF_SYSCTL = 0x040, | |||||
DA_REF_REPROBE = 0x080, | |||||
} da_ref_src; | |||||
typedef enum { | |||||
DA_FLAG_PACK_INVALID = 0x000001, | DA_FLAG_PACK_INVALID = 0x000001, | ||||
DA_FLAG_NEW_PACK = 0x000002, | DA_FLAG_NEW_PACK = 0x000002, | ||||
DA_FLAG_PACK_LOCKED = 0x000004, | DA_FLAG_PACK_LOCKED = 0x000004, | ||||
Context not available. | |||||
da_state state; | da_state state; | ||||
da_flags flags; | da_flags flags; | ||||
da_quirks quirks; | da_quirks quirks; | ||||
da_ref_src ref_src; | |||||
int minimum_cmd_size; | int minimum_cmd_size; | ||||
int error_inject; | int error_inject; | ||||
int trim_max_ranges; | int trim_max_ranges; | ||||
Context not available. | |||||
}, | }, | ||||
}; | }; | ||||
static cam_status daacquire(struct cam_periph *periph, da_ref_src src); | |||||
static void darelease(struct cam_periph *periph, da_ref_src src, | |||||
int locked); | |||||
static void daallocrel(struct cam_periph *periph); | |||||
static void dastatus(struct cam_periph *periph); | |||||
static disk_strategy_t dastrategy; | static disk_strategy_t dastrategy; | ||||
static dumper_t dadump; | static dumper_t dadump; | ||||
static periph_init_t dainit; | static periph_init_t dainit; | ||||
Context not available. | |||||
static MALLOC_DEFINE(M_SCSIDA, "scsi_da", "scsi_da buffers"); | static MALLOC_DEFINE(M_SCSIDA, "scsi_da", "scsi_da buffers"); | ||||
static cam_status | |||||
daacquire(struct cam_periph *periph, da_ref_src src) | |||||
{ | |||||
struct da_softc *softc; | |||||
cam_status status; | |||||
softc = (struct da_softc *)periph->softc; | |||||
KASSERT((softc->ref_src & src) == 0, | |||||
("daacquire: src %#x is already held refcnt %d, mask %#x", | |||||
src, periph->refcount, softc->ref_src)); | |||||
status = cam_periph_acquire(periph); | |||||
if (status == CAM_REQ_CMP) | |||||
softc->ref_src |= src; | |||||
return (status); | |||||
} | |||||
static void | |||||
darelease(struct cam_periph *periph, da_ref_src src, int locked) | |||||
{ | |||||
struct da_softc *softc; | |||||
struct mtx *mtx; | |||||
softc = (struct da_softc *)periph->softc; | |||||
mtx = cam_periph_mtx(periph); | |||||
if (locked == 0) | |||||
mtx_lock(mtx); | |||||
KASSERT((softc->ref_src & src) != 0, | |||||
("darelease: src %#x is NOT held", src)); | |||||
softc->ref_src &= ~src; | |||||
cam_periph_release_locked(periph); | |||||
if (locked == 0) | |||||
mtx_unlock(mtx); | |||||
} | |||||
static void | |||||
daallocrel(struct cam_periph *periph) | |||||
{ | |||||
darelease(periph, DA_REF_ALLOC, /*locked*/ 1); | |||||
} | |||||
static void | |||||
dastatus(struct cam_periph *periph) | |||||
{ | |||||
struct da_softc *softc; | |||||
cam_periph_assert(periph, MA_OWNED); | |||||
softc = (struct da_softc *)periph->softc; | |||||
printf("%s%u: ref src %#x, refcount %d, softc refcount %d\n", | |||||
periph->periph_name, periph->unit_number, softc->ref_src, | |||||
periph->refcount, softc->refcount); | |||||
} | |||||
static int | static int | ||||
daopen(struct disk *dp) | daopen(struct disk *dp) | ||||
{ | { | ||||
Context not available. | |||||
int error; | int error; | ||||
periph = (struct cam_periph *)dp->d_drv1; | periph = (struct cam_periph *)dp->d_drv1; | ||||
if (cam_periph_acquire(periph) != CAM_REQ_CMP) { | if (daacquire(periph, DA_REF_OPEN) != CAM_REQ_CMP) { | ||||
return (ENXIO); | return (ENXIO); | ||||
} | } | ||||
cam_periph_lock(periph); | cam_periph_lock(periph); | ||||
if ((error = cam_periph_hold(periph, PRIBIO|PCATCH)) != 0) { | if ((error = cam_periph_hold(periph, PRIBIO|PCATCH)) != 0) { | ||||
cam_periph_unlock(periph); | cam_periph_unlock(periph); | ||||
cam_periph_release(periph); | darelease(periph, DA_REF_OPEN, /*locked*/ 0); | ||||
return (error); | return (error); | ||||
} | } | ||||
Context not available. | |||||
cam_periph_unlock(periph); | cam_periph_unlock(periph); | ||||
if (error != 0) | if (error != 0) | ||||
cam_periph_release(periph); | darelease(periph, DA_REF_OPEN, /*locked*/ 0); | ||||
return (error); | return (error); | ||||
} | } | ||||
Context not available. | |||||
while (softc->refcount != 0) | while (softc->refcount != 0) | ||||
cam_periph_sleep(periph, &softc->refcount, PRIBIO, "daclose", 1); | cam_periph_sleep(periph, &softc->refcount, PRIBIO, "daclose", 1); | ||||
cam_periph_unlock(periph); | cam_periph_unlock(periph); | ||||
cam_periph_release(periph); | darelease(periph, DA_REF_OPEN, /*locked*/ 0); | ||||
return (0); | return (0); | ||||
} | } | ||||
Context not available. | |||||
struct cam_periph *periph; | struct cam_periph *periph; | ||||
periph = (struct cam_periph *)dp->d_drv1; | periph = (struct cam_periph *)dp->d_drv1; | ||||
cam_periph_release(periph); | |||||
printf("(%s%d:%s%d:%d:%d:%jx): got GEOM disk gone callback\n", | |||||
periph->periph_name, periph->unit_number, | |||||
xpt_path_sim(periph->path)->sim_name, | |||||
xpt_path_sim(periph->path)->unit_number, | |||||
xpt_path_sim(periph->path)->bus_id, | |||||
xpt_path_target_id(periph->path), | |||||
(uintmax_t)xpt_path_lun_id(periph->path)); | |||||
darelease(periph, DA_REF_GEOM, /*locked*/ 0); | |||||
} | } | ||||
static void | static void | ||||
Context not available. | |||||
softc = (struct da_softc *)periph->softc; | softc = (struct da_softc *)periph->softc; | ||||
printf("(%s%d:%s%d:%d:%d:%jx): lost device\n", | |||||
periph->periph_name, periph->unit_number, | |||||
xpt_path_sim(periph->path)->sim_name, | |||||
xpt_path_sim(periph->path)->unit_number, | |||||
xpt_path_sim(periph->path)->bus_id, | |||||
xpt_path_target_id(periph->path), | |||||
(uintmax_t)xpt_path_lun_id(periph->path)); | |||||
cam_periph_assert(periph, MA_OWNED); | |||||
/* | /* | ||||
* De-register any async callbacks. | * De-register any async callbacks. | ||||
*/ | */ | ||||
Context not available. | |||||
cam_iosched_flush(softc->cam_iosched, NULL, ENXIO); | cam_iosched_flush(softc->cam_iosched, NULL, ENXIO); | ||||
/* | /* | ||||
* Stop the ordered tag callout. If it isn't pending or executing | |||||
* we can go ahead and release the reference. If it couldn't be | |||||
* cancelled, the callout will | |||||
*/ | |||||
if (callout_stop(&softc->sendordered_c) != 0) | |||||
darelease(periph, DA_REF_OTAG, /*locked*/ 1); | |||||
/* | |||||
* Drain the media poll callout. If it isn't pending or executing | |||||
* we can go ahead and release the reference. If it couldn't be | |||||
* cancelled, we'll get a callback when it is done. | |||||
*/ | |||||
if (callout_stop(&softc->mediapoll_c) != 0) | |||||
darelease(periph, DA_REF_MEDIA, /*locked*/ 1); | |||||
/* | |||||
* If we are not allocating, we have the responsibility to release | |||||
* the reference held for the allocation code (xpt_run_allocq()). | |||||
* If the allocation code is active, it will release the reference | |||||
* once it completes. | |||||
*/ | |||||
if (periph->periph_allocating == 0) | |||||
darelease(periph, DA_REF_ALLOC, /*locked*/ 1); | |||||
/* | |||||
* If this device went away during the initial probe, it still has | |||||
* an active hold. Release the hold now that it has been | |||||
* invalidated. | |||||
* | |||||
* XXX KDM make sure this doesn't open up any holes in the probe. | |||||
*/ | |||||
#if 0 | |||||
if ((softc->flags & DA_FLAG_ANNOUNCED) == 0) { | |||||
softc->flags |= DA_FLAG_ANNOUNCED; | |||||
cam_periph_unhold(periph); | |||||
} | |||||
#endif | |||||
/* | |||||
* Tell GEOM that we've gone away, we'll get a callback when it is | * Tell GEOM that we've gone away, we'll get a callback when it is | ||||
* done cleaning up its resources. | * done cleaning up its resources. | ||||
*/ | */ | ||||
Context not available. | |||||
softc = (struct da_softc *)periph->softc; | softc = (struct da_softc *)periph->softc; | ||||
printf("(%s%d:%s%d:%d:%d:%jx): removing device entry\n", | |||||
periph->periph_name, periph->unit_number, | |||||
xpt_path_sim(periph->path)->sim_name, | |||||
xpt_path_sim(periph->path)->unit_number, | |||||
xpt_path_sim(periph->path)->bus_id, | |||||
xpt_path_target_id(periph->path), | |||||
(uintmax_t)xpt_path_lun_id(periph->path)); | |||||
cam_periph_unlock(periph); | cam_periph_unlock(periph); | ||||
cam_iosched_fini(softc->cam_iosched); | cam_iosched_fini(softc->cam_iosched); | ||||
Context not available. | |||||
"can't remove sysctl context\n"); | "can't remove sysctl context\n"); | ||||
} | } | ||||
callout_drain(&softc->mediapoll_c); | |||||
disk_destroy(softc->disk); | disk_destroy(softc->disk); | ||||
callout_drain(&softc->sendordered_c); | |||||
free(softc, M_DEVBUF); | free(softc, M_DEVBUF); | ||||
cam_periph_lock(periph); | cam_periph_lock(periph); | ||||
} | } | ||||
Context not available. | |||||
} | } | ||||
case AC_SCSI_AEN: | case AC_SCSI_AEN: | ||||
softc = (struct da_softc *)periph->softc; | softc = (struct da_softc *)periph->softc; | ||||
if (!cam_iosched_has_work_flags(softc->cam_iosched, DA_WORK_TUR)) { | if (!cam_iosched_has_work_flags(softc->cam_iosched, | ||||
if (cam_periph_acquire(periph) == CAM_REQ_CMP) { | DA_WORK_TUR)) { | ||||
cam_iosched_set_work_flags(softc->cam_iosched, DA_WORK_TUR); | cam_iosched_set_work_flags(softc->cam_iosched, | ||||
daschedule(periph); | DA_WORK_TUR); | ||||
} | daschedule(periph); | ||||
} | } | ||||
/* FALLTHROUGH */ | /* FALLTHROUGH */ | ||||
case AC_SENT_BDR: | case AC_SENT_BDR: | ||||
Context not available. | |||||
* periph was held for us when this task was enqueued | * periph was held for us when this task was enqueued | ||||
*/ | */ | ||||
if (periph->flags & CAM_PERIPH_INVALID) { | if (periph->flags & CAM_PERIPH_INVALID) { | ||||
cam_periph_release(periph); | darelease(periph, DA_REF_SYSCTL, /*locked*/ 0); | ||||
return; | return; | ||||
} | } | ||||
Context not available. | |||||
CTLFLAG_RD, 0, tmpstr); | CTLFLAG_RD, 0, tmpstr); | ||||
if (softc->sysctl_tree == NULL) { | if (softc->sysctl_tree == NULL) { | ||||
printf("dasysctlinit: unable to allocate sysctl tree\n"); | printf("dasysctlinit: unable to allocate sysctl tree\n"); | ||||
cam_periph_release(periph); | darelease(periph, DA_REF_SYSCTL, /*locked*/ 0); | ||||
return; | return; | ||||
} | } | ||||
Context not available. | |||||
xpt_action((union ccb *)&cts); | xpt_action((union ccb *)&cts); | ||||
cam_periph_unlock(periph); | cam_periph_unlock(periph); | ||||
if (cts.ccb_h.status != CAM_REQ_CMP) { | if (cts.ccb_h.status != CAM_REQ_CMP) { | ||||
cam_periph_release(periph); | darelease(periph, DA_REF_SYSCTL, /*locked*/ 0); | ||||
return; | return; | ||||
} | } | ||||
if (cts.protocol == PROTO_SCSI && cts.transport == XPORT_FC) { | if (cts.protocol == PROTO_SCSI && cts.transport == XPORT_FC) { | ||||
Context not available. | |||||
cam_iosched_sysctl_init(softc->cam_iosched, &softc->sysctl_ctx, | cam_iosched_sysctl_init(softc->cam_iosched, &softc->sysctl_ctx, | ||||
softc->sysctl_tree); | softc->sysctl_tree); | ||||
cam_periph_release(periph); | darelease(periph, DA_REF_SYSCTL, /*locked*/ 0); | ||||
} | } | ||||
static int | static int | ||||
Context not available. | |||||
softc->flags |= DA_FLAG_ANNOUNCED; | softc->flags |= DA_FLAG_ANNOUNCED; | ||||
cam_periph_unhold(periph); | cam_periph_unhold(periph); | ||||
} else | } else | ||||
cam_periph_release_locked(periph); | darelease(periph, DA_REF_REPROBE, /*locked*/ 1); | ||||
} | } | ||||
static void | static void | ||||
Context not available. | |||||
softc->rotating = 1; | softc->rotating = 1; | ||||
periph->softc = softc; | periph->softc = softc; | ||||
periph->periph_alloc_rel = daallocrel; | |||||
periph->periph_status = dastatus; | |||||
/* | /* | ||||
* See if this device has any quirks. | * See if this device has any quirks. | ||||
Context not available. | |||||
(void)cam_periph_hold(periph, PRIBIO); | (void)cam_periph_hold(periph, PRIBIO); | ||||
/* | /* | ||||
* Acquire a reference for allocating. This will be released by | |||||
* the allocation code (xpt_run_allocq()) if the device goes away | |||||
* while we're allocating. Otherwise, it'll be released by | |||||
* daoninvalidate(). | |||||
*/ | |||||
if (daacquire(periph, DA_REF_ALLOC) != CAM_REQ_CMP) { | |||||
cam_periph_unhold(periph); | |||||
xpt_print(periph->path, "%s: lost periph during " | |||||
"registration!\n", __func__); | |||||
return (CAM_REQ_CMP_ERR); | |||||
} | |||||
/* | |||||
* Tell the allocation code that we have acquired a reference for | |||||
* it that we will release if it is not active. | |||||
*/ | |||||
periph->flags |= CAM_PERIPH_ALLOC_REF; | |||||
/* | |||||
* Acquire a reference to the periph before we start the ordered | |||||
* tag callout. We'll release this reference once we have shut down | |||||
* the callout. | |||||
*/ | |||||
if (daacquire(periph, DA_REF_OTAG) != CAM_REQ_CMP) { | |||||
cam_periph_unhold(periph); | |||||
xpt_print(periph->path, "%s: lost periph during " | |||||
"registration!\n", __func__); | |||||
return (CAM_REQ_CMP_ERR); | |||||
} | |||||
/* | |||||
* Schedule a periodic event to occasionally send an | * Schedule a periodic event to occasionally send an | ||||
* ordered tag to a device. | * ordered tag to a device. | ||||
*/ | */ | ||||
callout_init_mtx(&softc->sendordered_c, cam_periph_mtx(periph), 0); | callout_init_mtx(&softc->sendordered_c, cam_periph_mtx(periph), | ||||
CALLOUT_RETURNUNLOCKED); | |||||
callout_reset(&softc->sendordered_c, | callout_reset(&softc->sendordered_c, | ||||
(da_default_timeout * hz) / DA_ORDEREDTAG_INTERVAL, | (da_default_timeout * hz) / DA_ORDEREDTAG_INTERVAL, | ||||
dasendorderedtag, softc); | dasendorderedtag, periph); | ||||
cam_periph_unlock(periph); | cam_periph_unlock(periph); | ||||
/* | /* | ||||
Context not available. | |||||
* We'll release this reference once GEOM calls us back (via | * We'll release this reference once GEOM calls us back (via | ||||
* dadiskgonecb()) telling us that our provider has been freed. | * dadiskgonecb()) telling us that our provider has been freed. | ||||
*/ | */ | ||||
if (cam_periph_acquire(periph) != CAM_REQ_CMP) { | if (daacquire(periph, DA_REF_GEOM) != CAM_REQ_CMP) { | ||||
xpt_print(periph->path, "%s: lost periph during " | xpt_print(periph->path, "%s: lost periph during " | ||||
"registration!\n", __func__); | "registration!\n", __func__); | ||||
cam_periph_lock(periph); | cam_periph_lock(periph); | ||||
cam_periph_unhold(periph); | |||||
return (CAM_REQ_CMP_ERR); | return (CAM_REQ_CMP_ERR); | ||||
} | } | ||||
Context not available. | |||||
disk_attr_changed(softc->disk, "GEOM::physpath", M_NOWAIT); | disk_attr_changed(softc->disk, "GEOM::physpath", M_NOWAIT); | ||||
/* | /* | ||||
* Schedule a periodic media polling events. | * Acquire a reference to the periph before we start the media poll | ||||
* callout. We'll release this reference once we have shut down | |||||
* the callout. | |||||
*/ | */ | ||||
callout_init_mtx(&softc->mediapoll_c, cam_periph_mtx(periph), 0); | if (daacquire(periph, DA_REF_MEDIA) != CAM_REQ_CMP) { | ||||
xpt_print(periph->path, "%s: lost periph during " | |||||
"registration!\n", __func__); | |||||
cam_periph_unhold(periph); | |||||
return (CAM_REQ_CMP_ERR); | |||||
} | |||||
/* | |||||
* Schedule a periodic media polling event. | |||||
*/ | |||||
callout_init_mtx(&softc->mediapoll_c, cam_periph_mtx(periph), | |||||
CALLOUT_RETURNUNLOCKED); | |||||
if ((softc->flags & DA_FLAG_PACK_REMOVABLE) && | if ((softc->flags & DA_FLAG_PACK_REMOVABLE) && | ||||
(cgd->inq_flags & SID_AEN) == 0 && | (cgd->inq_flags & SID_AEN) == 0 && | ||||
da_poll_period != 0) | da_poll_period != 0) { | ||||
callout_reset(&softc->mediapoll_c, da_poll_period * hz, | callout_reset(&softc->mediapoll_c, da_poll_period * hz, | ||||
damediapoll, periph); | damediapoll, periph); | ||||
} | |||||
xpt_schedule(periph, CAM_PRIORITY_DEV); | xpt_schedule(periph, CAM_PRIORITY_DEV); | ||||
Context not available. | |||||
more: | more: | ||||
bp = cam_iosched_next_bio(softc->cam_iosched); | bp = cam_iosched_next_bio(softc->cam_iosched); | ||||
if (bp == NULL) { | if (bp == NULL) { | ||||
if (cam_iosched_has_work_flags(softc->cam_iosched, DA_WORK_TUR)) { | /* | ||||
cam_iosched_clr_work_flags(softc->cam_iosched, DA_WORK_TUR); | * Note that we're acquiring a reference to the | ||||
* peripheral if we need to send a media poll TUR. | |||||
* This keeps the device from going away while | |||||
* we have I/O outstanding. | |||||
* | |||||
* In the general I/O case, we're protected from | |||||
* the peripheral going away while I/O is | |||||
* outstanding by the acquire in daopen() and | |||||
* release in daclose(). GEOM shouldn't send a close | |||||
* while I/O is outstanding. | |||||
*/ | |||||
if ((cam_iosched_has_work_flags(softc->cam_iosched, | |||||
DA_WORK_TUR)) | |||||
&& (daacquire(periph, DA_REF_TUR) == CAM_REQ_CMP)) { | |||||
cam_iosched_clr_work_flags(softc->cam_iosched, | |||||
DA_WORK_TUR); | |||||
scsi_test_unit_ready(&start_ccb->csio, | scsi_test_unit_ready(&start_ccb->csio, | ||||
/*retries*/ da_retry_count, | /*retries*/ da_retry_count, | ||||
dadone, | dadone, | ||||
Context not available. | |||||
} | } | ||||
} | } | ||||
if (cam_iosched_has_work_flags(softc->cam_iosched, DA_WORK_TUR)) { | if (cam_iosched_has_work_flags(softc->cam_iosched, | ||||
cam_iosched_clr_work_flags(softc->cam_iosched, DA_WORK_TUR); | DA_WORK_TUR)) | ||||
cam_periph_release_locked(periph); /* XXX is this still valid? I think so but unverified */ | cam_iosched_clr_work_flags(softc->cam_iosched, | ||||
} | DA_WORK_TUR); | ||||
if ((bp->bio_flags & BIO_ORDERED) != 0 || | if ((bp->bio_flags & BIO_ORDERED) != 0 || | ||||
(softc->flags & DA_FLAG_NEED_OTAG) != 0) { | (softc->flags & DA_FLAG_NEED_OTAG) != 0) { | ||||
Context not available. | |||||
* we have successfully attached. | * we have successfully attached. | ||||
*/ | */ | ||||
/* increase the refcount */ | /* increase the refcount */ | ||||
if (cam_periph_acquire(periph) == CAM_REQ_CMP) { | if (daacquire(periph, DA_REF_SYSCTL) == CAM_REQ_CMP) { | ||||
taskqueue_enqueue(taskqueue_thread, | taskqueue_enqueue(taskqueue_thread, | ||||
&softc->sysctl_task); | &softc->sysctl_task); | ||||
xpt_announce_periph(periph, announce_buf); | xpt_announce_periph(periph, announce_buf); | ||||
Context not available. | |||||
/*getcount_only*/0); | /*getcount_only*/0); | ||||
} | } | ||||
xpt_release_ccb(done_ccb); | xpt_release_ccb(done_ccb); | ||||
cam_periph_release_locked(periph); | /* | ||||
* Release the reference we acquired when we queued this | |||||
* CCB. | |||||
*/ | |||||
darelease(periph, DA_REF_TUR, /*locked*/ 1); | |||||
return; | return; | ||||
} | } | ||||
default: | default: | ||||
Context not available. | |||||
if (softc->state != DA_STATE_NORMAL) | if (softc->state != DA_STATE_NORMAL) | ||||
return; | return; | ||||
status = cam_periph_acquire(periph); | status = daacquire(periph, DA_REF_REPROBE); | ||||
KASSERT(status == CAM_REQ_CMP, | KASSERT(status == CAM_REQ_CMP, | ||||
("dareprobe: cam_periph_acquire failed")); | ("dareprobe: cam_periph_acquire failed")); | ||||
Context not available. | |||||
struct cam_periph *periph = arg; | struct cam_periph *periph = arg; | ||||
struct da_softc *softc = periph->softc; | struct da_softc *softc = periph->softc; | ||||
if (periph->flags & CAM_PERIPH_INVALID) { | |||||
callout_deactivate(&softc->mediapoll_c); | |||||
cam_periph_unlock(periph); | |||||
darelease(periph, DA_REF_MEDIA, /*locked*/ 0); | |||||
return; | |||||
} | |||||
if (!cam_iosched_has_work_flags(softc->cam_iosched, DA_WORK_TUR) && | if (!cam_iosched_has_work_flags(softc->cam_iosched, DA_WORK_TUR) && | ||||
LIST_EMPTY(&softc->pending_ccbs)) { | LIST_EMPTY(&softc->pending_ccbs)) { | ||||
if (cam_periph_acquire(periph) == CAM_REQ_CMP) { | cam_iosched_set_work_flags(softc->cam_iosched, DA_WORK_TUR); | ||||
cam_iosched_set_work_flags(softc->cam_iosched, DA_WORK_TUR); | daschedule(periph); | ||||
daschedule(periph); | |||||
} | |||||
} | } | ||||
/* Queue us up again */ | /* Queue us up again */ | ||||
if (da_poll_period != 0) | if (da_poll_period != 0) | ||||
callout_schedule(&softc->mediapoll_c, da_poll_period * hz); | callout_schedule(&softc->mediapoll_c, | ||||
da_poll_period * hz); | |||||
cam_periph_unlock(periph); | |||||
} | } | ||||
static void | static void | ||||
Context not available. | |||||
static void | static void | ||||
dasendorderedtag(void *arg) | dasendorderedtag(void *arg) | ||||
{ | { | ||||
struct da_softc *softc = arg; | struct cam_periph *periph = arg; | ||||
struct da_softc *softc = periph->softc; | |||||
/* | |||||
* If the callout is pending, that means that it was rescheduled | |||||
* just before this instance was due to run. Normally the pending | |||||
* bit should be clear when we enter. | |||||
*/ | |||||
if (callout_pending(&softc->sendordered_c)) { | |||||
cam_periph_unlock(periph); | |||||
return; | |||||
} | |||||
if (da_send_ordered) { | if (da_send_ordered) { | ||||
if (!LIST_EMPTY(&softc->pending_ccbs)) { | if (!LIST_EMPTY(&softc->pending_ccbs)) { | ||||
if ((softc->flags & DA_FLAG_WAS_OTAG) == 0) | if ((softc->flags & DA_FLAG_WAS_OTAG) == 0) | ||||
Context not available. | |||||
softc->flags &= ~DA_FLAG_WAS_OTAG; | softc->flags &= ~DA_FLAG_WAS_OTAG; | ||||
} | } | ||||
} | } | ||||
/* Queue us up again */ | |||||
callout_reset(&softc->sendordered_c, | /* | ||||
(da_default_timeout * hz) / DA_ORDEREDTAG_INTERVAL, | * Check to see whether this peripheral has been invalidated. If | ||||
dasendorderedtag, softc); | * it has, and the callout has fired, it means that this callout | ||||
* was pending and could not be stopped. So, in that case, we need | |||||
* to release the reference held on the peripheral for this callout. | |||||
* | |||||
* This callout was initialized with the CALLOUT_RETURNUNLOCKED | |||||
* flag, because in the case where we're the last reference held | |||||
* on the peripheral, our call to cam_periph_release() may trigger | |||||
* a free of the peripheral driver. If we didn't return unlocked, | |||||
* the callout code would have to unlock the mutex after this call | |||||
* finishes. If this is the last reference, though, the mutex will | |||||
* have already been freed. | |||||
*/ | |||||
if (periph->flags & CAM_PERIPH_INVALID) { | |||||
callout_deactivate(&softc->sendordered_c); | |||||
cam_periph_unlock(periph); | |||||
darelease(periph, DA_REF_OTAG, /*locked*/ 0); | |||||
} else { | |||||
/* Queue us up again */ | |||||
callout_reset(&softc->sendordered_c, | |||||
(da_default_timeout * hz) / DA_ORDEREDTAG_INTERVAL, | |||||
dasendorderedtag, periph); | |||||
cam_periph_unlock(periph); | |||||
} | |||||
} | } | ||||
/* | /* | ||||
Context not available. |