diff options
author | 2007-05-30 13:55:47 +0000 | |
---|---|---|
committer | 2007-05-30 13:55:47 +0000 | |
commit | ed078b947550d68b9b3939e616affd56bae92773 (patch) | |
tree | cff7a22bfda2874103f6e7bb5f835374ef15550f /sys/dev/softraid.c | |
parent | document \&$Mdocdate$; prodded by xsa (diff) | |
download | wireguard-openbsd-ed078b947550d68b9b3939e616affd56bae92773.tar.xz wireguard-openbsd-ed078b947550d68b9b3939e616affd56bae92773.zip |
add basic support for a crypto(9) backed raid C discipline
ok marco
Diffstat (limited to 'sys/dev/softraid.c')
-rw-r--r-- | sys/dev/softraid.c | 494 |
1 files changed, 453 insertions, 41 deletions
diff --git a/sys/dev/softraid.c b/sys/dev/softraid.c index 84af7ae27a2..222a807e7fc 100644 --- a/sys/dev/softraid.c +++ b/sys/dev/softraid.c @@ -1,4 +1,4 @@ -/* $OpenBSD: softraid.c,v 1.57 2007/05/29 23:20:02 marco Exp $ */ +/* $OpenBSD: softraid.c,v 1.58 2007/05/30 13:55:47 tedu Exp $ */ /* * Copyright (c) 2007 Marco Peereboom <marco@peereboom.us> * @@ -34,6 +34,9 @@ #include <sys/sensors.h> #include <sys/stat.h> #include <sys/conf.h> +#include <sys/uio.h> + +#include <crypto/cryptodev.h> #include <machine/bus.h> @@ -109,21 +112,30 @@ struct sr_workunit *sr_get_wu(struct sr_discipline *); void sr_put_wu(struct sr_workunit *); /* discipline functions */ +int sr_raid_inquiry(struct sr_workunit *); +int sr_raid_read_cap(struct sr_workunit *); +int sr_raid_tur(struct sr_workunit *); +int sr_raid_request_sense( struct sr_workunit *); +int sr_raid_start_stop(struct sr_workunit *); +int sr_raid_sync(struct sr_workunit *); +void sr_raid_set_chunk_state(struct sr_discipline *, + int, int); +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 *); -int sr_raid1_inquiry(struct sr_workunit *); -int sr_raid1_read_cap(struct sr_workunit *); -int sr_raid1_tur(struct sr_workunit *); -int sr_raid1_request_sense( struct sr_workunit *); -int sr_raid1_start_stop(struct sr_workunit *); -int sr_raid1_sync(struct sr_workunit *); void sr_raid1_intr(struct buf *); -void sr_raid1_set_chunk_state(struct sr_discipline *, - int, int); -void sr_raid1_set_vol_state(struct sr_discipline *); -void sr_raid1_startwu(struct sr_workunit *); + +struct cryptop * sr_raidc_getcryptop(struct sr_workunit *, int); +void * sr_raidc_putcryptop(struct cryptop *); +int sr_raidc_alloc_resources(struct sr_discipline *); +int sr_raidc_free_resources(struct sr_discipline *); +int sr_raidc_rw(struct sr_workunit *); +int sr_raidc_rw2(struct cryptop *); +void sr_raidc_intr(struct buf *); +int sr_raidc_intr2(struct cryptop *); /* utility functions */ void sr_shutdown(void *); @@ -817,6 +829,13 @@ sr_ioctl_createraid(struct sr_softc *sc, struct bioc_createraid *bc, int user) goto unwind; strlcpy(sd->sd_name, "RAID 1", sizeof(sd->sd_name)); break; + case 'c': + if (no_chunk != 1) { + printf("too many c chunks\n"); + goto unwind; + } + strlcpy(sd->sd_name, "RAID C", sizeof(sd->sd_name)); + break; default: goto unwind; } @@ -887,17 +906,37 @@ sr_ioctl_createraid(struct sr_softc *sc, struct bioc_createraid *bc, int user) /* setup discipline pointers */ sd->sd_alloc_resources = sr_raid1_alloc_resources; sd->sd_free_resources = sr_raid1_free_resources; - sd->sd_scsi_inquiry = sr_raid1_inquiry; - sd->sd_scsi_read_cap = sr_raid1_read_cap; - sd->sd_scsi_tur = sr_raid1_tur; - sd->sd_scsi_req_sense = sr_raid1_request_sense; - sd->sd_scsi_start_stop = sr_raid1_start_stop; - sd->sd_scsi_sync = sr_raid1_sync; + sd->sd_scsi_inquiry = sr_raid_inquiry; + sd->sd_scsi_read_cap = sr_raid_read_cap; + sd->sd_scsi_tur = sr_raid_tur; + sd->sd_scsi_req_sense = sr_raid_request_sense; + sd->sd_scsi_start_stop = sr_raid_start_stop; + sd->sd_scsi_sync = sr_raid_sync; sd->sd_scsi_rw = sr_raid1_rw; - sd->sd_set_chunk_state = sr_raid1_set_chunk_state; - sd->sd_set_vol_state = sr_raid1_set_vol_state; + sd->sd_set_chunk_state = sr_raid_set_chunk_state; + sd->sd_set_vol_state = sr_raid_set_vol_state; + break; + case 'c': + /* fill out discipline members */ + sd->sd_type = SR_MD_RAIDC; + sd->sd_max_ccb_per_wu = no_chunk; + sd->sd_max_wu = SR_RAIDC_NOWU; + + /* setup discipline pointers */ + sd->sd_alloc_resources = sr_raidc_alloc_resources; + sd->sd_free_resources = sr_raidc_free_resources; + sd->sd_scsi_inquiry = sr_raid_inquiry; + sd->sd_scsi_read_cap = sr_raid_read_cap; + sd->sd_scsi_tur = sr_raid_tur; + sd->sd_scsi_req_sense = sr_raid_request_sense; + sd->sd_scsi_start_stop = sr_raid_start_stop; + sd->sd_scsi_sync = sr_raid_sync; + sd->sd_scsi_rw = sr_raidc_rw; + sd->sd_set_chunk_state = sr_raid_set_chunk_state; + sd->sd_set_vol_state = sr_raid_set_vol_state; break; default: + printf("default %d\n", bc->bc_level); goto unwind; } @@ -1355,13 +1394,13 @@ sr_raid1_free_resources(struct sr_discipline *sd) } int -sr_raid1_inquiry(struct sr_workunit *wu) +sr_raid_inquiry(struct sr_workunit *wu) { struct sr_discipline *sd = wu->swu_dis; struct scsi_xfer *xs = wu->swu_xs; struct scsi_inquiry_data inq; - DNPRINTF(SR_D_DIS, "%s: sr_raid1_inquiry\n", DEVNAME(sd->sd_sc)); + DNPRINTF(SR_D_DIS, "%s: sr_raid_inquiry\n", DEVNAME(sd->sd_sc)); bzero(&inq, sizeof(inq)); inq.device = T_DIRECT; @@ -1381,13 +1420,13 @@ sr_raid1_inquiry(struct sr_workunit *wu) } int -sr_raid1_read_cap(struct sr_workunit *wu) +sr_raid_read_cap(struct sr_workunit *wu) { struct sr_discipline *sd = wu->swu_dis; struct scsi_xfer *xs = wu->swu_xs; struct scsi_read_cap_data rcd; - DNPRINTF(SR_D_DIS, "%s: sr_raid1_read_cap\n", DEVNAME(sd->sd_sc)); + DNPRINTF(SR_D_DIS, "%s: sr_raid_read_cap\n", DEVNAME(sd->sd_sc)); bzero(&rcd, sizeof(rcd)); _lto4b(sd->sd_vol.sv_meta.svm_size, rcd.addr); @@ -1398,11 +1437,11 @@ sr_raid1_read_cap(struct sr_workunit *wu) } int -sr_raid1_tur(struct sr_workunit *wu) +sr_raid_tur(struct sr_workunit *wu) { struct sr_discipline *sd = wu->swu_dis; - DNPRINTF(SR_D_DIS, "%s: sr_raid1_tur\n", DEVNAME(sd->sd_sc)); + DNPRINTF(SR_D_DIS, "%s: sr_raid_tur\n", DEVNAME(sd->sd_sc)); if (sd->sd_vol.sv_meta.svm_status == BIOC_SVOFFLINE) { sd->sd_scsi_sense.error_code = SSD_ERRCODE_CURRENT; @@ -1428,12 +1467,12 @@ sr_raid1_tur(struct sr_workunit *wu) } int -sr_raid1_request_sense(struct sr_workunit *wu) +sr_raid_request_sense(struct sr_workunit *wu) { struct sr_discipline *sd = wu->swu_dis; struct scsi_xfer *xs = wu->swu_xs; - DNPRINTF(SR_D_DIS, "%s: sr_raid1_request_sense\n", + DNPRINTF(SR_D_DIS, "%s: sr_raid_request_sense\n", DEVNAME(sd->sd_sc)); /* use latest sense data */ @@ -1452,14 +1491,14 @@ sr_raid1_request_sense(struct sr_workunit *wu) } int -sr_raid1_start_stop(struct sr_workunit *wu) +sr_raid_start_stop(struct sr_workunit *wu) { struct sr_discipline *sd = wu->swu_dis; struct scsi_xfer *xs = wu->swu_xs; struct scsi_start_stop *ss = (struct scsi_start_stop *)xs->cmd; int rv = 1; - DNPRINTF(SR_D_DIS, "%s: sr_raid1_start_stop\n", + DNPRINTF(SR_D_DIS, "%s: sr_raid_start_stop\n", DEVNAME(sd->sd_sc)); if (!ss) @@ -1486,19 +1525,19 @@ sr_raid1_start_stop(struct sr_workunit *wu) } int -sr_raid1_sync(struct sr_workunit *wu) +sr_raid_sync(struct sr_workunit *wu) { struct sr_discipline *sd = wu->swu_dis; int s, rv = 0; - DNPRINTF(SR_D_DIS, "%s: sr_raid1_sync\n", DEVNAME(sd->sd_sc)); + DNPRINTF(SR_D_DIS, "%s: sr_raid_sync\n", DEVNAME(sd->sd_sc)); s = splbio(); sd->sd_sync = 1; while (sd->sd_wu_pending > 1) if (tsleep(sd, PRIBIO, "sr_sync", 60 * hz) == EWOULDBLOCK) { - DNPRINTF(SR_D_DIS, "%s: sr_raid1_sync timeout\n", + DNPRINTF(SR_D_DIS, "%s: sr_raid_sync timeout\n", DEVNAME(sd->sd_sc)); rv = 1; break; @@ -1689,7 +1728,7 @@ ragain: /* XXX deal with polling */ - sr_raid1_startwu(wu); + sr_raid_startwu(wu); queued: splx(s); @@ -1700,7 +1739,7 @@ bad: } void -sr_raid1_startwu(struct sr_workunit *wu) +sr_raid_startwu(struct sr_workunit *wu) { struct sr_discipline *sd = wu->swu_dis; struct sr_ccb *ccb; @@ -1775,7 +1814,7 @@ sr_raid1_intr(struct buf *bp) SR_WU_INPROGRESS; TAILQ_REMOVE(&sd->sd_wu_defq, wu->swu_collider, swu_link); - sr_raid1_startwu(wu->swu_collider); + sr_raid_startwu(wu->swu_collider); } break; } @@ -1797,11 +1836,11 @@ sr_raid1_intr(struct buf *bp) } void -sr_raid1_set_chunk_state(struct sr_discipline *sd, int c, int new_state) +sr_raid_set_chunk_state(struct sr_discipline *sd, int c, int new_state) { int old_state, s; - DNPRINTF(SR_D_STATE, "%s: %s: %s: sr_raid1_set_chunk_state %d -> %d\n", + DNPRINTF(SR_D_STATE, "%s: %s: %s: sr_raid_set_chunk_state %d -> %d\n", DEVNAME(sd->sd_sc), sd->sd_vol.sv_meta.svm_devname, sd->sd_vol.sv_chunks[c]->src_meta.scm_devname, c, new_state); @@ -1872,13 +1911,13 @@ done: } void -sr_raid1_set_vol_state(struct sr_discipline *sd) +sr_raid_set_vol_state(struct sr_discipline *sd) { int states[SR_MAX_STATES]; int new_state, i, s, nd; int old_state = sd->sd_vol.sv_meta.svm_status; - DNPRINTF(SR_D_STATE, "%s: %s: sr_raid1_set_vol_state\n", + DNPRINTF(SR_D_STATE, "%s: %s: sr_raid_set_vol_state\n", DEVNAME(sd->sd_sc), sd->sd_vol.sv_meta.svm_devname); nd = sd->sd_vol.sv_meta.svm_no_chunk; @@ -1914,7 +1953,7 @@ sr_raid1_set_vol_state(struct sr_discipline *sd) panic("invalid new_state"); } - DNPRINTF(SR_D_STATE, "%s: %s: sr_raid1_set_vol_state %d -> %d\n", + DNPRINTF(SR_D_STATE, "%s: %s: sr_raid_set_vol_state %d -> %d\n", DEVNAME(sd->sd_sc), sd->sd_vol.sv_meta.svm_devname, old_state, new_state); @@ -2727,3 +2766,376 @@ sr_print_metadata(struct sr_metadata *sm) } } #endif /* SR_DEBUG */ + +/* RAID crypto functions */ +struct cryptop * +sr_raidc_getcryptop(struct sr_workunit *wu, int encrypt) +{ + struct scsi_xfer *xs = wu->swu_xs; + struct sr_discipline *sd = wu->swu_dis; + struct cryptop *crp; + struct cryptodesc *crd; + struct uio *uio; + int flags, i, n; + int blk = 0; + + uio = malloc(sizeof(*uio), M_DEVBUF, M_WAITOK); + memset(uio, 0, sizeof(*uio)); + uio->uio_iov = malloc(sizeof(*uio->uio_iov), M_DEVBUF, M_WAITOK); + uio->uio_iovcnt = 1; + uio->uio_iov->iov_base = xs->data; + uio->uio_iov->iov_len = xs->datalen; + + 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); + + n = xs->datalen / 512; + flags = (encrypt ? CRD_F_ENCRYPT : 0) | + CRD_F_IV_PRESENT | CRD_F_IV_EXPLICIT; + + crp = crypto_getreq(n); + + crp->crp_sid = sd->mds.mdd_raidc.src_sid; + crp->crp_ilen = xs->datalen; + crp->crp_alloctype = M_DEVBUF; + crp->crp_buf = uio; + for (i = 0, crd = crp->crp_desc; crd; i++, crd = crd->crd_next) { + crd->crd_skip = 512 * i; + crd->crd_len = 512; + crd->crd_inject = 0; + crd->crd_flags = flags; + crd->crd_alg = CRYPTO_AES_CBC; + crd->crd_klen = 256; + crd->crd_rnd = 14; + crd->crd_key = sd->mds.mdd_raidc.src_key; + memset(crd->crd_iv, blk + i, sizeof(crd->crd_iv)); + } + return crp; +} + +void * +sr_raidc_putcryptop(struct cryptop *crp) +{ + struct uio *uio = crp->crp_buf; + void *opaque = crp->crp_opaque; + free(uio->uio_iov, M_DEVBUF); + free(uio, M_DEVBUF); + crypto_freereq(crp); + + return opaque; +} + +int +sr_raidc_alloc_resources(struct sr_discipline *sd) +{ + int rv = EINVAL; + struct cryptoini cri; + + if (!sd) + return (rv); + + DNPRINTF(SR_D_DIS, "%s: sr_raidc_alloc_resources\n", + DEVNAME(sd->sd_sc)); + + sr_alloc_wu(sd); + sr_alloc_ccb(sd); + memset(sd->mds.mdd_raidc.src_key, 'k', sizeof sd->mds.mdd_raidc.src_key); + bzero(&cri, sizeof(cri)); + cri.cri_alg = CRYPTO_AES_CBC; + cri.cri_klen = 256; + cri.cri_rnd = 14; + cri.cri_key = sd->mds.mdd_raidc.src_key; + rv = crypto_newsession(&sd->mds.mdd_raidc.src_sid, &cri, 0); + + return (rv); +} + +int +sr_raidc_free_resources(struct sr_discipline *sd) +{ + int rv = EINVAL; + + if (!sd) + return (rv); + + DNPRINTF(SR_D_DIS, "%s: sr_raidc_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_raidc_rw(struct sr_workunit *wu) +{ + struct cryptop *crp; + + crp = sr_raidc_getcryptop(wu, 1); + crp->crp_callback = sr_raidc_rw2; + crp->crp_opaque = wu; + crypto_dispatch(crp); + return 0; +} + +int +sr_raidc_rw2(struct cryptop *crp) +{ + struct sr_workunit *wu = sr_raidc_putcryptop(crp); + 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 s, rt; + daddr64_t blk; + + + DNPRINTF(SR_D_DIS, "%s: sr_raidc_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_raidc_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; + } + + blk += SR_META_SIZE + SR_META_OFFSET; + + wu->swu_blk_start = blk; + wu->swu_blk_end = blk + xs->datalen - 1; + wu->swu_io_count = 1; + + 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) { + panic("p"); + 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_raidc_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: + scp = sd->sd_vol.sv_chunks[0]; + 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 { + scp = sd->sd_vol.sv_chunks[0]; + 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); + goto bad; + + default: + goto bad; + } + + } + ccb->ccb_target = 0; + ccb->ccb_buf.b_dev = sd->sd_vol.sv_chunks[0]->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_raidc: 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); + + + /* walk queue backwards and fill in collider if we have one */ + s = splbio(); + 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 */ + + sr_raid_startwu(wu); + +queued: + splx(s); + return (0); +bad: + /* wu is unwound by sr_put_wu */ + return (1); +} + +void +sr_raidc_intr(struct buf *bp) +{ + struct sr_ccb *ccb = (struct sr_ccb *)bp; + struct sr_workunit *wu = ccb->ccb_wu; + struct cryptop *crp; + + 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\n", DEVNAME(sc), ccb->ccb_buf.b_bcount, + ccb->ccb_buf.b_resid, ccb->ccb_buf.b_flags); + + crp = sr_raidc_getcryptop(wu, 0); + crp->crp_callback = sr_raidc_intr2; + crp->crp_opaque = bp; + crypto_dispatch(crp); +} + +int +sr_raidc_intr2(struct cryptop *crp) +{ + struct buf *bp = sr_raidc_putcryptop(crp); + 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; + + s = splbio(); + + if (ccb->ccb_buf.b_flags & B_ERROR) { + printf("%s: i/o error on block %llu\n", DEVNAME(sc), + ccb->ccb_buf.b_blkno); + 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\n", + DEVNAME(sc), wu->swu_ios_complete, wu->swu_io_count); + + if (wu->swu_ios_complete == wu->swu_io_count) { + if (wu->swu_ios_failed == wu->swu_ios_complete) + xs->error = XS_DRIVER_STUFFUP; + else + 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) { + /* 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); + } + + splx(s); + return 0; +} |