[BACK]Return to softraid.c CVS log [TXT][DIR] Up to [local] / sys / dev

Annotation of sys/dev/softraid.c, Revision 1.1

1.1     ! nbrk        1: /* $OpenBSD: softraid.c,v 1.82 2007/06/24 05:34:35 dlg Exp $ */
        !             2: /*
        !             3:  * Copyright (c) 2007 Marco Peereboom <marco@peereboom.us>
        !             4:  *
        !             5:  * Permission to use, copy, modify, and distribute this software for any
        !             6:  * purpose with or without fee is hereby granted, provided that the above
        !             7:  * copyright notice and this permission notice appear in all copies.
        !             8:  *
        !             9:  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
        !            10:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
        !            11:  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
        !            12:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
        !            13:  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
        !            14:  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
        !            15:  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
        !            16:  */
        !            17:
        !            18: #include "bio.h"
        !            19:
        !            20: #include <sys/param.h>
        !            21: #include <sys/systm.h>
        !            22: #include <sys/buf.h>
        !            23: #include <sys/device.h>
        !            24: #include <sys/ioctl.h>
        !            25: #include <sys/proc.h>
        !            26: #include <sys/malloc.h>
        !            27: #include <sys/kernel.h>
        !            28: #include <sys/disk.h>
        !            29: #include <sys/rwlock.h>
        !            30: #include <sys/queue.h>
        !            31: #include <sys/fcntl.h>
        !            32: #include <sys/disklabel.h>
        !            33: #include <sys/mount.h>
        !            34: #include <sys/sensors.h>
        !            35: #include <sys/stat.h>
        !            36: #include <sys/conf.h>
        !            37: #include <sys/uio.h>
        !            38:
        !            39: #include <crypto/cryptodev.h>
        !            40:
        !            41: #include <scsi/scsi_all.h>
        !            42: #include <scsi/scsiconf.h>
        !            43: #include <scsi/scsi_disk.h>
        !            44:
        !            45: #include <dev/softraidvar.h>
        !            46: #include <dev/rndvar.h>
        !            47:
        !            48: /* #define SR_FANCY_STATS */
        !            49:
        !            50: #ifdef SR_DEBUG
        !            51: #define SR_FANCY_STATS
        !            52: uint32_t       sr_debug = 0
        !            53:                    /* | SR_D_CMD */
        !            54:                    /* | SR_D_MISC */
        !            55:                    /* | SR_D_INTR */
        !            56:                    /* | SR_D_IOCTL */
        !            57:                    /* | SR_D_CCB */
        !            58:                    /* | SR_D_WU */
        !            59:                    /* | SR_D_META */
        !            60:                    /* | SR_D_DIS */
        !            61:                    /* | SR_D_STATE */
        !            62:                ;
        !            63: #endif
        !            64:
        !            65: int            sr_match(struct device *, void *, void *);
        !            66: void           sr_attach(struct device *, struct device *, void *);
        !            67: int            sr_detach(struct device *, int);
        !            68: int            sr_activate(struct device *, enum devact);
        !            69:
        !            70: struct cfattach softraid_ca = {
        !            71:        sizeof(struct sr_softc), sr_match, sr_attach, sr_detach,
        !            72:        sr_activate
        !            73: };
        !            74:
        !            75: struct cfdriver softraid_cd = {
        !            76:        NULL, "softraid", DV_DULL
        !            77: };
        !            78:
        !            79: int                    sr_scsi_cmd(struct scsi_xfer *);
        !            80: void                   sr_minphys(struct buf *bp);
        !            81: void                   sr_copy_internal_data(struct scsi_xfer *,
        !            82:                            void *, size_t);
        !            83: int                    sr_scsi_ioctl(struct scsi_link *, u_long,
        !            84:                            caddr_t, int, struct proc *);
        !            85: int                    sr_ioctl(struct device *, u_long, caddr_t);
        !            86: int                    sr_ioctl_inq(struct sr_softc *, struct bioc_inq *);
        !            87: int                    sr_ioctl_vol(struct sr_softc *, struct bioc_vol *);
        !            88: int                    sr_ioctl_disk(struct sr_softc *, struct bioc_disk *);
        !            89: int                    sr_ioctl_setstate(struct sr_softc *,
        !            90:                            struct bioc_setstate *);
        !            91: int                    sr_ioctl_createraid(struct sr_softc *,
        !            92:                            struct bioc_createraid *, int);
        !            93: int                    sr_open_chunks(struct sr_softc *,
        !            94:                            struct sr_chunk_head *, dev_t *, int);
        !            95: int                    sr_read_meta(struct sr_discipline *);
        !            96: int                    sr_create_chunk_meta(struct sr_softc *,
        !            97:                            struct sr_chunk_head *);
        !            98: void                   sr_unwind_chunks(struct sr_softc *,
        !            99:                            struct sr_chunk_head *);
        !           100: void                   sr_free_discipline(struct sr_discipline *);
        !           101: void                   sr_shutdown_discipline(struct sr_discipline *);
        !           102:
        !           103: /* work units & ccbs */
        !           104: int                    sr_alloc_ccb(struct sr_discipline *);
        !           105: void                   sr_free_ccb(struct sr_discipline *);
        !           106: struct sr_ccb          *sr_get_ccb(struct sr_discipline *);
        !           107: void                   sr_put_ccb(struct sr_ccb *);
        !           108: int                    sr_alloc_wu(struct sr_discipline *);
        !           109: void                   sr_free_wu(struct sr_discipline *);
        !           110: struct sr_workunit     *sr_get_wu(struct sr_discipline *);
        !           111: void                   sr_put_wu(struct sr_workunit *);
        !           112:
        !           113: /* discipline functions */
        !           114: int                    sr_raid_inquiry(struct sr_workunit *);
        !           115: int                    sr_raid_read_cap(struct sr_workunit *);
        !           116: int                    sr_raid_tur(struct sr_workunit *);
        !           117: int                    sr_raid_request_sense( struct sr_workunit *);
        !           118: int                    sr_raid_start_stop(struct sr_workunit *);
        !           119: int                    sr_raid_sync(struct sr_workunit *);
        !           120: void                   sr_raid_set_chunk_state(struct sr_discipline *,
        !           121:                            int, int);
        !           122: void                   sr_raid_set_vol_state(struct sr_discipline *);
        !           123: void                   sr_raid_startwu(struct sr_workunit *);
        !           124:
        !           125: int                    sr_raid1_alloc_resources(struct sr_discipline *);
        !           126: int                    sr_raid1_free_resources(struct sr_discipline *);
        !           127: int                    sr_raid1_rw(struct sr_workunit *);
        !           128: void                   sr_raid1_intr(struct buf *);
        !           129: void                   sr_raid1_recreate_wu(struct sr_workunit *);
        !           130:
        !           131: struct cryptop *       sr_raidc_getcryptop(struct sr_workunit *, int);
        !           132: void *                 sr_raidc_putcryptop(struct cryptop *);
        !           133: int                    sr_raidc_alloc_resources(struct sr_discipline *);
        !           134: int                    sr_raidc_free_resources(struct sr_discipline *);
        !           135: int                    sr_raidc_rw(struct sr_workunit *);
        !           136: int                    sr_raidc_rw2(struct cryptop *);
        !           137: void                   sr_raidc_intr(struct buf *);
        !           138: int                    sr_raidc_intr2(struct cryptop *);
        !           139:
        !           140: /* utility functions */
        !           141: void                   sr_shutdown(void *);
        !           142: void                   sr_get_uuid(struct sr_uuid *);
        !           143: void                   sr_print_uuid(struct sr_uuid *, int);
        !           144: u_int32_t              sr_checksum(char *, u_int32_t *, u_int32_t);
        !           145: int                    sr_clear_metadata(struct sr_discipline *);
        !           146: int                    sr_save_metadata(struct sr_discipline *, u_int32_t);
        !           147: void                   sr_save_metadata_callback(void *, void *);
        !           148: int                    sr_boot_assembly(struct sr_softc *);
        !           149: int                    sr_already_assembled(struct sr_discipline *);
        !           150: int                    sr_validate_metadata(struct sr_softc *, dev_t,
        !           151:                            struct sr_metadata *);
        !           152:
        !           153: /* don't include these on RAMDISK */
        !           154: #ifndef SMALL_KERNEL
        !           155: void                   sr_refresh_sensors(void *);
        !           156: int                    sr_create_sensors(struct sr_discipline *);
        !           157: void                   sr_delete_sensors(struct sr_discipline *);
        !           158: #endif
        !           159:
        !           160: #ifdef SR_DEBUG
        !           161: void                   sr_print_metadata(struct sr_metadata *);
        !           162: #else
        !           163: #define                        sr_print_metadata(m)
        !           164: #endif
        !           165:
        !           166: struct scsi_adapter sr_switch = {
        !           167:        sr_scsi_cmd, sr_minphys, NULL, NULL, sr_scsi_ioctl
        !           168: };
        !           169:
        !           170: struct scsi_device sr_dev = {
        !           171:        NULL, NULL, NULL, NULL
        !           172: };
        !           173:
        !           174: int
        !           175: sr_match(struct device *parent, void *match, void *aux)
        !           176: {
        !           177:        return (1);
        !           178: }
        !           179:
        !           180: void
        !           181: sr_attach(struct device *parent, struct device *self, void *aux)
        !           182: {
        !           183:        struct sr_softc         *sc = (void *)self;
        !           184:
        !           185:        DNPRINTF(SR_D_MISC, "\n%s: sr_attach", DEVNAME(sc));
        !           186:
        !           187:        rw_init(&sc->sc_lock, "sr_lock");
        !           188:
        !           189:        if (bio_register(&sc->sc_dev, sr_ioctl) != 0)
        !           190:                printf("%s: controller registration failed", DEVNAME(sc));
        !           191:        else
        !           192:                sc->sc_ioctl = sr_ioctl;
        !           193:
        !           194:        printf("\n");
        !           195:
        !           196:        sr_boot_assembly(sc);
        !           197: }
        !           198:
        !           199: int
        !           200: sr_detach(struct device *self, int flags)
        !           201: {
        !           202:        return (0);
        !           203: }
        !           204:
        !           205: int
        !           206: sr_activate(struct device *self, enum devact act)
        !           207: {
        !           208:        return (1);
        !           209: }
        !           210:
        !           211: void
        !           212: sr_minphys(struct buf *bp)
        !           213: {
        !           214:        DNPRINTF(SR_D_MISC, "sr_minphys: %d\n", bp->b_bcount);
        !           215:
        !           216:        /* XXX currently using SR_MAXFER = MAXPHYS */
        !           217:        if (bp->b_bcount > SR_MAXFER)
        !           218:                bp->b_bcount = SR_MAXFER;
        !           219:        minphys(bp);
        !           220: }
        !           221:
        !           222: void
        !           223: sr_copy_internal_data(struct scsi_xfer *xs, void *v, size_t size)
        !           224: {
        !           225:        size_t                  copy_cnt;
        !           226:
        !           227:        DNPRINTF(SR_D_MISC, "sr_copy_internal_data xs: %p size: %d\n",
        !           228:            xs, size);
        !           229:
        !           230:        if (xs->datalen) {
        !           231:                copy_cnt = MIN(size, xs->datalen);
        !           232:                bcopy(v, xs->data, copy_cnt);
        !           233:        }
        !           234: }
        !           235:
        !           236: int
        !           237: sr_alloc_ccb(struct sr_discipline *sd)
        !           238: {
        !           239:        struct sr_ccb           *ccb;
        !           240:        int                     i;
        !           241:
        !           242:        if (!sd)
        !           243:                return (1);
        !           244:
        !           245:        DNPRINTF(SR_D_CCB, "%s: sr_alloc_ccb\n", DEVNAME(sd->sd_sc));
        !           246:
        !           247:        if (sd->sd_ccb)
        !           248:                return (1);
        !           249:
        !           250:        sd->sd_ccb = malloc(sizeof(struct sr_ccb) *
        !           251:            sd->sd_max_wu * sd->sd_max_ccb_per_wu, M_DEVBUF, M_WAITOK);
        !           252:        memset(sd->sd_ccb, 0, sizeof(struct sr_ccb) *
        !           253:            sd->sd_max_wu * sd->sd_max_ccb_per_wu);
        !           254:        TAILQ_INIT(&sd->sd_ccb_freeq);
        !           255:        for (i = 0; i < sd->sd_max_wu * sd->sd_max_ccb_per_wu; i++) {
        !           256:                ccb = &sd->sd_ccb[i];
        !           257:                ccb->ccb_dis = sd;
        !           258:                sr_put_ccb(ccb);
        !           259:        }
        !           260:
        !           261:        DNPRINTF(SR_D_CCB, "%s: sr_alloc_ccb ccb: %d\n",
        !           262:            DEVNAME(sd->sd_sc), sd->sd_max_wu * sd->sd_max_ccb_per_wu);
        !           263:
        !           264:        return (0);
        !           265: }
        !           266:
        !           267: void
        !           268: sr_free_ccb(struct sr_discipline *sd)
        !           269: {
        !           270:        struct sr_ccb           *ccb;
        !           271:
        !           272:        if (!sd)
        !           273:                return;
        !           274:
        !           275:        DNPRINTF(SR_D_CCB, "%s: sr_free_ccb %p\n", DEVNAME(sd->sd_sc), sd);
        !           276:
        !           277:        while ((ccb = TAILQ_FIRST(&sd->sd_ccb_freeq)) != NULL)
        !           278:                TAILQ_REMOVE(&sd->sd_ccb_freeq, ccb, ccb_link);
        !           279:
        !           280:        if (sd->sd_ccb)
        !           281:                free(sd->sd_ccb, M_DEVBUF);
        !           282: }
        !           283:
        !           284: struct sr_ccb *
        !           285: sr_get_ccb(struct sr_discipline *sd)
        !           286: {
        !           287:        struct sr_ccb           *ccb;
        !           288:        int                     s;
        !           289:
        !           290:        s = splbio();
        !           291:
        !           292:        ccb = TAILQ_FIRST(&sd->sd_ccb_freeq);
        !           293:        if (ccb) {
        !           294:                TAILQ_REMOVE(&sd->sd_ccb_freeq, ccb, ccb_link);
        !           295:                ccb->ccb_state = SR_CCB_INPROGRESS;
        !           296:        }
        !           297:
        !           298:        splx(s);
        !           299:
        !           300:        DNPRINTF(SR_D_CCB, "%s: sr_get_ccb: %p\n", DEVNAME(sd->sd_sc),
        !           301:            ccb);
        !           302:
        !           303:        return (ccb);
        !           304: }
        !           305:
        !           306: void
        !           307: sr_put_ccb(struct sr_ccb *ccb)
        !           308: {
        !           309:        struct sr_discipline    *sd = ccb->ccb_dis;
        !           310:        int                     s;
        !           311:
        !           312:        DNPRINTF(SR_D_CCB, "%s: sr_put_ccb: %p\n", DEVNAME(sd->sd_sc),
        !           313:            ccb);
        !           314:
        !           315:        s = splbio();
        !           316:
        !           317:        ccb->ccb_wu = NULL;
        !           318:        ccb->ccb_state = SR_CCB_FREE;
        !           319:        ccb->ccb_target = -1;
        !           320:
        !           321:        TAILQ_INSERT_TAIL(&sd->sd_ccb_freeq, ccb, ccb_link);
        !           322:
        !           323:        splx(s);
        !           324: }
        !           325:
        !           326: int
        !           327: sr_alloc_wu(struct sr_discipline *sd)
        !           328: {
        !           329:        struct sr_workunit      *wu;
        !           330:        int                     i, no_wu;
        !           331:
        !           332:        if (!sd)
        !           333:                return (1);
        !           334:
        !           335:        DNPRINTF(SR_D_WU, "%s: sr_alloc_wu %p %d\n", DEVNAME(sd->sd_sc),
        !           336:            sd, sd->sd_max_wu);
        !           337:
        !           338:        if (sd->sd_wu)
        !           339:                return (1);
        !           340:
        !           341:        no_wu = sd->sd_max_wu;
        !           342:        sd->sd_wu_pending = no_wu;
        !           343:
        !           344:        sd->sd_wu = malloc(sizeof(struct sr_workunit) * no_wu,
        !           345:            M_DEVBUF, M_WAITOK);
        !           346:        memset(sd->sd_wu, 0, sizeof(struct sr_workunit) * no_wu);
        !           347:        TAILQ_INIT(&sd->sd_wu_freeq);
        !           348:        TAILQ_INIT(&sd->sd_wu_pendq);
        !           349:        TAILQ_INIT(&sd->sd_wu_defq);
        !           350:        for (i = 0; i < no_wu; i++) {
        !           351:                wu = &sd->sd_wu[i];
        !           352:                wu->swu_dis = sd;
        !           353:                sr_put_wu(wu);
        !           354:        }
        !           355:
        !           356:        return (0);
        !           357: }
        !           358:
        !           359: void
        !           360: sr_free_wu(struct sr_discipline *sd)
        !           361: {
        !           362:        struct sr_workunit      *wu;
        !           363:
        !           364:        if (!sd)
        !           365:                return;
        !           366:
        !           367:        DNPRINTF(SR_D_WU, "%s: sr_free_wu %p\n", DEVNAME(sd->sd_sc), sd);
        !           368:
        !           369:        while ((wu = TAILQ_FIRST(&sd->sd_wu_freeq)) != NULL)
        !           370:                TAILQ_REMOVE(&sd->sd_wu_freeq, wu, swu_link);
        !           371:        while ((wu = TAILQ_FIRST(&sd->sd_wu_pendq)) != NULL)
        !           372:                TAILQ_REMOVE(&sd->sd_wu_pendq, wu, swu_link);
        !           373:        while ((wu = TAILQ_FIRST(&sd->sd_wu_defq)) != NULL)
        !           374:                TAILQ_REMOVE(&sd->sd_wu_defq, wu, swu_link);
        !           375:
        !           376:        if (sd->sd_wu)
        !           377:                free(sd->sd_wu, M_DEVBUF);
        !           378: }
        !           379:
        !           380: void
        !           381: sr_put_wu(struct sr_workunit *wu)
        !           382: {
        !           383:        struct sr_discipline    *sd = wu->swu_dis;
        !           384:        struct sr_ccb           *ccb;
        !           385:
        !           386:        int                     s;
        !           387:
        !           388:        DNPRINTF(SR_D_WU, "%s: sr_put_wu: %p\n", DEVNAME(sd->sd_sc), wu);
        !           389:
        !           390:        s = splbio();
        !           391:
        !           392:        wu->swu_xs = NULL;
        !           393:        wu->swu_state = SR_WU_FREE;
        !           394:        wu->swu_ios_complete = 0;
        !           395:        wu->swu_ios_failed = 0;
        !           396:        wu->swu_ios_succeeded = 0;
        !           397:        wu->swu_io_count = 0;
        !           398:        wu->swu_blk_start = 0;
        !           399:        wu->swu_blk_end = 0;
        !           400:        wu->swu_collider = NULL;
        !           401:        wu->swu_fake = 0;
        !           402:
        !           403:        while ((ccb = TAILQ_FIRST(&wu->swu_ccb)) != NULL) {
        !           404:                TAILQ_REMOVE(&wu->swu_ccb, ccb, ccb_link);
        !           405:                sr_put_ccb(ccb);
        !           406:        }
        !           407:        TAILQ_INIT(&wu->swu_ccb);
        !           408:
        !           409:        TAILQ_INSERT_TAIL(&sd->sd_wu_freeq, wu, swu_link);
        !           410:        sd->sd_wu_pending--;
        !           411:
        !           412:        splx(s);
        !           413: }
        !           414:
        !           415: struct sr_workunit *
        !           416: sr_get_wu(struct sr_discipline *sd)
        !           417: {
        !           418:        struct sr_workunit      *wu;
        !           419:        int                     s;
        !           420:
        !           421:        s = splbio();
        !           422:
        !           423:        wu = TAILQ_FIRST(&sd->sd_wu_freeq);
        !           424:        if (wu) {
        !           425:                TAILQ_REMOVE(&sd->sd_wu_freeq, wu, swu_link);
        !           426:                wu->swu_state = SR_WU_INPROGRESS;
        !           427:        }
        !           428:        sd->sd_wu_pending++;
        !           429:
        !           430:        splx(s);
        !           431:
        !           432:        DNPRINTF(SR_D_WU, "%s: sr_get_wu: %p\n", DEVNAME(sd->sd_sc), wu);
        !           433:
        !           434:        return (wu);
        !           435: }
        !           436:
        !           437: int
        !           438: sr_scsi_cmd(struct scsi_xfer *xs)
        !           439: {
        !           440:        int                     s;
        !           441:        struct scsi_link        *link = xs->sc_link;
        !           442:        struct sr_softc         *sc = link->adapter_softc;
        !           443:        struct sr_workunit      *wu;
        !           444:        struct sr_discipline    *sd;
        !           445:
        !           446:        DNPRINTF(SR_D_CMD, "%s: sr_scsi_cmd: scsibus%d xs: %p "
        !           447:            "flags: %#x\n", DEVNAME(sc), link->scsibus, xs, xs->flags);
        !           448:
        !           449:        sd = sc->sc_dis[link->scsibus];
        !           450:        if (sd == NULL) {
        !           451:                s = splhigh();
        !           452:                sd = sc->sc_attach_dis;
        !           453:                splx(s);
        !           454:
        !           455:                DNPRINTF(SR_D_CMD, "%s: sr_scsi_cmd: attaching %p\n",
        !           456:                    DEVNAME(sc), sd);
        !           457:                if (sd == NULL) {
        !           458:                        wu = NULL;
        !           459:                        printf("%s: sr_scsi_cmd NULL discipline\n",
        !           460:                            DEVNAME(sc));
        !           461:                        goto stuffup;
        !           462:                }
        !           463:        }
        !           464:
        !           465:        if ((wu = sr_get_wu(sd)) == NULL) {
        !           466:                DNPRINTF(SR_D_CMD, "%s: sr_scsi_cmd no wu\n", DEVNAME(sc));
        !           467:                return (TRY_AGAIN_LATER);
        !           468:        }
        !           469:
        !           470:        xs->error = XS_NOERROR;
        !           471:        wu->swu_xs = xs;
        !           472:
        !           473:        switch (xs->cmd->opcode) {
        !           474:        case READ_COMMAND:
        !           475:        case READ_BIG:
        !           476:        case WRITE_COMMAND:
        !           477:        case WRITE_BIG:
        !           478:                DNPRINTF(SR_D_CMD, "%s: sr_scsi_cmd: READ/WRITE %02x\n",
        !           479:                    DEVNAME(sc), xs->cmd->opcode);
        !           480:                if (sd->sd_scsi_rw(wu))
        !           481:                        goto stuffup;
        !           482:                break;
        !           483:
        !           484:        case SYNCHRONIZE_CACHE:
        !           485:                DNPRINTF(SR_D_CMD, "%s: sr_scsi_cmd: SYNCHRONIZE_CACHE\n",
        !           486:                    DEVNAME(sc));
        !           487:                if (sd->sd_scsi_sync(wu))
        !           488:                        goto stuffup;
        !           489:                goto complete;
        !           490:
        !           491:        case TEST_UNIT_READY:
        !           492:                DNPRINTF(SR_D_CMD, "%s: sr_scsi_cmd: TEST_UNIT_READY\n",
        !           493:                    DEVNAME(sc));
        !           494:                if (sd->sd_scsi_tur(wu))
        !           495:                        goto stuffup;
        !           496:                goto complete;
        !           497:
        !           498:        case START_STOP:
        !           499:                DNPRINTF(SR_D_CMD, "%s: sr_scsi_cmd: START_STOP\n",
        !           500:                    DEVNAME(sc));
        !           501:                if (sd->sd_scsi_start_stop(wu))
        !           502:                        goto stuffup;
        !           503:                goto complete;
        !           504:
        !           505:        case INQUIRY:
        !           506:                DNPRINTF(SR_D_CMD, "%s: sr_scsi_cmd: INQUIRY\n",
        !           507:                    DEVNAME(sc));
        !           508:                if (sd->sd_scsi_inquiry(wu))
        !           509:                        goto stuffup;
        !           510:                goto complete;
        !           511:
        !           512:        case READ_CAPACITY:
        !           513:                DNPRINTF(SR_D_CMD, "%s: sr_scsi_cmd READ CAPACITY\n",
        !           514:                    DEVNAME(sc));
        !           515:                if (sd->sd_scsi_read_cap(wu))
        !           516:                        goto stuffup;
        !           517:                goto complete;
        !           518:
        !           519:        case REQUEST_SENSE:
        !           520:                DNPRINTF(SR_D_CMD, "%s: sr_scsi_cmd REQUEST SENSE\n",
        !           521:                    DEVNAME(sc));
        !           522:                if (sd->sd_scsi_req_sense(wu))
        !           523:                        goto stuffup;
        !           524:                goto complete;
        !           525:
        !           526:        default:
        !           527:                DNPRINTF(SR_D_CMD, "%s: unsupported scsi command %x\n",
        !           528:                    DEVNAME(sc), xs->cmd->opcode);
        !           529:                /* XXX might need to add generic function to handle others */
        !           530:                goto stuffup;
        !           531:        }
        !           532:
        !           533:        return (SUCCESSFULLY_QUEUED);
        !           534: stuffup:
        !           535:        if (sd->sd_scsi_sense.error_code) {
        !           536:                xs->error = XS_SENSE;
        !           537:                bcopy(&sd->sd_scsi_sense, &xs->sense, sizeof(xs->sense));
        !           538:                bzero(&sd->sd_scsi_sense, sizeof(sd->sd_scsi_sense));
        !           539:        } else {
        !           540:                xs->error = XS_DRIVER_STUFFUP;
        !           541:                xs->flags |= ITSDONE;
        !           542:        }
        !           543: complete:
        !           544:        s = splbio();
        !           545:        scsi_done(xs);
        !           546:        splx(s);
        !           547:        if (wu)
        !           548:                sr_put_wu(wu);
        !           549:        return (COMPLETE);
        !           550: }
        !           551: int
        !           552: sr_scsi_ioctl(struct scsi_link *link, u_long cmd, caddr_t addr, int flag,
        !           553:     struct proc *p)
        !           554: {
        !           555:        DNPRINTF(SR_D_IOCTL, "%s: sr_scsi_ioctl cmd: %#x\n",
        !           556:            DEVNAME((struct sr_softc *)link->adapter_softc), cmd);
        !           557:
        !           558:        return (sr_ioctl(link->adapter_softc, cmd, addr));
        !           559: }
        !           560:
        !           561: int
        !           562: sr_ioctl(struct device *dev, u_long cmd, caddr_t addr)
        !           563: {
        !           564:        struct sr_softc         *sc = (struct sr_softc *)dev;
        !           565:        int                     rv = 0;
        !           566:
        !           567:        DNPRINTF(SR_D_IOCTL, "%s: sr_ioctl ", DEVNAME(sc));
        !           568:
        !           569:        rw_enter_write(&sc->sc_lock);
        !           570:
        !           571:        switch (cmd) {
        !           572:        case BIOCINQ:
        !           573:                DNPRINTF(SR_D_IOCTL, "inq\n");
        !           574:                rv = sr_ioctl_inq(sc, (struct bioc_inq *)addr);
        !           575:                break;
        !           576:
        !           577:        case BIOCVOL:
        !           578:                DNPRINTF(SR_D_IOCTL, "vol\n");
        !           579:                rv = sr_ioctl_vol(sc, (struct bioc_vol *)addr);
        !           580:                break;
        !           581:
        !           582:        case BIOCDISK:
        !           583:                DNPRINTF(SR_D_IOCTL, "disk\n");
        !           584:                rv = sr_ioctl_disk(sc, (struct bioc_disk *)addr);
        !           585:                break;
        !           586:
        !           587:        case BIOCALARM:
        !           588:                DNPRINTF(SR_D_IOCTL, "alarm\n");
        !           589:                /*rv = sr_ioctl_alarm(sc, (struct bioc_alarm *)addr); */
        !           590:                break;
        !           591:
        !           592:        case BIOCBLINK:
        !           593:                DNPRINTF(SR_D_IOCTL, "blink\n");
        !           594:                /*rv = sr_ioctl_blink(sc, (struct bioc_blink *)addr); */
        !           595:                break;
        !           596:
        !           597:        case BIOCSETSTATE:
        !           598:                DNPRINTF(SR_D_IOCTL, "setstate\n");
        !           599:                rv = sr_ioctl_setstate(sc, (struct bioc_setstate *)addr);
        !           600:                break;
        !           601:
        !           602:        case BIOCCREATERAID:
        !           603:                DNPRINTF(SR_D_IOCTL, "createraid\n");
        !           604:                rv = sr_ioctl_createraid(sc, (struct bioc_createraid *)addr, 1);
        !           605:                break;
        !           606:
        !           607:        default:
        !           608:                DNPRINTF(SR_D_IOCTL, "invalid ioctl\n");
        !           609:                rv = EINVAL;
        !           610:        }
        !           611:
        !           612:        rw_exit_write(&sc->sc_lock);
        !           613:
        !           614:        return (rv);
        !           615: }
        !           616:
        !           617: int
        !           618: sr_ioctl_inq(struct sr_softc *sc, struct bioc_inq *bi)
        !           619: {
        !           620:        int                     i, vol, disk;
        !           621:
        !           622:        for (i = 0, vol = 0, disk = 0; i < SR_MAXSCSIBUS; i++)
        !           623:                /* XXX this will not work when we stagger disciplines */
        !           624:                if (sc->sc_dis[i]) {
        !           625:                        vol++;
        !           626:                        disk += sc->sc_dis[i]->sd_vol.sv_meta.svm_no_chunk;
        !           627:                }
        !           628:
        !           629:        strlcpy(bi->bi_dev, sc->sc_dev.dv_xname, sizeof(bi->bi_dev));
        !           630:        bi->bi_novol = vol;
        !           631:        bi->bi_nodisk = disk;
        !           632:
        !           633:        return (0);
        !           634: }
        !           635:
        !           636: int
        !           637: sr_ioctl_vol(struct sr_softc *sc, struct bioc_vol *bv)
        !           638: {
        !           639:        int                     i, vol, rv = EINVAL;
        !           640:        struct sr_volume        *sv;
        !           641:
        !           642:        for (i = 0, vol = -1; i < SR_MAXSCSIBUS; i++) {
        !           643:                /* XXX this will not work when we stagger disciplines */
        !           644:                if (sc->sc_dis[i])
        !           645:                        vol++;
        !           646:                if (vol != bv->bv_volid)
        !           647:                        continue;
        !           648:
        !           649:                sv = &sc->sc_dis[i]->sd_vol;
        !           650:                bv->bv_status = sv->sv_meta.svm_status;
        !           651:                bv->bv_size = sv->sv_meta.svm_size;
        !           652:                bv->bv_level = sv->sv_meta.svm_level;
        !           653:                bv->bv_nodisk = sv->sv_meta.svm_no_chunk;
        !           654:                strlcpy(bv->bv_dev, sv->sv_meta.svm_devname,
        !           655:                    sizeof(bv->bv_dev));
        !           656:                strlcpy(bv->bv_vendor, sv->sv_meta.svm_vendor,
        !           657:                    sizeof(bv->bv_vendor));
        !           658:                rv = 0;
        !           659:                break;
        !           660:        }
        !           661:
        !           662:        return (rv);
        !           663: }
        !           664:
        !           665: int
        !           666: sr_ioctl_disk(struct sr_softc *sc, struct bioc_disk *bd)
        !           667: {
        !           668:        int                     i, vol, rv = EINVAL, id;
        !           669:        struct sr_chunk         *src;
        !           670:
        !           671:        for (i = 0, vol = -1; i < SR_MAXSCSIBUS; i++) {
        !           672:                /* XXX this will not work when we stagger disciplines */
        !           673:                if (sc->sc_dis[i])
        !           674:                        vol++;
        !           675:                if (vol != bd->bd_volid)
        !           676:                        continue;
        !           677:
        !           678:                id = bd->bd_diskid;
        !           679:                if (id >= sc->sc_dis[i]->sd_vol.sv_meta.svm_no_chunk)
        !           680:                        break;
        !           681:
        !           682:                src = sc->sc_dis[i]->sd_vol.sv_chunks[id];
        !           683:                bd->bd_status = src->src_meta.scm_status;
        !           684:                bd->bd_size = src->src_meta.scm_size;
        !           685:                bd->bd_channel = vol;
        !           686:                bd->bd_target = id;
        !           687:                strlcpy(bd->bd_vendor, src->src_meta.scm_devname,
        !           688:                    sizeof(bd->bd_vendor));
        !           689:                rv = 0;
        !           690:                break;
        !           691:        }
        !           692:
        !           693:        return (rv);
        !           694: }
        !           695:
        !           696: int
        !           697: sr_ioctl_setstate(struct sr_softc *sc, struct bioc_setstate *bs)
        !           698: {
        !           699:        int                     rv = EINVAL;
        !           700:
        !           701: #ifdef SR_UNIT_TEST
        !           702:        int                     i, vol, state;
        !           703:        struct sr_discipline    *sd;
        !           704:
        !           705:        for (i = 0, vol = -1; i < SR_MAXSCSIBUS; i++) {
        !           706:                /* XXX this will not work when we stagger disciplines */
        !           707:                if (sc->sc_dis[i])
        !           708:                        vol++;
        !           709:                if (vol != bs->bs_channel)
        !           710:                        continue;
        !           711:
        !           712:                sd = sc->sc_dis[vol];
        !           713:                if (bs->bs_target >= sd->sd_vol.sv_meta.svm_no_chunk)
        !           714:                        goto done;
        !           715:
        !           716:                switch (bs->bs_status) {
        !           717:                case BIOC_SSONLINE:
        !           718:                        state = BIOC_SDONLINE;
        !           719:                        break;
        !           720:                case BIOC_SSOFFLINE:
        !           721:                        state = BIOC_SDOFFLINE;
        !           722:                        break;
        !           723:                case BIOC_SSHOTSPARE:
        !           724:                        state = BIOC_SDHOTSPARE;
        !           725:                        break;
        !           726:                case BIOC_SSREBUILD:
        !           727:                        state = BIOC_SDREBUILD;
        !           728:                        break;
        !           729:                default:
        !           730:                        printf("invalid state %d\n", bs->bs_status);
        !           731:                        goto done;
        !           732:                }
        !           733:
        !           734:                printf("status change for %u:%u -> %u %u\n",
        !           735:                    bs->bs_channel, bs->bs_target, bs->bs_status, state);
        !           736:
        !           737:                sd->sd_set_chunk_state(sd, bs->bs_target, bs->bs_status);
        !           738:
        !           739:                rv = 0;
        !           740:
        !           741:                break;
        !           742:        }
        !           743:
        !           744: done:
        !           745: #endif
        !           746:        return (rv);
        !           747: }
        !           748:
        !           749: int
        !           750: sr_ioctl_createraid(struct sr_softc *sc, struct bioc_createraid *bc, int user)
        !           751: {
        !           752:        dev_t                   *dt;
        !           753:        int                     i, s, no_chunk, rv = EINVAL, vol;
        !           754:        int                     no_meta, updatemeta = 0;
        !           755:        int64_t                 vol_size;
        !           756:        struct sr_chunk_head    *cl;
        !           757:        struct sr_discipline    *sd = NULL;
        !           758:        struct sr_chunk         *ch_entry;
        !           759:        struct device           *dev, *dev2;
        !           760:        struct scsibus_attach_args saa;
        !           761:
        !           762:        DNPRINTF(SR_D_IOCTL, "%s: sr_ioctl_createraid(%d)\n",
        !           763:            DEVNAME(sc), user);
        !           764:
        !           765:        /* user input */
        !           766:        if (bc->bc_dev_list_len > BIOC_CRMAXLEN)
        !           767:                goto unwind;
        !           768:
        !           769:        dt = malloc(bc->bc_dev_list_len, M_DEVBUF, M_WAITOK);
        !           770:        bzero(dt, bc->bc_dev_list_len);
        !           771:        if (user)
        !           772:                copyin(bc->bc_dev_list, dt, bc->bc_dev_list_len);
        !           773:        else
        !           774:                bcopy(bc->bc_dev_list, dt, bc->bc_dev_list_len);
        !           775:
        !           776:        sd = malloc(sizeof(struct sr_discipline), M_DEVBUF, M_WAITOK);
        !           777:        memset(sd, 0, sizeof(struct sr_discipline));
        !           778:        sd->sd_sc = sc;
        !           779:
        !           780:        no_chunk = bc->bc_dev_list_len / sizeof(dev_t);
        !           781:        cl = &sd->sd_vol.sv_chunk_list;
        !           782:        SLIST_INIT(cl);
        !           783:        if (sr_open_chunks(sc, cl, dt, no_chunk))
        !           784:                goto unwind;
        !           785:
        !           786:        /* in memory copy of metadata */
        !           787:        sd->sd_meta = malloc(SR_META_SIZE * 512 , M_DEVBUF, M_WAITOK);
        !           788:        bzero(sd->sd_meta, SR_META_SIZE  * 512);
        !           789:
        !           790:        /* we have a valid list now create an array index */
        !           791:        sd->sd_vol.sv_chunks = malloc(sizeof(struct sr_chunk *) * no_chunk,
        !           792:            M_DEVBUF, M_WAITOK);
        !           793:        bzero(sd->sd_vol.sv_chunks, sizeof(struct sr_chunk *) * no_chunk);
        !           794:
        !           795:        /* force the raid volume by clearing metadata region */
        !           796:        if (bc->bc_flags & BIOC_SCFORCE) {
        !           797:                /* make sure disk isn't up and running */
        !           798:                if (sr_read_meta(sd))
        !           799:                        if (sr_already_assembled(sd)) {
        !           800:                                printf("%s: disk ", DEVNAME(sc));
        !           801:                                sr_print_uuid(&sd->sd_meta->ssd_uuid, 0);
        !           802:                                printf(" is currently in use; can't force "
        !           803:                                    "create\n");
        !           804:                                goto unwind;
        !           805:                        }
        !           806:
        !           807:                /* zero out pointers and metadata again to create disk */
        !           808:                bzero(sd->sd_vol.sv_chunks,
        !           809:                    sizeof(struct sr_chunk *) * no_chunk);
        !           810:                bzero(sd->sd_meta, SR_META_SIZE  * 512);
        !           811:
        !           812:                if (sr_clear_metadata(sd)) {
        !           813:                        printf("%s: failed to clear metadata\n");
        !           814:                        goto unwind;
        !           815:                }
        !           816:        }
        !           817:
        !           818:        if ((no_meta = sr_read_meta(sd)) == 0) {
        !           819:                /* no metadata available */
        !           820:                switch (bc->bc_level) {
        !           821:                case 1:
        !           822:                        if (no_chunk < 2)
        !           823:                                goto unwind;
        !           824:                        strlcpy(sd->sd_name, "RAID 1", sizeof(sd->sd_name));
        !           825:                        break;
        !           826: #if 0
        !           827:                case 'c':
        !           828:                        if (no_chunk != 1)
        !           829:                                goto unwind;
        !           830:                        strlcpy(sd->sd_name, "RAID C", sizeof(sd->sd_name));
        !           831:                        break;
        !           832: #endif
        !           833:                default:
        !           834:                        goto unwind;
        !           835:                }
        !           836:
        !           837:                /* fill out chunk array */
        !           838:                i = 0;
        !           839:                SLIST_FOREACH(ch_entry, cl, src_link)
        !           840:                        sd->sd_vol.sv_chunks[i++] = ch_entry;
        !           841:
        !           842:                /* fill out all chunk metadata */
        !           843:                sr_create_chunk_meta(sc, cl);
        !           844:
        !           845:                /* fill out all volume metadata */
        !           846:                ch_entry = SLIST_FIRST(cl);
        !           847:                vol_size = ch_entry->src_meta.scm_coerced_size;
        !           848:                DNPRINTF(SR_D_IOCTL,
        !           849:                    "%s: sr_ioctl_createraid: vol_size: %lld\n",
        !           850:                    DEVNAME(sc), vol_size);
        !           851:                sd->sd_vol.sv_meta.svm_no_chunk = no_chunk;
        !           852:                sd->sd_vol.sv_meta.svm_size = vol_size;
        !           853:                sd->sd_vol.sv_meta.svm_status = BIOC_SVONLINE;
        !           854:                sd->sd_vol.sv_meta.svm_level = bc->bc_level;
        !           855:                strlcpy(sd->sd_vol.sv_meta.svm_vendor, "OPENBSD",
        !           856:                    sizeof(sd->sd_vol.sv_meta.svm_vendor));
        !           857:                snprintf(sd->sd_vol.sv_meta.svm_product,
        !           858:                    sizeof(sd->sd_vol.sv_meta.svm_product), "SR %s",
        !           859:                    sd->sd_name);
        !           860:                snprintf(sd->sd_vol.sv_meta.svm_revision,
        !           861:                    sizeof(sd->sd_vol.sv_meta.svm_revision), "%03d",
        !           862:                    SR_META_VERSION);
        !           863:
        !           864:                sd->sd_meta_flags = bc->bc_flags & BIOC_SCNOAUTOASSEMBLE;
        !           865:                updatemeta = 1;
        !           866:        } else if (no_meta == no_chunk) {
        !           867:                if (user == 0 && sd->sd_meta_flags & BIOC_SCNOAUTOASSEMBLE) {
        !           868:                        DNPRINTF(SR_D_META, "%s: disk not auto assembled from "
        !           869:                            "metadata\n", DEVNAME(sc));
        !           870:                        goto unwind;
        !           871:                }
        !           872:                if (sr_already_assembled(sd)) {
        !           873:                        printf("%s: disk ", DEVNAME(sc));
        !           874:                        sr_print_uuid(&sd->sd_meta->ssd_uuid, 0);
        !           875:                        printf(" already assembled\n");
        !           876:                        goto unwind;
        !           877:                }
        !           878:                DNPRINTF(SR_D_META, "%s: disk assembled from metadata\n",
        !           879:                    DEVNAME(sc));
        !           880:                updatemeta = 0;
        !           881:        } else {
        !           882:                if (sr_already_assembled(sd)) {
        !           883:                        printf("%s: disk ", DEVNAME(sc));
        !           884:                        sr_print_uuid(&sd->sd_meta->ssd_uuid, 0);
        !           885:                        printf(" already assembled; will not partial "
        !           886:                            "assemble it\n");
        !           887:                        goto unwind;
        !           888:                }
        !           889:                printf("%s: not yet partial bringup\n", DEVNAME(sc));
        !           890:                goto unwind;
        !           891:        }
        !           892:
        !           893:        /* XXX metadata SHALL be fully filled in at this point */
        !           894:
        !           895:        switch (bc->bc_level) {
        !           896:        case 1:
        !           897:                /* fill out discipline members */
        !           898:                sd->sd_type = SR_MD_RAID1;
        !           899:                sd->sd_max_ccb_per_wu = no_chunk;
        !           900:                sd->sd_max_wu = SR_RAID1_NOWU;
        !           901:
        !           902:                /* setup discipline pointers */
        !           903:                sd->sd_alloc_resources = sr_raid1_alloc_resources;
        !           904:                sd->sd_free_resources = sr_raid1_free_resources;
        !           905:                sd->sd_scsi_inquiry = sr_raid_inquiry;
        !           906:                sd->sd_scsi_read_cap = sr_raid_read_cap;
        !           907:                sd->sd_scsi_tur = sr_raid_tur;
        !           908:                sd->sd_scsi_req_sense = sr_raid_request_sense;
        !           909:                sd->sd_scsi_start_stop = sr_raid_start_stop;
        !           910:                sd->sd_scsi_sync = sr_raid_sync;
        !           911:                sd->sd_scsi_rw = sr_raid1_rw;
        !           912:                sd->sd_set_chunk_state = sr_raid_set_chunk_state;
        !           913:                sd->sd_set_vol_state = sr_raid_set_vol_state;
        !           914:                break;
        !           915: #ifdef CRYPTO
        !           916:        case 'c':
        !           917:                /* fill out discipline members */
        !           918:                sd->sd_type = SR_MD_RAIDC;
        !           919:                sd->sd_max_ccb_per_wu = no_chunk;
        !           920:                sd->sd_max_wu = SR_RAIDC_NOWU;
        !           921:
        !           922:                /* setup discipline pointers */
        !           923:                sd->sd_alloc_resources = sr_raidc_alloc_resources;
        !           924:                sd->sd_free_resources = sr_raidc_free_resources;
        !           925:                sd->sd_scsi_inquiry = sr_raid_inquiry;
        !           926:                sd->sd_scsi_read_cap = sr_raid_read_cap;
        !           927:                sd->sd_scsi_tur = sr_raid_tur;
        !           928:                sd->sd_scsi_req_sense = sr_raid_request_sense;
        !           929:                sd->sd_scsi_start_stop = sr_raid_start_stop;
        !           930:                sd->sd_scsi_sync = sr_raid_sync;
        !           931:                sd->sd_scsi_rw = sr_raidc_rw;
        !           932:                sd->sd_set_chunk_state = sr_raid_set_chunk_state;
        !           933:                sd->sd_set_vol_state = sr_raid_set_vol_state;
        !           934:                break;
        !           935: #endif
        !           936:        default:
        !           937:                printf("default %d\n", bc->bc_level);
        !           938:                goto unwind;
        !           939:        }
        !           940:
        !           941:        /* allocate all resources */
        !           942:        if ((rv = sd->sd_alloc_resources(sd)))
        !           943:                goto unwind;
        !           944:
        !           945:        /* setup scsi midlayer */
        !           946:        sd->sd_link.openings = sd->sd_max_wu;
        !           947:        sd->sd_link.device = &sr_dev;
        !           948:        sd->sd_link.device_softc = sc;
        !           949:        sd->sd_link.adapter_softc = sc;
        !           950:        sd->sd_link.adapter = &sr_switch;
        !           951:        sd->sd_link.adapter_target = SR_MAX_LD;
        !           952:        sd->sd_link.adapter_buswidth = 1;
        !           953:        bzero(&saa, sizeof(saa));
        !           954:        saa.saa_sc_link = &sd->sd_link;
        !           955:
        !           956:        /* we passed all checks return ENXIO if volume can't be created */
        !           957:        rv = ENXIO;
        !           958:
        !           959:        /* clear sense data */
        !           960:        bzero(&sd->sd_scsi_sense, sizeof(sd->sd_scsi_sense));
        !           961:
        !           962:        /* use temporary discipline pointer */
        !           963:        s = splhigh();
        !           964:        sc->sc_attach_dis = sd;
        !           965:        splx(s);
        !           966:        dev2 = config_found(&sc->sc_dev, &saa, scsiprint);
        !           967:        s = splhigh();
        !           968:        sc->sc_attach_dis = NULL;
        !           969:        splx(s);
        !           970:        TAILQ_FOREACH(dev, &alldevs, dv_list)
        !           971:                if (dev->dv_parent == dev2)
        !           972:                        break;
        !           973:        if (dev == NULL)
        !           974:                goto unwind;
        !           975:
        !           976:        DNPRINTF(SR_D_IOCTL, "%s: sr device added: %s on scsibus%d\n",
        !           977:            DEVNAME(sc), dev->dv_xname, sd->sd_link.scsibus);
        !           978:
        !           979:        sc->sc_dis[sd->sd_link.scsibus] = sd;
        !           980:        for (i = 0, vol = -1; i <= sd->sd_link.scsibus; i++)
        !           981:                if (sc->sc_dis[i])
        !           982:                        vol++;
        !           983:
        !           984:        rv = 0;
        !           985:        if (updatemeta) {
        !           986:                /* fill out remaining volume metadata */
        !           987:                sd->sd_vol.sv_meta.svm_volid = vol;
        !           988:                strlcpy(sd->sd_vol.sv_meta.svm_devname, dev->dv_xname,
        !           989:                    sizeof(sd->sd_vol.sv_meta.svm_devname));
        !           990:
        !           991:        }
        !           992:
        !           993:        /* save metadata to disk */
        !           994:        rv = sr_save_metadata(sd, SR_VOL_DIRTY);
        !           995:
        !           996: #ifndef SMALL_KERNEL
        !           997:        if (sr_create_sensors(sd))
        !           998:                printf("%s: unable to create sensor for %s\n", DEVNAME(sc),
        !           999:                    dev->dv_xname);
        !          1000:        else
        !          1001:                sd->sd_vol.sv_sensor_valid = 1;
        !          1002: #endif /* SMALL_KERNEL */
        !          1003:
        !          1004:        sd->sd_scsibus_dev = dev2;
        !          1005:        sd->sd_shutdownhook = shutdownhook_establish(sr_shutdown, sd);
        !          1006:
        !          1007:        return (rv);
        !          1008:
        !          1009: unwind:
        !          1010:        sr_shutdown_discipline(sd);
        !          1011:
        !          1012:        return (rv);
        !          1013: }
        !          1014:
        !          1015: int
        !          1016: sr_open_chunks(struct sr_softc *sc, struct sr_chunk_head *cl, dev_t *dt,
        !          1017:     int no_chunk)
        !          1018: {
        !          1019:        struct sr_chunk         *ch_entry, *ch_prev = NULL;
        !          1020:        struct disklabel        label;
        !          1021:        struct bdevsw           *bdsw;
        !          1022:        char                    *name;
        !          1023:        int                     maj, unit, part, i, error;
        !          1024:        daddr64_t               size;
        !          1025:        dev_t                   dev;
        !          1026:
        !          1027:        DNPRINTF(SR_D_IOCTL, "%s: sr_open_chunks(%d)\n", DEVNAME(sc), no_chunk);
        !          1028:
        !          1029:        /* fill out chunk list */
        !          1030:        for (i = 0; i < no_chunk; i++) {
        !          1031:                ch_entry = malloc(sizeof(struct sr_chunk), M_DEVBUF, M_WAITOK);
        !          1032:                bzero(ch_entry, sizeof(struct sr_chunk));
        !          1033:                /* keep disks in user supplied order */
        !          1034:                if (ch_prev)
        !          1035:                        SLIST_INSERT_AFTER(ch_prev, ch_entry, src_link);
        !          1036:                else
        !          1037:                        SLIST_INSERT_HEAD(cl, ch_entry, src_link);
        !          1038:                ch_prev = ch_entry;
        !          1039:
        !          1040:                dev = dt[i];
        !          1041:                maj = major(dev);
        !          1042:                part = DISKPART(dev);
        !          1043:                unit = DISKUNIT(dev);
        !          1044:                bdsw = &bdevsw[maj];
        !          1045:
        !          1046:                name = findblkname(maj);
        !          1047:                if (name == NULL)
        !          1048:                        goto unwind;
        !          1049:
        !          1050:                snprintf(ch_entry->src_devname, sizeof(ch_entry->src_devname),
        !          1051:                    "%s%d%c", name, unit, part + 'a');
        !          1052:                name = ch_entry->src_devname;
        !          1053:
        !          1054:                /* open device */
        !          1055:                error = bdsw->d_open(dev, FREAD | FWRITE , S_IFBLK, curproc);
        !          1056:
        !          1057:                /* get disklabel */
        !          1058:                error = bdsw->d_ioctl(dev, DIOCGDINFO, (void *)&label,
        !          1059:                    0, NULL);
        !          1060:                if (error) {
        !          1061:                        printf("%s: %s can't obtain disklabel\n",
        !          1062:                            DEVNAME(sc), name);
        !          1063:                        bdsw->d_close(dev, FWRITE, S_IFBLK, curproc);
        !          1064:                        goto unwind;
        !          1065:                }
        !          1066:
        !          1067:                /* make sure the partition is of the right type */
        !          1068:                if (label.d_partitions[part].p_fstype != FS_RAID) {
        !          1069:                        printf("%s: %s partition not of type RAID (%d)\n",
        !          1070:                            DEVNAME(sc), name,
        !          1071:                            label.d_partitions[part].p_fstype);
        !          1072:                        bdsw->d_close(dev, FWRITE, S_IFBLK, curproc);
        !          1073:                        goto unwind;
        !          1074:                }
        !          1075:
        !          1076:                /* get partition size */
        !          1077:                ch_entry->src_size = size = DL_GETPSIZE(&label.d_partitions[part]) -
        !          1078:                    SR_META_SIZE - SR_META_OFFSET;
        !          1079:                if (size <= 0) {
        !          1080:                        printf("%s: %s partition too small\n",
        !          1081:                            DEVNAME(sc), name);
        !          1082:                        bdsw->d_close(dev, FWRITE, S_IFBLK, curproc);
        !          1083:                        goto unwind;
        !          1084:                }
        !          1085:
        !          1086:
        !          1087:                ch_entry->src_dev_mm = dev; /* major/minor */
        !          1088:
        !          1089:                DNPRINTF(SR_D_IOCTL, "%s: found %s size %d\n", DEVNAME(sc),
        !          1090:                    name, size);
        !          1091:        }
        !          1092:
        !          1093:        return (0);
        !          1094: unwind:
        !          1095:        printf("%s: invalid device: %s\n", DEVNAME(sc), name ? name : "nodev");
        !          1096:        return (1);
        !          1097: }
        !          1098:
        !          1099: int
        !          1100: sr_read_meta(struct sr_discipline *sd)
        !          1101: {
        !          1102:        struct sr_softc         *sc = sd->sd_sc;
        !          1103:        struct sr_chunk_head    *cl = &sd->sd_vol.sv_chunk_list;
        !          1104:        struct sr_metadata      *sm = sd->sd_meta, *m;
        !          1105:        struct sr_chunk         *ch_entry;
        !          1106:        struct buf              b;
        !          1107:        struct sr_vol_meta      *mv;
        !          1108:        struct sr_chunk_meta    *mc;
        !          1109:        size_t                  sz = SR_META_SIZE * 512;
        !          1110:        int                     no_chunk = 0;
        !          1111:        u_int32_t               volid, ondisk = 0, cid;
        !          1112:
        !          1113:        DNPRINTF(SR_D_META, "%s: sr_read_meta\n", DEVNAME(sc));
        !          1114:
        !          1115:        m = malloc(sz , M_DEVBUF, M_WAITOK);
        !          1116:        bzero(m, sz);
        !          1117:
        !          1118:        SLIST_FOREACH(ch_entry, cl, src_link) {
        !          1119:                bzero(&b, sizeof(b));
        !          1120:
        !          1121:                b.b_flags = B_READ;
        !          1122:                b.b_blkno = SR_META_OFFSET;
        !          1123:                b.b_bcount = sz;
        !          1124:                b.b_bufsize = sz;
        !          1125:                b.b_resid = sz;
        !          1126:                b.b_data = (void *)m;
        !          1127:                b.b_error = 0;
        !          1128:                b.b_proc = curproc;
        !          1129:                b.b_dev = ch_entry->src_dev_mm;
        !          1130:                b.b_vp = NULL;
        !          1131:                b.b_iodone = NULL;
        !          1132:                LIST_INIT(&b.b_dep);
        !          1133:                bdevsw_lookup(b.b_dev)->d_strategy(&b);
        !          1134:                biowait(&b);
        !          1135:
        !          1136:                /* XXX mark chunk offline and restart metadata write */
        !          1137:                if (b.b_flags & B_ERROR) {
        !          1138:                        printf("%s: %s i/o error on block %d while reading "
        !          1139:                            "metadata %d\n", DEVNAME(sc),
        !          1140:                            ch_entry->src_devname, b.b_blkno, b.b_error);
        !          1141:                        continue;
        !          1142:                }
        !          1143:
        !          1144:                if (m->ssd_magic != SR_MAGIC)
        !          1145:                        continue;
        !          1146:
        !          1147:                /* validate metadata */
        !          1148:                if (sr_validate_metadata(sc, ch_entry->src_dev_mm, m)) {
        !          1149:                        printf("%s: invalid metadata\n", DEVNAME(sc));
        !          1150:                        no_chunk = -1;
        !          1151:                        goto bad;
        !          1152:                }
        !          1153:
        !          1154:                mv = (struct sr_vol_meta *)(m + 1);
        !          1155:                mc = (struct sr_chunk_meta *)(mv + 1);
        !          1156:
        !          1157:                /* we asssume that the first chunk has the initial metadata */
        !          1158:                if (no_chunk++ == 0) {
        !          1159:                        bcopy(m, sm, sz);
        !          1160:                        bcopy(m, sd->sd_meta, sizeof(*sd->sd_meta));
        !          1161:                        bcopy(mv, &sd->sd_vol.sv_meta,
        !          1162:                            sizeof(sd->sd_vol.sv_meta));
        !          1163:
        !          1164:                        volid = m->ssd_vd_volid;
        !          1165:                        sd->sd_meta_flags = sm->ssd_flags;
        !          1166:                }
        !          1167:
        !          1168:                if (bcmp(&sm->ssd_uuid, &sd->sd_vol.sv_meta.svm_uuid,
        !          1169:                    sizeof(struct sr_uuid))) {
        !          1170:                        printf("%s: %s invalid chunk uuid ",
        !          1171:                            DEVNAME(sc), ch_entry->src_devname);
        !          1172:                        sr_print_uuid(&sm->ssd_uuid, 0);
        !          1173:                        printf(", expected ");
        !          1174:                        sr_print_uuid(&sd->sd_vol.sv_meta.svm_uuid, 1);
        !          1175:                        no_chunk = -1;
        !          1176:                        goto bad;
        !          1177:                }
        !          1178:
        !          1179:                /* we have meta data on disk */
        !          1180:                ch_entry->src_meta_ondisk = 1;
        !          1181:
        !          1182:                /* make sure we are part of this vd */
        !          1183:                if (volid != m->ssd_vd_volid) {
        !          1184:                        printf("%s: %s invalid volume id %d, expected %d\n",
        !          1185:                            DEVNAME(sc), ch_entry->src_devname,
        !          1186:                            volid, m->ssd_vd_volid);
        !          1187:                        no_chunk = -1;
        !          1188:                        goto bad;
        !          1189:                }
        !          1190:
        !          1191:                if (m->ssd_chunk_id > m->ssd_chunk_no) {
        !          1192:                        printf("%s: %s chunk id out of range %d, expected "
        !          1193:                            "lower than %d\n", DEVNAME(sc),
        !          1194:                            ch_entry->src_devname,
        !          1195:                            m->ssd_chunk_id, m->ssd_chunk_no);
        !          1196:                        no_chunk = -1;
        !          1197:                        goto bad;
        !          1198:                }
        !          1199:
        !          1200:                if (sd->sd_vol.sv_chunks[m->ssd_chunk_id]) {
        !          1201:                        printf("%s: %s chunk id %d already in use\n",
        !          1202:                            DEVNAME(sc), ch_entry->src_devname,
        !          1203:                            m->ssd_chunk_id);
        !          1204:                        no_chunk = -1;
        !          1205:                        goto bad;
        !          1206:                }
        !          1207:
        !          1208:                sd->sd_vol.sv_chunks[m->ssd_chunk_id] = ch_entry;
        !          1209:                bcopy(mc + m->ssd_chunk_id, &ch_entry->src_meta,
        !          1210:                    sizeof(ch_entry->src_meta));
        !          1211:
        !          1212:                if (ondisk == 0) {
        !          1213:                        ondisk = m->ssd_ondisk;
        !          1214:                        cid = m->ssd_chunk_id;
        !          1215:                }
        !          1216:
        !          1217:                if (m->ssd_ondisk != ondisk) {
        !          1218:                        printf("%s: %s chunk id %d contains stale metadata\n",
        !          1219:                            DEVNAME(sc), ch_entry->src_devname,
        !          1220:                            m->ssd_ondisk < ondisk ? m->ssd_chunk_id : cid);
        !          1221:                        no_chunk = -1;
        !          1222:                        goto bad;
        !          1223:                }
        !          1224:        }
        !          1225:
        !          1226:        if (no_chunk != m->ssd_chunk_no) {
        !          1227:                DNPRINTF(SR_D_META, "%s: not enough chunks supplied\n",
        !          1228:                    DEVNAME(sc));
        !          1229:                no_chunk = -1;
        !          1230:                goto bad;
        !          1231:        }
        !          1232:
        !          1233:        DNPRINTF(SR_D_META, "%s: sr_read_meta: found %d elements\n",
        !          1234:            DEVNAME(sc), no_chunk);
        !          1235:
        !          1236:        sr_print_metadata(m);
        !          1237:
        !          1238: bad:
        !          1239:        /* return nr of chunks that contain metadata */
        !          1240:        free(m, M_DEVBUF);
        !          1241:        return (no_chunk);
        !          1242: }
        !          1243:
        !          1244: int
        !          1245: sr_create_chunk_meta(struct sr_softc *sc, struct sr_chunk_head *cl)
        !          1246: {
        !          1247:        struct sr_chunk         *ch_entry;
        !          1248:        struct sr_uuid          uuid;
        !          1249:        int                     rv = 1, cid = 0;
        !          1250:        char                    *name;
        !          1251:        u_int64_t               max_chunk_sz = 0, min_chunk_sz;
        !          1252:
        !          1253:        DNPRINTF(SR_D_IOCTL, "%s: sr_create_chunk_meta\n", DEVNAME(sc));
        !          1254:
        !          1255:        sr_get_uuid(&uuid);
        !          1256:
        !          1257:        /* fill out stuff and get largest chunk size while looping */
        !          1258:        SLIST_FOREACH(ch_entry, cl, src_link) {
        !          1259:                name = ch_entry->src_devname;
        !          1260:                ch_entry->src_meta.scm_size = ch_entry->src_size;
        !          1261:                ch_entry->src_meta.scm_chunk_id = cid++;
        !          1262:                ch_entry->src_meta.scm_status = BIOC_SDONLINE;
        !          1263:                strlcpy(ch_entry->src_meta.scm_devname, name,
        !          1264:                    sizeof(ch_entry->src_meta.scm_devname));
        !          1265:                bcopy(&uuid,  &ch_entry->src_meta.scm_uuid,
        !          1266:                    sizeof(ch_entry->src_meta.scm_uuid));
        !          1267:
        !          1268:                if (ch_entry->src_meta.scm_size > max_chunk_sz)
        !          1269:                        max_chunk_sz = ch_entry->src_meta.scm_size;
        !          1270:        }
        !          1271:
        !          1272:        /* get smallest chunk size */
        !          1273:        min_chunk_sz = max_chunk_sz;
        !          1274:        SLIST_FOREACH(ch_entry, cl, src_link)
        !          1275:                if (ch_entry->src_meta.scm_size < min_chunk_sz)
        !          1276:                        min_chunk_sz = ch_entry->src_meta.scm_size;
        !          1277:
        !          1278:        /* equalize all sizes */
        !          1279:        SLIST_FOREACH(ch_entry, cl, src_link)
        !          1280:                ch_entry->src_meta.scm_coerced_size = min_chunk_sz;
        !          1281:
        !          1282:        /* whine if chunks are not the same size */
        !          1283:        if (min_chunk_sz != max_chunk_sz)
        !          1284:                printf("%s: chunk sizes are not equal; up to %llu blocks "
        !          1285:                    "wasted per chunk\n",
        !          1286:                    DEVNAME(sc), max_chunk_sz - min_chunk_sz);
        !          1287:
        !          1288:        rv = 0;
        !          1289:
        !          1290:        return (rv);
        !          1291: }
        !          1292:
        !          1293: void
        !          1294: sr_unwind_chunks(struct sr_softc *sc, struct sr_chunk_head *cl)
        !          1295: {
        !          1296:        struct sr_chunk         *ch_entry, *ch_next;
        !          1297:        dev_t                   dev;
        !          1298:
        !          1299:        DNPRINTF(SR_D_IOCTL, "%s: sr_unwind_chunks\n", DEVNAME(sc));
        !          1300:
        !          1301:        if (!cl)
        !          1302:                return;
        !          1303:
        !          1304:        for (ch_entry = SLIST_FIRST(cl);
        !          1305:            ch_entry != SLIST_END(cl); ch_entry = ch_next) {
        !          1306:                ch_next = SLIST_NEXT(ch_entry, src_link);
        !          1307:
        !          1308:                dev = ch_entry->src_dev_mm;
        !          1309:
        !          1310:                if (dev != NODEV)
        !          1311:                        bdevsw_lookup(dev)->d_close(dev, FWRITE, S_IFBLK,
        !          1312:                            curproc);
        !          1313:
        !          1314:                free(ch_entry, M_DEVBUF);
        !          1315:        }
        !          1316:        SLIST_INIT(cl);
        !          1317: }
        !          1318:
        !          1319: void
        !          1320: sr_free_discipline(struct sr_discipline *sd)
        !          1321: {
        !          1322: #ifdef SR_DEBUG
        !          1323:        struct sr_softc         *sc = sd->sd_sc;
        !          1324: #endif
        !          1325:        if (!sd)
        !          1326:                return;
        !          1327:
        !          1328:        DNPRINTF(SR_D_DIS, "%s: sr_free_discipline %s\n",
        !          1329:            DEVNAME(sc), sd->sd_vol.sv_meta.svm_devname);
        !          1330:
        !          1331:        if (sd->sd_free_resources)
        !          1332:                sd->sd_free_resources(sd);
        !          1333:        if (sd->sd_vol.sv_chunks)
        !          1334:                free(sd->sd_vol.sv_chunks, M_DEVBUF);
        !          1335:        free(sd, M_DEVBUF);
        !          1336: }
        !          1337:
        !          1338: void
        !          1339: sr_shutdown_discipline(struct sr_discipline *sd)
        !          1340: {
        !          1341:        struct sr_softc         *sc = sd->sd_sc;
        !          1342:        int                     s;
        !          1343:
        !          1344:        if (!sd || !sc)
        !          1345:                return;
        !          1346:
        !          1347:        DNPRINTF(SR_D_DIS, "%s: sr_shutdown_discipline %s\n",
        !          1348:            DEVNAME(sc), sd->sd_vol.sv_meta.svm_devname);
        !          1349:
        !          1350:        s = splbio();
        !          1351:
        !          1352:        /* make sure there isn't a sync pending and yield */
        !          1353:        wakeup(sd);
        !          1354:        while (sd->sd_sync || sd->sd_must_flush)
        !          1355:                if (tsleep(&sd->sd_sync, MAXPRI, "sr_down", 60 * hz) ==
        !          1356:                    EWOULDBLOCK)
        !          1357:                        break;
        !          1358:
        !          1359: #ifndef SMALL_KERNEL
        !          1360:        sr_delete_sensors(sd);
        !          1361: #endif /* SMALL_KERNEL */
        !          1362:
        !          1363:        if (sd->sd_scsibus_dev)
        !          1364:                config_detach(sd->sd_scsibus_dev, DETACH_FORCE);
        !          1365:
        !          1366:        sr_unwind_chunks(sc, &sd->sd_vol.sv_chunk_list);
        !          1367:
        !          1368:        if (sd)
        !          1369:                sr_free_discipline(sd);
        !          1370:
        !          1371:        splx(s);
        !          1372: }
        !          1373:
        !          1374: int
        !          1375: sr_raid_inquiry(struct sr_workunit *wu)
        !          1376: {
        !          1377:        struct sr_discipline    *sd = wu->swu_dis;
        !          1378:        struct scsi_xfer        *xs = wu->swu_xs;
        !          1379:        struct scsi_inquiry_data inq;
        !          1380:
        !          1381:        DNPRINTF(SR_D_DIS, "%s: sr_raid_inquiry\n", DEVNAME(sd->sd_sc));
        !          1382:
        !          1383:        bzero(&inq, sizeof(inq));
        !          1384:        inq.device = T_DIRECT;
        !          1385:        inq.dev_qual2 = 0;
        !          1386:        inq.version = 2;
        !          1387:        inq.response_format = 2;
        !          1388:        inq.additional_length = 32;
        !          1389:        strlcpy(inq.vendor, sd->sd_vol.sv_meta.svm_vendor,
        !          1390:            sizeof(inq.vendor));
        !          1391:        strlcpy(inq.product, sd->sd_vol.sv_meta.svm_product,
        !          1392:            sizeof(inq.product));
        !          1393:        strlcpy(inq.revision, sd->sd_vol.sv_meta.svm_revision,
        !          1394:            sizeof(inq.revision));
        !          1395:        sr_copy_internal_data(xs, &inq, sizeof(inq));
        !          1396:
        !          1397:        return (0);
        !          1398: }
        !          1399:
        !          1400: int
        !          1401: sr_raid_read_cap(struct sr_workunit *wu)
        !          1402: {
        !          1403:        struct sr_discipline    *sd = wu->swu_dis;
        !          1404:        struct scsi_xfer        *xs = wu->swu_xs;
        !          1405:        struct scsi_read_cap_data rcd;
        !          1406:
        !          1407:        DNPRINTF(SR_D_DIS, "%s: sr_raid_read_cap\n", DEVNAME(sd->sd_sc));
        !          1408:
        !          1409:        bzero(&rcd, sizeof(rcd));
        !          1410:        _lto4b(sd->sd_vol.sv_meta.svm_size, rcd.addr);
        !          1411:        _lto4b(512, rcd.length);
        !          1412:        sr_copy_internal_data(xs, &rcd, sizeof(rcd));
        !          1413:
        !          1414:        return (0);
        !          1415: }
        !          1416:
        !          1417: int
        !          1418: sr_raid_tur(struct sr_workunit *wu)
        !          1419: {
        !          1420:        struct sr_discipline    *sd = wu->swu_dis;
        !          1421:
        !          1422:        DNPRINTF(SR_D_DIS, "%s: sr_raid_tur\n", DEVNAME(sd->sd_sc));
        !          1423:
        !          1424:        if (sd->sd_vol.sv_meta.svm_status == BIOC_SVOFFLINE) {
        !          1425:                sd->sd_scsi_sense.error_code = SSD_ERRCODE_CURRENT;
        !          1426:                sd->sd_scsi_sense.flags = SKEY_NOT_READY;
        !          1427:                sd->sd_scsi_sense.add_sense_code = 0x04;
        !          1428:                sd->sd_scsi_sense.add_sense_code_qual = 0x11;
        !          1429:                sd->sd_scsi_sense.extra_len = 4;
        !          1430:                return (1);
        !          1431:        } else if (sd->sd_vol.sv_meta.svm_status == BIOC_SVINVALID) {
        !          1432:                sd->sd_scsi_sense.error_code = SSD_ERRCODE_CURRENT;
        !          1433:                sd->sd_scsi_sense.flags = SKEY_HARDWARE_ERROR;
        !          1434:                sd->sd_scsi_sense.add_sense_code = 0x05;
        !          1435:                sd->sd_scsi_sense.add_sense_code_qual = 0x00;
        !          1436:                sd->sd_scsi_sense.extra_len = 4;
        !          1437:                return (1);
        !          1438:        }
        !          1439:
        !          1440:        return (0);
        !          1441: }
        !          1442:
        !          1443: int
        !          1444: sr_raid_request_sense(struct sr_workunit *wu)
        !          1445: {
        !          1446:        struct sr_discipline    *sd = wu->swu_dis;
        !          1447:        struct scsi_xfer        *xs = wu->swu_xs;
        !          1448:
        !          1449:        DNPRINTF(SR_D_DIS, "%s: sr_raid_request_sense\n",
        !          1450:            DEVNAME(sd->sd_sc));
        !          1451:
        !          1452:        /* use latest sense data */
        !          1453:        bcopy(&sd->sd_scsi_sense, &xs->sense, sizeof(xs->sense));
        !          1454:
        !          1455:        /* clear sense data */
        !          1456:        bzero(&sd->sd_scsi_sense, sizeof(sd->sd_scsi_sense));
        !          1457:
        !          1458:        return (0);
        !          1459: }
        !          1460:
        !          1461: int
        !          1462: sr_raid_start_stop(struct sr_workunit *wu)
        !          1463: {
        !          1464:        struct sr_discipline    *sd = wu->swu_dis;
        !          1465:        struct scsi_xfer        *xs = wu->swu_xs;
        !          1466:        struct scsi_start_stop  *ss = (struct scsi_start_stop *)xs->cmd;
        !          1467:        int                     rv = 1;
        !          1468:
        !          1469:        DNPRINTF(SR_D_DIS, "%s: sr_raid_start_stop\n",
        !          1470:            DEVNAME(sd->sd_sc));
        !          1471:
        !          1472:        if (!ss)
        !          1473:                return (rv);
        !          1474:
        !          1475:        if (ss->byte2 == 0x00) {
        !          1476:                /* START */
        !          1477:                if (sd->sd_vol.sv_meta.svm_status == BIOC_SVOFFLINE) {
        !          1478:                        /* bring volume online */
        !          1479:                        /* XXX check to see if volume can be brought online */
        !          1480:                        sd->sd_vol.sv_meta.svm_status = BIOC_SVONLINE;
        !          1481:                }
        !          1482:                rv = 0;
        !          1483:        } else /* XXX is this the check? if (byte == 0x01) */ {
        !          1484:                /* STOP */
        !          1485:                if (sd->sd_vol.sv_meta.svm_status == BIOC_SVONLINE) {
        !          1486:                        /* bring volume offline */
        !          1487:                        sd->sd_vol.sv_meta.svm_status = BIOC_SVOFFLINE;
        !          1488:                }
        !          1489:                rv = 0;
        !          1490:        }
        !          1491:
        !          1492:        return (rv);
        !          1493: }
        !          1494:
        !          1495: int
        !          1496: sr_raid_sync(struct sr_workunit *wu)
        !          1497: {
        !          1498:        struct sr_discipline    *sd = wu->swu_dis;
        !          1499:        int                     s, rv = 0, ios;
        !          1500:
        !          1501:        DNPRINTF(SR_D_DIS, "%s: sr_raid_sync\n", DEVNAME(sd->sd_sc));
        !          1502:
        !          1503:        /* when doing a fake sync don't coun't the wu */
        !          1504:        ios = wu->swu_fake ? 0 : 1;
        !          1505:
        !          1506:        s = splbio();
        !          1507:        sd->sd_sync = 1;
        !          1508:
        !          1509:        while (sd->sd_wu_pending > ios)
        !          1510:                if (tsleep(sd, PRIBIO, "sr_sync", 15 * hz) == EWOULDBLOCK) {
        !          1511:                        DNPRINTF(SR_D_DIS, "%s: sr_raid_sync timeout\n",
        !          1512:                            DEVNAME(sd->sd_sc));
        !          1513:                        rv = 1;
        !          1514:                        break;
        !          1515:                }
        !          1516:
        !          1517:        sd->sd_sync = 0;
        !          1518:        splx(s);
        !          1519:
        !          1520:        wakeup(&sd->sd_sync);
        !          1521:
        !          1522:        return (rv);
        !          1523: }
        !          1524:
        !          1525: void
        !          1526: sr_raid_startwu(struct sr_workunit *wu)
        !          1527: {
        !          1528:        struct sr_discipline    *sd = wu->swu_dis;
        !          1529:        struct sr_ccb           *ccb;
        !          1530:
        !          1531:        splassert(IPL_BIO);
        !          1532:
        !          1533:        if (wu->swu_state == SR_WU_RESTART)
        !          1534:                /*
        !          1535:                 * no need to put the wu on the pending queue since we
        !          1536:                 * are restarting the io
        !          1537:                 */
        !          1538:                 ;
        !          1539:        else
        !          1540:                /* move wu to pending queue */
        !          1541:                TAILQ_INSERT_TAIL(&sd->sd_wu_pendq, wu, swu_link);
        !          1542:
        !          1543:        /* start all individual ios */
        !          1544:        TAILQ_FOREACH(ccb, &wu->swu_ccb, ccb_link) {
        !          1545:                bdevsw_lookup(ccb->ccb_buf.b_dev)->d_strategy(&ccb->ccb_buf);
        !          1546:        }
        !          1547: }
        !          1548:
        !          1549: void
        !          1550: sr_raid_set_chunk_state(struct sr_discipline *sd, int c, int new_state)
        !          1551: {
        !          1552:        int                     old_state, s;
        !          1553:
        !          1554:        DNPRINTF(SR_D_STATE, "%s: %s: %s: sr_raid_set_chunk_state %d -> %d\n",
        !          1555:            DEVNAME(sd->sd_sc), sd->sd_vol.sv_meta.svm_devname,
        !          1556:            sd->sd_vol.sv_chunks[c]->src_meta.scm_devname, c, new_state);
        !          1557:
        !          1558:        /* ok to go to splbio since this only happens in error path */
        !          1559:        s = splbio();
        !          1560:        old_state = sd->sd_vol.sv_chunks[c]->src_meta.scm_status;
        !          1561:
        !          1562:        /* multiple IOs to the same chunk that fail will come through here */
        !          1563:        if (old_state == new_state)
        !          1564:                goto done;
        !          1565:
        !          1566:        switch (old_state) {
        !          1567:        case BIOC_SDONLINE:
        !          1568:                switch (new_state) {
        !          1569:                case BIOC_SDOFFLINE:
        !          1570:                        break;
        !          1571:                case BIOC_SDSCRUB:
        !          1572:                        break;
        !          1573:                default:
        !          1574:                        goto die;
        !          1575:                }
        !          1576:                break;
        !          1577:
        !          1578:        case BIOC_SDOFFLINE:
        !          1579:                if (new_state == BIOC_SDREBUILD) {
        !          1580:                        ;
        !          1581:                } else
        !          1582:                        goto die;
        !          1583:                break;
        !          1584:
        !          1585:        case BIOC_SDSCRUB:
        !          1586:                if (new_state == BIOC_SDONLINE) {
        !          1587:                        ;
        !          1588:                } else
        !          1589:                        goto die;
        !          1590:                break;
        !          1591:
        !          1592:        case BIOC_SDREBUILD:
        !          1593:                if (new_state == BIOC_SDONLINE) {
        !          1594:                        ;
        !          1595:                } else
        !          1596:                        goto die;
        !          1597:                break;
        !          1598:
        !          1599:        case BIOC_SDHOTSPARE:
        !          1600:                if (new_state == BIOC_SDREBUILD) {
        !          1601:                        ;
        !          1602:                } else
        !          1603:                        goto die;
        !          1604:                break;
        !          1605:
        !          1606:        default:
        !          1607: die:
        !          1608:                splx(s); /* XXX */
        !          1609:                panic("%s: %s: %s: invalid chunk state transition "
        !          1610:                    "%d -> %d\n", DEVNAME(sd->sd_sc),
        !          1611:                    sd->sd_vol.sv_meta.svm_devname,
        !          1612:                    sd->sd_vol.sv_chunks[c]->src_meta.scm_devname,
        !          1613:                    old_state, new_state);
        !          1614:                /* NOTREACHED */
        !          1615:        }
        !          1616:
        !          1617:        sd->sd_vol.sv_chunks[c]->src_meta.scm_status = new_state;
        !          1618:        sd->sd_set_vol_state(sd);
        !          1619:
        !          1620:        sd->sd_must_flush = 1;
        !          1621:        workq_add_task(NULL, 0, sr_save_metadata_callback, sd, NULL);
        !          1622: done:
        !          1623:        splx(s);
        !          1624: }
        !          1625:
        !          1626: void
        !          1627: sr_raid_set_vol_state(struct sr_discipline *sd)
        !          1628: {
        !          1629:        int                     states[SR_MAX_STATES];
        !          1630:        int                     new_state, i, s, nd;
        !          1631:        int                     old_state = sd->sd_vol.sv_meta.svm_status;
        !          1632:
        !          1633:        DNPRINTF(SR_D_STATE, "%s: %s: sr_raid_set_vol_state\n",
        !          1634:            DEVNAME(sd->sd_sc), sd->sd_vol.sv_meta.svm_devname);
        !          1635:
        !          1636:        nd = sd->sd_vol.sv_meta.svm_no_chunk;
        !          1637:
        !          1638:        for (i = 0; i < SR_MAX_STATES; i++)
        !          1639:                states[i] = 0;
        !          1640:
        !          1641:        for (i = 0; i < nd; i++) {
        !          1642:                s = sd->sd_vol.sv_chunks[i]->src_meta.scm_status;
        !          1643:                if (s > SR_MAX_STATES)
        !          1644:                        panic("%s: %s: %s: invalid chunk state",
        !          1645:                            DEVNAME(sd->sd_sc),
        !          1646:                            sd->sd_vol.sv_meta.svm_devname,
        !          1647:                            sd->sd_vol.sv_chunks[i]->src_meta.scm_devname);
        !          1648:                states[s]++;
        !          1649:        }
        !          1650:
        !          1651:        if (states[BIOC_SDONLINE] == nd)
        !          1652:                new_state = BIOC_SVONLINE;
        !          1653:        else if (states[BIOC_SDONLINE] == 0)
        !          1654:                new_state = BIOC_SVOFFLINE;
        !          1655:        else if (states[BIOC_SDSCRUB] != 0)
        !          1656:                new_state = BIOC_SVSCRUB;
        !          1657:        else if (states[BIOC_SDREBUILD] != 0)
        !          1658:                new_state = BIOC_SVREBUILD;
        !          1659:        else if (states[BIOC_SDOFFLINE] != 0)
        !          1660:                new_state = BIOC_SVDEGRADED;
        !          1661:        else {
        !          1662:                printf("old_state = %d, ", old_state);
        !          1663:                for (i = 0; i < nd; i++)
        !          1664:                        printf("%d = %d, ", i,
        !          1665:                            sd->sd_vol.sv_chunks[i]->src_meta.scm_status);
        !          1666:                panic("invalid new_state");
        !          1667:        }
        !          1668:
        !          1669:        DNPRINTF(SR_D_STATE, "%s: %s: sr_raid_set_vol_state %d -> %d\n",
        !          1670:            DEVNAME(sd->sd_sc), sd->sd_vol.sv_meta.svm_devname,
        !          1671:            old_state, new_state);
        !          1672:
        !          1673:        switch (old_state) {
        !          1674:        case BIOC_SVONLINE:
        !          1675:                switch (new_state) {
        !          1676:                case BIOC_SVOFFLINE:
        !          1677:                case BIOC_SVDEGRADED:
        !          1678:                        break;
        !          1679:                default:
        !          1680:                        goto die;
        !          1681:                }
        !          1682:                break;
        !          1683:
        !          1684:        case BIOC_SVOFFLINE:
        !          1685:                /* XXX this might be a little too much */
        !          1686:                goto die;
        !          1687:
        !          1688:        case BIOC_SVSCRUB:
        !          1689:                switch (new_state) {
        !          1690:                case BIOC_SVONLINE:
        !          1691:                case BIOC_SVOFFLINE:
        !          1692:                case BIOC_SVDEGRADED:
        !          1693:                case BIOC_SVSCRUB: /* can go to same state */
        !          1694:                        break;
        !          1695:                default:
        !          1696:                        goto die;
        !          1697:                }
        !          1698:                break;
        !          1699:
        !          1700:        case BIOC_SVBUILDING:
        !          1701:                switch (new_state) {
        !          1702:                case BIOC_SVONLINE:
        !          1703:                case BIOC_SVOFFLINE:
        !          1704:                case BIOC_SVBUILDING: /* can go to the same state */
        !          1705:                        break;
        !          1706:                default:
        !          1707:                        goto die;
        !          1708:                }
        !          1709:                break;
        !          1710:
        !          1711:        case BIOC_SVREBUILD:
        !          1712:                switch (new_state) {
        !          1713:                case BIOC_SVONLINE:
        !          1714:                case BIOC_SVOFFLINE:
        !          1715:                case BIOC_SVREBUILD: /* can go to the same state */
        !          1716:                        break;
        !          1717:                default:
        !          1718:                        goto die;
        !          1719:                }
        !          1720:                break;
        !          1721:
        !          1722:        case BIOC_SVDEGRADED:
        !          1723:                switch (new_state) {
        !          1724:                case BIOC_SVOFFLINE:
        !          1725:                case BIOC_SVREBUILD:
        !          1726:                case BIOC_SVDEGRADED: /* can go to the same state */
        !          1727:                        break;
        !          1728:                default:
        !          1729:                        goto die;
        !          1730:                }
        !          1731:                break;
        !          1732:
        !          1733:        default:
        !          1734: die:
        !          1735:                panic("%s: %s: invalid volume state transition "
        !          1736:                    "%d -> %d\n", DEVNAME(sd->sd_sc),
        !          1737:                    sd->sd_vol.sv_meta.svm_devname,
        !          1738:                    old_state, new_state);
        !          1739:                /* NOTREACHED */
        !          1740:        }
        !          1741:
        !          1742:        sd->sd_vol.sv_meta.svm_status = new_state;
        !          1743: }
        !          1744:
        !          1745: u_int32_t
        !          1746: sr_checksum(char *s, u_int32_t *p, u_int32_t size)
        !          1747: {
        !          1748:        u_int32_t               chk = 0;
        !          1749:        int                     i;
        !          1750:
        !          1751:        DNPRINTF(SR_D_MISC, "%s: sr_checksum %p %d\n", s, p, size);
        !          1752:
        !          1753:        if (size % sizeof(u_int32_t))
        !          1754:                return (0); /* 0 is failure */
        !          1755:
        !          1756:        for (i = 0; i < size / sizeof(u_int32_t); i++)
        !          1757:                chk ^= p[i];
        !          1758:
        !          1759:        return (chk);
        !          1760: }
        !          1761:
        !          1762: void
        !          1763: sr_get_uuid(struct sr_uuid *uuid)
        !          1764: {
        !          1765:        int                     i;
        !          1766:
        !          1767:        for (i = 0; i < SR_UUID_MAX; i++)
        !          1768:                uuid->sui_id[i] = arc4random();
        !          1769: }
        !          1770:
        !          1771: void
        !          1772: sr_print_uuid(struct sr_uuid *uuid, int cr)
        !          1773: {
        !          1774:        int                     i;
        !          1775:
        !          1776:        for (i = 0; i < SR_UUID_MAX; i++)
        !          1777:                printf("%x%s", uuid->sui_id[i],
        !          1778:                    i < SR_UUID_MAX - 1 ? ":" : "");
        !          1779:
        !          1780:        if (cr)
        !          1781:                printf("\n");
        !          1782: }
        !          1783:
        !          1784: int
        !          1785: sr_clear_metadata(struct sr_discipline *sd)
        !          1786: {
        !          1787:        struct sr_softc         *sc = sd->sd_sc;
        !          1788:        struct sr_chunk_head    *cl = &sd->sd_vol.sv_chunk_list;
        !          1789:        struct sr_chunk         *ch_entry;
        !          1790:        struct buf              b;
        !          1791:        size_t                  sz = SR_META_SIZE * 512;
        !          1792:        void                    *m;
        !          1793:        int                     rv = 0;
        !          1794:
        !          1795:        DNPRINTF(SR_D_META, "%s: sr_clear_metadata\n", DEVNAME(sc));
        !          1796:
        !          1797:        m = malloc(sz , M_DEVBUF, M_WAITOK);
        !          1798:        bzero(m, sz);
        !          1799:
        !          1800:        SLIST_FOREACH(ch_entry, cl, src_link) {
        !          1801:                bzero(&b, sizeof(b));
        !          1802:
        !          1803:                b.b_flags = B_WRITE;
        !          1804:                b.b_blkno = SR_META_OFFSET;
        !          1805:                b.b_bcount = sz;
        !          1806:                b.b_bufsize = sz;
        !          1807:                b.b_resid = sz;
        !          1808:                b.b_data = (void *)m;
        !          1809:                b.b_error = 0;
        !          1810:                b.b_proc = curproc;
        !          1811:                b.b_dev = ch_entry->src_dev_mm;
        !          1812:                b.b_vp = NULL;
        !          1813:                b.b_iodone = NULL;
        !          1814:                LIST_INIT(&b.b_dep);
        !          1815:                bdevsw_lookup(b.b_dev)->d_strategy(&b);
        !          1816:                biowait(&b);
        !          1817:
        !          1818:                if (b.b_flags & B_ERROR) {
        !          1819:                        printf("%s: %s i/o error on block %d while clearing "
        !          1820:                            "metadata %d\n", DEVNAME(sc),
        !          1821:                            ch_entry->src_devname, b.b_blkno, b.b_error);
        !          1822:                        rv++;
        !          1823:                        continue;
        !          1824:                }
        !          1825:        }
        !          1826:
        !          1827:        free(m, M_DEVBUF);
        !          1828:        return (rv);
        !          1829: }
        !          1830:
        !          1831: int
        !          1832: sr_already_assembled(struct sr_discipline *sd)
        !          1833: {
        !          1834:        struct sr_softc         *sc = sd->sd_sc;
        !          1835:        int                     i;
        !          1836:
        !          1837:        for (i = 0; i < SR_MAXSCSIBUS; i++)
        !          1838:                if (sc->sc_dis[i])
        !          1839:                        if (!bcmp(&sd->sd_meta->ssd_uuid,
        !          1840:                            &sc->sc_dis[i]->sd_meta->ssd_uuid,
        !          1841:                            sizeof(sd->sd_meta->ssd_uuid)))
        !          1842:                                return (1);
        !          1843:
        !          1844:        return (0);
        !          1845: }
        !          1846:
        !          1847: void
        !          1848: sr_save_metadata_callback(void *arg1, void *arg2)
        !          1849: {
        !          1850:        struct sr_discipline    *sd = arg1;
        !          1851:        int                     s;
        !          1852:
        !          1853:        s = splbio();
        !          1854:
        !          1855:        if (sr_save_metadata(arg1, SR_VOL_DIRTY))
        !          1856:                printf("%s: save metadata failed\n",
        !          1857:                    DEVNAME(sd->sd_sc));
        !          1858:
        !          1859:        sd->sd_must_flush = 0;
        !          1860:        splx(s);
        !          1861: }
        !          1862:
        !          1863: int
        !          1864: sr_save_metadata(struct sr_discipline *sd, u_int32_t flags)
        !          1865: {
        !          1866:        struct sr_softc         *sc = sd->sd_sc;
        !          1867:        struct sr_metadata      *sm = sd->sd_meta;
        !          1868:        struct sr_vol_meta      *sv = &sd->sd_vol.sv_meta, *im_sv;
        !          1869:        struct sr_chunk_meta    *im_sc;
        !          1870:        struct sr_chunk         *src;
        !          1871:        struct buf              b;
        !          1872:        struct sr_workunit      wu;
        !          1873:        int                     i, rv = 1, ch = 0;
        !          1874:        size_t                  sz = SR_META_SIZE * 512;
        !          1875:
        !          1876:        DNPRINTF(SR_D_META, "%s: sr_save_metadata %s\n",
        !          1877:            DEVNAME(sc), sd->sd_vol.sv_meta.svm_devname);
        !          1878:
        !          1879:        if (!sm) {
        !          1880:                printf("%s: no in memory copy of metadata\n", DEVNAME(sc));
        !          1881:                goto bad;
        !          1882:        }
        !          1883:
        !          1884:        im_sv = (struct sr_vol_meta *)(sm + 1);
        !          1885:        im_sc = (struct sr_chunk_meta *)(im_sv + 1);
        !          1886:
        !          1887:        if (sizeof(struct sr_metadata) + sizeof(struct sr_vol_meta) +
        !          1888:            (sizeof(struct sr_chunk_meta) * sd->sd_vol.sv_meta.svm_no_chunk) >
        !          1889:            sz) {
        !          1890:                printf("%s: too much metadata; metadata NOT written\n",
        !          1891:                    DEVNAME(sc));
        !          1892:                goto bad;
        !          1893:        }
        !          1894:
        !          1895:        if (sm->ssd_magic == 0) {
        !          1896:                /* initial metadata */
        !          1897:                sm->ssd_magic = SR_MAGIC;
        !          1898:                sm->ssd_version = SR_META_VERSION;
        !          1899:                sm->ssd_size = sizeof(struct sr_metadata);
        !          1900:                sm->ssd_ondisk = 0;
        !          1901:                sm->ssd_flags = sd->sd_meta_flags;
        !          1902:                /* get uuid from chunk 0 */
        !          1903:                bcopy(&sd->sd_vol.sv_chunks[0]->src_meta.scm_uuid,
        !          1904:                    &sm->ssd_uuid,
        !          1905:                    sizeof(struct sr_uuid));
        !          1906:
        !          1907:                /* volume */
        !          1908:                bcopy(sv, im_sv, sizeof(struct sr_vol_meta));
        !          1909:                bcopy(&sm->ssd_uuid, &im_sv->svm_uuid,
        !          1910:                    sizeof(im_sv->svm_uuid));
        !          1911:                sm->ssd_vd_ver = SR_VOL_VERSION;
        !          1912:                sm->ssd_vd_size = sizeof(struct sr_vol_meta);
        !          1913:
        !          1914:                /* chunk */
        !          1915:                for (i = 0; i < sd->sd_vol.sv_meta.svm_no_chunk; i++)
        !          1916:                        bcopy(sd->sd_vol.sv_chunks[i], &im_sc[i],
        !          1917:                            sizeof(struct sr_chunk_meta));
        !          1918:
        !          1919:                sm->ssd_chunk_ver = SR_CHUNK_VERSION;
        !          1920:                sm->ssd_chunk_size = sizeof(struct sr_chunk_meta);
        !          1921:                sm->ssd_chunk_no = sd->sd_vol.sv_meta.svm_no_chunk;
        !          1922:
        !          1923:                /* optional */
        !          1924:                sm->ssd_opt_ver = SR_OPT_VERSION;
        !          1925:                sm->ssd_opt_size = 0; /* unused */
        !          1926:                sm->ssd_opt_no = 0; /* unused */
        !          1927:        }
        !          1928:
        !          1929:        /* from here on out metadata is updated */
        !          1930:        sm->ssd_ondisk++;
        !          1931:        im_sv->svm_flags |= flags;
        !          1932:        sm->ssd_vd_chk = sr_checksum(DEVNAME(sc),
        !          1933:            (u_int32_t *)im_sv, sm->ssd_vd_size);
        !          1934:
        !          1935:        sm->ssd_chunk_chk = 0;
        !          1936:        for (ch = 0; ch < sm->ssd_chunk_no; ch++)
        !          1937:                sm->ssd_chunk_chk ^= sr_checksum(DEVNAME(sc),
        !          1938:                    (u_int32_t *)&im_sc[ch], sm->ssd_chunk_size);
        !          1939:
        !          1940:        sr_print_metadata(sm);
        !          1941:
        !          1942:        for (i = 0; i < sm->ssd_chunk_no; i++) {
        !          1943:                memset(&b, 0, sizeof(b));
        !          1944:
        !          1945:                src = sd->sd_vol.sv_chunks[i];
        !          1946:
        !          1947:                /* skip disks that are offline */
        !          1948:                if (src->src_meta.scm_status == BIOC_SDOFFLINE)
        !          1949:                        continue;
        !          1950:
        !          1951:                /* calculate metdata checksum and ids */
        !          1952:                sm->ssd_vd_volid = im_sv->svm_volid;
        !          1953:                sm->ssd_chunk_id = i;
        !          1954:                sm->ssd_checksum = sr_checksum(DEVNAME(sc),
        !          1955:                    (u_int32_t *)sm, sm->ssd_size);
        !          1956:                DNPRINTF(SR_D_META, "%s: sr_save_metadata %s: volid: %d "
        !          1957:                    "chunkid: %d checksum: 0x%x\n",
        !          1958:                    DEVNAME(sc), src->src_meta.scm_devname,
        !          1959:                    sm->ssd_vd_volid, sm->ssd_chunk_id,
        !          1960:                    sm->ssd_checksum);
        !          1961:
        !          1962:                b.b_flags = B_WRITE;
        !          1963:                b.b_blkno = SR_META_OFFSET;
        !          1964:                b.b_bcount = sz;
        !          1965:                b.b_bufsize = sz;
        !          1966:                b.b_resid = sz;
        !          1967:                b.b_data = (void *)sm;
        !          1968:                b.b_error = 0;
        !          1969:                b.b_proc = curproc;
        !          1970:                b.b_dev = src->src_dev_mm;
        !          1971:                b.b_vp = NULL;
        !          1972:                b.b_iodone = NULL;
        !          1973:                LIST_INIT(&b.b_dep);
        !          1974:                bdevsw_lookup(b.b_dev)->d_strategy(&b);
        !          1975:                biowait(&b);
        !          1976:
        !          1977:                /* make sure in memory copy is clean */
        !          1978:                sm->ssd_vd_volid = 0;
        !          1979:                sm->ssd_chunk_id = 0;
        !          1980:                sm->ssd_checksum = 0;
        !          1981:
        !          1982:                /* XXX do something smart here */
        !          1983:                /* mark chunk offline and restart metadata write */
        !          1984:                if (b.b_flags & B_ERROR) {
        !          1985:                        printf("%s: %s i/o error on block %d while writing "
        !          1986:                            "metadata %d\n", DEVNAME(sc),
        !          1987:                            src->src_meta.scm_devname, b.b_blkno, b.b_error);
        !          1988:                        goto bad;
        !          1989:                }
        !          1990:
        !          1991:                DNPRINTF(SR_D_META, "%s: sr_save_metadata written to %s\n",
        !          1992:                    DEVNAME(sc), src->src_meta.scm_devname);
        !          1993:        }
        !          1994:
        !          1995:        bzero(&wu, sizeof(wu));
        !          1996:        wu.swu_fake = 1;
        !          1997:        wu.swu_dis = sd;
        !          1998:        sd->sd_scsi_sync(&wu);
        !          1999:
        !          2000:        rv = 0;
        !          2001: bad:
        !          2002:        return (rv);
        !          2003: }
        !          2004:
        !          2005: int
        !          2006: sr_boot_assembly(struct sr_softc *sc)
        !          2007: {
        !          2008:        struct device           *dv;
        !          2009:        struct buf              *bp;
        !          2010:        struct bdevsw           *bdsw;
        !          2011:        struct disklabel        label;
        !          2012:        struct sr_metadata      *sm;
        !          2013:        struct sr_metadata_list_head mlh;
        !          2014:        struct sr_metadata_list *mle, *mle2;
        !          2015:        struct sr_vol_meta      *vm;
        !          2016:        struct bioc_createraid  bc;
        !          2017:        dev_t                   dev, devr, *dt = NULL;
        !          2018:        int                     error, majdev, i, no_dev, rv = 0;
        !          2019:        size_t                  sz = SR_META_SIZE * 512;
        !          2020:
        !          2021:        DNPRINTF(SR_D_META, "%s: sr_boot_assembly\n", DEVNAME(sc));
        !          2022:
        !          2023:        SLIST_INIT(&mlh);
        !          2024:        bp = geteblk(sz);
        !          2025:        if (!bp)
        !          2026:                return (ENOMEM);
        !          2027:
        !          2028:        TAILQ_FOREACH(dv, &alldevs, dv_list) {
        !          2029:                if (dv->dv_class != DV_DISK)
        !          2030:                        continue;
        !          2031:
        !          2032:                majdev = findblkmajor(dv);
        !          2033:                if (majdev == -1)
        !          2034:                        continue;
        !          2035:
        !          2036:                bp->b_dev = dev = MAKEDISKDEV(majdev, dv->dv_unit, RAW_PART);
        !          2037:                bdsw = &bdevsw[majdev];
        !          2038:
        !          2039:                /* XXX is there  a better way of excluding some devices? */
        !          2040:                if (!strncmp(dv->dv_xname, "fd", 2) ||
        !          2041:                    !strncmp(dv->dv_xname, "cd", 2) ||
        !          2042:                    !strncmp(dv->dv_xname, "rx", 2))
        !          2043:                        continue;
        !          2044:                /*
        !          2045:                 * The devices are being opened with S_IFCHR instead of
        !          2046:                 * S_IFBLK so that the SCSI mid-layer does not whine when
        !          2047:                 * media is not inserted in certain devices like zip drives
        !          2048:                 * and such.
        !          2049:                 */
        !          2050:
        !          2051:                /* open device */
        !          2052:                error = (*bdsw->d_open)(dev, FREAD, S_IFCHR, curproc);
        !          2053:                if (error) {
        !          2054:                        DNPRINTF(SR_D_META, "%s: sr_boot_assembly open failed"
        !          2055:                            "\n", DEVNAME(sc));
        !          2056:                        continue;
        !          2057:                }
        !          2058:
        !          2059:                /* get disklabel */
        !          2060:                error = (*bdsw->d_ioctl)(dev, DIOCGDINFO, (void *)&label,
        !          2061:                    FREAD, curproc);
        !          2062:                if (error) {
        !          2063:                        DNPRINTF(SR_D_META, "%s: sr_boot_assembly ioctl "
        !          2064:                            "failed\n", DEVNAME(sc));
        !          2065:                        error = (*bdsw->d_close)(dev, FREAD, S_IFCHR, curproc);
        !          2066:                        continue;
        !          2067:                }
        !          2068:
        !          2069:                /* we are done, close device */
        !          2070:                error = (*bdsw->d_close)(dev, FREAD, S_IFCHR, curproc);
        !          2071:                if (error) {
        !          2072:                        DNPRINTF(SR_D_META, "%s: sr_boot_assembly close "
        !          2073:                            "failed\n", DEVNAME(sc));
        !          2074:                        continue;
        !          2075:                }
        !          2076:
        !          2077:                /* are we a softraid partition? */
        !          2078:                for (i = 0; i < MAXPARTITIONS; i++) {
        !          2079:                        if (label.d_partitions[i].p_fstype != FS_RAID)
        !          2080:                                continue;
        !          2081:
        !          2082:                        /* open device */
        !          2083:                        bp->b_dev = devr = MAKEDISKDEV(majdev, dv->dv_unit, i);
        !          2084:                        error = (*bdsw->d_open)(devr, FREAD, S_IFCHR, curproc);
        !          2085:                        if (error) {
        !          2086:                                DNPRINTF(SR_D_META, "%s: sr_boot_assembly "
        !          2087:                                    "open failed, partition %d\n",
        !          2088:                                    DEVNAME(sc), i);
        !          2089:                                continue;
        !          2090:                        }
        !          2091:                        /* read metadat */
        !          2092:                        bp->b_flags = B_BUSY | B_READ;
        !          2093:                        bp->b_blkno = SR_META_OFFSET;
        !          2094:                        bp->b_cylinder = 0;
        !          2095:                        bp->b_bcount = sz;
        !          2096:                        bp->b_bufsize = sz;
        !          2097:                        bp->b_resid = sz;
        !          2098:                        (*bdsw->d_strategy)(bp);
        !          2099:                        if ((error = biowait(bp))) {
        !          2100:                                DNPRINTF(SR_D_META, "%s: sr_boot_assembly "
        !          2101:                                    "strategy failed, partition %d\n",
        !          2102:                                    DEVNAME(sc));
        !          2103:                                error = (*bdsw->d_close)(devr, FREAD, S_IFCHR,
        !          2104:                                    curproc);
        !          2105:                                continue;
        !          2106:                        }
        !          2107:
        !          2108:                        sm = (struct sr_metadata *)bp->b_data;
        !          2109:                        if (!sr_validate_metadata(sc, devr, sm)) {
        !          2110:                                /* we got one; save it off */
        !          2111:                                mle = malloc(sizeof(*mle), M_DEVBUF, M_WAITOK);
        !          2112:                                bzero(mle, sizeof(*mle));
        !          2113:                                mle->sml_metadata = malloc(sz, M_DEVBUF,
        !          2114:                                    M_WAITOK);
        !          2115:                                bzero(mle->sml_metadata, sz);
        !          2116:                                bcopy(sm, mle->sml_metadata, sz);
        !          2117:                                mle->sml_mm = devr;
        !          2118:                                SLIST_INSERT_HEAD(&mlh, mle, sml_link);
        !          2119:                        }
        !          2120:
        !          2121:                        /* we are done, close device */
        !          2122:                        error = (*bdsw->d_close)(devr, FREAD, S_IFCHR,
        !          2123:                            curproc);
        !          2124:                        if (error) {
        !          2125:                                DNPRINTF(SR_D_META, "%s: sr_boot_assembly "
        !          2126:                                    "close failed\n", DEVNAME(sc));
        !          2127:                                continue;
        !          2128:                        }
        !          2129:                }
        !          2130:        }
        !          2131:
        !          2132:        /*
        !          2133:         * XXX poor mans hack that doesn't keep disks in order and does not
        !          2134:         * roam disks correctly.  replace this with something smarter that
        !          2135:         * orders disks by volid, chunkid and uuid.
        !          2136:         */
        !          2137:        dt = malloc(BIOC_CRMAXLEN, M_DEVBUF, M_WAITOK);
        !          2138:        SLIST_FOREACH(mle, &mlh, sml_link) {
        !          2139:                /* chunk used already? */
        !          2140:                if (mle->sml_used)
        !          2141:                        continue;
        !          2142:
        !          2143:                no_dev = 0;
        !          2144:                bzero(dt, BIOC_CRMAXLEN);
        !          2145:                SLIST_FOREACH(mle2, &mlh, sml_link) {
        !          2146:                        /* chunk used already? */
        !          2147:                        if (mle2->sml_used)
        !          2148:                                continue;
        !          2149:
        !          2150:                        /* are we the same volume? */
        !          2151:                        if (mle->sml_metadata->ssd_vd_volid !=
        !          2152:                            mle2->sml_metadata->ssd_vd_volid)
        !          2153:                                continue;
        !          2154:
        !          2155:                        /* same uuid? */
        !          2156:                        if (bcmp(&mle->sml_metadata->ssd_uuid,
        !          2157:                            &mle2->sml_metadata->ssd_uuid,
        !          2158:                            sizeof(mle->sml_metadata->ssd_uuid)))
        !          2159:                                continue;
        !          2160:
        !          2161:                        /* sanity */
        !          2162:                        if (dt[mle2->sml_metadata->ssd_chunk_id]) {
        !          2163:                                printf("%s: chunk id already in use; can not "
        !          2164:                                    "assemble volume\n", DEVNAME(sc));
        !          2165:                                goto unwind;
        !          2166:                        }
        !          2167:                        dt[mle2->sml_metadata->ssd_chunk_id] = mle2->sml_mm;
        !          2168:                        no_dev++;
        !          2169:                        mle2->sml_used = 1;
        !          2170:                }
        !          2171:                if (mle->sml_metadata->ssd_chunk_no != no_dev) {
        !          2172:                        printf("%s: not assembling partial disk that used to "
        !          2173:                            "be volume %d\n", DEVNAME(sc),
        !          2174:                            mle->sml_metadata->ssd_vd_volid);
        !          2175:                        continue;
        !          2176:                }
        !          2177:
        !          2178:                bzero(&bc, sizeof(bc));
        !          2179:                vm = (struct sr_vol_meta *)(mle->sml_metadata + 1);
        !          2180:                bc.bc_level = vm->svm_level;
        !          2181:                bc.bc_dev_list_len = no_dev * sizeof(dev_t);
        !          2182:                bc.bc_dev_list = dt;
        !          2183:                bc.bc_flags = BIOC_SCDEVT;
        !          2184:                sr_ioctl_createraid(sc, &bc, 0);
        !          2185:                rv++;
        !          2186:        }
        !          2187:
        !          2188: unwind:
        !          2189:        if (dt)
        !          2190:                free(dt, M_DEVBUF);
        !          2191:
        !          2192:        for (mle = SLIST_FIRST(&mlh); mle != SLIST_END(&mlh); mle = mle2) {
        !          2193:                mle2 = SLIST_NEXT(mle, sml_link);
        !          2194:
        !          2195:                free(mle->sml_metadata, M_DEVBUF);
        !          2196:                free(mle, M_DEVBUF);
        !          2197:        }
        !          2198:        SLIST_INIT(&mlh);
        !          2199:
        !          2200:        return (rv);
        !          2201: }
        !          2202:
        !          2203: int
        !          2204: sr_validate_metadata(struct sr_softc *sc, dev_t dev, struct sr_metadata *sm)
        !          2205: {
        !          2206:        struct sr_vol_meta      *mv;
        !          2207:        struct sr_chunk_meta    *mc;
        !          2208:        char                    *name, devname[32];
        !          2209:        int                     maj, part, unit;
        !          2210:        u_int32_t               chk;
        !          2211:
        !          2212:        DNPRINTF(SR_D_META, "%s: sr_validate_metadata(0x%x)\n",
        !          2213:            DEVNAME(sc), dev);
        !          2214:
        !          2215:        bzero(devname, sizeof(devname));
        !          2216:
        !          2217:        if (sm->ssd_magic != SR_MAGIC)
        !          2218:                goto bad;
        !          2219:
        !          2220:        maj = major(dev);
        !          2221:        part = DISKPART(dev);
        !          2222:        unit = DISKUNIT(dev);
        !          2223:
        !          2224:        name = findblkname(maj);
        !          2225:        if (name == NULL)
        !          2226:                goto bad;
        !          2227:
        !          2228:        snprintf(devname, sizeof(devname),
        !          2229:            "%s%d%c", name, unit, part + 'a');
        !          2230:        name = devname;
        !          2231:
        !          2232:        /* validate metadata */
        !          2233:        if (sm->ssd_version != SR_META_VERSION) {
        !          2234:                printf("%s: %s can not read metadata version %d, "
        !          2235:                    "expected %d\n", DEVNAME(sc),
        !          2236:                    devname, sm->ssd_version,
        !          2237:                    SR_META_VERSION);
        !          2238:                goto bad;
        !          2239:        }
        !          2240:        if (sm->ssd_size != sizeof(struct sr_metadata)) {
        !          2241:                printf("%s: %s invalid metadata size %d, "
        !          2242:                    "expected %d\n", DEVNAME(sc),
        !          2243:                    devname, sm->ssd_size,
        !          2244:                    sizeof(struct sr_metadata));
        !          2245:                goto bad;
        !          2246:        }
        !          2247:        chk = sr_checksum(DEVNAME(sc), (u_int32_t *)sm, sm->ssd_size);
        !          2248:        /*
        !          2249:         * since the checksum value is part of the checksum a good
        !          2250:         * result equals 0
        !          2251:         */
        !          2252:        if (chk != 0) {
        !          2253:                printf("%s: %s invalid metadata checksum 0x%x, "
        !          2254:                    "expected 0x%x\n", DEVNAME(sc),
        !          2255:                    devname, sm->ssd_checksum, chk);
        !          2256:                goto bad;
        !          2257:        }
        !          2258:
        !          2259:        /* validate volume metadata */
        !          2260:        if (sm->ssd_vd_ver != SR_VOL_VERSION) {
        !          2261:                printf("%s: %s can not read volume metadata version "
        !          2262:                    "%d, expected %d\n", DEVNAME(sc),
        !          2263:                    devname, sm->ssd_vd_ver,
        !          2264:                    SR_VOL_VERSION);
        !          2265:                goto bad;
        !          2266:        }
        !          2267:        if (sm->ssd_vd_size != sizeof(struct sr_vol_meta)) {
        !          2268:                printf("%s: %s invalid volume metadata size %d, "
        !          2269:                    "expected %d\n", DEVNAME(sc),
        !          2270:                    devname, sm->ssd_vd_size,
        !          2271:                    sizeof(struct sr_vol_meta));
        !          2272:                goto bad;
        !          2273:        }
        !          2274:        mv = (struct sr_vol_meta *)(sm + 1);
        !          2275:        chk = sr_checksum(DEVNAME(sc), (u_int32_t *)mv, sm->ssd_vd_size);
        !          2276:        if (chk != sm->ssd_vd_chk) {
        !          2277:                printf("%s: %s invalid volume metadata checksum 0x%x, "
        !          2278:                    "expected 0x%x\n", DEVNAME(sc),
        !          2279:                    devname, sm->ssd_vd_chk, chk);
        !          2280:                goto bad;
        !          2281:        }
        !          2282:
        !          2283:        /* validate chunk metadata */
        !          2284:        if (sm->ssd_chunk_ver != SR_CHUNK_VERSION) {
        !          2285:                printf("%s: %s can not read chunk metadata version "
        !          2286:                    "%d, expected %d\n", DEVNAME(sc),
        !          2287:                    devname, sm->ssd_chunk_ver,
        !          2288:                    SR_CHUNK_VERSION);
        !          2289:                goto bad;
        !          2290:        }
        !          2291:        if (sm->ssd_chunk_size != sizeof(struct sr_chunk_meta)) {
        !          2292:                printf("%s: %s invalid chunk metadata size %d, "
        !          2293:                    "expected %d\n", DEVNAME(sc),
        !          2294:                    devname, sm->ssd_chunk_size,
        !          2295:                    sizeof(struct sr_chunk_meta));
        !          2296:                goto bad;
        !          2297:        }
        !          2298:
        !          2299:        mc = (struct sr_chunk_meta *)(mv + 1);
        !          2300:        /* checksum is calculated over ALL chunks */
        !          2301:        chk = sr_checksum(DEVNAME(sc), (u_int32_t *)(mc),
        !          2302:            sm->ssd_chunk_size * sm->ssd_chunk_no);
        !          2303:
        !          2304:        if (chk != sm->ssd_chunk_chk) {
        !          2305:                printf("%s: %s invalid chunk metadata checksum 0x%x, "
        !          2306:                    "expected 0x%x\n", DEVNAME(sc),
        !          2307:                    devname, sm->ssd_chunk_chk, chk);
        !          2308:                goto bad;
        !          2309:        }
        !          2310:
        !          2311:        /* warn if disk changed order */
        !          2312:        if (strncmp(mc[sm->ssd_chunk_id].scm_devname, name,
        !          2313:            sizeof(mc[sm->ssd_chunk_id].scm_devname)))
        !          2314:                printf("%s: roaming device %s -> %s\n", DEVNAME(sc),
        !          2315:                    mc[sm->ssd_chunk_id].scm_devname, name);
        !          2316:
        !          2317:        /* we have meta data on disk */
        !          2318:        DNPRINTF(SR_D_META, "%s: sr_validate_metadata valid metadata %s\n",
        !          2319:            DEVNAME(sc), devname);
        !          2320:
        !          2321:        return (0);
        !          2322: bad:
        !          2323:        DNPRINTF(SR_D_META, "%s: sr_validate_metadata invalid metadata %s\n",
        !          2324:            DEVNAME(sc), devname);
        !          2325:
        !          2326:        return (1);
        !          2327: }
        !          2328:
        !          2329: void
        !          2330: sr_shutdown(void *arg)
        !          2331: {
        !          2332:        struct sr_discipline    *sd = arg;
        !          2333: #ifdef SR_DEBUG
        !          2334:        struct sr_softc         *sc = sd->sd_sc;
        !          2335: #endif
        !          2336:        DNPRINTF(SR_D_DIS, "%s: sr_shutdown %s\n",
        !          2337:            DEVNAME(sc), sd->sd_vol.sv_meta.svm_devname);
        !          2338:
        !          2339:        sr_save_metadata(sd, 0);
        !          2340:
        !          2341:        sr_shutdown_discipline(sd);
        !          2342: }
        !          2343:
        !          2344: #ifndef SMALL_KERNEL
        !          2345: int
        !          2346: sr_create_sensors(struct sr_discipline *sd)
        !          2347: {
        !          2348:        struct sr_softc         *sc = sd->sd_sc;
        !          2349:        int                     rv = 1;
        !          2350:
        !          2351:        DNPRINTF(SR_D_STATE, "%s: %s: sr_create_sensors\n",
        !          2352:            DEVNAME(sc), sd->sd_vol.sv_meta.svm_devname);
        !          2353:
        !          2354:        strlcpy(sd->sd_vol.sv_sensordev.xname, DEVNAME(sc),
        !          2355:            sizeof(sd->sd_vol.sv_sensordev.xname));
        !          2356:
        !          2357:        sd->sd_vol.sv_sensor.type = SENSOR_DRIVE;
        !          2358:        sd->sd_vol.sv_sensor.status = SENSOR_S_UNKNOWN;
        !          2359:        strlcpy(sd->sd_vol.sv_sensor.desc, sd->sd_vol.sv_meta.svm_devname,
        !          2360:            sizeof(sd->sd_vol.sv_sensor.desc));
        !          2361:
        !          2362:        sensor_attach(&sd->sd_vol.sv_sensordev, &sd->sd_vol.sv_sensor);
        !          2363:
        !          2364:        if (sc->sc_sensors_running == 0) {
        !          2365:                if (sensor_task_register(sc, sr_refresh_sensors, 10) == NULL)
        !          2366:                        goto bad;
        !          2367:                sc->sc_sensors_running = 1;
        !          2368:        }
        !          2369:        sensordev_install(&sd->sd_vol.sv_sensordev);
        !          2370:
        !          2371:        rv = 0;
        !          2372: bad:
        !          2373:        return (rv);
        !          2374: }
        !          2375:
        !          2376: void
        !          2377: sr_delete_sensors(struct sr_discipline *sd)
        !          2378: {
        !          2379: #ifdef SR_DEBUG
        !          2380:        struct sr_softc         *sc = sd->sd_sc;
        !          2381: #endif
        !          2382:        DNPRINTF(SR_D_STATE, "%s: %s: sr_delete_sensors\n",
        !          2383:            DEVNAME(sc), sd->sd_vol.sv_meta.svm_devname);
        !          2384:
        !          2385:        if (sd->sd_vol.sv_sensor_valid)
        !          2386:                sensordev_deinstall(&sd->sd_vol.sv_sensordev);
        !          2387: }
        !          2388:
        !          2389: void
        !          2390: sr_refresh_sensors(void *arg)
        !          2391: {
        !          2392:        struct sr_softc         *sc = arg;
        !          2393:        int                     i, vol;
        !          2394:        struct sr_volume        *sv;
        !          2395:
        !          2396:        DNPRINTF(SR_D_STATE, "%s: sr_refresh_sensors\n", DEVNAME(sc));
        !          2397:
        !          2398:        for (i = 0, vol = -1; i < SR_MAXSCSIBUS; i++) {
        !          2399:                /* XXX this will not work when we stagger disciplines */
        !          2400:                if (!sc->sc_dis[i])
        !          2401:                        continue;
        !          2402:
        !          2403:                sv = &sc->sc_dis[i]->sd_vol;
        !          2404:
        !          2405:                switch(sv->sv_meta.svm_status) {
        !          2406:                case BIOC_SVOFFLINE:
        !          2407:                        sv->sv_sensor.value = SENSOR_DRIVE_FAIL;
        !          2408:                        sv->sv_sensor.status = SENSOR_S_CRIT;
        !          2409:                        break;
        !          2410:
        !          2411:                case BIOC_SVDEGRADED:
        !          2412:                        sv->sv_sensor.value = SENSOR_DRIVE_PFAIL;
        !          2413:                        sv->sv_sensor.status = SENSOR_S_WARN;
        !          2414:                        break;
        !          2415:
        !          2416:                case BIOC_SVSCRUB:
        !          2417:                case BIOC_SVONLINE:
        !          2418:                        sv->sv_sensor.value = SENSOR_DRIVE_ONLINE;
        !          2419:                        sv->sv_sensor.status = SENSOR_S_OK;
        !          2420:                        break;
        !          2421:
        !          2422:                default:
        !          2423:                        sv->sv_sensor.value = 0; /* unknown */
        !          2424:                        sv->sv_sensor.status = SENSOR_S_UNKNOWN;
        !          2425:                }
        !          2426:        }
        !          2427: }
        !          2428: #endif /* SMALL_KERNEL */
        !          2429:
        !          2430: #ifdef SR_FANCY_STATS
        !          2431: void                           sr_print_stats(void);
        !          2432:
        !          2433: void
        !          2434: sr_print_stats(void)
        !          2435: {
        !          2436:        struct sr_softc         *sc;
        !          2437:        struct sr_discipline    *sd;
        !          2438:        int                     i, vol;
        !          2439:
        !          2440:        for (i = 0; i < softraid_cd.cd_ndevs; i++)
        !          2441:                if (softraid_cd.cd_devs[i]) {
        !          2442:                        sc = softraid_cd.cd_devs[i];
        !          2443:                        /* we'll only have one softc */
        !          2444:                        break;
        !          2445:                }
        !          2446:
        !          2447:        if (!sc) {
        !          2448:                printf("no softraid softc found\n");
        !          2449:                return;
        !          2450:        }
        !          2451:
        !          2452:        for (i = 0, vol = -1; i < SR_MAXSCSIBUS; i++) {
        !          2453:                /* XXX this will not work when we stagger disciplines */
        !          2454:                if (!sc->sc_dis[i])
        !          2455:                        continue;
        !          2456:
        !          2457:                sd = sc->sc_dis[i];
        !          2458:                printf("%s: ios pending: %d  collisions %llu\n",
        !          2459:                    sd->sd_vol.sv_meta.svm_devname,
        !          2460:                    sd->sd_wu_pending,
        !          2461:                    sd->sd_wu_collisions);
        !          2462:        }
        !          2463: }
        !          2464: #endif /* SR_FANCY_STATS */
        !          2465:
        !          2466: #ifdef SR_DEBUG
        !          2467: void
        !          2468: sr_print_metadata(struct sr_metadata *sm)
        !          2469: {
        !          2470:        struct sr_vol_meta      *im_sv;
        !          2471:        struct sr_chunk_meta    *im_sc;
        !          2472:        int                     ch;
        !          2473:
        !          2474:        im_sv = (struct sr_vol_meta *)(sm + 1);
        !          2475:        im_sc = (struct sr_chunk_meta *)(im_sv + 1);
        !          2476:
        !          2477:        DNPRINTF(SR_D_META, "\tmeta magic 0x%llx\n", sm->ssd_magic);
        !          2478:        DNPRINTF(SR_D_META, "\tmeta version %d\n", sm->ssd_version);
        !          2479:        DNPRINTF(SR_D_META, "\tmeta checksum 0x%x\n", sm->ssd_checksum);
        !          2480:        DNPRINTF(SR_D_META, "\tmeta size %d\n", sm->ssd_size);
        !          2481:        DNPRINTF(SR_D_META, "\tmeta on disk version %u\n", sm->ssd_ondisk);
        !          2482:        DNPRINTF(SR_D_META, "\tmeta uuid ");
        !          2483:        sr_print_uuid(&sm->ssd_uuid, 1);
        !          2484:        DNPRINTF(SR_D_META, "\tvd version %d\n", sm->ssd_vd_ver);
        !          2485:        DNPRINTF(SR_D_META, "\tvd size %lu\n", sm->ssd_vd_size);
        !          2486:        DNPRINTF(SR_D_META, "\tvd id %u\n", sm->ssd_vd_volid);
        !          2487:        DNPRINTF(SR_D_META, "\tvd checksum 0x%x\n", sm->ssd_vd_chk);
        !          2488:        DNPRINTF(SR_D_META, "\tchunk version %d\n", sm->ssd_chunk_ver);
        !          2489:        DNPRINTF(SR_D_META, "\tchunks %d\n", sm->ssd_chunk_no);
        !          2490:        DNPRINTF(SR_D_META, "\tchunk size %u\n", sm->ssd_chunk_size);
        !          2491:        DNPRINTF(SR_D_META, "\tchunk id %u\n", sm->ssd_chunk_id);
        !          2492:        DNPRINTF(SR_D_META, "\tchunk checksum 0x%x\n", sm->ssd_chunk_chk);
        !          2493:
        !          2494:        DNPRINTF(SR_D_META, "\t\tvol id %d\n", im_sv->svm_volid);
        !          2495:        DNPRINTF(SR_D_META, "\t\tvol status %d\n", im_sv->svm_status);
        !          2496:        DNPRINTF(SR_D_META, "\t\tvol flags 0x%x\n", im_sv->svm_flags);
        !          2497:        DNPRINTF(SR_D_META, "\t\tvol level %d\n", im_sv->svm_level);
        !          2498:        DNPRINTF(SR_D_META, "\t\tvol size %lld\n", im_sv->svm_size);
        !          2499:        DNPRINTF(SR_D_META, "\t\tvol name %s\n", im_sv->svm_devname);
        !          2500:        DNPRINTF(SR_D_META, "\t\tvol vendor %s\n", im_sv->svm_vendor);
        !          2501:        DNPRINTF(SR_D_META, "\t\tvol prod %s\n", im_sv->svm_product);
        !          2502:        DNPRINTF(SR_D_META, "\t\tvol rev %s\n", im_sv->svm_revision);
        !          2503:        DNPRINTF(SR_D_META, "\t\tvol no chunks %d\n", im_sv->svm_no_chunk);
        !          2504:        DNPRINTF(SR_D_META, "\t\tvol uuid ");
        !          2505:        sr_print_uuid(& im_sv->svm_uuid, 1);
        !          2506:
        !          2507:        for (ch = 0; ch < im_sv->svm_no_chunk; ch++) {
        !          2508:                DNPRINTF(SR_D_META, "\t\t\tchunk vol id %d\n",
        !          2509:                    im_sc[ch].scm_volid);
        !          2510:                DNPRINTF(SR_D_META, "\t\t\tchunk id %d\n",
        !          2511:                    im_sc[ch].scm_chunk_id);
        !          2512:                DNPRINTF(SR_D_META, "\t\t\tchunk status %d\n",
        !          2513:                    im_sc[ch].scm_status);
        !          2514:                DNPRINTF(SR_D_META, "\t\t\tchunk name %s\n",
        !          2515:                    im_sc[ch].scm_devname);
        !          2516:                DNPRINTF(SR_D_META, "\t\t\tchunk size %lld\n",
        !          2517:                    im_sc[ch].scm_size);
        !          2518:                DNPRINTF(SR_D_META, "\t\t\tchunk coerced size %lld\n",
        !          2519:                    im_sc[ch].scm_coerced_size);
        !          2520:                DNPRINTF(SR_D_META, "\t\t\tchunk uuid ");
        !          2521:                sr_print_uuid(&im_sc[ch].scm_uuid, 1);
        !          2522:        }
        !          2523: }
        !          2524: #endif /* SR_DEBUG */
        !          2525:
        !          2526: /* RAID 1 functions */
        !          2527: int
        !          2528: sr_raid1_alloc_resources(struct sr_discipline *sd)
        !          2529: {
        !          2530:        int                     rv = EINVAL;
        !          2531:
        !          2532:        if (!sd)
        !          2533:                return (rv);
        !          2534:
        !          2535:        DNPRINTF(SR_D_DIS, "%s: sr_raid1_alloc_resources\n",
        !          2536:            DEVNAME(sd->sd_sc));
        !          2537:
        !          2538:        if (sr_alloc_wu(sd))
        !          2539:                goto bad;
        !          2540:        if (sr_alloc_ccb(sd))
        !          2541:                goto bad;
        !          2542:
        !          2543:        rv = 0;
        !          2544: bad:
        !          2545:        return (rv);
        !          2546: }
        !          2547:
        !          2548: int
        !          2549: sr_raid1_free_resources(struct sr_discipline *sd)
        !          2550: {
        !          2551:        int                     rv = EINVAL;
        !          2552:
        !          2553:        if (!sd)
        !          2554:                return (rv);
        !          2555:
        !          2556:        DNPRINTF(SR_D_DIS, "%s: sr_raid1_free_resources\n",
        !          2557:            DEVNAME(sd->sd_sc));
        !          2558:
        !          2559:        sr_free_wu(sd);
        !          2560:        sr_free_ccb(sd);
        !          2561:
        !          2562:        if (sd->sd_meta)
        !          2563:                free(sd->sd_meta, M_DEVBUF);
        !          2564:
        !          2565:        rv = 0;
        !          2566:        return (rv);
        !          2567: }
        !          2568:
        !          2569: int
        !          2570: sr_raid1_rw(struct sr_workunit *wu)
        !          2571: {
        !          2572:        struct sr_discipline    *sd = wu->swu_dis;
        !          2573:        struct scsi_xfer        *xs = wu->swu_xs;
        !          2574:        struct sr_workunit      *wup;
        !          2575:        struct sr_ccb           *ccb;
        !          2576:        struct sr_chunk         *scp;
        !          2577:        int                     ios, x, i, s, rt;
        !          2578:        daddr64_t               blk;
        !          2579:
        !          2580:        DNPRINTF(SR_D_DIS, "%s: sr_raid1_rw 0x%02x\n", DEVNAME(sd->sd_sc),
        !          2581:            xs->cmd->opcode);
        !          2582:
        !          2583:        if (sd->sd_vol.sv_meta.svm_status == BIOC_SVOFFLINE) {
        !          2584:                DNPRINTF(SR_D_DIS, "%s: sr_raid1_rw device offline\n",
        !          2585:                    DEVNAME(sd->sd_sc));
        !          2586:                goto bad;
        !          2587:        }
        !          2588:
        !          2589:        if (xs->datalen == 0) {
        !          2590:                printf("%s: %s: illegal block count\n",
        !          2591:                    DEVNAME(sd->sd_sc), sd->sd_vol.sv_meta.svm_devname);
        !          2592:                goto bad;
        !          2593:        }
        !          2594:
        !          2595:        if (xs->cmdlen == 10)
        !          2596:                blk = _4btol(((struct scsi_rw_big *)xs->cmd)->addr);
        !          2597:        else if (xs->cmdlen == 6)
        !          2598:                blk = _3btol(((struct scsi_rw *)xs->cmd)->addr);
        !          2599:        else {
        !          2600:                printf("%s: %s: illegal cmdlen\n", DEVNAME(sd->sd_sc),
        !          2601:                    sd->sd_vol.sv_meta.svm_devname);
        !          2602:                goto bad;
        !          2603:        }
        !          2604:
        !          2605:        wu->swu_blk_start = blk;
        !          2606:        wu->swu_blk_end = blk + (xs->datalen >> 9) - 1;
        !          2607:
        !          2608:        if (wu->swu_blk_end > sd->sd_vol.sv_meta.svm_size) {
        !          2609:                DNPRINTF(SR_D_DIS, "%s: sr_raid1_rw out of bounds start: %lld "
        !          2610:                    "end: %lld length: %d\n", wu->swu_blk_start,
        !          2611:                    wu->swu_blk_end, xs->datalen);
        !          2612:
        !          2613:                sd->sd_scsi_sense.error_code = SSD_ERRCODE_CURRENT |
        !          2614:                    SSD_ERRCODE_VALID;
        !          2615:                sd->sd_scsi_sense.flags = SKEY_ILLEGAL_REQUEST;
        !          2616:                sd->sd_scsi_sense.add_sense_code = 0x21;
        !          2617:                sd->sd_scsi_sense.add_sense_code_qual = 0x00;
        !          2618:                sd->sd_scsi_sense.extra_len = 4;
        !          2619:                goto bad;
        !          2620:        }
        !          2621:
        !          2622:        /* calculate physical block */
        !          2623:        blk += SR_META_SIZE + SR_META_OFFSET;
        !          2624:
        !          2625:        if (xs->flags & SCSI_DATA_IN)
        !          2626:                ios = 1;
        !          2627:        else
        !          2628:                ios = sd->sd_vol.sv_meta.svm_no_chunk;
        !          2629:        wu->swu_io_count = ios;
        !          2630:
        !          2631:        for (i = 0; i < ios; i++) {
        !          2632:                ccb = sr_get_ccb(sd);
        !          2633:                if (!ccb) {
        !          2634:                        /* should never happen but handle more gracefully */
        !          2635:                        printf("%s: %s: too many ccbs queued\n",
        !          2636:                            DEVNAME(sd->sd_sc),
        !          2637:                            sd->sd_vol.sv_meta.svm_devname);
        !          2638:                        goto bad;
        !          2639:                }
        !          2640:
        !          2641:                if (xs->flags & SCSI_POLL) {
        !          2642:                        ccb->ccb_buf.b_flags = 0;
        !          2643:                        ccb->ccb_buf.b_iodone = NULL;
        !          2644:                } else {
        !          2645:                        ccb->ccb_buf.b_flags = B_CALL;
        !          2646:                        ccb->ccb_buf.b_iodone = sr_raid1_intr;
        !          2647:                }
        !          2648:
        !          2649:                ccb->ccb_buf.b_blkno = blk;
        !          2650:                ccb->ccb_buf.b_bcount = xs->datalen;
        !          2651:                ccb->ccb_buf.b_bufsize = xs->datalen;
        !          2652:                ccb->ccb_buf.b_resid = xs->datalen;
        !          2653:                ccb->ccb_buf.b_data = xs->data;
        !          2654:                ccb->ccb_buf.b_error = 0;
        !          2655:                ccb->ccb_buf.b_proc = curproc;
        !          2656:                ccb->ccb_wu = wu;
        !          2657:
        !          2658:                if (xs->flags & SCSI_DATA_IN) {
        !          2659:                        rt = 0;
        !          2660: ragain:
        !          2661:                        /* interleave reads */
        !          2662:                        x = sd->mds.mdd_raid1.sr1_counter++ %
        !          2663:                            sd->sd_vol.sv_meta.svm_no_chunk;
        !          2664:                        scp = sd->sd_vol.sv_chunks[x];
        !          2665:                        switch (scp->src_meta.scm_status) {
        !          2666:                        case BIOC_SDONLINE:
        !          2667:                        case BIOC_SDSCRUB:
        !          2668:                                ccb->ccb_buf.b_flags |= B_READ;
        !          2669:                                break;
        !          2670:
        !          2671:                        case BIOC_SDOFFLINE:
        !          2672:                        case BIOC_SDREBUILD:
        !          2673:                        case BIOC_SDHOTSPARE:
        !          2674:                                if (rt++ < sd->sd_vol.sv_meta.svm_no_chunk)
        !          2675:                                        goto ragain;
        !          2676:
        !          2677:                                /* FALLTHROUGH */
        !          2678:                        default:
        !          2679:                                /* volume offline */
        !          2680:                                printf("%s: is offline, can't read\n",
        !          2681:                                    DEVNAME(sd->sd_sc));
        !          2682:                                sr_put_ccb(ccb);
        !          2683:                                goto bad;
        !          2684:                        }
        !          2685:                } else {
        !          2686:                        /* writes go on all working disks */
        !          2687:                        x = i;
        !          2688:                        scp = sd->sd_vol.sv_chunks[x];
        !          2689:                        switch (scp->src_meta.scm_status) {
        !          2690:                        case BIOC_SDONLINE:
        !          2691:                        case BIOC_SDSCRUB:
        !          2692:                        case BIOC_SDREBUILD:
        !          2693:                                ccb->ccb_buf.b_flags |= B_WRITE;
        !          2694:                                break;
        !          2695:
        !          2696:                        case BIOC_SDHOTSPARE: /* should never happen */
        !          2697:                        case BIOC_SDOFFLINE:
        !          2698:                                wu->swu_io_count--;
        !          2699:                                sr_put_ccb(ccb);
        !          2700:                                continue;
        !          2701:
        !          2702:                        default:
        !          2703:                                goto bad;
        !          2704:                        }
        !          2705:
        !          2706:                }
        !          2707:                ccb->ccb_target = x;
        !          2708:                ccb->ccb_buf.b_dev = sd->sd_vol.sv_chunks[x]->src_dev_mm;
        !          2709:                ccb->ccb_buf.b_vp = NULL;
        !          2710:
        !          2711:                LIST_INIT(&ccb->ccb_buf.b_dep);
        !          2712:
        !          2713:                TAILQ_INSERT_TAIL(&wu->swu_ccb, ccb, ccb_link);
        !          2714:
        !          2715:                DNPRINTF(SR_D_DIS, "%s: %s: sr_raid1: b_bcount: %d "
        !          2716:                    "b_blkno: %x b_flags 0x%0x b_data %p\n",
        !          2717:                    DEVNAME(sd->sd_sc), sd->sd_vol.sv_meta.svm_devname,
        !          2718:                    ccb->ccb_buf.b_bcount, ccb->ccb_buf.b_blkno,
        !          2719:                    ccb->ccb_buf.b_flags, ccb->ccb_buf.b_data);
        !          2720:        }
        !          2721:
        !          2722:        s = splbio();
        !          2723:
        !          2724:        /* current io failed, restart */
        !          2725:        if (wu->swu_state == SR_WU_RESTART)
        !          2726:                goto start;
        !          2727:
        !          2728:        /* deferred io failed, don't restart */
        !          2729:        if (wu->swu_state == SR_WU_REQUEUE)
        !          2730:                goto queued;
        !          2731:
        !          2732:        /* walk queue backwards and fill in collider if we have one */
        !          2733:        TAILQ_FOREACH_REVERSE(wup, &sd->sd_wu_pendq, sr_wu_list, swu_link) {
        !          2734:                if (wu->swu_blk_end < wup->swu_blk_start ||
        !          2735:                    wup->swu_blk_end < wu->swu_blk_start)
        !          2736:                        continue;
        !          2737:
        !          2738:                /* we have an LBA collision, defer wu */
        !          2739:                wu->swu_state = SR_WU_DEFERRED;
        !          2740:                if (wup->swu_collider)
        !          2741:                        /* wu is on deferred queue, append to last wu */
        !          2742:                        while (wup->swu_collider)
        !          2743:                                wup = wup->swu_collider;
        !          2744:
        !          2745:                wup->swu_collider = wu;
        !          2746:                TAILQ_INSERT_TAIL(&sd->sd_wu_defq, wu, swu_link);
        !          2747:                sd->sd_wu_collisions++;
        !          2748:                goto queued;
        !          2749:        }
        !          2750:
        !          2751:        /* XXX deal with polling */
        !          2752: start:
        !          2753:        sr_raid_startwu(wu);
        !          2754: queued:
        !          2755:        splx(s);
        !          2756:        return (0);
        !          2757: bad:
        !          2758:        /* wu is unwound by sr_put_wu */
        !          2759:        return (1);
        !          2760: }
        !          2761:
        !          2762: void
        !          2763: sr_raid1_intr(struct buf *bp)
        !          2764: {
        !          2765:        struct sr_ccb           *ccb = (struct sr_ccb *)bp;
        !          2766:        struct sr_workunit      *wu = ccb->ccb_wu, *wup;
        !          2767:        struct sr_discipline    *sd = wu->swu_dis;
        !          2768:        struct scsi_xfer        *xs = wu->swu_xs;
        !          2769:        struct sr_softc         *sc = sd->sd_sc;
        !          2770:        int                     s, pend;
        !          2771:
        !          2772:        DNPRINTF(SR_D_INTR, "%s: sr_intr bp %x xs %x\n",
        !          2773:            DEVNAME(sc), bp, xs);
        !          2774:
        !          2775:        DNPRINTF(SR_D_INTR, "%s: sr_intr: b_bcount: %d b_resid: %d"
        !          2776:            " b_flags: 0x%0x block: %lld target: %d\n", DEVNAME(sc),
        !          2777:            ccb->ccb_buf.b_bcount, ccb->ccb_buf.b_resid, ccb->ccb_buf.b_flags,
        !          2778:            ccb->ccb_buf.b_blkno, ccb->ccb_target);
        !          2779:
        !          2780:        s = splbio();
        !          2781:
        !          2782:        if (ccb->ccb_buf.b_flags & B_ERROR) {
        !          2783:                DNPRINTF(SR_D_INTR, "%s: i/o error on block %lld target: %d\n",
        !          2784:                    DEVNAME(sc), ccb->ccb_buf.b_blkno, ccb->ccb_target);
        !          2785:                wu->swu_ios_failed++;
        !          2786:                ccb->ccb_state = SR_CCB_FAILED;
        !          2787:                if (ccb->ccb_target != -1)
        !          2788:                        sd->sd_set_chunk_state(sd, ccb->ccb_target,
        !          2789:                            BIOC_SDOFFLINE);
        !          2790:                else
        !          2791:                        panic("%s: invalid target on wu: %p", DEVNAME(sc), wu);
        !          2792:        } else {
        !          2793:                ccb->ccb_state = SR_CCB_OK;
        !          2794:                wu->swu_ios_succeeded++;
        !          2795:        }
        !          2796:        wu->swu_ios_complete++;
        !          2797:
        !          2798:        DNPRINTF(SR_D_INTR, "%s: sr_intr: comp: %d count: %d failed: %d\n",
        !          2799:            DEVNAME(sc), wu->swu_ios_complete, wu->swu_io_count,
        !          2800:            wu->swu_ios_failed);
        !          2801:
        !          2802:        if (wu->swu_ios_complete >= wu->swu_io_count) {
        !          2803:                /* if all ios failed, retry reads and give up on writes */
        !          2804:                if (wu->swu_ios_failed == wu->swu_ios_complete) {
        !          2805:                        if (xs->flags & SCSI_DATA_IN) {
        !          2806:                                printf("%s: retrying read on block %lld\n",
        !          2807:                                    DEVNAME(sc), ccb->ccb_buf.b_blkno);
        !          2808:                                sr_put_ccb(ccb);
        !          2809:                                TAILQ_INIT(&wu->swu_ccb);
        !          2810:                                wu->swu_state = SR_WU_RESTART;
        !          2811:                                if (sd->sd_scsi_rw(wu))
        !          2812:                                        goto bad;
        !          2813:                                else
        !          2814:                                        goto retry;
        !          2815:                        } else {
        !          2816:                                printf("%s: permanently fail write on block "
        !          2817:                                    "%lld\n", DEVNAME(sc),
        !          2818:                                    ccb->ccb_buf.b_blkno);
        !          2819:                                xs->error = XS_DRIVER_STUFFUP;
        !          2820:                                goto bad;
        !          2821:                        }
        !          2822:                }
        !          2823:
        !          2824:                xs->error = XS_NOERROR;
        !          2825:                xs->resid = 0;
        !          2826:                xs->flags |= ITSDONE;
        !          2827:
        !          2828:                pend = 0;
        !          2829:                TAILQ_FOREACH(wup, &sd->sd_wu_pendq, swu_link) {
        !          2830:                        if (wu == wup) {
        !          2831:                                /* wu on pendq, remove */
        !          2832:                                TAILQ_REMOVE(&sd->sd_wu_pendq, wu, swu_link);
        !          2833:                                pend = 1;
        !          2834:
        !          2835:                                if (wu->swu_collider) {
        !          2836:                                        if (wu->swu_ios_failed)
        !          2837:                                                /* toss all ccbs and recreate */
        !          2838:                                                sr_raid1_recreate_wu(wu->swu_collider);
        !          2839:
        !          2840:                                        /* restart deferred wu */
        !          2841:                                        wu->swu_collider->swu_state =
        !          2842:                                            SR_WU_INPROGRESS;
        !          2843:                                        TAILQ_REMOVE(&sd->sd_wu_defq,
        !          2844:                                            wu->swu_collider, swu_link);
        !          2845:                                        sr_raid_startwu(wu->swu_collider);
        !          2846:                                }
        !          2847:                                break;
        !          2848:                        }
        !          2849:                }
        !          2850:
        !          2851:                if (!pend)
        !          2852:                        printf("%s: wu: %p not on pending queue\n",
        !          2853:                            DEVNAME(sc), wu);
        !          2854:
        !          2855:                /* do not change the order of these 2 functions */
        !          2856:                sr_put_wu(wu);
        !          2857:                scsi_done(xs);
        !          2858:
        !          2859:                if (sd->sd_sync && sd->sd_wu_pending == 0)
        !          2860:                        wakeup(sd);
        !          2861:        }
        !          2862:
        !          2863: retry:
        !          2864:        splx(s);
        !          2865:        return;
        !          2866: bad:
        !          2867:        xs->error = XS_DRIVER_STUFFUP;
        !          2868:        xs->flags |= ITSDONE;
        !          2869:        sr_put_wu(wu);
        !          2870:        scsi_done(xs);
        !          2871:        splx(s);
        !          2872: }
        !          2873:
        !          2874: void
        !          2875: sr_raid1_recreate_wu(struct sr_workunit *wu)
        !          2876: {
        !          2877:        struct sr_discipline    *sd = wu->swu_dis;
        !          2878:        struct sr_workunit      *wup = wu;
        !          2879:        struct sr_ccb           *ccb;
        !          2880:
        !          2881:        do {
        !          2882:                DNPRINTF(SR_D_INTR, "%s: sr_raid1_recreate_wu: %p\n", wup);
        !          2883:
        !          2884:                /* toss all ccbs */
        !          2885:                while ((ccb = TAILQ_FIRST(&wup->swu_ccb)) != NULL) {
        !          2886:                        TAILQ_REMOVE(&wup->swu_ccb, ccb, ccb_link);
        !          2887:                        sr_put_ccb(ccb);
        !          2888:                }
        !          2889:                TAILQ_INIT(&wup->swu_ccb);
        !          2890:
        !          2891:                /* recreate ccbs */
        !          2892:                wup->swu_state = SR_WU_REQUEUE;
        !          2893:                if (sd->sd_scsi_rw(wup))
        !          2894:                        panic("could not requeue io");
        !          2895:
        !          2896:                wup = wup->swu_collider;
        !          2897:        } while (wup);
        !          2898: }
        !          2899:
        !          2900: #ifdef CRYPTO
        !          2901: /* RAID crypto functions */
        !          2902: struct cryptop *
        !          2903: sr_raidc_getcryptop(struct sr_workunit *wu, int encrypt)
        !          2904: {
        !          2905:        struct scsi_xfer        *xs = wu->swu_xs;
        !          2906:        struct sr_discipline    *sd = wu->swu_dis;
        !          2907:        struct cryptop          *crp;
        !          2908:        struct cryptodesc       *crd;
        !          2909:        struct uio              *uio;
        !          2910:        int                     flags, i, n;
        !          2911:        int                     blk = 0;
        !          2912:
        !          2913:        DNPRINTF(SR_D_DIS, "%s: sr_raidc_getcryptop wu: %p encrypt: %d\n",
        !          2914:            DEVNAME(sd->sd_sc), wu, encrypt);
        !          2915:
        !          2916:        uio = malloc(sizeof(*uio), M_DEVBUF, M_WAITOK);
        !          2917:        memset(uio, 0, sizeof(*uio));
        !          2918:        uio->uio_iov = malloc(sizeof(*uio->uio_iov), M_DEVBUF, M_WAITOK);
        !          2919:        uio->uio_iovcnt = 1;
        !          2920:        uio->uio_iov->iov_base = xs->data;
        !          2921:        uio->uio_iov->iov_len = xs->datalen;
        !          2922:
        !          2923:        if (xs->cmdlen == 10)
        !          2924:                blk = _4btol(((struct scsi_rw_big *)xs->cmd)->addr);
        !          2925:        else if (xs->cmdlen == 6)
        !          2926:                blk = _3btol(((struct scsi_rw *)xs->cmd)->addr);
        !          2927:
        !          2928:        n = xs->datalen >> 9;
        !          2929:        flags = (encrypt ? CRD_F_ENCRYPT : 0) |
        !          2930:            CRD_F_IV_PRESENT | CRD_F_IV_EXPLICIT;
        !          2931:
        !          2932:        crp = crypto_getreq(n);
        !          2933:
        !          2934:        crp->crp_sid = sd->mds.mdd_raidc.src_sid;
        !          2935:        crp->crp_ilen = xs->datalen;
        !          2936:        crp->crp_alloctype = M_DEVBUF;
        !          2937:        crp->crp_buf = uio;
        !          2938:        for (i = 0, crd = crp->crp_desc; crd; i++, crd = crd->crd_next) {
        !          2939:                crd->crd_skip = 512 * i;
        !          2940:                crd->crd_len = 512;
        !          2941:                crd->crd_inject = 0;
        !          2942:                crd->crd_flags = flags;
        !          2943:                crd->crd_alg = CRYPTO_AES_CBC;
        !          2944:                crd->crd_klen = 256;
        !          2945:                crd->crd_rnd = 14;
        !          2946:                crd->crd_key = sd->mds.mdd_raidc.src_key;
        !          2947:                memset(crd->crd_iv, blk + i, sizeof(crd->crd_iv));
        !          2948:        }
        !          2949:
        !          2950:        return (crp);
        !          2951: }
        !          2952:
        !          2953: void *
        !          2954: sr_raidc_putcryptop(struct cryptop *crp)
        !          2955: {
        !          2956:        struct uio              *uio = crp->crp_buf;
        !          2957:        void                    *opaque = crp->crp_opaque;
        !          2958:
        !          2959:        DNPRINTF(SR_D_DIS, "sr_raidc_putcryptop crp: %p\n", crp);
        !          2960:
        !          2961:        free(uio->uio_iov, M_DEVBUF);
        !          2962:        free(uio, M_DEVBUF);
        !          2963:        crypto_freereq(crp);
        !          2964:
        !          2965:        return (opaque);
        !          2966: }
        !          2967:
        !          2968: int
        !          2969: sr_raidc_alloc_resources(struct sr_discipline *sd)
        !          2970: {
        !          2971:        struct cryptoini        cri;
        !          2972:
        !          2973:        if (!sd)
        !          2974:                return (EINVAL);
        !          2975:
        !          2976:        DNPRINTF(SR_D_DIS, "%s: sr_raidc_alloc_resources\n",
        !          2977:            DEVNAME(sd->sd_sc));
        !          2978:
        !          2979:        if (sr_alloc_wu(sd))
        !          2980:                return (ENOMEM);
        !          2981:        if (sr_alloc_ccb(sd))
        !          2982:                return (ENOMEM);
        !          2983:
        !          2984:        /* XXX we need a real key later */
        !          2985:        memset(sd->mds.mdd_raidc.src_key, 'k',
        !          2986:            sizeof sd->mds.mdd_raidc.src_key);
        !          2987:
        !          2988:        bzero(&cri, sizeof(cri));
        !          2989:        cri.cri_alg = CRYPTO_AES_CBC;
        !          2990:        cri.cri_klen = 256;
        !          2991:        cri.cri_rnd = 14;
        !          2992:        cri.cri_key = sd->mds.mdd_raidc.src_key;
        !          2993:
        !          2994:        return (crypto_newsession(&sd->mds.mdd_raidc.src_sid, &cri, 0));
        !          2995: }
        !          2996:
        !          2997: int
        !          2998: sr_raidc_free_resources(struct sr_discipline *sd)
        !          2999: {
        !          3000:        int                     rv = EINVAL;
        !          3001:
        !          3002:        if (!sd)
        !          3003:                return (rv);
        !          3004:
        !          3005:        DNPRINTF(SR_D_DIS, "%s: sr_raidc_free_resources\n",
        !          3006:            DEVNAME(sd->sd_sc));
        !          3007:
        !          3008:        sr_free_wu(sd);
        !          3009:        sr_free_ccb(sd);
        !          3010:
        !          3011:        if (sd->sd_meta)
        !          3012:                free(sd->sd_meta, M_DEVBUF);
        !          3013:
        !          3014:        rv = 0;
        !          3015:        return (rv);
        !          3016: }
        !          3017:
        !          3018: int
        !          3019: sr_raidc_rw(struct sr_workunit *wu)
        !          3020: {
        !          3021:        struct cryptop          *crp;
        !          3022:
        !          3023:        DNPRINTF(SR_D_DIS, "%s: sr_raidc_rw wu: %p\n",
        !          3024:            DEVNAME(wu->swu_dis->sd_sc), wu);
        !          3025:
        !          3026:        crp = sr_raidc_getcryptop(wu, 1);
        !          3027:        crp->crp_callback = sr_raidc_rw2;
        !          3028:        crp->crp_opaque = wu;
        !          3029:        crypto_dispatch(crp);
        !          3030:
        !          3031:        return (0);
        !          3032: }
        !          3033:
        !          3034: int
        !          3035: sr_raidc_rw2(struct cryptop *crp)
        !          3036: {
        !          3037:        struct sr_workunit      *wu = sr_raidc_putcryptop(crp);
        !          3038:        struct sr_discipline    *sd = wu->swu_dis;
        !          3039:        struct scsi_xfer        *xs = wu->swu_xs;
        !          3040:        struct sr_workunit      *wup;
        !          3041:        struct sr_ccb           *ccb;
        !          3042:        struct sr_chunk         *scp;
        !          3043:        int                     s, rt;
        !          3044:        daddr64_t               blk;
        !          3045:
        !          3046:        DNPRINTF(SR_D_DIS, "%s: sr_raidc_rw2 0x%02x\n", DEVNAME(sd->sd_sc),
        !          3047:            xs->cmd->opcode);
        !          3048:
        !          3049:        if (sd->sd_vol.sv_meta.svm_status == BIOC_SVOFFLINE) {
        !          3050:                DNPRINTF(SR_D_DIS, "%s: sr_raidc_rw device offline\n",
        !          3051:                    DEVNAME(sd->sd_sc));
        !          3052:                goto bad;
        !          3053:        }
        !          3054:
        !          3055:        if (xs->datalen == 0) {
        !          3056:                printf("%s: %s: illegal block count\n",
        !          3057:                    DEVNAME(sd->sd_sc), sd->sd_vol.sv_meta.svm_devname);
        !          3058:                goto bad;
        !          3059:        }
        !          3060:
        !          3061:        if (xs->cmdlen == 10)
        !          3062:                blk = _4btol(((struct scsi_rw_big *)xs->cmd)->addr);
        !          3063:        else if (xs->cmdlen == 6)
        !          3064:                blk = _3btol(((struct scsi_rw *)xs->cmd)->addr);
        !          3065:        else {
        !          3066:                printf("%s: %s: illegal cmdlen\n", DEVNAME(sd->sd_sc),
        !          3067:                    sd->sd_vol.sv_meta.svm_devname);
        !          3068:                goto bad;
        !          3069:        }
        !          3070:
        !          3071:        wu->swu_blk_start = blk;
        !          3072:        wu->swu_blk_end = blk + (xs->datalen >> 9) - 1;
        !          3073:
        !          3074:        if (wu->swu_blk_end > sd->sd_vol.sv_meta.svm_size) {
        !          3075:                DNPRINTF(SR_D_DIS, "%s: sr_raidc_rw2 out of bounds start: %lld "
        !          3076:                    "end: %lld length: %d\n", wu->swu_blk_start,
        !          3077:                    wu->swu_blk_end, xs->datalen);
        !          3078:
        !          3079:                sd->sd_scsi_sense.error_code = SSD_ERRCODE_CURRENT |
        !          3080:                    SSD_ERRCODE_VALID;
        !          3081:                sd->sd_scsi_sense.flags = SKEY_ILLEGAL_REQUEST;
        !          3082:                sd->sd_scsi_sense.add_sense_code = 0x21;
        !          3083:                sd->sd_scsi_sense.add_sense_code_qual = 0x00;
        !          3084:                sd->sd_scsi_sense.extra_len = 4;
        !          3085:                goto bad;
        !          3086:        }
        !          3087:
        !          3088:        /* calculate physical block */
        !          3089:        blk += SR_META_SIZE + SR_META_OFFSET;
        !          3090:
        !          3091:        wu->swu_io_count = 1;
        !          3092:
        !          3093:        ccb = sr_get_ccb(sd);
        !          3094:        if (!ccb) {
        !          3095:                /* should never happen but handle more gracefully */
        !          3096:                printf("%s: %s: too many ccbs queued\n",
        !          3097:                    DEVNAME(sd->sd_sc),
        !          3098:                    sd->sd_vol.sv_meta.svm_devname);
        !          3099:                goto bad;
        !          3100:        }
        !          3101:
        !          3102:        if (xs->flags & SCSI_POLL) {
        !          3103:                panic("not yet, crypto poll");
        !          3104:                ccb->ccb_buf.b_flags = 0;
        !          3105:                ccb->ccb_buf.b_iodone = NULL;
        !          3106:        } else {
        !          3107:                ccb->ccb_buf.b_flags = B_CALL;
        !          3108:                ccb->ccb_buf.b_iodone = sr_raidc_intr;
        !          3109:        }
        !          3110:
        !          3111:        ccb->ccb_buf.b_blkno = blk;
        !          3112:        ccb->ccb_buf.b_bcount = xs->datalen;
        !          3113:        ccb->ccb_buf.b_bufsize = xs->datalen;
        !          3114:        ccb->ccb_buf.b_resid = xs->datalen;
        !          3115:        ccb->ccb_buf.b_data = xs->data;
        !          3116:        ccb->ccb_buf.b_error = 0;
        !          3117:        ccb->ccb_buf.b_proc = curproc;
        !          3118:        ccb->ccb_wu = wu;
        !          3119:
        !          3120:        if (xs->flags & SCSI_DATA_IN) {
        !          3121:                rt = 0;
        !          3122: ragain:
        !          3123:                scp = sd->sd_vol.sv_chunks[0];
        !          3124:                switch (scp->src_meta.scm_status) {
        !          3125:                case BIOC_SDONLINE:
        !          3126:                case BIOC_SDSCRUB:
        !          3127:                        ccb->ccb_buf.b_flags |= B_READ;
        !          3128:                        break;
        !          3129:
        !          3130:                case BIOC_SDOFFLINE:
        !          3131:                case BIOC_SDREBUILD:
        !          3132:                case BIOC_SDHOTSPARE:
        !          3133:                        if (rt++ < sd->sd_vol.sv_meta.svm_no_chunk)
        !          3134:                                goto ragain;
        !          3135:
        !          3136:                        /* FALLTHROUGH */
        !          3137:                default:
        !          3138:                        /* volume offline */
        !          3139:                        printf("%s: is offline, can't read\n",
        !          3140:                            DEVNAME(sd->sd_sc));
        !          3141:                        sr_put_ccb(ccb);
        !          3142:                        goto bad;
        !          3143:                }
        !          3144:        } else {
        !          3145:                scp = sd->sd_vol.sv_chunks[0];
        !          3146:                switch (scp->src_meta.scm_status) {
        !          3147:                case BIOC_SDONLINE:
        !          3148:                case BIOC_SDSCRUB:
        !          3149:                case BIOC_SDREBUILD:
        !          3150:                        ccb->ccb_buf.b_flags |= B_WRITE;
        !          3151:                        break;
        !          3152:
        !          3153:                case BIOC_SDHOTSPARE: /* should never happen */
        !          3154:                case BIOC_SDOFFLINE:
        !          3155:                        wu->swu_io_count--;
        !          3156:                        sr_put_ccb(ccb);
        !          3157:                        goto bad;
        !          3158:
        !          3159:                default:
        !          3160:                        goto bad;
        !          3161:                }
        !          3162:
        !          3163:        }
        !          3164:        ccb->ccb_target = 0;
        !          3165:        ccb->ccb_buf.b_dev = sd->sd_vol.sv_chunks[0]->src_dev_mm;
        !          3166:        ccb->ccb_buf.b_vp = NULL;
        !          3167:
        !          3168:        LIST_INIT(&ccb->ccb_buf.b_dep);
        !          3169:
        !          3170:        TAILQ_INSERT_TAIL(&wu->swu_ccb, ccb, ccb_link);
        !          3171:
        !          3172:        DNPRINTF(SR_D_DIS, "%s: %s: sr_raidc: b_bcount: %d "
        !          3173:            "b_blkno: %x b_flags 0x%0x b_data %p\n",
        !          3174:            DEVNAME(sd->sd_sc), sd->sd_vol.sv_meta.svm_devname,
        !          3175:            ccb->ccb_buf.b_bcount, ccb->ccb_buf.b_blkno,
        !          3176:            ccb->ccb_buf.b_flags, ccb->ccb_buf.b_data);
        !          3177:
        !          3178:
        !          3179:        /* walk queue backwards and fill in collider if we have one */
        !          3180:        s = splbio();
        !          3181:        TAILQ_FOREACH_REVERSE(wup, &sd->sd_wu_pendq, sr_wu_list, swu_link) {
        !          3182:                if (wu->swu_blk_end < wup->swu_blk_start ||
        !          3183:                    wup->swu_blk_end < wu->swu_blk_start)
        !          3184:                        continue;
        !          3185:
        !          3186:                /* we have an LBA collision, defer wu */
        !          3187:                wu->swu_state = SR_WU_DEFERRED;
        !          3188:                if (wup->swu_collider)
        !          3189:                        /* wu is on deferred queue, append to last wu */
        !          3190:                        while (wup->swu_collider)
        !          3191:                                wup = wup->swu_collider;
        !          3192:
        !          3193:                wup->swu_collider = wu;
        !          3194:                TAILQ_INSERT_TAIL(&sd->sd_wu_defq, wu, swu_link);
        !          3195:                sd->sd_wu_collisions++;
        !          3196:                goto queued;
        !          3197:        }
        !          3198:
        !          3199:        /* XXX deal with polling */
        !          3200:
        !          3201:        sr_raid_startwu(wu);
        !          3202:
        !          3203: queued:
        !          3204:        splx(s);
        !          3205:        return (0);
        !          3206: bad:
        !          3207:        /* wu is unwound by sr_put_wu */
        !          3208:        return (1);
        !          3209: }
        !          3210:
        !          3211: void
        !          3212: sr_raidc_intr(struct buf *bp)
        !          3213: {
        !          3214:        struct sr_ccb           *ccb = (struct sr_ccb *)bp;
        !          3215:        struct sr_workunit      *wu = ccb->ccb_wu;
        !          3216:        struct cryptop          *crp;
        !          3217: #ifdef SR_DEBUG
        !          3218:        struct sr_softc         *sc = wu->swu_dis->sd_sc;
        !          3219: #endif
        !          3220:
        !          3221:        DNPRINTF(SR_D_INTR, "%s: sr_raidc_intr bp: %x xs: %x\n",
        !          3222:            DEVNAME(sc), bp, wu->swu_xs);
        !          3223:
        !          3224:        DNPRINTF(SR_D_INTR, "%s: sr_raidc_intr: b_bcount: %d b_resid: %d"
        !          3225:            " b_flags: 0x%0x\n", DEVNAME(sc), ccb->ccb_buf.b_bcount,
        !          3226:            ccb->ccb_buf.b_resid, ccb->ccb_buf.b_flags);
        !          3227:
        !          3228:        crp = sr_raidc_getcryptop(wu, 0);
        !          3229:        crp->crp_callback = sr_raidc_intr2;
        !          3230:        crp->crp_opaque = bp;
        !          3231:        crypto_dispatch(crp);
        !          3232: }
        !          3233:
        !          3234: int
        !          3235: sr_raidc_intr2(struct cryptop *crp)
        !          3236: {
        !          3237:        struct buf              *bp = sr_raidc_putcryptop(crp);
        !          3238:        struct sr_ccb           *ccb = (struct sr_ccb *)bp;
        !          3239:        struct sr_workunit      *wu = ccb->ccb_wu, *wup;
        !          3240:        struct sr_discipline    *sd = wu->swu_dis;

CVSweb