diff options
Diffstat (limited to 'sys/cam/scsi/scsi_da.c')
-rw-r--r-- | sys/cam/scsi/scsi_da.c | 185 |
1 files changed, 75 insertions, 110 deletions
diff --git a/sys/cam/scsi/scsi_da.c b/sys/cam/scsi/scsi_da.c index 59a332c..f1ea06a 100644 --- a/sys/cam/scsi/scsi_da.c +++ b/sys/cam/scsi/scsi_da.c @@ -84,7 +84,7 @@ typedef enum { DA_FLAG_PACK_LOCKED = 0x004, DA_FLAG_PACK_REMOVABLE = 0x008, DA_FLAG_NEED_OTAG = 0x020, - DA_FLAG_WENT_IDLE = 0x040, + DA_FLAG_WAS_OTAG = 0x040, DA_FLAG_RETRY_UA = 0x080, DA_FLAG_OPEN = 0x100, DA_FLAG_SCTX_INIT = 0x200, @@ -118,7 +118,6 @@ typedef enum { DA_CCB_PROBE_BDC = 0x05, DA_CCB_PROBE_ATA = 0x06, DA_CCB_BUFFER_IO = 0x07, - DA_CCB_WAITING = 0x08, DA_CCB_DUMP = 0x0A, DA_CCB_DELETE = 0x0B, DA_CCB_TUR = 0x0C, @@ -199,19 +198,17 @@ struct da_softc { struct bio_queue_head bio_queue; struct bio_queue_head delete_queue; struct bio_queue_head delete_run_queue; - SLIST_ENTRY(da_softc) links; LIST_HEAD(, ccb_hdr) pending_ccbs; + int tur; /* TEST UNIT READY should be sent */ + int refcount; /* Active xpt_action() calls */ da_state state; da_flags flags; da_quirks quirks; int sort_io_queue; int minimum_cmd_size; int error_inject; - int ordered_tag_count; - int outstanding_cmds; int trim_max_ranges; int delete_running; - int tur; int delete_available; /* Delete methods possibly available */ uint32_t unmap_max_ranges; uint32_t unmap_max_lba; @@ -1269,86 +1266,72 @@ daclose(struct disk *dp) { struct cam_periph *periph; struct da_softc *softc; + union ccb *ccb; int error; periph = (struct cam_periph *)dp->d_drv1; - cam_periph_lock(periph); - if (cam_periph_hold(periph, PRIBIO) != 0) { - cam_periph_unlock(periph); - cam_periph_release(periph); - return (0); - } - softc = (struct da_softc *)periph->softc; - + cam_periph_lock(periph); CAM_DEBUG(periph->path, CAM_DEBUG_TRACE | CAM_DEBUG_PERIPH, ("daclose\n")); - if ((softc->flags & DA_FLAG_DIRTY) != 0 && - (softc->quirks & DA_Q_NO_SYNC_CACHE) == 0 && - (softc->flags & DA_FLAG_PACK_INVALID) == 0) { - union ccb *ccb; - - ccb = cam_periph_getccb(periph, CAM_PRIORITY_NORMAL); - - scsi_synchronize_cache(&ccb->csio, - /*retries*/1, - /*cbfcnp*/dadone, - MSG_SIMPLE_Q_TAG, - /*begin_lba*/0,/* Cover the whole disk */ - /*lb_count*/0, - SSD_FULL_SIZE, - 5 * 60 * 1000); + if (cam_periph_hold(periph, PRIBIO) == 0) { + + /* Flush disk cache. */ + if ((softc->flags & DA_FLAG_DIRTY) != 0 && + (softc->quirks & DA_Q_NO_SYNC_CACHE) == 0 && + (softc->flags & DA_FLAG_PACK_INVALID) == 0) { + ccb = cam_periph_getccb(periph, CAM_PRIORITY_NORMAL); + scsi_synchronize_cache(&ccb->csio, /*retries*/1, + /*cbfcnp*/dadone, MSG_SIMPLE_Q_TAG, + /*begin_lba*/0, /*lb_count*/0, SSD_FULL_SIZE, + 5 * 60 * 1000); + error = cam_periph_runccb(ccb, daerror, /*cam_flags*/0, + /*sense_flags*/SF_RETRY_UA | SF_QUIET_IR, + softc->disk->d_devstat); + if (error == 0) + softc->flags &= ~DA_FLAG_DIRTY; + xpt_release_ccb(ccb); + } - error = cam_periph_runccb(ccb, daerror, /*cam_flags*/0, - /*sense_flags*/SF_RETRY_UA | SF_QUIET_IR, - softc->disk->d_devstat); - if (error == 0) - softc->flags &= ~DA_FLAG_DIRTY; - xpt_release_ccb(ccb); + /* Allow medium removal. */ + if ((softc->flags & DA_FLAG_PACK_REMOVABLE) != 0 && + (softc->quirks & DA_Q_NO_PREVENT) == 0) + daprevent(periph, PR_ALLOW); + cam_periph_unhold(periph); } - if ((softc->flags & DA_FLAG_PACK_REMOVABLE) != 0) { - if ((softc->quirks & DA_Q_NO_PREVENT) == 0) - daprevent(periph, PR_ALLOW); - /* - * If we've got removeable media, mark the blocksize as - * unavailable, since it could change when new media is - * inserted. - */ + /* + * If we've got removeable media, mark the blocksize as + * unavailable, since it could change when new media is + * inserted. + */ + if ((softc->flags & DA_FLAG_PACK_REMOVABLE) != 0) softc->disk->d_devstat->flags |= DEVSTAT_BS_UNAVAILABLE; - } softc->flags &= ~DA_FLAG_OPEN; - cam_periph_unhold(periph); + while (softc->refcount != 0) + cam_periph_sleep(periph, &softc->refcount, PRIBIO, "daclose", 1); cam_periph_unlock(periph); cam_periph_release(periph); - return (0); + return (0); } static void daschedule(struct cam_periph *periph) { struct da_softc *softc = (struct da_softc *)periph->softc; - uint32_t prio; if (softc->state != DA_STATE_NORMAL) return; - /* Check if cam_periph_getccb() was called. */ - prio = periph->immediate_priority; - /* Check if we have more work to do. */ if (bioq_first(&softc->bio_queue) || (!softc->delete_running && bioq_first(&softc->delete_queue)) || softc->tur) { - prio = CAM_PRIORITY_NORMAL; + xpt_schedule(periph, CAM_PRIORITY_NORMAL); } - - /* Schedule CCB if any of above is true. */ - if (prio != CAM_PRIORITY_NONE) - xpt_schedule(periph, prio); } /* @@ -1382,9 +1365,7 @@ dastrategy(struct bio *bp) * Place it in the queue of disk activities for this disk */ if (bp->bio_cmd == BIO_DELETE) { - if (bp->bio_bcount == 0) - biodone(bp); - else if (DA_SIO) + if (DA_SIO) bioq_disksort(&softc->delete_queue, bp); else bioq_insert_tail(&softc->delete_queue, bp); @@ -1621,7 +1602,7 @@ daasync(void *callback_arg, u_int32_t code, status = cam_periph_alloc(daregister, daoninvalidate, dacleanup, dastart, "da", CAM_PERIPH_BIO, - cgd->ccb_h.path, daasync, + path, daasync, AC_FOUND_DEVICE, cgd); if (status != CAM_REQ_CMP @@ -2066,7 +2047,7 @@ daregister(struct cam_periph *periph, void *arg) * Schedule a periodic event to occasionally send an * ordered tag to a device. */ - callout_init_mtx(&softc->sendordered_c, periph->sim->mtx, 0); + callout_init_mtx(&softc->sendordered_c, cam_periph_mtx(periph), 0); callout_reset(&softc->sendordered_c, (da_default_timeout * hz) / DA_ORDEREDTAG_INTERVAL, dasendorderedtag, softc); @@ -2186,7 +2167,7 @@ daregister(struct cam_periph *periph, void *arg) /* * Schedule a periodic media polling events. */ - callout_init_mtx(&softc->mediapoll_c, periph->sim->mtx, 0); + callout_init_mtx(&softc->mediapoll_c, cam_periph_mtx(periph), 0); if ((softc->flags & DA_FLAG_PACK_REMOVABLE) && (cgd->inq_flags & SID_AEN) == 0 && da_poll_period != 0) @@ -2214,20 +2195,6 @@ skipstate: struct bio *bp; uint8_t tag_code; - /* Execute immediate CCB if waiting. */ - if (periph->immediate_priority <= periph->pinfo.priority) { - CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, - ("queuing for immediate ccb\n")); - start_ccb->ccb_h.ccb_state = DA_CCB_WAITING; - SLIST_INSERT_HEAD(&periph->ccb_list, &start_ccb->ccb_h, - periph_links.sle); - periph->immediate_priority = CAM_PRIORITY_NONE; - wakeup(&periph->ccb_list); - /* May have more work to do, so ensure we stay scheduled */ - daschedule(periph); - break; - } - /* Run BIO_DELETE if not running yet. */ if (!softc->delete_running && (bp = bioq_first(&softc->delete_queue)) != NULL) { @@ -2266,7 +2233,7 @@ skipstate: if ((bp->bio_flags & BIO_ORDERED) != 0 || (softc->flags & DA_FLAG_NEED_OTAG) != 0) { softc->flags &= ~DA_FLAG_NEED_OTAG; - softc->ordered_tag_count++; + softc->flags |= DA_FLAG_WAS_OTAG; tag_code = MSG_ORDERED_Q_TAG; } else { tag_code = MSG_SIMPLE_Q_TAG; @@ -2316,15 +2283,11 @@ skipstate: break; } start_ccb->ccb_h.ccb_state = DA_CCB_BUFFER_IO; + start_ccb->ccb_h.flags |= CAM_UNLOCKED; out: - /* - * Block out any asynchronous callbacks - * while we touch the pending ccb list. - */ LIST_INSERT_HEAD(&softc->pending_ccbs, &start_ccb->ccb_h, periph_links.le); - softc->outstanding_cmds++; /* We expect a unit attention from this device */ if ((softc->flags & DA_FLAG_RETRY_UA) != 0) { @@ -2333,7 +2296,11 @@ out: } start_ccb->ccb_h.ccb_bp = bp; + softc->refcount++; + cam_periph_unlock(periph); xpt_action(start_ccb); + cam_periph_lock(periph); + softc->refcount--; /* May have more work to do, so ensure we stay scheduled */ daschedule(periph); @@ -2628,6 +2595,7 @@ da_delete_unmap(struct cam_periph *periph, union ccb *ccb, struct bio *bp) /*sense_len*/SSD_FULL_SIZE, da_default_timeout * 1000); ccb->ccb_h.ccb_state = DA_CCB_DELETE; + ccb->ccb_h.flags |= CAM_UNLOCKED; } static void @@ -2708,6 +2676,7 @@ da_delete_trim(struct cam_periph *periph, union ccb *ccb, struct bio *bp) /*sense_len*/SSD_FULL_SIZE, da_default_timeout * 1000); ccb->ccb_h.ccb_state = DA_CCB_DELETE; + ccb->ccb_h.flags |= CAM_UNLOCKED; } /* @@ -2764,6 +2733,7 @@ da_delete_ws(struct cam_periph *periph, union ccb *ccb, struct bio *bp) /*sense_len*/SSD_FULL_SIZE, da_default_timeout * 1000); ccb->ccb_h.ccb_state = DA_CCB_DELETE; + ccb->ccb_h.flags |= CAM_UNLOCKED; } static int @@ -2898,6 +2868,7 @@ dadone(struct cam_periph *periph, union ccb *done_ccb) { struct bio *bp, *bp1; + cam_periph_lock(periph); bp = (struct bio *)done_ccb->ccb_h.ccb_bp; if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { int error; @@ -2914,6 +2885,7 @@ dadone(struct cam_periph *periph, union ccb *done_ccb) * A retry was scheduled, so * just return. */ + cam_periph_unlock(periph); return; } bp = (struct bio *)done_ccb->ccb_h.ccb_bp; @@ -2981,18 +2953,22 @@ dadone(struct cam_periph *periph, union ccb *done_ccb) } } - /* - * Block out any asynchronous callbacks - * while we touch the pending ccb list. - */ LIST_REMOVE(&done_ccb->ccb_h, periph_links.le); - softc->outstanding_cmds--; - if (softc->outstanding_cmds == 0) - softc->flags |= DA_FLAG_WENT_IDLE; + if (LIST_EMPTY(&softc->pending_ccbs)) + softc->flags |= DA_FLAG_WAS_OTAG; + xpt_release_ccb(done_ccb); if (state == DA_CCB_DELETE) { - while ((bp1 = bioq_takefirst(&softc->delete_run_queue)) - != NULL) { + TAILQ_HEAD(, bio) queue; + + TAILQ_INIT(&queue); + TAILQ_CONCAT(&queue, &softc->delete_run_queue.queue, bio_queue); + softc->delete_run_queue.insert_point = NULL; + softc->delete_running = 0; + daschedule(periph); + cam_periph_unlock(periph); + while ((bp1 = TAILQ_FIRST(&queue)) != NULL) { + TAILQ_REMOVE(&queue, bp1, bio_queue); bp1->bio_error = bp->bio_error; if (bp->bio_flags & BIO_ERROR) { bp1->bio_flags |= BIO_ERROR; @@ -3001,13 +2977,11 @@ dadone(struct cam_periph *periph, union ccb *done_ccb) bp1->bio_resid = 0; biodone(bp1); } - softc->delete_running = 0; - if (bp != NULL) - biodone(bp); - daschedule(periph); - } else if (bp != NULL) + } else + cam_periph_unlock(periph); + if (bp != NULL) biodone(bp); - break; + return; } case DA_CCB_PROBE_RC: case DA_CCB_PROBE_RC16: @@ -3457,12 +3431,6 @@ dadone(struct cam_periph *periph, union ccb *done_ccb) daprobedone(periph, done_ccb); return; } - case DA_CCB_WAITING: - { - /* Caller will release the CCB */ - wakeup(&done_ccb->ccb_h.cbfcnp); - return; - } case DA_CCB_DUMP: /* No-op. We're polling */ return; @@ -3573,7 +3541,7 @@ damediapoll(void *arg) struct cam_periph *periph = arg; struct da_softc *softc = periph->softc; - if (!softc->tur && softc->outstanding_cmds == 0) { + if (!softc->tur && LIST_EMPTY(&softc->pending_ccbs)) { if (cam_periph_acquire(periph) == CAM_REQ_CMP) { softc->tur = 1; daschedule(periph); @@ -3745,14 +3713,11 @@ dasendorderedtag(void *arg) struct da_softc *softc = arg; if (da_send_ordered) { - if ((softc->ordered_tag_count == 0) - && ((softc->flags & DA_FLAG_WENT_IDLE) == 0)) { - softc->flags |= DA_FLAG_NEED_OTAG; + if (!LIST_EMPTY(&softc->pending_ccbs)) { + if ((softc->flags & DA_FLAG_WAS_OTAG) == 0) + softc->flags |= DA_FLAG_NEED_OTAG; + softc->flags &= ~DA_FLAG_WAS_OTAG; } - if (softc->outstanding_cmds > 0) - softc->flags &= ~DA_FLAG_WENT_IDLE; - - softc->ordered_tag_count = 0; } /* Queue us up again */ callout_reset(&softc->sendordered_c, |