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