diff options
Diffstat (limited to 'sys/dev/softraid.c')
-rw-r--r-- | sys/dev/softraid.c | 382 |
1 files changed, 1 insertions, 381 deletions
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); -} |