summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorTed Unangst <tedu@cvs.openbsd.org>2007-11-27 17:21:53 +0000
committerTed Unangst <tedu@cvs.openbsd.org>2007-11-27 17:21:53 +0000
commit336a74325b737793f3dcbbf25488657fbabcec2e (patch)
treee1c7ccd7b233d383519df3cb8ef835b5d14f68ed /sys
parentb8a0b44a0a7580978824d793ef83bc0c2ff22267 (diff)
also move softraid raid1 into own file, ok marco
Diffstat (limited to 'sys')
-rw-r--r--sys/conf/files5
-rw-r--r--sys/dev/softraid.c382
-rw-r--r--sys/dev/softraid_raid1.c418
-rw-r--r--sys/dev/softraidvar.h9
4 files changed, 430 insertions, 384 deletions
diff --git a/sys/conf/files b/sys/conf/files
index fd3639a397c..36a01970701 100644
--- a/sys/conf/files
+++ b/sys/conf/files
@@ -1,4 +1,4 @@
-# $OpenBSD: files,v 1.419 2007/11/27 16:37:05 tedu Exp $
+# $OpenBSD: files,v 1.420 2007/11/27 17:21:52 tedu Exp $
# $NetBSD: files,v 1.87 1996/05/19 17:17:50 jonathan Exp $
# @(#)files.newconf 7.5 (Berkeley) 5/10/93
@@ -438,7 +438,8 @@ file dev/ipmi.c ipmi needs-flag
device softraid: scsi
attach softraid at root
file dev/softraid.c softraid needs-flag
-file dev/softraid_crypto.c softraid & crypto
+file dev/softraid_raid1.c softraid
+file dev/softraid_crypto.c softraid & crypto
# legitimate pseudo-devices
pseudo-device vnd: disk
diff --git a/sys/dev/softraid.c b/sys/dev/softraid.c
index 14d76d1fc34..ddfef49b72b 100644
--- a/sys/dev/softraid.c
+++ b/sys/dev/softraid.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: softraid.c,v 1.88 2007/11/27 16:37:05 tedu Exp $ */
+/* $OpenBSD: softraid.c,v 1.89 2007/11/27 17:21:52 tedu Exp $ */
/*
* Copyright (c) 2007 Marco Peereboom <marco@peereboom.us>
*
@@ -100,12 +100,6 @@ void sr_unwind_chunks(struct sr_softc *,
void sr_free_discipline(struct sr_discipline *);
void sr_shutdown_discipline(struct sr_discipline *);
-int sr_raid1_alloc_resources(struct sr_discipline *);
-int sr_raid1_free_resources(struct sr_discipline *);
-int sr_raid1_rw(struct sr_workunit *);
-void sr_raid1_intr(struct buf *);
-void sr_raid1_recreate_wu(struct sr_workunit *);
-
/* utility functions */
void sr_shutdown(void *);
void sr_get_uuid(struct sr_uuid *);
@@ -2478,377 +2472,3 @@ sr_print_metadata(struct sr_metadata *sm)
}
}
#endif /* SR_DEBUG */
-
-/* RAID 1 functions */
-int
-sr_raid1_alloc_resources(struct sr_discipline *sd)
-{
- int rv = EINVAL;
-
- if (!sd)
- return (rv);
-
- DNPRINTF(SR_D_DIS, "%s: sr_raid1_alloc_resources\n",
- DEVNAME(sd->sd_sc));
-
- if (sr_alloc_wu(sd))
- goto bad;
- if (sr_alloc_ccb(sd))
- goto bad;
-
- rv = 0;
-bad:
- return (rv);
-}
-
-int
-sr_raid1_free_resources(struct sr_discipline *sd)
-{
- int rv = EINVAL;
-
- if (!sd)
- return (rv);
-
- DNPRINTF(SR_D_DIS, "%s: sr_raid1_free_resources\n",
- DEVNAME(sd->sd_sc));
-
- sr_free_wu(sd);
- sr_free_ccb(sd);
-
- if (sd->sd_meta)
- free(sd->sd_meta, M_DEVBUF);
-
- rv = 0;
- return (rv);
-}
-
-int
-sr_raid1_rw(struct sr_workunit *wu)
-{
- struct sr_discipline *sd = wu->swu_dis;
- struct scsi_xfer *xs = wu->swu_xs;
- struct sr_workunit *wup;
- struct sr_ccb *ccb;
- struct sr_chunk *scp;
- int ios, x, i, s, rt;
- daddr64_t blk;
-
- DNPRINTF(SR_D_DIS, "%s: sr_raid1_rw 0x%02x\n", DEVNAME(sd->sd_sc),
- xs->cmd->opcode);
-
- if (sd->sd_vol.sv_meta.svm_status == BIOC_SVOFFLINE) {
- DNPRINTF(SR_D_DIS, "%s: sr_raid1_rw device offline\n",
- DEVNAME(sd->sd_sc));
- goto bad;
- }
-
- if (xs->datalen == 0) {
- printf("%s: %s: illegal block count\n",
- DEVNAME(sd->sd_sc), sd->sd_vol.sv_meta.svm_devname);
- goto bad;
- }
-
- if (xs->cmdlen == 10)
- blk = _4btol(((struct scsi_rw_big *)xs->cmd)->addr);
- else if (xs->cmdlen == 6)
- blk = _3btol(((struct scsi_rw *)xs->cmd)->addr);
- else {
- printf("%s: %s: illegal cmdlen\n", DEVNAME(sd->sd_sc),
- sd->sd_vol.sv_meta.svm_devname);
- goto bad;
- }
-
- wu->swu_blk_start = blk;
- wu->swu_blk_end = blk + (xs->datalen >> 9) - 1;
-
- if (wu->swu_blk_end > sd->sd_vol.sv_meta.svm_size) {
- DNPRINTF(SR_D_DIS, "%s: sr_raid1_rw out of bounds start: %lld "
- "end: %lld length: %d\n", wu->swu_blk_start,
- wu->swu_blk_end, xs->datalen);
-
- sd->sd_scsi_sense.error_code = SSD_ERRCODE_CURRENT |
- SSD_ERRCODE_VALID;
- sd->sd_scsi_sense.flags = SKEY_ILLEGAL_REQUEST;
- sd->sd_scsi_sense.add_sense_code = 0x21;
- sd->sd_scsi_sense.add_sense_code_qual = 0x00;
- sd->sd_scsi_sense.extra_len = 4;
- goto bad;
- }
-
- /* calculate physical block */
- blk += SR_META_SIZE + SR_META_OFFSET;
-
- if (xs->flags & SCSI_DATA_IN)
- ios = 1;
- else
- ios = sd->sd_vol.sv_meta.svm_no_chunk;
- wu->swu_io_count = ios;
-
- for (i = 0; i < ios; i++) {
- ccb = sr_get_ccb(sd);
- if (!ccb) {
- /* should never happen but handle more gracefully */
- printf("%s: %s: too many ccbs queued\n",
- DEVNAME(sd->sd_sc),
- sd->sd_vol.sv_meta.svm_devname);
- goto bad;
- }
-
- if (xs->flags & SCSI_POLL) {
- ccb->ccb_buf.b_flags = 0;
- ccb->ccb_buf.b_iodone = NULL;
- } else {
- ccb->ccb_buf.b_flags = B_CALL;
- ccb->ccb_buf.b_iodone = sr_raid1_intr;
- }
-
- ccb->ccb_buf.b_blkno = blk;
- ccb->ccb_buf.b_bcount = xs->datalen;
- ccb->ccb_buf.b_bufsize = xs->datalen;
- ccb->ccb_buf.b_resid = xs->datalen;
- ccb->ccb_buf.b_data = xs->data;
- ccb->ccb_buf.b_error = 0;
- ccb->ccb_buf.b_proc = curproc;
- ccb->ccb_wu = wu;
-
- if (xs->flags & SCSI_DATA_IN) {
- rt = 0;
-ragain:
- /* interleave reads */
- x = sd->mds.mdd_raid1.sr1_counter++ %
- sd->sd_vol.sv_meta.svm_no_chunk;
- scp = sd->sd_vol.sv_chunks[x];
- switch (scp->src_meta.scm_status) {
- case BIOC_SDONLINE:
- case BIOC_SDSCRUB:
- ccb->ccb_buf.b_flags |= B_READ;
- break;
-
- case BIOC_SDOFFLINE:
- case BIOC_SDREBUILD:
- case BIOC_SDHOTSPARE:
- if (rt++ < sd->sd_vol.sv_meta.svm_no_chunk)
- goto ragain;
-
- /* FALLTHROUGH */
- default:
- /* volume offline */
- printf("%s: is offline, can't read\n",
- DEVNAME(sd->sd_sc));
- sr_put_ccb(ccb);
- goto bad;
- }
- } else {
- /* writes go on all working disks */
- x = i;
- scp = sd->sd_vol.sv_chunks[x];
- switch (scp->src_meta.scm_status) {
- case BIOC_SDONLINE:
- case BIOC_SDSCRUB:
- case BIOC_SDREBUILD:
- ccb->ccb_buf.b_flags |= B_WRITE;
- break;
-
- case BIOC_SDHOTSPARE: /* should never happen */
- case BIOC_SDOFFLINE:
- wu->swu_io_count--;
- sr_put_ccb(ccb);
- continue;
-
- default:
- goto bad;
- }
-
- }
- ccb->ccb_target = x;
- ccb->ccb_buf.b_dev = sd->sd_vol.sv_chunks[x]->src_dev_mm;
- ccb->ccb_buf.b_vp = NULL;
-
- LIST_INIT(&ccb->ccb_buf.b_dep);
-
- TAILQ_INSERT_TAIL(&wu->swu_ccb, ccb, ccb_link);
-
- DNPRINTF(SR_D_DIS, "%s: %s: sr_raid1: b_bcount: %d "
- "b_blkno: %x b_flags 0x%0x b_data %p\n",
- DEVNAME(sd->sd_sc), sd->sd_vol.sv_meta.svm_devname,
- ccb->ccb_buf.b_bcount, ccb->ccb_buf.b_blkno,
- ccb->ccb_buf.b_flags, ccb->ccb_buf.b_data);
- }
-
- s = splbio();
-
- /* current io failed, restart */
- if (wu->swu_state == SR_WU_RESTART)
- goto start;
-
- /* deferred io failed, don't restart */
- if (wu->swu_state == SR_WU_REQUEUE)
- goto queued;
-
- /* walk queue backwards and fill in collider if we have one */
- TAILQ_FOREACH_REVERSE(wup, &sd->sd_wu_pendq, sr_wu_list, swu_link) {
- if (wu->swu_blk_end < wup->swu_blk_start ||
- wup->swu_blk_end < wu->swu_blk_start)
- continue;
-
- /* we have an LBA collision, defer wu */
- wu->swu_state = SR_WU_DEFERRED;
- if (wup->swu_collider)
- /* wu is on deferred queue, append to last wu */
- while (wup->swu_collider)
- wup = wup->swu_collider;
-
- wup->swu_collider = wu;
- TAILQ_INSERT_TAIL(&sd->sd_wu_defq, wu, swu_link);
- sd->sd_wu_collisions++;
- goto queued;
- }
-
- /* XXX deal with polling */
-start:
- sr_raid_startwu(wu);
-queued:
- splx(s);
- return (0);
-bad:
- /* wu is unwound by sr_put_wu */
- return (1);
-}
-
-void
-sr_raid1_intr(struct buf *bp)
-{
- struct sr_ccb *ccb = (struct sr_ccb *)bp;
- struct sr_workunit *wu = ccb->ccb_wu, *wup;
- struct sr_discipline *sd = wu->swu_dis;
- struct scsi_xfer *xs = wu->swu_xs;
- struct sr_softc *sc = sd->sd_sc;
- int s, pend;
-
- DNPRINTF(SR_D_INTR, "%s: sr_intr bp %x xs %x\n",
- DEVNAME(sc), bp, xs);
-
- DNPRINTF(SR_D_INTR, "%s: sr_intr: b_bcount: %d b_resid: %d"
- " b_flags: 0x%0x block: %lld target: %d\n", DEVNAME(sc),
- ccb->ccb_buf.b_bcount, ccb->ccb_buf.b_resid, ccb->ccb_buf.b_flags,
- ccb->ccb_buf.b_blkno, ccb->ccb_target);
-
- s = splbio();
-
- if (ccb->ccb_buf.b_flags & B_ERROR) {
- DNPRINTF(SR_D_INTR, "%s: i/o error on block %lld target: %d\n",
- DEVNAME(sc), ccb->ccb_buf.b_blkno, ccb->ccb_target);
- wu->swu_ios_failed++;
- ccb->ccb_state = SR_CCB_FAILED;
- if (ccb->ccb_target != -1)
- sd->sd_set_chunk_state(sd, ccb->ccb_target,
- BIOC_SDOFFLINE);
- else
- panic("%s: invalid target on wu: %p", DEVNAME(sc), wu);
- } else {
- ccb->ccb_state = SR_CCB_OK;
- wu->swu_ios_succeeded++;
- }
- wu->swu_ios_complete++;
-
- DNPRINTF(SR_D_INTR, "%s: sr_intr: comp: %d count: %d failed: %d\n",
- DEVNAME(sc), wu->swu_ios_complete, wu->swu_io_count,
- wu->swu_ios_failed);
-
- if (wu->swu_ios_complete >= wu->swu_io_count) {
- /* if all ios failed, retry reads and give up on writes */
- if (wu->swu_ios_failed == wu->swu_ios_complete) {
- if (xs->flags & SCSI_DATA_IN) {
- printf("%s: retrying read on block %lld\n",
- DEVNAME(sc), ccb->ccb_buf.b_blkno);
- sr_put_ccb(ccb);
- TAILQ_INIT(&wu->swu_ccb);
- wu->swu_state = SR_WU_RESTART;
- if (sd->sd_scsi_rw(wu))
- goto bad;
- else
- goto retry;
- } else {
- printf("%s: permanently fail write on block "
- "%lld\n", DEVNAME(sc),
- ccb->ccb_buf.b_blkno);
- xs->error = XS_DRIVER_STUFFUP;
- goto bad;
- }
- }
-
- xs->error = XS_NOERROR;
- xs->resid = 0;
- xs->flags |= ITSDONE;
-
- pend = 0;
- TAILQ_FOREACH(wup, &sd->sd_wu_pendq, swu_link) {
- if (wu == wup) {
- /* wu on pendq, remove */
- TAILQ_REMOVE(&sd->sd_wu_pendq, wu, swu_link);
- pend = 1;
-
- if (wu->swu_collider) {
- if (wu->swu_ios_failed)
- /* toss all ccbs and recreate */
- sr_raid1_recreate_wu(wu->swu_collider);
-
- /* restart deferred wu */
- wu->swu_collider->swu_state =
- SR_WU_INPROGRESS;
- TAILQ_REMOVE(&sd->sd_wu_defq,
- wu->swu_collider, swu_link);
- sr_raid_startwu(wu->swu_collider);
- }
- break;
- }
- }
-
- if (!pend)
- printf("%s: wu: %p not on pending queue\n",
- DEVNAME(sc), wu);
-
- /* do not change the order of these 2 functions */
- sr_put_wu(wu);
- scsi_done(xs);
-
- if (sd->sd_sync && sd->sd_wu_pending == 0)
- wakeup(sd);
- }
-
-retry:
- splx(s);
- return;
-bad:
- xs->error = XS_DRIVER_STUFFUP;
- xs->flags |= ITSDONE;
- sr_put_wu(wu);
- scsi_done(xs);
- splx(s);
-}
-
-void
-sr_raid1_recreate_wu(struct sr_workunit *wu)
-{
- struct sr_discipline *sd = wu->swu_dis;
- struct sr_workunit *wup = wu;
- struct sr_ccb *ccb;
-
- do {
- DNPRINTF(SR_D_INTR, "%s: sr_raid1_recreate_wu: %p\n", wup);
-
- /* toss all ccbs */
- while ((ccb = TAILQ_FIRST(&wup->swu_ccb)) != NULL) {
- TAILQ_REMOVE(&wup->swu_ccb, ccb, ccb_link);
- sr_put_ccb(ccb);
- }
- TAILQ_INIT(&wup->swu_ccb);
-
- /* recreate ccbs */
- wup->swu_state = SR_WU_REQUEUE;
- if (sd->sd_scsi_rw(wup))
- panic("could not requeue io");
-
- wup = wup->swu_collider;
- } while (wup);
-}
diff --git a/sys/dev/softraid_raid1.c b/sys/dev/softraid_raid1.c
new file mode 100644
index 00000000000..94dd8be3823
--- /dev/null
+++ b/sys/dev/softraid_raid1.c
@@ -0,0 +1,418 @@
+/* $OpenBSD: softraid_raid1.c,v 1.1 2007/11/27 17:21:52 tedu Exp $ */
+/*
+ * Copyright (c) 2007 Marco Peereboom <marco@peereboom.us>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "bio.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/buf.h>
+#include <sys/device.h>
+#include <sys/ioctl.h>
+#include <sys/proc.h>
+#include <sys/malloc.h>
+#include <sys/kernel.h>
+#include <sys/disk.h>
+#include <sys/rwlock.h>
+#include <sys/queue.h>
+#include <sys/fcntl.h>
+#include <sys/disklabel.h>
+#include <sys/mount.h>
+#include <sys/sensors.h>
+#include <sys/stat.h>
+#include <sys/conf.h>
+#include <sys/uio.h>
+
+#include <scsi/scsi_all.h>
+#include <scsi/scsiconf.h>
+#include <scsi/scsi_disk.h>
+
+#include <dev/softraidvar.h>
+#include <dev/rndvar.h>
+
+/* RAID 1 functions */
+int
+sr_raid1_alloc_resources(struct sr_discipline *sd)
+{
+ int rv = EINVAL;
+
+ if (!sd)
+ return (rv);
+
+ DNPRINTF(SR_D_DIS, "%s: sr_raid1_alloc_resources\n",
+ DEVNAME(sd->sd_sc));
+
+ if (sr_alloc_wu(sd))
+ goto bad;
+ if (sr_alloc_ccb(sd))
+ goto bad;
+
+ rv = 0;
+bad:
+ return (rv);
+}
+
+int
+sr_raid1_free_resources(struct sr_discipline *sd)
+{
+ int rv = EINVAL;
+
+ if (!sd)
+ return (rv);
+
+ DNPRINTF(SR_D_DIS, "%s: sr_raid1_free_resources\n",
+ DEVNAME(sd->sd_sc));
+
+ sr_free_wu(sd);
+ sr_free_ccb(sd);
+
+ if (sd->sd_meta)
+ free(sd->sd_meta, M_DEVBUF);
+
+ rv = 0;
+ return (rv);
+}
+
+int
+sr_raid1_rw(struct sr_workunit *wu)
+{
+ struct sr_discipline *sd = wu->swu_dis;
+ struct scsi_xfer *xs = wu->swu_xs;
+ struct sr_workunit *wup;
+ struct sr_ccb *ccb;
+ struct sr_chunk *scp;
+ int ios, x, i, s, rt;
+ daddr64_t blk;
+
+ DNPRINTF(SR_D_DIS, "%s: sr_raid1_rw 0x%02x\n", DEVNAME(sd->sd_sc),
+ xs->cmd->opcode);
+
+ if (sd->sd_vol.sv_meta.svm_status == BIOC_SVOFFLINE) {
+ DNPRINTF(SR_D_DIS, "%s: sr_raid1_rw device offline\n",
+ DEVNAME(sd->sd_sc));
+ goto bad;
+ }
+
+ if (xs->datalen == 0) {
+ printf("%s: %s: illegal block count\n",
+ DEVNAME(sd->sd_sc), sd->sd_vol.sv_meta.svm_devname);
+ goto bad;
+ }
+
+ if (xs->cmdlen == 10)
+ blk = _4btol(((struct scsi_rw_big *)xs->cmd)->addr);
+ else if (xs->cmdlen == 6)
+ blk = _3btol(((struct scsi_rw *)xs->cmd)->addr);
+ else {
+ printf("%s: %s: illegal cmdlen\n", DEVNAME(sd->sd_sc),
+ sd->sd_vol.sv_meta.svm_devname);
+ goto bad;
+ }
+
+ wu->swu_blk_start = blk;
+ wu->swu_blk_end = blk + (xs->datalen >> 9) - 1;
+
+ if (wu->swu_blk_end > sd->sd_vol.sv_meta.svm_size) {
+ DNPRINTF(SR_D_DIS, "%s: sr_raid1_rw out of bounds start: %lld "
+ "end: %lld length: %d\n", wu->swu_blk_start,
+ wu->swu_blk_end, xs->datalen);
+
+ sd->sd_scsi_sense.error_code = SSD_ERRCODE_CURRENT |
+ SSD_ERRCODE_VALID;
+ sd->sd_scsi_sense.flags = SKEY_ILLEGAL_REQUEST;
+ sd->sd_scsi_sense.add_sense_code = 0x21;
+ sd->sd_scsi_sense.add_sense_code_qual = 0x00;
+ sd->sd_scsi_sense.extra_len = 4;
+ goto bad;
+ }
+
+ /* calculate physical block */
+ blk += SR_META_SIZE + SR_META_OFFSET;
+
+ if (xs->flags & SCSI_DATA_IN)
+ ios = 1;
+ else
+ ios = sd->sd_vol.sv_meta.svm_no_chunk;
+ wu->swu_io_count = ios;
+
+ for (i = 0; i < ios; i++) {
+ ccb = sr_get_ccb(sd);
+ if (!ccb) {
+ /* should never happen but handle more gracefully */
+ printf("%s: %s: too many ccbs queued\n",
+ DEVNAME(sd->sd_sc),
+ sd->sd_vol.sv_meta.svm_devname);
+ goto bad;
+ }
+
+ if (xs->flags & SCSI_POLL) {
+ ccb->ccb_buf.b_flags = 0;
+ ccb->ccb_buf.b_iodone = NULL;
+ } else {
+ ccb->ccb_buf.b_flags = B_CALL;
+ ccb->ccb_buf.b_iodone = sr_raid1_intr;
+ }
+
+ ccb->ccb_buf.b_blkno = blk;
+ ccb->ccb_buf.b_bcount = xs->datalen;
+ ccb->ccb_buf.b_bufsize = xs->datalen;
+ ccb->ccb_buf.b_resid = xs->datalen;
+ ccb->ccb_buf.b_data = xs->data;
+ ccb->ccb_buf.b_error = 0;
+ ccb->ccb_buf.b_proc = curproc;
+ ccb->ccb_wu = wu;
+
+ if (xs->flags & SCSI_DATA_IN) {
+ rt = 0;
+ragain:
+ /* interleave reads */
+ x = sd->mds.mdd_raid1.sr1_counter++ %
+ sd->sd_vol.sv_meta.svm_no_chunk;
+ scp = sd->sd_vol.sv_chunks[x];
+ switch (scp->src_meta.scm_status) {
+ case BIOC_SDONLINE:
+ case BIOC_SDSCRUB:
+ ccb->ccb_buf.b_flags |= B_READ;
+ break;
+
+ case BIOC_SDOFFLINE:
+ case BIOC_SDREBUILD:
+ case BIOC_SDHOTSPARE:
+ if (rt++ < sd->sd_vol.sv_meta.svm_no_chunk)
+ goto ragain;
+
+ /* FALLTHROUGH */
+ default:
+ /* volume offline */
+ printf("%s: is offline, can't read\n",
+ DEVNAME(sd->sd_sc));
+ sr_put_ccb(ccb);
+ goto bad;
+ }
+ } else {
+ /* writes go on all working disks */
+ x = i;
+ scp = sd->sd_vol.sv_chunks[x];
+ switch (scp->src_meta.scm_status) {
+ case BIOC_SDONLINE:
+ case BIOC_SDSCRUB:
+ case BIOC_SDREBUILD:
+ ccb->ccb_buf.b_flags |= B_WRITE;
+ break;
+
+ case BIOC_SDHOTSPARE: /* should never happen */
+ case BIOC_SDOFFLINE:
+ wu->swu_io_count--;
+ sr_put_ccb(ccb);
+ continue;
+
+ default:
+ goto bad;
+ }
+
+ }
+ ccb->ccb_target = x;
+ ccb->ccb_buf.b_dev = sd->sd_vol.sv_chunks[x]->src_dev_mm;
+ ccb->ccb_buf.b_vp = NULL;
+
+ LIST_INIT(&ccb->ccb_buf.b_dep);
+
+ TAILQ_INSERT_TAIL(&wu->swu_ccb, ccb, ccb_link);
+
+ DNPRINTF(SR_D_DIS, "%s: %s: sr_raid1: b_bcount: %d "
+ "b_blkno: %x b_flags 0x%0x b_data %p\n",
+ DEVNAME(sd->sd_sc), sd->sd_vol.sv_meta.svm_devname,
+ ccb->ccb_buf.b_bcount, ccb->ccb_buf.b_blkno,
+ ccb->ccb_buf.b_flags, ccb->ccb_buf.b_data);
+ }
+
+ s = splbio();
+
+ /* current io failed, restart */
+ if (wu->swu_state == SR_WU_RESTART)
+ goto start;
+
+ /* deferred io failed, don't restart */
+ if (wu->swu_state == SR_WU_REQUEUE)
+ goto queued;
+
+ /* walk queue backwards and fill in collider if we have one */
+ TAILQ_FOREACH_REVERSE(wup, &sd->sd_wu_pendq, sr_wu_list, swu_link) {
+ if (wu->swu_blk_end < wup->swu_blk_start ||
+ wup->swu_blk_end < wu->swu_blk_start)
+ continue;
+
+ /* we have an LBA collision, defer wu */
+ wu->swu_state = SR_WU_DEFERRED;
+ if (wup->swu_collider)
+ /* wu is on deferred queue, append to last wu */
+ while (wup->swu_collider)
+ wup = wup->swu_collider;
+
+ wup->swu_collider = wu;
+ TAILQ_INSERT_TAIL(&sd->sd_wu_defq, wu, swu_link);
+ sd->sd_wu_collisions++;
+ goto queued;
+ }
+
+ /* XXX deal with polling */
+start:
+ sr_raid_startwu(wu);
+queued:
+ splx(s);
+ return (0);
+bad:
+ /* wu is unwound by sr_put_wu */
+ return (1);
+}
+
+void
+sr_raid1_intr(struct buf *bp)
+{
+ struct sr_ccb *ccb = (struct sr_ccb *)bp;
+ struct sr_workunit *wu = ccb->ccb_wu, *wup;
+ struct sr_discipline *sd = wu->swu_dis;
+ struct scsi_xfer *xs = wu->swu_xs;
+ struct sr_softc *sc = sd->sd_sc;
+ int s, pend;
+
+ DNPRINTF(SR_D_INTR, "%s: sr_intr bp %x xs %x\n",
+ DEVNAME(sc), bp, xs);
+
+ DNPRINTF(SR_D_INTR, "%s: sr_intr: b_bcount: %d b_resid: %d"
+ " b_flags: 0x%0x block: %lld target: %d\n", DEVNAME(sc),
+ ccb->ccb_buf.b_bcount, ccb->ccb_buf.b_resid, ccb->ccb_buf.b_flags,
+ ccb->ccb_buf.b_blkno, ccb->ccb_target);
+
+ s = splbio();
+
+ if (ccb->ccb_buf.b_flags & B_ERROR) {
+ DNPRINTF(SR_D_INTR, "%s: i/o error on block %lld target: %d\n",
+ DEVNAME(sc), ccb->ccb_buf.b_blkno, ccb->ccb_target);
+ wu->swu_ios_failed++;
+ ccb->ccb_state = SR_CCB_FAILED;
+ if (ccb->ccb_target != -1)
+ sd->sd_set_chunk_state(sd, ccb->ccb_target,
+ BIOC_SDOFFLINE);
+ else
+ panic("%s: invalid target on wu: %p", DEVNAME(sc), wu);
+ } else {
+ ccb->ccb_state = SR_CCB_OK;
+ wu->swu_ios_succeeded++;
+ }
+ wu->swu_ios_complete++;
+
+ DNPRINTF(SR_D_INTR, "%s: sr_intr: comp: %d count: %d failed: %d\n",
+ DEVNAME(sc), wu->swu_ios_complete, wu->swu_io_count,
+ wu->swu_ios_failed);
+
+ if (wu->swu_ios_complete >= wu->swu_io_count) {
+ /* if all ios failed, retry reads and give up on writes */
+ if (wu->swu_ios_failed == wu->swu_ios_complete) {
+ if (xs->flags & SCSI_DATA_IN) {
+ printf("%s: retrying read on block %lld\n",
+ DEVNAME(sc), ccb->ccb_buf.b_blkno);
+ sr_put_ccb(ccb);
+ TAILQ_INIT(&wu->swu_ccb);
+ wu->swu_state = SR_WU_RESTART;
+ if (sd->sd_scsi_rw(wu))
+ goto bad;
+ else
+ goto retry;
+ } else {
+ printf("%s: permanently fail write on block "
+ "%lld\n", DEVNAME(sc),
+ ccb->ccb_buf.b_blkno);
+ xs->error = XS_DRIVER_STUFFUP;
+ goto bad;
+ }
+ }
+
+ xs->error = XS_NOERROR;
+ xs->resid = 0;
+ xs->flags |= ITSDONE;
+
+ pend = 0;
+ TAILQ_FOREACH(wup, &sd->sd_wu_pendq, swu_link) {
+ if (wu == wup) {
+ /* wu on pendq, remove */
+ TAILQ_REMOVE(&sd->sd_wu_pendq, wu, swu_link);
+ pend = 1;
+
+ if (wu->swu_collider) {
+ if (wu->swu_ios_failed)
+ /* toss all ccbs and recreate */
+ sr_raid1_recreate_wu(wu->swu_collider);
+
+ /* restart deferred wu */
+ wu->swu_collider->swu_state =
+ SR_WU_INPROGRESS;
+ TAILQ_REMOVE(&sd->sd_wu_defq,
+ wu->swu_collider, swu_link);
+ sr_raid_startwu(wu->swu_collider);
+ }
+ break;
+ }
+ }
+
+ if (!pend)
+ printf("%s: wu: %p not on pending queue\n",
+ DEVNAME(sc), wu);
+
+ /* do not change the order of these 2 functions */
+ sr_put_wu(wu);
+ scsi_done(xs);
+
+ if (sd->sd_sync && sd->sd_wu_pending == 0)
+ wakeup(sd);
+ }
+
+retry:
+ splx(s);
+ return;
+bad:
+ xs->error = XS_DRIVER_STUFFUP;
+ xs->flags |= ITSDONE;
+ sr_put_wu(wu);
+ scsi_done(xs);
+ splx(s);
+}
+
+void
+sr_raid1_recreate_wu(struct sr_workunit *wu)
+{
+ struct sr_discipline *sd = wu->swu_dis;
+ struct sr_workunit *wup = wu;
+ struct sr_ccb *ccb;
+
+ do {
+ DNPRINTF(SR_D_INTR, "%s: sr_raid1_recreate_wu: %p\n", wup);
+
+ /* toss all ccbs */
+ while ((ccb = TAILQ_FIRST(&wup->swu_ccb)) != NULL) {
+ TAILQ_REMOVE(&wup->swu_ccb, ccb, ccb_link);
+ sr_put_ccb(ccb);
+ }
+ TAILQ_INIT(&wup->swu_ccb);
+
+ /* recreate ccbs */
+ wup->swu_state = SR_WU_REQUEUE;
+ if (sd->sd_scsi_rw(wup))
+ panic("could not requeue io");
+
+ wup = wup->swu_collider;
+ } while (wup);
+}
diff --git a/sys/dev/softraidvar.h b/sys/dev/softraidvar.h
index 04352a8a40f..3b5a4b6bf7c 100644
--- a/sys/dev/softraidvar.h
+++ b/sys/dev/softraidvar.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: softraidvar.h,v 1.34 2007/11/27 16:37:05 tedu Exp $ */
+/* $OpenBSD: softraidvar.h,v 1.35 2007/11/27 17:21:52 tedu Exp $ */
/*
* Copyright (c) 2006 Marco Peereboom <marco@peereboom.us>
*
@@ -362,6 +362,13 @@ void sr_raid_set_chunk_state(struct sr_discipline *,
void sr_raid_set_vol_state(struct sr_discipline *);
void sr_raid_startwu(struct sr_workunit *);
+int sr_raid1_alloc_resources(struct sr_discipline *);
+int sr_raid1_free_resources(struct sr_discipline *);
+int sr_raid1_rw(struct sr_workunit *);
+void sr_raid1_intr(struct buf *);
+void sr_raid1_recreate_wu(struct sr_workunit *);
+
+
/* crypto discipline */
struct cryptop * sr_crypto_getcryptop(struct sr_workunit *, int);
void * sr_crypto_putcryptop(struct cryptop *);