Date: Tue, 4 Jan 2011 22:44:11 +0000 (UTC) From: Warner Losh <imp@FreeBSD.org> To: src-committers@freebsd.org, svn-src-projects@freebsd.org Subject: svn commit: r216978 - in projects/graid/head/sys: cam/ata conf Message-ID: <201101042244.p04MiBf6057193@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: imp Date: Tue Jan 4 22:44:10 2011 New Revision: 216978 URL: http://svn.freebsd.org/changeset/base/216978 Log: Implement three types of forced errors in the ada layer for the purpose of testing uppper layers in the stack. kern.cam.ada.X.periodic_read_error specifies that every Nth read will fail. kern.cam.ada.X.force_read_error specifies that the next N reads will fail. kern.cam.ada.X.force_write_error specifies that the next N writes will fail. These are enabled with 'options ADA_TEST_FAILURE'. Otherwise, they aren't added to the kernel. Also, the sysctl stuff is only used for this feature, so move it under this option ifdef. Modified: projects/graid/head/sys/cam/ata/ata_da.c projects/graid/head/sys/conf/options Modified: projects/graid/head/sys/cam/ata/ata_da.c ============================================================================== --- projects/graid/head/sys/cam/ata/ata_da.c Tue Jan 4 20:51:28 2011 (r216977) +++ projects/graid/head/sys/cam/ata/ata_da.c Tue Jan 4 22:44:10 2011 (r216978) @@ -27,6 +27,8 @@ #include <sys/cdefs.h> __FBSDID("$FreeBSD$"); +#include "opt_ada.h" + #include <sys/param.h> #ifdef _KERNEL @@ -125,11 +127,19 @@ struct ada_softc { int outstanding_cmds; int trim_max_ranges; int trim_running; +#ifdef ADA_TEST_FAILURE + int force_read_error; + int force_write_error; + int periodic_read_error; + int periodic_read_count; +#endif struct disk_params params; struct disk *disk; struct task sysctl_task; +#ifdef ADA_TEST_FAILURE struct sysctl_ctx_list sysctl_ctx; struct sysctl_oid *sysctl_tree; +#endif struct callout sendordered_c; struct trim_request trim_req; }; @@ -156,7 +166,12 @@ static dumper_t adadump; static periph_init_t adainit; static void adaasync(void *callback_arg, u_int32_t code, struct cam_path *path, void *arg); +#ifdef ADA_TEST_FAILURE static void adasysctlinit(void *context, int pending); +static int adaforcereaderrsysctl(SYSCTL_HANDLER_ARGS); +static int adaforcewriteerrsysctl(SYSCTL_HANDLER_ARGS); +static int adaperiodicreaderrsysctl(SYSCTL_HANDLER_ARGS); +#endif static periph_ctor_t adaregister; static periph_dtor_t adacleanup; static periph_start_t adastart; @@ -549,6 +564,7 @@ adacleanup(struct cam_periph *periph) xpt_print(periph->path, "removing device entry\n"); cam_periph_unlock(periph); +#ifdef ADA_TEST_FAILURE /* * If we can't free the sysctl tree, oh well... */ @@ -556,6 +572,7 @@ adacleanup(struct cam_periph *periph) && sysctl_ctx_free(&softc->sysctl_ctx) != 0) { xpt_print(periph->path, "can't remove sysctl context\n"); } +#endif disk_destroy(softc->disk); callout_drain(&softc->sendordered_c); @@ -606,6 +623,7 @@ adaasync(void *callback_arg, u_int32_t c } } +#ifdef ADA_TEST_FAILURE static void adasysctlinit(void *context, int pending) { @@ -632,9 +650,66 @@ adasysctlinit(void *context, int pending return; } + /* + * Add a 'door bell' sysctl which allows one to set it from userland + * and cause something bad to happen. For the moment, we only allow + * whacking the next read or write. + */ + SYSCTL_ADD_PROC(&softc->sysctl_ctx, SYSCTL_CHILDREN(softc->sysctl_tree), + OID_AUTO, "force_read_error", CTLTYPE_INT | CTLFLAG_RW, + &softc->force_read_error, 0, adaforcereaderrsysctl, "I", + "Force a read error for the next N reads."); + SYSCTL_ADD_PROC(&softc->sysctl_ctx, SYSCTL_CHILDREN(softc->sysctl_tree), + OID_AUTO, "force_write_error", CTLTYPE_INT | CTLFLAG_RW, + &softc->force_write_error, 0, adaforcewriteerrsysctl, "I", + "Force a write error for the next N writes."); + SYSCTL_ADD_PROC(&softc->sysctl_ctx, SYSCTL_CHILDREN(softc->sysctl_tree), + OID_AUTO, "periodic_read_error", CTLTYPE_INT | CTLFLAG_RW, + &softc->periodic_read_error, 0, adaperiodicreaderrsysctl, "I", + "Force a read error every N reads (don't set too low)."); cam_periph_release(periph); } +static int +adaforcereaderrsysctl(SYSCTL_HANDLER_ARGS) +{ + int error, value; + + value = *(int *)arg1; + error = sysctl_handle_int(oidp, &value, 0, req); + if (error != 0 || req->newptr == NULL) + return (error); + *(int *)arg1 = value; + return (0); +} + +static int +adaforcewriteerrsysctl(SYSCTL_HANDLER_ARGS) +{ + int error, value; + + value = *(int *)arg1; + error = sysctl_handle_int(oidp, &value, 0, req); + if (error != 0 || req->newptr == NULL) + return (error); + *(int *)arg1 = value; + return (0); +} + +static int +adaperiodicreaderrsysctl(SYSCTL_HANDLER_ARGS) +{ + int error, value; + + value = *(int *)arg1; + error = sysctl_handle_int(oidp, &value, 0, req); + if (error != 0 || req->newptr == NULL) + return (error); + *(int *)arg1 = value; + return (0); +} +#endif + static cam_status adaregister(struct cam_periph *periph, void *arg) { @@ -712,7 +787,9 @@ adaregister(struct cam_periph *periph, v cpi.ccb_h.func_code = XPT_PATH_INQ; xpt_action((union ccb *)&cpi); +#ifdef ADA_TEST_FAILURE TASK_INIT(&softc->sysctl_task, 0, adasysctlinit, periph); +#endif /* * Register this media as a disk @@ -779,6 +856,12 @@ adaregister(struct cam_periph *periph, v dp->secs_per_track, dp->cylinders); xpt_announce_periph(periph, announce_buf); /* + * Create our sysctl variables, now that we know + * we have successfully attached. + * XXX: da code does a cam_periph_acquire(periph) here -- why?. + */ + taskqueue_enqueue(taskqueue_thread, &softc->sysctl_task); + /* * Add async callbacks for bus reset and * bus device reset calls. I don't bother * checking if this fails as, in most cases, @@ -900,7 +983,45 @@ adastart(struct cam_periph *periph, unio { uint64_t lba = bp->bio_pblkno; uint16_t count = bp->bio_bcount / softc->params.secsize; +#ifdef ADA_TEST_FAILURE + int fail = 0; + /* + * Support the failure ioctls. If the command is a + * read, and there are pending forced read errors, or + * if a write and pending write errors, then fail this + * operation with EIO. This is useful for testing + * purposes. Also, support having every Nth read fail. + * + * This is a rather blunt tool. + */ + if (bp->bio_cmd == BIO_READ) { + if (softc->force_read_error) { + softc->force_read_error--; + fail = 1; + } + if (softc->periodic_read_error > 0) { + if (++softc->periodic_read_count >= + softc->periodic_read_error) { + softc->periodic_read_count = 0; + fail = 1; + } + } + } else { + if (softc->force_write_error) { + softc->force_write_error--; + fail = 1; + } + } + if (fail) { + bp->bio_error = EIO; + bp->bio_flags |= BIO_ERROR; + biodone(bp); + xpt_release_ccb(start_ccb); + adaschedule(periph); + return; + } +#endif cam_fill_ataio(ataio, ada_retry_count, adadone, Modified: projects/graid/head/sys/conf/options ============================================================================== --- projects/graid/head/sys/conf/options Tue Jan 4 20:51:28 2011 (r216977) +++ projects/graid/head/sys/conf/options Tue Jan 4 22:44:10 2011 (r216978) @@ -306,6 +306,9 @@ SCSI_DELAY opt_scsi.h SCSI_NO_SENSE_STRINGS opt_scsi.h SCSI_NO_OP_STRINGS opt_scsi.h +# Options used only in cam/ata/ata_da.c +ADA_TEST_FAILURE opt_ada.h + # Options used only in cam/scsi/scsi_cd.c CHANGER_MIN_BUSY_SECONDS opt_cd.h CHANGER_MAX_BUSY_SECONDS opt_cd.h
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201101042244.p04MiBf6057193>