svn commit: r216978 - in projects/graid/head/sys: cam/ata conf
Warner Losh
imp at FreeBSD.org
Tue Jan 4 22:44:11 UTC 2011
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
More information about the svn-src-projects
mailing list