diff options
Diffstat (limited to 'sys/cam/scsi/scsi_da.c')
-rw-r--r-- | sys/cam/scsi/scsi_da.c | 305 |
1 files changed, 222 insertions, 83 deletions
diff --git a/sys/cam/scsi/scsi_da.c b/sys/cam/scsi/scsi_da.c index 07a6435..d97e99d 100644 --- a/sys/cam/scsi/scsi_da.c +++ b/sys/cam/scsi/scsi_da.c @@ -60,6 +60,7 @@ __FBSDID("$FreeBSD$"); #include <cam/cam_periph.h> #include <cam/cam_xpt_periph.h> #include <cam/cam_sim.h> +#include <cam/cam_iosched.h> #include <cam/scsi/scsi_message.h> @@ -199,21 +200,19 @@ struct disk_params { #define ATA_TRIM_MAX_RANGES ((UNMAP_BUF_SIZE / \ (ATA_DSM_RANGE_SIZE * ATA_DSM_BLK_SIZE)) * ATA_DSM_BLK_SIZE) +#define DA_WORK_TUR (1 << 16) + struct da_softc { - struct bio_queue_head bio_queue; - struct bio_queue_head delete_queue; + struct cam_iosched_softc *cam_iosched; struct bio_queue_head delete_run_queue; 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 trim_max_ranges; - int delete_running; int delete_available; /* Delete methods possibly available */ u_int maxio; uint32_t unmap_max_ranges; @@ -222,6 +221,8 @@ struct da_softc { da_delete_methods delete_method_pref; da_delete_methods delete_method; da_delete_func_t *delete_func; + int unmappedio; + int rotating; struct disk_params params; struct disk *disk; union ccb saved_ccb; @@ -233,6 +234,13 @@ struct da_softc { uint8_t unmap_buf[UNMAP_BUF_SIZE]; struct scsi_read_capacity_data_long rcaplong; struct callout mediapoll_c; +#ifdef CAM_IO_STATS + struct sysctl_ctx_list sysctl_stats_ctx; + struct sysctl_oid *sysctl_stats_tree; + u_int errors; + u_int timeouts; + u_int invalidations; +#endif }; #define dadeleteflag(softc, delete_method, enable) \ @@ -1193,6 +1201,7 @@ static periph_init_t dainit; static void daasync(void *callback_arg, u_int32_t code, struct cam_path *path, void *arg); static void dasysctlinit(void *context, int pending); +static int dasysctlsofttimeout(SYSCTL_HANDLER_ARGS); static int dacmdsizesysctl(SYSCTL_HANDLER_ARGS); static int dadeletemethodsysctl(SYSCTL_HANDLER_ARGS); static int dadeletemaxsysctl(SYSCTL_HANDLER_ARGS); @@ -1230,6 +1239,10 @@ static timeout_t damediapoll; #define DA_DEFAULT_TIMEOUT 60 /* Timeout in seconds */ #endif +#ifndef DA_DEFAULT_SOFTTIMEOUT +#define DA_DEFAULT_SOFTTIMEOUT 0 +#endif + #ifndef DA_DEFAULT_RETRY #define DA_DEFAULT_RETRY 4 #endif @@ -1238,12 +1251,10 @@ static timeout_t damediapoll; #define DA_DEFAULT_SEND_ORDERED 1 #endif -#define DA_SIO (softc->sort_io_queue >= 0 ? \ - softc->sort_io_queue : cam_sort_io_queues) - static int da_poll_period = DA_DEFAULT_POLL_PERIOD; static int da_retry_count = DA_DEFAULT_RETRY; static int da_default_timeout = DA_DEFAULT_TIMEOUT; +static sbintime_t da_default_softtimeout = DA_DEFAULT_SOFTTIMEOUT; static int da_send_ordered = DA_DEFAULT_SEND_ORDERED; static SYSCTL_NODE(_kern_cam, OID_AUTO, da, CTLFLAG_RD, 0, @@ -1257,6 +1268,11 @@ SYSCTL_INT(_kern_cam_da, OID_AUTO, default_timeout, CTLFLAG_RWTUN, SYSCTL_INT(_kern_cam_da, OID_AUTO, send_ordered, CTLFLAG_RWTUN, &da_send_ordered, 0, "Send Ordered Tags"); +SYSCTL_PROC(_kern_cam_da, OID_AUTO, default_softtimeout, + CTLTYPE_UINT | CTLFLAG_RW, NULL, 0, dasysctlsofttimeout, "I", + "Soft I/O timeout (ms)"); +TUNABLE_INT64("kern.cam.da.default_softtimeout", &da_default_softtimeout); + /* * DA_ORDEREDTAG_INTERVAL determines how often, relative * to the default timeout, we check to see whether an ordered @@ -1400,12 +1416,7 @@ daschedule(struct cam_periph *periph) if (softc->state != DA_STATE_NORMAL) return; - /* Check if we have more work to do. */ - if (bioq_first(&softc->bio_queue) || - (!softc->delete_running && bioq_first(&softc->delete_queue)) || - softc->tur) { - xpt_schedule(periph, CAM_PRIORITY_NORMAL); - } + cam_iosched_schedule(softc->cam_iosched, periph); } /* @@ -1438,13 +1449,7 @@ dastrategy(struct bio *bp) /* * Place it in the queue of disk activities for this disk */ - if (bp->bio_cmd == BIO_DELETE) { - bioq_disksort(&softc->delete_queue, bp); - } else if (DA_SIO) { - bioq_disksort(&softc->bio_queue, bp); - } else { - bioq_insert_tail(&softc->bio_queue, bp); - } + cam_iosched_queue_work(softc->cam_iosched, bp); /* * Schedule ourselves for performing the work. @@ -1519,7 +1524,7 @@ dadump(void *arg, void *virtual, vm_offset_t physical, off_t offset, size_t leng /*begin_lba*/0,/* Cover the whole disk */ /*lb_count*/0, SSD_FULL_SIZE, - 5 * 60 * 1000); + 5 * 1000); xpt_polled_action((union ccb *)&csio); error = cam_periph_error((union ccb *)&csio, @@ -1599,14 +1604,16 @@ daoninvalidate(struct cam_periph *periph) xpt_register_async(0, daasync, periph, periph->path); softc->flags |= DA_FLAG_PACK_INVALID; +#ifdef CAM_IO_STATS + softc->invalidations++; +#endif /* * Return all queued I/O with ENXIO. * XXX Handle any transactions queued to the card * with XPT_ABORT_CCB. */ - bioq_flush(&softc->bio_queue, NULL, ENXIO); - bioq_flush(&softc->delete_queue, NULL, ENXIO); + cam_iosched_flush(softc->cam_iosched, NULL, ENXIO); /* * Tell GEOM that we've gone away, we'll get a callback when it is @@ -1624,12 +1631,20 @@ dacleanup(struct cam_periph *periph) cam_periph_unlock(periph); + cam_iosched_fini(softc->cam_iosched); + /* * If we can't free the sysctl tree, oh well... */ - if ((softc->flags & DA_FLAG_SCTX_INIT) != 0 - && sysctl_ctx_free(&softc->sysctl_ctx) != 0) { - xpt_print(periph->path, "can't remove sysctl context\n"); + if ((softc->flags & DA_FLAG_SCTX_INIT) != 0) { +#ifdef CAM_IO_STATS + if (sysctl_ctx_free(&softc->sysctl_stats_ctx) != 0) + xpt_print(periph->path, + "can't remove sysctl stats context\n"); +#endif + if (sysctl_ctx_free(&softc->sysctl_ctx) != 0) + xpt_print(periph->path, + "can't remove sysctl context\n"); } callout_drain(&softc->mediapoll_c); @@ -1732,9 +1747,9 @@ daasync(void *callback_arg, u_int32_t code, } case AC_SCSI_AEN: softc = (struct da_softc *)periph->softc; - if (!softc->tur) { + if (!cam_iosched_has_work_flags(softc->cam_iosched, DA_WORK_TUR)) { if (cam_periph_acquire(periph) == CAM_REQ_CMP) { - softc->tur = 1; + cam_iosched_set_work_flags(softc->cam_iosched, DA_WORK_TUR); daschedule(periph); } } @@ -1808,9 +1823,6 @@ dasysctlinit(void *context, int pending) OID_AUTO, "minimum_cmd_size", CTLTYPE_INT | CTLFLAG_RW, &softc->minimum_cmd_size, 0, dacmdsizesysctl, "I", "Minimum CDB size"); - SYSCTL_ADD_INT(&softc->sysctl_ctx, SYSCTL_CHILDREN(softc->sysctl_tree), - OID_AUTO, "sort_io_queue", CTLFLAG_RW, &softc->sort_io_queue, 0, - "Sort IO queue to try and optimise disk access patterns"); SYSCTL_ADD_INT(&softc->sysctl_ctx, SYSCTL_CHILDREN(softc->sysctl_tree), @@ -1821,6 +1833,23 @@ dasysctlinit(void *context, int pending) 0, "error_inject leaf"); + SYSCTL_ADD_INT(&softc->sysctl_ctx, + SYSCTL_CHILDREN(softc->sysctl_tree), + OID_AUTO, + "unmapped_io", + CTLFLAG_RD, + &softc->unmappedio, + 0, + "Unmapped I/O leaf"); + + SYSCTL_ADD_INT(&softc->sysctl_ctx, + SYSCTL_CHILDREN(softc->sysctl_tree), + OID_AUTO, + "rotating", + CTLFLAG_RD, + &softc->rotating, + 0, + "Rotating media"); /* * Add some addressing info. @@ -1846,6 +1875,44 @@ dasysctlinit(void *context, int pending) &softc->wwpn, "World Wide Port Name"); } } + +#ifdef CAM_IO_STATS + /* + * Now add some useful stats. + * XXX These should live in cam_periph and be common to all periphs + */ + softc->sysctl_stats_tree = SYSCTL_ADD_NODE(&softc->sysctl_stats_ctx, + SYSCTL_CHILDREN(softc->sysctl_tree), OID_AUTO, "stats", + CTLFLAG_RD, 0, "Statistics"); + SYSCTL_ADD_INT(&softc->sysctl_stats_ctx, + SYSCTL_CHILDREN(softc->sysctl_stats_tree), + OID_AUTO, + "errors", + CTLFLAG_RD, + &softc->errors, + 0, + "Transport errors reported by the SIM"); + SYSCTL_ADD_INT(&softc->sysctl_stats_ctx, + SYSCTL_CHILDREN(softc->sysctl_stats_tree), + OID_AUTO, + "timeouts", + CTLFLAG_RD, + &softc->timeouts, + 0, + "Device timeouts reported by the SIM"); + SYSCTL_ADD_INT(&softc->sysctl_stats_ctx, + SYSCTL_CHILDREN(softc->sysctl_stats_tree), + OID_AUTO, + "pack_invalidations", + CTLFLAG_RD, + &softc->invalidations, + 0, + "Device pack invalidations"); +#endif + + cam_iosched_sysctl_init(softc->cam_iosched, &softc->sysctl_ctx, + softc->sysctl_tree); + cam_periph_release(periph); } @@ -1904,6 +1971,26 @@ dacmdsizesysctl(SYSCTL_HANDLER_ARGS) return (0); } +static int +dasysctlsofttimeout(SYSCTL_HANDLER_ARGS) +{ + sbintime_t value; + int error; + + value = da_default_softtimeout / SBT_1MS; + + error = sysctl_handle_int(oidp, (int *)&value, 0, req); + if ((error != 0) || (req->newptr == NULL)) + return (error); + + /* XXX Should clip this to a reasonable level */ + if (value > da_default_timeout * 1000) + return (EINVAL); + + da_default_softtimeout = value * SBT_1MS; + return (0); +} + static void dadeletemethodset(struct da_softc *softc, da_delete_methods delete_method) { @@ -2075,14 +2162,18 @@ daregister(struct cam_periph *periph, void *arg) if (softc == NULL) { printf("daregister: Unable to probe new device. " - "Unable to allocate softc\n"); + "Unable to allocate softc\n"); return(CAM_REQ_CMP_ERR); } + if (cam_iosched_init(&softc->cam_iosched, periph) != 0) { + printf("daregister: Unable to probe new device. " + "Unable to allocate iosched memory\n"); + return(CAM_REQ_CMP_ERR); + } + LIST_INIT(&softc->pending_ccbs); softc->state = DA_STATE_PROBE_RC; - bioq_init(&softc->bio_queue); - bioq_init(&softc->delete_queue); bioq_init(&softc->delete_run_queue); if (SID_IS_REMOVABLE(&cgd->inq_data)) softc->flags |= DA_FLAG_PACK_REMOVABLE; @@ -2090,7 +2181,7 @@ daregister(struct cam_periph *periph, void *arg) softc->unmap_max_lba = UNMAP_RANGE_MAX; softc->ws_max_blks = WS16_MAX_BLKS; softc->trim_max_ranges = ATA_TRIM_MAX_RANGES; - softc->sort_io_queue = -1; + softc->rotating = 1; periph->softc = softc; @@ -2199,8 +2290,11 @@ daregister(struct cam_periph *periph, void *arg) softc->disk->d_flags = DISKFLAG_DIRECT_COMPLETION; if ((softc->quirks & DA_Q_NO_SYNC_CACHE) == 0) softc->disk->d_flags |= DISKFLAG_CANFLUSHCACHE; - if ((cpi.hba_misc & PIM_UNMAPPED) != 0) + if ((cpi.hba_misc & PIM_UNMAPPED) != 0) { + softc->unmappedio = 1; softc->disk->d_flags |= DISKFLAG_UNMAPPED_BIO; + xpt_print(periph->path, "UNMAPPED\n"); + } cam_strvis(softc->disk->d_descr, cgd->inq_data.vendor, sizeof(cgd->inq_data.vendor), sizeof(softc->disk->d_descr)); strlcat(softc->disk->d_descr, " ", sizeof(softc->disk->d_descr)); @@ -2277,23 +2371,11 @@ skipstate: struct bio *bp; uint8_t tag_code; - /* Run BIO_DELETE if not running yet. */ - if (!softc->delete_running && - (bp = bioq_first(&softc->delete_queue)) != NULL) { - if (softc->delete_func != NULL) { - softc->delete_func(periph, start_ccb, bp); - goto out; - } else { - bioq_flush(&softc->delete_queue, NULL, 0); - /* FALLTHROUGH */ - } - } - - /* Run regular command. */ - bp = bioq_takefirst(&softc->bio_queue); +more: + bp = cam_iosched_next_bio(softc->cam_iosched); if (bp == NULL) { - if (softc->tur) { - softc->tur = 0; + if (cam_iosched_has_work_flags(softc->cam_iosched, DA_WORK_TUR)) { + cam_iosched_clr_work_flags(softc->cam_iosched, DA_WORK_TUR); scsi_test_unit_ready(&start_ccb->csio, /*retries*/ da_retry_count, dadone, @@ -2307,9 +2389,21 @@ skipstate: xpt_release_ccb(start_ccb); break; } - if (softc->tur) { - softc->tur = 0; - cam_periph_release_locked(periph); + + if (bp->bio_cmd == BIO_DELETE) { + if (softc->delete_func != NULL) { + softc->delete_func(periph, start_ccb, bp); + goto out; + } else { + /* Not sure this is possible, but failsafe by lying and saying "sure, done." */ + biofinish(bp, NULL, 0); + goto more; + } + } + + if (cam_iosched_has_work_flags(softc->cam_iosched, DA_WORK_TUR)) { + cam_iosched_clr_work_flags(softc->cam_iosched, DA_WORK_TUR); + cam_periph_release_locked(periph); /* XXX is this still valid? I think so but unverified */ } if ((bp->bio_flags & BIO_ORDERED) != 0 || @@ -2377,6 +2471,7 @@ skipstate: } start_ccb->ccb_h.ccb_state = DA_CCB_BUFFER_IO; start_ccb->ccb_h.flags |= CAM_UNLOCKED; + start_ccb->ccb_h.softtimeout = sbttotv(da_default_softtimeout); out: LIST_INSERT_HEAD(&softc->pending_ccbs, @@ -2625,11 +2720,19 @@ da_delete_unmap(struct cam_periph *periph, union ccb *ccb, struct bio *bp) * fewer LBA's than requested. */ - softc->delete_running = 1; bzero(softc->unmap_buf, sizeof(softc->unmap_buf)); bp1 = bp; do { - bioq_remove(&softc->delete_queue, bp1); + /* + * Note: ada and da are different in how they store the + * pending bp's in a trim. ada stores all of them in the + * trim_req.bps. da stores all but the first one in the + * delete_run_queue. ada then completes all the bps in + * its adadone() loop. da completes all the bps in the + * delete_run_queue in dadone, and relies on the biodone + * after to complete. This should be reconciled since there's + * no real reason to do it differently. XXX + */ if (bp1 != bp) bioq_insert_tail(&softc->delete_run_queue, bp1); lba = bp1->bio_pblkno; @@ -2669,11 +2772,15 @@ da_delete_unmap(struct cam_periph *periph, union ccb *ccb, struct bio *bp) lastcount = c; } lastlba = lba; - bp1 = bioq_first(&softc->delete_queue); - if (bp1 == NULL || ranges >= softc->unmap_max_ranges || + bp1 = cam_iosched_next_trim(softc->cam_iosched); + if (bp1 == NULL) + break; + if (ranges >= softc->unmap_max_ranges || totalcount + bp1->bio_bcount / - softc->params.secsize > softc->unmap_max_lba) + softc->params.secsize > softc->unmap_max_lba) { + cam_iosched_put_back_trim(softc->cam_iosched, bp1); break; + } } while (1); scsi_ulto2b(ranges * 16 + 6, &buf[0]); scsi_ulto2b(ranges * 16, &buf[2]); @@ -2689,6 +2796,7 @@ da_delete_unmap(struct cam_periph *periph, union ccb *ccb, struct bio *bp) da_default_timeout * 1000); ccb->ccb_h.ccb_state = DA_CCB_DELETE; ccb->ccb_h.flags |= CAM_UNLOCKED; + cam_iosched_submit_trim(softc->cam_iosched); } static void @@ -2703,12 +2811,10 @@ da_delete_trim(struct cam_periph *periph, union ccb *ccb, struct bio *bp) uint32_t lastcount = 0, c, requestcount; int ranges = 0, off, block_count; - softc->delete_running = 1; bzero(softc->unmap_buf, sizeof(softc->unmap_buf)); bp1 = bp; do { - bioq_remove(&softc->delete_queue, bp1); - if (bp1 != bp) + if (bp1 != bp)//XXX imp XXX bioq_insert_tail(&softc->delete_run_queue, bp1); lba = bp1->bio_pblkno; count = bp1->bio_bcount / softc->params.secsize; @@ -2752,10 +2858,14 @@ da_delete_trim(struct cam_periph *periph, union ccb *ccb, struct bio *bp) } } lastlba = lba; - bp1 = bioq_first(&softc->delete_queue); - if (bp1 == NULL || bp1->bio_bcount / softc->params.secsize > - (softc->trim_max_ranges - ranges) * ATA_DSM_RANGE_MAX) + bp1 = cam_iosched_next_trim(softc->cam_iosched); + if (bp1 == NULL) + break; + if (bp1->bio_bcount / softc->params.secsize > + (softc->trim_max_ranges - ranges) * ATA_DSM_RANGE_MAX) { + cam_iosched_put_back_trim(softc->cam_iosched, bp1); break; + } } while (1); block_count = (ranges + ATA_DSM_BLK_RANGES - 1) / ATA_DSM_BLK_RANGES; @@ -2770,6 +2880,7 @@ da_delete_trim(struct cam_periph *periph, union ccb *ccb, struct bio *bp) da_default_timeout * 1000); ccb->ccb_h.ccb_state = DA_CCB_DELETE; ccb->ccb_h.flags |= CAM_UNLOCKED; + cam_iosched_submit_trim(softc->cam_iosched); } /* @@ -2788,13 +2899,11 @@ da_delete_ws(struct cam_periph *periph, union ccb *ccb, struct bio *bp) softc = (struct da_softc *)periph->softc; ws_max_blks = softc->disk->d_delmaxsize / softc->params.secsize; - softc->delete_running = 1; lba = bp->bio_pblkno; count = 0; bp1 = bp; do { - bioq_remove(&softc->delete_queue, bp1); - if (bp1 != bp) + if (bp1 != bp)//XXX imp XXX bioq_insert_tail(&softc->delete_run_queue, bp1); count += bp1->bio_bcount / softc->params.secsize; if (count > ws_max_blks) { @@ -2805,11 +2914,15 @@ da_delete_ws(struct cam_periph *periph, union ccb *ccb, struct bio *bp) count = omin(count, ws_max_blks); break; } - bp1 = bioq_first(&softc->delete_queue); - if (bp1 == NULL || lba + count != bp1->bio_pblkno || + bp1 = cam_iosched_next_trim(softc->cam_iosched); + if (bp1 == NULL) + break; + if (lba + count != bp1->bio_pblkno || count + bp1->bio_bcount / - softc->params.secsize > ws_max_blks) + softc->params.secsize > ws_max_blks) { + cam_iosched_put_back_trim(softc->cam_iosched, bp1); break; + } } while (1); scsi_write_same(&ccb->csio, @@ -2827,6 +2940,7 @@ da_delete_ws(struct cam_periph *periph, union ccb *ccb, struct bio *bp) da_default_timeout * 1000); ccb->ccb_h.ccb_state = DA_CCB_DELETE; ccb->ccb_h.flags |= CAM_UNLOCKED; + cam_iosched_submit_trim(softc->cam_iosched); } static int @@ -2870,8 +2984,8 @@ cmd6workaround(union ccb *ccb) da_delete_method_desc[softc->delete_method]); while ((bp = bioq_takefirst(&softc->delete_run_queue)) != NULL) - bioq_disksort(&softc->delete_queue, bp); - bioq_disksort(&softc->delete_queue, + cam_iosched_queue_work(softc->cam_iosched, bp); + cam_iosched_queue_work(softc->cam_iosched, (struct bio *)ccb->ccb_h.ccb_bp); ccb->ccb_h.ccb_bp = NULL; return (0); @@ -2998,9 +3112,12 @@ dadone(struct cam_periph *periph, union ccb *done_ccb) xpt_print(periph->path, "Invalidating pack\n"); softc->flags |= DA_FLAG_PACK_INVALID; +#ifdef CAM_IO_STATS + softc->invalidations++; +#endif queued_error = ENXIO; } - bioq_flush(&softc->bio_queue, NULL, + cam_iosched_flush(softc->cam_iosched, NULL, queued_error); if (bp != NULL) { bp->bio_error = error; @@ -3043,6 +3160,7 @@ dadone(struct cam_periph *periph, union ccb *done_ccb) if (LIST_EMPTY(&softc->pending_ccbs)) softc->flags |= DA_FLAG_WAS_OTAG; + cam_iosched_bio_complete(softc->cam_iosched, bp, done_ccb); xpt_release_ccb(done_ccb); if (state == DA_CCB_DELETE) { TAILQ_HEAD(, bio) queue; @@ -3060,7 +3178,7 @@ dadone(struct cam_periph *periph, union ccb *done_ccb) * and call daschedule again so that we don't stall if * there are no other I/Os pending apart from BIO_DELETEs. */ - softc->delete_running = 0; + cam_iosched_trim_done(softc->cam_iosched); daschedule(periph); cam_periph_unlock(periph); while ((bp1 = TAILQ_FIRST(&queue)) != NULL) { @@ -3073,8 +3191,10 @@ dadone(struct cam_periph *periph, union ccb *done_ccb) bp1->bio_resid = 0; biodone(bp1); } - } else + } else { + daschedule(periph); cam_periph_unlock(periph); + } if (bp != NULL) biodone(bp); return; @@ -3459,7 +3579,8 @@ dadone(struct cam_periph *periph, union ccb *done_ccb) scsi_2btoul(bdc->medium_rotation_rate); if (softc->disk->d_rotation_rate == SVPD_BDC_RATE_NON_ROTATING) { - softc->sort_io_queue = 0; + cam_iosched_set_sort_queue(softc->cam_iosched, 0); + softc->rotating = 0; } if (softc->disk->d_rotation_rate != old_rate) { disk_attr_changed(softc->disk, @@ -3521,9 +3642,9 @@ dadone(struct cam_periph *periph, union ccb *done_ccb) ata_params->media_rotation_rate; if (softc->disk->d_rotation_rate == ATA_RATE_NON_ROTATING) { - softc->sort_io_queue = 0; + cam_iosched_set_sort_queue(softc->cam_iosched, 0); + softc->rotating = 0; } - if (softc->disk->d_rotation_rate != old_rate) { disk_attr_changed(softc->disk, "GEOM::rotation_rate", M_NOWAIT); @@ -3652,6 +3773,23 @@ daerror(union ccb *ccb, u_int32_t cam_flags, u_int32_t sense_flags) if (error == ERESTART) return (ERESTART); +#ifdef CAM_IO_STATS + switch (ccb->ccb_h.status & CAM_STATUS_MASK) { + case CAM_CMD_TIMEOUT: + softc->timeouts++; + break; + case CAM_REQ_ABORTED: + case CAM_REQ_CMP_ERR: + case CAM_REQ_TERMIO: + case CAM_UNREC_HBA_ERROR: + case CAM_DATA_RUN_ERR: + softc->errors++; + break; + default: + break; + } +#endif + /* * XXX * Until we have a better way of doing pack validation, @@ -3671,9 +3809,10 @@ damediapoll(void *arg) struct cam_periph *periph = arg; struct da_softc *softc = periph->softc; - if (!softc->tur && LIST_EMPTY(&softc->pending_ccbs)) { + if (!cam_iosched_has_work_flags(softc->cam_iosched, DA_WORK_TUR) && + LIST_EMPTY(&softc->pending_ccbs)) { if (cam_periph_acquire(periph) == CAM_REQ_CMP) { - softc->tur = 1; + cam_iosched_set_work_flags(softc->cam_iosched, DA_WORK_TUR); daschedule(periph); } } |