1*c1b3d7c5SThomas E. Spanjaard /*- 2*c1b3d7c5SThomas E. Spanjaard * Copyright (c) 2000 - 2006 S�ren Schmidt <sos@FreeBSD.org> 3*c1b3d7c5SThomas E. Spanjaard * All rights reserved. 4*c1b3d7c5SThomas E. Spanjaard * 5*c1b3d7c5SThomas E. Spanjaard * Redistribution and use in source and binary forms, with or without 6*c1b3d7c5SThomas E. Spanjaard * modification, are permitted provided that the following conditions 7*c1b3d7c5SThomas E. Spanjaard * are met: 8*c1b3d7c5SThomas E. Spanjaard * 1. Redistributions of source code must retain the above copyright 9*c1b3d7c5SThomas E. Spanjaard * notice, this list of conditions and the following disclaimer, 10*c1b3d7c5SThomas E. Spanjaard * without modification, immediately at the beginning of the file. 11*c1b3d7c5SThomas E. Spanjaard * 2. Redistributions in binary form must reproduce the above copyright 12*c1b3d7c5SThomas E. Spanjaard * notice, this list of conditions and the following disclaimer in the 13*c1b3d7c5SThomas E. Spanjaard * documentation and/or other materials provided with the distribution. 14*c1b3d7c5SThomas E. Spanjaard * 15*c1b3d7c5SThomas E. Spanjaard * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16*c1b3d7c5SThomas E. Spanjaard * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17*c1b3d7c5SThomas E. Spanjaard * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18*c1b3d7c5SThomas E. Spanjaard * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19*c1b3d7c5SThomas E. Spanjaard * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20*c1b3d7c5SThomas E. Spanjaard * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21*c1b3d7c5SThomas E. Spanjaard * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22*c1b3d7c5SThomas E. Spanjaard * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23*c1b3d7c5SThomas E. Spanjaard * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24*c1b3d7c5SThomas E. Spanjaard * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25*c1b3d7c5SThomas E. Spanjaard * 26*c1b3d7c5SThomas E. Spanjaard * $FreeBSD: src/sys/dev/ata/ata-raid.c,v 1.120 2006/04/15 10:27:41 maxim Exp $ 27*c1b3d7c5SThomas E. Spanjaard * $DragonFly: src/sys/dev/disk/nata/ata-raid.c,v 1.1 2006/12/04 14:40:37 tgen Exp $ 28*c1b3d7c5SThomas E. Spanjaard */ 29*c1b3d7c5SThomas E. Spanjaard 30*c1b3d7c5SThomas E. Spanjaard #include <sys/cdefs.h> 31*c1b3d7c5SThomas E. Spanjaard 32*c1b3d7c5SThomas E. Spanjaard #include "opt_ata.h" 33*c1b3d7c5SThomas E. Spanjaard #include <sys/param.h> 34*c1b3d7c5SThomas E. Spanjaard #include <sys/systm.h> 35*c1b3d7c5SThomas E. Spanjaard #include <sys/nata.h> 36*c1b3d7c5SThomas E. Spanjaard #include <sys/kernel.h> 37*c1b3d7c5SThomas E. Spanjaard #include <sys/malloc.h> 38*c1b3d7c5SThomas E. Spanjaard #include <sys/module.h> 39*c1b3d7c5SThomas E. Spanjaard #include <sys/endian.h> 40*c1b3d7c5SThomas E. Spanjaard #include <sys/bio.h> 41*c1b3d7c5SThomas E. Spanjaard #include <sys/bus.h> 42*c1b3d7c5SThomas E. Spanjaard #include <sys/conf.h> 43*c1b3d7c5SThomas E. Spanjaard #include <sys/disk.h> 44*c1b3d7c5SThomas E. Spanjaard #include <sys/cons.h> 45*c1b3d7c5SThomas E. Spanjaard #include <sys/sema.h> 46*c1b3d7c5SThomas E. Spanjaard #include <sys/taskqueue.h> 47*c1b3d7c5SThomas E. Spanjaard #include <sys/objcache.h> 48*c1b3d7c5SThomas E. Spanjaard #include <machine/bus.h> 49*c1b3d7c5SThomas E. Spanjaard #include <sys/rman.h> 50*c1b3d7c5SThomas E. Spanjaard #include <dev/pci/pcivar.h> 51*c1b3d7c5SThomas E. Spanjaard #include <geom/geom_disk.h> 52*c1b3d7c5SThomas E. Spanjaard #include <dev/ata/ata-all.h> 53*c1b3d7c5SThomas E. Spanjaard #include <dev/ata/ata-disk.h> 54*c1b3d7c5SThomas E. Spanjaard #include <dev/ata/ata-raid.h> 55*c1b3d7c5SThomas E. Spanjaard #include <dev/ata/ata-pci.h> 56*c1b3d7c5SThomas E. Spanjaard #include <ata_if.h> 57*c1b3d7c5SThomas E. Spanjaard 58*c1b3d7c5SThomas E. Spanjaard /* device structure */ 59*c1b3d7c5SThomas E. Spanjaard static d_strategy_t ata_raid_strategy; 60*c1b3d7c5SThomas E. Spanjaard static d_dump_t ata_raid_dump; 61*c1b3d7c5SThomas E. Spanjaard static struct dev_ops ata_raid_ops = { 62*c1b3d7c5SThomas E. Spanjaard { "ata_raid", 157, D_DISK }, 63*c1b3d7c5SThomas E. Spanjaard .d_open = nullopen, 64*c1b3d7c5SThomas E. Spanjaard .d_close = nullclose, 65*c1b3d7c5SThomas E. Spanjaard .d_read = physread, 66*c1b3d7c5SThomas E. Spanjaard .d_write = physwrite, 67*c1b3d7c5SThomas E. Spanjaard .d_strategy = ata_raid_strategy, 68*c1b3d7c5SThomas E. Spanjaard .d_dump = ata_raid_dump, 69*c1b3d7c5SThomas E. Spanjaard }; 70*c1b3d7c5SThomas E. Spanjaard 71*c1b3d7c5SThomas E. Spanjaard /* prototypes */ 72*c1b3d7c5SThomas E. Spanjaard static void ata_raid_done(struct ata_request *request); 73*c1b3d7c5SThomas E. Spanjaard static void ata_raid_config_changed(struct ar_softc *rdp, int writeback); 74*c1b3d7c5SThomas E. Spanjaard static int ata_raid_status(struct ata_ioc_raid_config *config); 75*c1b3d7c5SThomas E. Spanjaard static int ata_raid_create(struct ata_ioc_raid_config *config); 76*c1b3d7c5SThomas E. Spanjaard static int ata_raid_delete(int array); 77*c1b3d7c5SThomas E. Spanjaard static int ata_raid_addspare(struct ata_ioc_raid_config *config); 78*c1b3d7c5SThomas E. Spanjaard static int ata_raid_rebuild(int array); 79*c1b3d7c5SThomas E. Spanjaard static int ata_raid_read_metadata(device_t subdisk); 80*c1b3d7c5SThomas E. Spanjaard static int ata_raid_write_metadata(struct ar_softc *rdp); 81*c1b3d7c5SThomas E. Spanjaard static int ata_raid_wipe_metadata(struct ar_softc *rdp); 82*c1b3d7c5SThomas E. Spanjaard static int ata_raid_adaptec_read_meta(device_t dev, struct ar_softc **raidp); 83*c1b3d7c5SThomas E. Spanjaard static int ata_raid_hptv2_read_meta(device_t dev, struct ar_softc **raidp); 84*c1b3d7c5SThomas E. Spanjaard static int ata_raid_hptv2_write_meta(struct ar_softc *rdp); 85*c1b3d7c5SThomas E. Spanjaard static int ata_raid_hptv3_read_meta(device_t dev, struct ar_softc **raidp); 86*c1b3d7c5SThomas E. Spanjaard static int ata_raid_intel_read_meta(device_t dev, struct ar_softc **raidp); 87*c1b3d7c5SThomas E. Spanjaard static int ata_raid_intel_write_meta(struct ar_softc *rdp); 88*c1b3d7c5SThomas E. Spanjaard static int ata_raid_ite_read_meta(device_t dev, struct ar_softc **raidp); 89*c1b3d7c5SThomas E. Spanjaard static int ata_raid_jmicron_read_meta(device_t dev, struct ar_softc **raidp); 90*c1b3d7c5SThomas E. Spanjaard static int ata_raid_jmicron_write_meta(struct ar_softc *rdp); 91*c1b3d7c5SThomas E. Spanjaard static int ata_raid_lsiv2_read_meta(device_t dev, struct ar_softc **raidp); 92*c1b3d7c5SThomas E. Spanjaard static int ata_raid_lsiv3_read_meta(device_t dev, struct ar_softc **raidp); 93*c1b3d7c5SThomas E. Spanjaard static int ata_raid_nvidia_read_meta(device_t dev, struct ar_softc **raidp); 94*c1b3d7c5SThomas E. Spanjaard static int ata_raid_promise_read_meta(device_t dev, struct ar_softc **raidp, int native); 95*c1b3d7c5SThomas E. Spanjaard static int ata_raid_promise_write_meta(struct ar_softc *rdp); 96*c1b3d7c5SThomas E. Spanjaard static int ata_raid_sii_read_meta(device_t dev, struct ar_softc **raidp); 97*c1b3d7c5SThomas E. Spanjaard static int ata_raid_sis_read_meta(device_t dev, struct ar_softc **raidp); 98*c1b3d7c5SThomas E. Spanjaard static int ata_raid_sis_write_meta(struct ar_softc *rdp); 99*c1b3d7c5SThomas E. Spanjaard static int ata_raid_via_read_meta(device_t dev, struct ar_softc **raidp); 100*c1b3d7c5SThomas E. Spanjaard static int ata_raid_via_write_meta(struct ar_softc *rdp); 101*c1b3d7c5SThomas E. Spanjaard static struct ata_request *ata_raid_init_request(struct ar_softc *rdp, struct bio *bio); 102*c1b3d7c5SThomas E. Spanjaard static int ata_raid_send_request(struct ata_request *request); 103*c1b3d7c5SThomas E. Spanjaard static int ata_raid_rw(device_t dev, u_int64_t lba, void *data, u_int bcount, int flags); 104*c1b3d7c5SThomas E. Spanjaard static char * ata_raid_format(struct ar_softc *rdp); 105*c1b3d7c5SThomas E. Spanjaard static char * ata_raid_type(struct ar_softc *rdp); 106*c1b3d7c5SThomas E. Spanjaard static char * ata_raid_flags(struct ar_softc *rdp); 107*c1b3d7c5SThomas E. Spanjaard 108*c1b3d7c5SThomas E. Spanjaard /* debugging only */ 109*c1b3d7c5SThomas E. Spanjaard static void ata_raid_print_meta(struct ar_softc *meta); 110*c1b3d7c5SThomas E. Spanjaard static void ata_raid_adaptec_print_meta(struct adaptec_raid_conf *meta); 111*c1b3d7c5SThomas E. Spanjaard static void ata_raid_hptv2_print_meta(struct hptv2_raid_conf *meta); 112*c1b3d7c5SThomas E. Spanjaard static void ata_raid_hptv3_print_meta(struct hptv3_raid_conf *meta); 113*c1b3d7c5SThomas E. Spanjaard static void ata_raid_intel_print_meta(struct intel_raid_conf *meta); 114*c1b3d7c5SThomas E. Spanjaard static void ata_raid_ite_print_meta(struct ite_raid_conf *meta); 115*c1b3d7c5SThomas E. Spanjaard static void ata_raid_jmicron_print_meta(struct jmicron_raid_conf *meta); 116*c1b3d7c5SThomas E. Spanjaard static void ata_raid_lsiv2_print_meta(struct lsiv2_raid_conf *meta); 117*c1b3d7c5SThomas E. Spanjaard static void ata_raid_lsiv3_print_meta(struct lsiv3_raid_conf *meta); 118*c1b3d7c5SThomas E. Spanjaard static void ata_raid_nvidia_print_meta(struct nvidia_raid_conf *meta); 119*c1b3d7c5SThomas E. Spanjaard static void ata_raid_promise_print_meta(struct promise_raid_conf *meta); 120*c1b3d7c5SThomas E. Spanjaard static void ata_raid_sii_print_meta(struct sii_raid_conf *meta); 121*c1b3d7c5SThomas E. Spanjaard static void ata_raid_sis_print_meta(struct sis_raid_conf *meta); 122*c1b3d7c5SThomas E. Spanjaard static void ata_raid_via_print_meta(struct via_raid_conf *meta); 123*c1b3d7c5SThomas E. Spanjaard 124*c1b3d7c5SThomas E. Spanjaard /* internal vars */ 125*c1b3d7c5SThomas E. Spanjaard static struct ar_softc *ata_raid_arrays[MAX_ARRAYS]; 126*c1b3d7c5SThomas E. Spanjaard static MALLOC_DEFINE(M_AR, "ar_driver", "ATA PseudoRAID driver"); 127*c1b3d7c5SThomas E. Spanjaard static devclass_t ata_raid_sub_devclass; 128*c1b3d7c5SThomas E. Spanjaard static int testing = 0; 129*c1b3d7c5SThomas E. Spanjaard 130*c1b3d7c5SThomas E. Spanjaard static void 131*c1b3d7c5SThomas E. Spanjaard ata_raid_attach(struct ar_softc *rdp, int writeback) 132*c1b3d7c5SThomas E. Spanjaard { 133*c1b3d7c5SThomas E. Spanjaard dev_t device; 134*c1b3d7c5SThomas E. Spanjaard char buffer[32]; 135*c1b3d7c5SThomas E. Spanjaard int disk; 136*c1b3d7c5SThomas E. Spanjaard 137*c1b3d7c5SThomas E. Spanjaard spin_init(&rdp->lock); 138*c1b3d7c5SThomas E. Spanjaard ata_raid_config_changed(rdp, writeback); 139*c1b3d7c5SThomas E. Spanjaard 140*c1b3d7c5SThomas E. Spanjaard /* sanitize arrays total_size % (width * interleave) == 0 */ 141*c1b3d7c5SThomas E. Spanjaard if (rdp->type == AR_T_RAID0 || rdp->type == AR_T_RAID01 || 142*c1b3d7c5SThomas E. Spanjaard rdp->type == AR_T_RAID5) { 143*c1b3d7c5SThomas E. Spanjaard rdp->total_sectors = (rdp->total_sectors/(rdp->interleave*rdp->width))* 144*c1b3d7c5SThomas E. Spanjaard (rdp->interleave * rdp->width); 145*c1b3d7c5SThomas E. Spanjaard sprintf(buffer, " (stripe %d KB)", 146*c1b3d7c5SThomas E. Spanjaard (rdp->interleave * DEV_BSIZE) / 1024); 147*c1b3d7c5SThomas E. Spanjaard } 148*c1b3d7c5SThomas E. Spanjaard else 149*c1b3d7c5SThomas E. Spanjaard buffer[0] = '\0'; 150*c1b3d7c5SThomas E. Spanjaard device = disk_create(rdp->lun, &rdp->disk, 0, &ata_raid_ops); 151*c1b3d7c5SThomas E. Spanjaard device->si_drv1 = rdp; 152*c1b3d7c5SThomas E. Spanjaard device->si_iosize_max = 128 * DEV_BSIZE; 153*c1b3d7c5SThomas E. Spanjaard rdp->dev = device; 154*c1b3d7c5SThomas E. Spanjaard rdp->disk.d_label.d_secsize = DEV_BSIZE; 155*c1b3d7c5SThomas E. Spanjaard rdp->disk.d_label.d_nsectors = rdp->sectors; 156*c1b3d7c5SThomas E. Spanjaard rdp->disk.d_label.d_ntracks = rdp->heads; 157*c1b3d7c5SThomas E. Spanjaard rdp->disk.d_label.d_ncylinders = rdp->total_secs/(rdp->heads*rdp->sectors); 158*c1b3d7c5SThomas E. Spanjaard rdp->disk.d_label.d_secpercyl = rdp->sectors * rdp->heads; 159*c1b3d7c5SThomas E. Spanjaard rdp->disk.d_label.d_secperunit = rdp->total_secs; 160*c1b3d7c5SThomas E. Spanjaard 161*c1b3d7c5SThomas E. Spanjaard printf("ar%d: %juMB <%s %s%s> status: %s\n", rdp->lun, 162*c1b3d7c5SThomas E. Spanjaard rdp->total_sectors / ((1024L * 1024L) / DEV_BSIZE), 163*c1b3d7c5SThomas E. Spanjaard ata_raid_format(rdp), ata_raid_type(rdp), 164*c1b3d7c5SThomas E. Spanjaard buffer, ata_raid_flags(rdp)); 165*c1b3d7c5SThomas E. Spanjaard 166*c1b3d7c5SThomas E. Spanjaard if (testing || bootverbose) 167*c1b3d7c5SThomas E. Spanjaard printf("ar%d: %ju sectors [%dC/%dH/%dS] <%s> subdisks defined as:\n", 168*c1b3d7c5SThomas E. Spanjaard rdp->lun, rdp->total_sectors, 169*c1b3d7c5SThomas E. Spanjaard rdp->cylinders, rdp->heads, rdp->sectors, rdp->name); 170*c1b3d7c5SThomas E. Spanjaard 171*c1b3d7c5SThomas E. Spanjaard for (disk = 0; disk < rdp->total_disks; disk++) { 172*c1b3d7c5SThomas E. Spanjaard printf("ar%d: disk%d ", rdp->lun, disk); 173*c1b3d7c5SThomas E. Spanjaard if (rdp->disks[disk].dev) { 174*c1b3d7c5SThomas E. Spanjaard if (rdp->disks[disk].flags & AR_DF_PRESENT) { 175*c1b3d7c5SThomas E. Spanjaard /* status of this disk in the array */ 176*c1b3d7c5SThomas E. Spanjaard if (rdp->disks[disk].flags & AR_DF_ONLINE) 177*c1b3d7c5SThomas E. Spanjaard printf("READY "); 178*c1b3d7c5SThomas E. Spanjaard else if (rdp->disks[disk].flags & AR_DF_SPARE) 179*c1b3d7c5SThomas E. Spanjaard printf("SPARE "); 180*c1b3d7c5SThomas E. Spanjaard else 181*c1b3d7c5SThomas E. Spanjaard printf("FREE "); 182*c1b3d7c5SThomas E. Spanjaard 183*c1b3d7c5SThomas E. Spanjaard /* what type of disk is this in the array */ 184*c1b3d7c5SThomas E. Spanjaard switch (rdp->type) { 185*c1b3d7c5SThomas E. Spanjaard case AR_T_RAID1: 186*c1b3d7c5SThomas E. Spanjaard case AR_T_RAID01: 187*c1b3d7c5SThomas E. Spanjaard if (disk < rdp->width) 188*c1b3d7c5SThomas E. Spanjaard printf("(master) "); 189*c1b3d7c5SThomas E. Spanjaard else 190*c1b3d7c5SThomas E. Spanjaard printf("(mirror) "); 191*c1b3d7c5SThomas E. Spanjaard } 192*c1b3d7c5SThomas E. Spanjaard 193*c1b3d7c5SThomas E. Spanjaard /* which physical disk is used */ 194*c1b3d7c5SThomas E. Spanjaard printf("using %s at ata%d-%s\n", 195*c1b3d7c5SThomas E. Spanjaard device_get_nameunit(rdp->disks[disk].dev), 196*c1b3d7c5SThomas E. Spanjaard device_get_unit(device_get_parent(rdp->disks[disk].dev)), 197*c1b3d7c5SThomas E. Spanjaard (((struct ata_device *) 198*c1b3d7c5SThomas E. Spanjaard device_get_softc(rdp->disks[disk].dev))->unit == 199*c1b3d7c5SThomas E. Spanjaard ATA_MASTER) ? "master" : "slave"); 200*c1b3d7c5SThomas E. Spanjaard } 201*c1b3d7c5SThomas E. Spanjaard else if (rdp->disks[disk].flags & AR_DF_ASSIGNED) 202*c1b3d7c5SThomas E. Spanjaard printf("DOWN\n"); 203*c1b3d7c5SThomas E. Spanjaard else 204*c1b3d7c5SThomas E. Spanjaard printf("INVALID no RAID config on this subdisk\n"); 205*c1b3d7c5SThomas E. Spanjaard } 206*c1b3d7c5SThomas E. Spanjaard else 207*c1b3d7c5SThomas E. Spanjaard printf("DOWN no device found for this subdisk\n"); 208*c1b3d7c5SThomas E. Spanjaard } 209*c1b3d7c5SThomas E. Spanjaard } 210*c1b3d7c5SThomas E. Spanjaard 211*c1b3d7c5SThomas E. Spanjaard /* 212*c1b3d7c5SThomas E. Spanjaard * ATA PseudoRAID ioctl function. Note that this does not need to be adjusted 213*c1b3d7c5SThomas E. Spanjaard * to the dev_ops way, because it's just chained from the generic ata ioctl. 214*c1b3d7c5SThomas E. Spanjaard */ 215*c1b3d7c5SThomas E. Spanjaard static int 216*c1b3d7c5SThomas E. Spanjaard ata_raid_ioctl(u_long cmd, caddr_t data) 217*c1b3d7c5SThomas E. Spanjaard { 218*c1b3d7c5SThomas E. Spanjaard struct ata_ioc_raid_config *config = (struct ata_ioc_raid_config *)data; 219*c1b3d7c5SThomas E. Spanjaard int *lun = (int *)data; 220*c1b3d7c5SThomas E. Spanjaard int error = EOPNOTSUPP; 221*c1b3d7c5SThomas E. Spanjaard 222*c1b3d7c5SThomas E. Spanjaard switch (cmd) { 223*c1b3d7c5SThomas E. Spanjaard case IOCATARAIDSTATUS: 224*c1b3d7c5SThomas E. Spanjaard error = ata_raid_status(config); 225*c1b3d7c5SThomas E. Spanjaard break; 226*c1b3d7c5SThomas E. Spanjaard 227*c1b3d7c5SThomas E. Spanjaard case IOCATARAIDCREATE: 228*c1b3d7c5SThomas E. Spanjaard error = ata_raid_create(config); 229*c1b3d7c5SThomas E. Spanjaard break; 230*c1b3d7c5SThomas E. Spanjaard 231*c1b3d7c5SThomas E. Spanjaard case IOCATARAIDDELETE: 232*c1b3d7c5SThomas E. Spanjaard error = ata_raid_delete(*lun); 233*c1b3d7c5SThomas E. Spanjaard break; 234*c1b3d7c5SThomas E. Spanjaard 235*c1b3d7c5SThomas E. Spanjaard case IOCATARAIDADDSPARE: 236*c1b3d7c5SThomas E. Spanjaard error = ata_raid_addspare(config); 237*c1b3d7c5SThomas E. Spanjaard break; 238*c1b3d7c5SThomas E. Spanjaard 239*c1b3d7c5SThomas E. Spanjaard case IOCATARAIDREBUILD: 240*c1b3d7c5SThomas E. Spanjaard error = ata_raid_rebuild(*lun); 241*c1b3d7c5SThomas E. Spanjaard break; 242*c1b3d7c5SThomas E. Spanjaard } 243*c1b3d7c5SThomas E. Spanjaard return error; 244*c1b3d7c5SThomas E. Spanjaard } 245*c1b3d7c5SThomas E. Spanjaard 246*c1b3d7c5SThomas E. Spanjaard /* 247*c1b3d7c5SThomas E. Spanjaard * XXX TGEN there are a lot of offset -> block number conversions going on 248*c1b3d7c5SThomas E. Spanjaard * here, which is suboptimal. 249*c1b3d7c5SThomas E. Spanjaard */ 250*c1b3d7c5SThomas E. Spanjaard static int 251*c1b3d7c5SThomas E. Spanjaard ata_raid_strategy(struct dev_strategy_args *ap) 252*c1b3d7c5SThomas E. Spanjaard { 253*c1b3d7c5SThomas E. Spanjaard struct bio *bp = ap->a_bio; 254*c1b3d7c5SThomas E. Spanjaard struct buf *bbp = bp->bio_buf; 255*c1b3d7c5SThomas E. Spanjaard struct ar_softc *rdp = ap->a_head.a_dev->si_drv1; 256*c1b3d7c5SThomas E. Spanjaard struct ata_request *request; 257*c1b3d7c5SThomas E. Spanjaard caddr_t data; 258*c1b3d7c5SThomas E. Spanjaard u_int64_t blkno, lba, blk = 0; 259*c1b3d7c5SThomas E. Spanjaard int count, chunk, drv, par = 0, change = 0; 260*c1b3d7c5SThomas E. Spanjaard 261*c1b3d7c5SThomas E. Spanjaard if (!(rdp->status & AR_S_READY) || 262*c1b3d7c5SThomas E. Spanjaard (bbp->b_cmd != BUF_CMD_READ && bbp->b_cmd != BUF_CMD_WRITE)) { 263*c1b3d7c5SThomas E. Spanjaard bbp->b_flags |= B_ERROR; 264*c1b3d7c5SThomas E. Spanjaard bbp->b_error = EIO; 265*c1b3d7c5SThomas E. Spanjaard biodone(bp); 266*c1b3d7c5SThomas E. Spanjaard return; 267*c1b3d7c5SThomas E. Spanjaard } 268*c1b3d7c5SThomas E. Spanjaard 269*c1b3d7c5SThomas E. Spanjaard bbp->b_resid = bbp->b_bcount; 270*c1b3d7c5SThomas E. Spanjaard for (count = howmany(bbp->b_bcount, DEV_BSIZE), 271*c1b3d7c5SThomas E. Spanjaard /* bio_offset is byte granularity, convert */ 272*c1b3d7c5SThomas E. Spanjaard blkno = (u_int64_t)(bp->bio_offset >> DEV_BSHIFT), 273*c1b3d7c5SThomas E. Spanjaard data = bbp->b_data; 274*c1b3d7c5SThomas E. Spanjaard count > 0; 275*c1b3d7c5SThomas E. Spanjaard count -= chunk, blkno += chunk, data += (chunk * DEV_BSIZE)) { 276*c1b3d7c5SThomas E. Spanjaard 277*c1b3d7c5SThomas E. Spanjaard switch (rdp->type) { 278*c1b3d7c5SThomas E. Spanjaard case AR_T_RAID1: 279*c1b3d7c5SThomas E. Spanjaard drv = 0; 280*c1b3d7c5SThomas E. Spanjaard lba = blkno; 281*c1b3d7c5SThomas E. Spanjaard chunk = count; 282*c1b3d7c5SThomas E. Spanjaard break; 283*c1b3d7c5SThomas E. Spanjaard 284*c1b3d7c5SThomas E. Spanjaard case AR_T_JBOD: 285*c1b3d7c5SThomas E. Spanjaard case AR_T_SPAN: 286*c1b3d7c5SThomas E. Spanjaard drv = 0; 287*c1b3d7c5SThomas E. Spanjaard lba = blkno; 288*c1b3d7c5SThomas E. Spanjaard while (lba >= rdp->disks[drv].sectors) 289*c1b3d7c5SThomas E. Spanjaard lba -= rdp->disks[drv++].sectors; 290*c1b3d7c5SThomas E. Spanjaard chunk = min(rdp->disks[drv].sectors - lba, count); 291*c1b3d7c5SThomas E. Spanjaard break; 292*c1b3d7c5SThomas E. Spanjaard 293*c1b3d7c5SThomas E. Spanjaard case AR_T_RAID0: 294*c1b3d7c5SThomas E. Spanjaard case AR_T_RAID01: 295*c1b3d7c5SThomas E. Spanjaard chunk = blkno % rdp->interleave; 296*c1b3d7c5SThomas E. Spanjaard drv = (blkno / rdp->interleave) % rdp->width; 297*c1b3d7c5SThomas E. Spanjaard lba = (((blkno/rdp->interleave)/rdp->width)*rdp->interleave)+chunk; 298*c1b3d7c5SThomas E. Spanjaard chunk = min(count, rdp->interleave - chunk); 299*c1b3d7c5SThomas E. Spanjaard break; 300*c1b3d7c5SThomas E. Spanjaard 301*c1b3d7c5SThomas E. Spanjaard case AR_T_RAID5: 302*c1b3d7c5SThomas E. Spanjaard drv = (blkno / rdp->interleave) % (rdp->width - 1); 303*c1b3d7c5SThomas E. Spanjaard par = rdp->width - 1 - 304*c1b3d7c5SThomas E. Spanjaard (blkno / (rdp->interleave * (rdp->width - 1))) % rdp->width; 305*c1b3d7c5SThomas E. Spanjaard if (drv >= par) 306*c1b3d7c5SThomas E. Spanjaard drv++; 307*c1b3d7c5SThomas E. Spanjaard lba = ((blkno/rdp->interleave)/(rdp->width-1))*(rdp->interleave) + 308*c1b3d7c5SThomas E. Spanjaard ((blkno%(rdp->interleave*(rdp->width-1)))%rdp->interleave); 309*c1b3d7c5SThomas E. Spanjaard chunk = min(count, rdp->interleave - (lba % rdp->interleave)); 310*c1b3d7c5SThomas E. Spanjaard break; 311*c1b3d7c5SThomas E. Spanjaard 312*c1b3d7c5SThomas E. Spanjaard default: 313*c1b3d7c5SThomas E. Spanjaard printf("ar%d: unknown array type in ata_raid_strategy\n", rdp->lun); 314*c1b3d7c5SThomas E. Spanjaard bbp->b_flags |= B_ERROR; 315*c1b3d7c5SThomas E. Spanjaard bbp->b_error = EIO; 316*c1b3d7c5SThomas E. Spanjaard biodone(bp); 317*c1b3d7c5SThomas E. Spanjaard return; 318*c1b3d7c5SThomas E. Spanjaard } 319*c1b3d7c5SThomas E. Spanjaard 320*c1b3d7c5SThomas E. Spanjaard /* offset on all but "first on HPTv2" */ 321*c1b3d7c5SThomas E. Spanjaard if (!(drv == 0 && rdp->format == AR_F_HPTV2_RAID)) 322*c1b3d7c5SThomas E. Spanjaard lba += rdp->offset_sectors; 323*c1b3d7c5SThomas E. Spanjaard 324*c1b3d7c5SThomas E. Spanjaard if (!(request = ata_raid_init_request(rdp, bp))) { 325*c1b3d7c5SThomas E. Spanjaard bbp->b_flags |= B_ERROR; 326*c1b3d7c5SThomas E. Spanjaard bbp->b_error = EIO; 327*c1b3d7c5SThomas E. Spanjaard biodone(bp); 328*c1b3d7c5SThomas E. Spanjaard return; 329*c1b3d7c5SThomas E. Spanjaard } 330*c1b3d7c5SThomas E. Spanjaard request->data = data; 331*c1b3d7c5SThomas E. Spanjaard request->bytecount = chunk * DEV_BSIZE; 332*c1b3d7c5SThomas E. Spanjaard request->u.ata.lba = lba; 333*c1b3d7c5SThomas E. Spanjaard request->u.ata.count = request->bytecount / DEV_BSIZE; 334*c1b3d7c5SThomas E. Spanjaard 335*c1b3d7c5SThomas E. Spanjaard switch (rdp->type) { 336*c1b3d7c5SThomas E. Spanjaard case AR_T_JBOD: 337*c1b3d7c5SThomas E. Spanjaard case AR_T_SPAN: 338*c1b3d7c5SThomas E. Spanjaard case AR_T_RAID0: 339*c1b3d7c5SThomas E. Spanjaard if (((rdp->disks[drv].flags & (AR_DF_PRESENT|AR_DF_ONLINE)) == 340*c1b3d7c5SThomas E. Spanjaard (AR_DF_PRESENT|AR_DF_ONLINE) && !rdp->disks[drv].dev)) { 341*c1b3d7c5SThomas E. Spanjaard rdp->disks[drv].flags &= ~AR_DF_ONLINE; 342*c1b3d7c5SThomas E. Spanjaard ata_raid_config_changed(rdp, 1); 343*c1b3d7c5SThomas E. Spanjaard ata_free_request(request); 344*c1b3d7c5SThomas E. Spanjaard bbp->b_flags |= B_ERROR; 345*c1b3d7c5SThomas E. Spanjaard bbp->b_error = EIO; 346*c1b3d7c5SThomas E. Spanjaard biodone(bp); 347*c1b3d7c5SThomas E. Spanjaard return; 348*c1b3d7c5SThomas E. Spanjaard } 349*c1b3d7c5SThomas E. Spanjaard request->this = drv; 350*c1b3d7c5SThomas E. Spanjaard request->dev = rdp->disks[request->this].dev; 351*c1b3d7c5SThomas E. Spanjaard ata_raid_send_request(request); 352*c1b3d7c5SThomas E. Spanjaard break; 353*c1b3d7c5SThomas E. Spanjaard 354*c1b3d7c5SThomas E. Spanjaard case AR_T_RAID1: 355*c1b3d7c5SThomas E. Spanjaard case AR_T_RAID01: 356*c1b3d7c5SThomas E. Spanjaard if ((rdp->disks[drv].flags & 357*c1b3d7c5SThomas E. Spanjaard (AR_DF_PRESENT|AR_DF_ONLINE))==(AR_DF_PRESENT|AR_DF_ONLINE) && 358*c1b3d7c5SThomas E. Spanjaard !rdp->disks[drv].dev) { 359*c1b3d7c5SThomas E. Spanjaard rdp->disks[drv].flags &= ~AR_DF_ONLINE; 360*c1b3d7c5SThomas E. Spanjaard change = 1; 361*c1b3d7c5SThomas E. Spanjaard } 362*c1b3d7c5SThomas E. Spanjaard if ((rdp->disks[drv + rdp->width].flags & 363*c1b3d7c5SThomas E. Spanjaard (AR_DF_PRESENT|AR_DF_ONLINE))==(AR_DF_PRESENT|AR_DF_ONLINE) && 364*c1b3d7c5SThomas E. Spanjaard !rdp->disks[drv + rdp->width].dev) { 365*c1b3d7c5SThomas E. Spanjaard rdp->disks[drv + rdp->width].flags &= ~AR_DF_ONLINE; 366*c1b3d7c5SThomas E. Spanjaard change = 1; 367*c1b3d7c5SThomas E. Spanjaard } 368*c1b3d7c5SThomas E. Spanjaard if (change) 369*c1b3d7c5SThomas E. Spanjaard ata_raid_config_changed(rdp, 1); 370*c1b3d7c5SThomas E. Spanjaard if (!(rdp->status & AR_S_READY)) { 371*c1b3d7c5SThomas E. Spanjaard ata_free_request(request); 372*c1b3d7c5SThomas E. Spanjaard bbp->b_flags |= B_ERROR; 373*c1b3d7c5SThomas E. Spanjaard bbp->b_error = EIO; 374*c1b3d7c5SThomas E. Spanjaard biodone(bp); 375*c1b3d7c5SThomas E. Spanjaard return; 376*c1b3d7c5SThomas E. Spanjaard } 377*c1b3d7c5SThomas E. Spanjaard 378*c1b3d7c5SThomas E. Spanjaard if (rdp->status & AR_S_REBUILDING) 379*c1b3d7c5SThomas E. Spanjaard blk = ((lba / rdp->interleave) * rdp->width) * rdp->interleave + 380*c1b3d7c5SThomas E. Spanjaard (rdp->interleave * (drv % rdp->width)) + 381*c1b3d7c5SThomas E. Spanjaard lba % rdp->interleave;; 382*c1b3d7c5SThomas E. Spanjaard 383*c1b3d7c5SThomas E. Spanjaard if (bbp->b_cmd == BUF_CMD_READ) { 384*c1b3d7c5SThomas E. Spanjaard int src_online = 385*c1b3d7c5SThomas E. Spanjaard (rdp->disks[drv].flags & AR_DF_ONLINE); 386*c1b3d7c5SThomas E. Spanjaard int mir_online = 387*c1b3d7c5SThomas E. Spanjaard (rdp->disks[drv+rdp->width].flags & AR_DF_ONLINE); 388*c1b3d7c5SThomas E. Spanjaard 389*c1b3d7c5SThomas E. Spanjaard /* if mirror gone or close to last access on source */ 390*c1b3d7c5SThomas E. Spanjaard if (!mir_online || 391*c1b3d7c5SThomas E. Spanjaard ((src_online) && 392*c1b3d7c5SThomas E. Spanjaard ((u_int64_t)(bp->bio_offset >> DEV_BSHIFT)) >= 393*c1b3d7c5SThomas E. Spanjaard (rdp->disks[drv].last_lba - AR_PROXIMITY) && 394*c1b3d7c5SThomas E. Spanjaard ((u_int64_t)(bp->bio_offset >> DEV_BSHIFT)) <= 395*c1b3d7c5SThomas E. Spanjaard (rdp->disks[drv].last_lba + AR_PROXIMITY))) { 396*c1b3d7c5SThomas E. Spanjaard rdp->toggle = 0; 397*c1b3d7c5SThomas E. Spanjaard } 398*c1b3d7c5SThomas E. Spanjaard /* if source gone or close to last access on mirror */ 399*c1b3d7c5SThomas E. Spanjaard else if (!src_online || 400*c1b3d7c5SThomas E. Spanjaard ((mir_online) && 401*c1b3d7c5SThomas E. Spanjaard ((u_int64_t)(bp->bio_offset >> DEV_BSHIFT)) >= 402*c1b3d7c5SThomas E. Spanjaard (rdp->disks[drv+rdp->width].last_lba-AR_PROXIMITY) && 403*c1b3d7c5SThomas E. Spanjaard ((u_int64_t)(bp->bio_offset >> DEV_BSHIFT)) <= 404*c1b3d7c5SThomas E. Spanjaard (rdp->disks[drv+rdp->width].last_lba+AR_PROXIMITY))) { 405*c1b3d7c5SThomas E. Spanjaard drv += rdp->width; 406*c1b3d7c5SThomas E. Spanjaard rdp->toggle = 1; 407*c1b3d7c5SThomas E. Spanjaard } 408*c1b3d7c5SThomas E. Spanjaard /* not close to any previous access, toggle */ 409*c1b3d7c5SThomas E. Spanjaard else { 410*c1b3d7c5SThomas E. Spanjaard if (rdp->toggle) 411*c1b3d7c5SThomas E. Spanjaard rdp->toggle = 0; 412*c1b3d7c5SThomas E. Spanjaard else { 413*c1b3d7c5SThomas E. Spanjaard drv += rdp->width; 414*c1b3d7c5SThomas E. Spanjaard rdp->toggle = 1; 415*c1b3d7c5SThomas E. Spanjaard } 416*c1b3d7c5SThomas E. Spanjaard } 417*c1b3d7c5SThomas E. Spanjaard 418*c1b3d7c5SThomas E. Spanjaard if ((rdp->status & AR_S_REBUILDING) && 419*c1b3d7c5SThomas E. Spanjaard (blk <= rdp->rebuild_lba) && 420*c1b3d7c5SThomas E. Spanjaard ((blk + chunk) > rdp->rebuild_lba)) { 421*c1b3d7c5SThomas E. Spanjaard struct ata_composite *composite; 422*c1b3d7c5SThomas E. Spanjaard struct ata_request *rebuild; 423*c1b3d7c5SThomas E. Spanjaard int this; 424*c1b3d7c5SThomas E. Spanjaard 425*c1b3d7c5SThomas E. Spanjaard /* figure out what part to rebuild */ 426*c1b3d7c5SThomas E. Spanjaard if (drv < rdp->width) 427*c1b3d7c5SThomas E. Spanjaard this = drv + rdp->width; 428*c1b3d7c5SThomas E. Spanjaard else 429*c1b3d7c5SThomas E. Spanjaard this = drv - rdp->width; 430*c1b3d7c5SThomas E. Spanjaard 431*c1b3d7c5SThomas E. Spanjaard /* do we have a spare to rebuild on ? */ 432*c1b3d7c5SThomas E. Spanjaard if (rdp->disks[this].flags & AR_DF_SPARE) { 433*c1b3d7c5SThomas E. Spanjaard if ((composite = ata_alloc_composite())) { 434*c1b3d7c5SThomas E. Spanjaard if ((rebuild = ata_alloc_request())) { 435*c1b3d7c5SThomas E. Spanjaard rdp->rebuild_lba = blk + chunk; 436*c1b3d7c5SThomas E. Spanjaard bcopy(request, rebuild, 437*c1b3d7c5SThomas E. Spanjaard sizeof(struct ata_request)); 438*c1b3d7c5SThomas E. Spanjaard rebuild->this = this; 439*c1b3d7c5SThomas E. Spanjaard rebuild->dev = rdp->disks[this].dev; 440*c1b3d7c5SThomas E. Spanjaard rebuild->flags &= ~ATA_R_READ; 441*c1b3d7c5SThomas E. Spanjaard rebuild->flags |= ATA_R_WRITE; 442*c1b3d7c5SThomas E. Spanjaard spin_init(&composite->lock); 443*c1b3d7c5SThomas E. Spanjaard composite->residual = request->bytecount; 444*c1b3d7c5SThomas E. Spanjaard composite->rd_needed |= (1 << drv); 445*c1b3d7c5SThomas E. Spanjaard composite->wr_depend |= (1 << drv); 446*c1b3d7c5SThomas E. Spanjaard composite->wr_needed |= (1 << this); 447*c1b3d7c5SThomas E. Spanjaard composite->request[drv] = request; 448*c1b3d7c5SThomas E. Spanjaard composite->request[this] = rebuild; 449*c1b3d7c5SThomas E. Spanjaard request->composite = composite; 450*c1b3d7c5SThomas E. Spanjaard rebuild->composite = composite; 451*c1b3d7c5SThomas E. Spanjaard ata_raid_send_request(rebuild); 452*c1b3d7c5SThomas E. Spanjaard } 453*c1b3d7c5SThomas E. Spanjaard else { 454*c1b3d7c5SThomas E. Spanjaard ata_free_composite(composite); 455*c1b3d7c5SThomas E. Spanjaard printf("DOH! ata_alloc_request failed!\n"); 456*c1b3d7c5SThomas E. Spanjaard } 457*c1b3d7c5SThomas E. Spanjaard } 458*c1b3d7c5SThomas E. Spanjaard else { 459*c1b3d7c5SThomas E. Spanjaard printf("DOH! ata_alloc_composite failed!\n"); 460*c1b3d7c5SThomas E. Spanjaard } 461*c1b3d7c5SThomas E. Spanjaard } 462*c1b3d7c5SThomas E. Spanjaard else if (rdp->disks[this].flags & AR_DF_ONLINE) { 463*c1b3d7c5SThomas E. Spanjaard /* 464*c1b3d7c5SThomas E. Spanjaard * if we got here we are a chunk of a RAID01 that 465*c1b3d7c5SThomas E. Spanjaard * does not need a rebuild, but we need to increment 466*c1b3d7c5SThomas E. Spanjaard * the rebuild_lba address to get the rebuild to 467*c1b3d7c5SThomas E. Spanjaard * move to the next chunk correctly 468*c1b3d7c5SThomas E. Spanjaard */ 469*c1b3d7c5SThomas E. Spanjaard rdp->rebuild_lba = blk + chunk; 470*c1b3d7c5SThomas E. Spanjaard } 471*c1b3d7c5SThomas E. Spanjaard else 472*c1b3d7c5SThomas E. Spanjaard printf("DOH! we didn't find the rebuild part\n"); 473*c1b3d7c5SThomas E. Spanjaard } 474*c1b3d7c5SThomas E. Spanjaard } 475*c1b3d7c5SThomas E. Spanjaard if (bbp->b_cmd == BUF_CMD_WRITE) { 476*c1b3d7c5SThomas E. Spanjaard if ((rdp->disks[drv+rdp->width].flags & AR_DF_ONLINE) || 477*c1b3d7c5SThomas E. Spanjaard ((rdp->status & AR_S_REBUILDING) && 478*c1b3d7c5SThomas E. Spanjaard (rdp->disks[drv+rdp->width].flags & AR_DF_SPARE) && 479*c1b3d7c5SThomas E. Spanjaard ((blk < rdp->rebuild_lba) || 480*c1b3d7c5SThomas E. Spanjaard ((blk <= rdp->rebuild_lba) && 481*c1b3d7c5SThomas E. Spanjaard ((blk + chunk) > rdp->rebuild_lba))))) { 482*c1b3d7c5SThomas E. Spanjaard if ((rdp->disks[drv].flags & AR_DF_ONLINE) || 483*c1b3d7c5SThomas E. Spanjaard ((rdp->status & AR_S_REBUILDING) && 484*c1b3d7c5SThomas E. Spanjaard (rdp->disks[drv].flags & AR_DF_SPARE) && 485*c1b3d7c5SThomas E. Spanjaard ((blk < rdp->rebuild_lba) || 486*c1b3d7c5SThomas E. Spanjaard ((blk <= rdp->rebuild_lba) && 487*c1b3d7c5SThomas E. Spanjaard ((blk + chunk) > rdp->rebuild_lba))))) { 488*c1b3d7c5SThomas E. Spanjaard struct ata_request *mirror; 489*c1b3d7c5SThomas E. Spanjaard struct ata_composite *composite; 490*c1b3d7c5SThomas E. Spanjaard int this = drv + rdp->width; 491*c1b3d7c5SThomas E. Spanjaard 492*c1b3d7c5SThomas E. Spanjaard if ((composite = ata_alloc_composite())) { 493*c1b3d7c5SThomas E. Spanjaard if ((mirror = ata_alloc_request())) { 494*c1b3d7c5SThomas E. Spanjaard if ((blk <= rdp->rebuild_lba) && 495*c1b3d7c5SThomas E. Spanjaard ((blk + chunk) > rdp->rebuild_lba)) 496*c1b3d7c5SThomas E. Spanjaard rdp->rebuild_lba = blk + chunk; 497*c1b3d7c5SThomas E. Spanjaard bcopy(request, mirror, 498*c1b3d7c5SThomas E. Spanjaard sizeof(struct ata_request)); 499*c1b3d7c5SThomas E. Spanjaard mirror->this = this; 500*c1b3d7c5SThomas E. Spanjaard mirror->dev = rdp->disks[this].dev; 501*c1b3d7c5SThomas E. Spanjaard spin_init(&composite->lock); 502*c1b3d7c5SThomas E. Spanjaard composite->residual = request->bytecount; 503*c1b3d7c5SThomas E. Spanjaard composite->wr_needed |= (1 << drv); 504*c1b3d7c5SThomas E. Spanjaard composite->wr_needed |= (1 << this); 505*c1b3d7c5SThomas E. Spanjaard composite->request[drv] = request; 506*c1b3d7c5SThomas E. Spanjaard composite->request[this] = mirror; 507*c1b3d7c5SThomas E. Spanjaard request->composite = composite; 508*c1b3d7c5SThomas E. Spanjaard mirror->composite = composite; 509*c1b3d7c5SThomas E. Spanjaard ata_raid_send_request(mirror); 510*c1b3d7c5SThomas E. Spanjaard rdp->disks[this].last_lba = 511*c1b3d7c5SThomas E. Spanjaard (u_int64_t)(bp->bio_offset >> DEV_BSHIFT) + 512*c1b3d7c5SThomas E. Spanjaard chunk; 513*c1b3d7c5SThomas E. Spanjaard } 514*c1b3d7c5SThomas E. Spanjaard else { 515*c1b3d7c5SThomas E. Spanjaard ata_free_composite(composite); 516*c1b3d7c5SThomas E. Spanjaard printf("DOH! ata_alloc_request failed!\n"); 517*c1b3d7c5SThomas E. Spanjaard } 518*c1b3d7c5SThomas E. Spanjaard } 519*c1b3d7c5SThomas E. Spanjaard else { 520*c1b3d7c5SThomas E. Spanjaard printf("DOH! ata_alloc_composite failed!\n"); 521*c1b3d7c5SThomas E. Spanjaard } 522*c1b3d7c5SThomas E. Spanjaard } 523*c1b3d7c5SThomas E. Spanjaard else 524*c1b3d7c5SThomas E. Spanjaard drv += rdp->width; 525*c1b3d7c5SThomas E. Spanjaard } 526*c1b3d7c5SThomas E. Spanjaard } 527*c1b3d7c5SThomas E. Spanjaard request->this = drv; 528*c1b3d7c5SThomas E. Spanjaard request->dev = rdp->disks[request->this].dev; 529*c1b3d7c5SThomas E. Spanjaard ata_raid_send_request(request); 530*c1b3d7c5SThomas E. Spanjaard rdp->disks[request->this].last_lba = (u_int64_t)(bp->bio_offset >> 531*c1b3d7c5SThomas E. Spanjaard DEV_BSIZE) + chunk; 532*c1b3d7c5SThomas E. Spanjaard break; 533*c1b3d7c5SThomas E. Spanjaard 534*c1b3d7c5SThomas E. Spanjaard case AR_T_RAID5: 535*c1b3d7c5SThomas E. Spanjaard if (((rdp->disks[drv].flags & (AR_DF_PRESENT|AR_DF_ONLINE)) == 536*c1b3d7c5SThomas E. Spanjaard (AR_DF_PRESENT|AR_DF_ONLINE) && !rdp->disks[drv].dev)) { 537*c1b3d7c5SThomas E. Spanjaard rdp->disks[drv].flags &= ~AR_DF_ONLINE; 538*c1b3d7c5SThomas E. Spanjaard change = 1; 539*c1b3d7c5SThomas E. Spanjaard } 540*c1b3d7c5SThomas E. Spanjaard if (((rdp->disks[par].flags & (AR_DF_PRESENT|AR_DF_ONLINE)) == 541*c1b3d7c5SThomas E. Spanjaard (AR_DF_PRESENT|AR_DF_ONLINE) && !rdp->disks[par].dev)) { 542*c1b3d7c5SThomas E. Spanjaard rdp->disks[par].flags &= ~AR_DF_ONLINE; 543*c1b3d7c5SThomas E. Spanjaard change = 1; 544*c1b3d7c5SThomas E. Spanjaard } 545*c1b3d7c5SThomas E. Spanjaard if (change) 546*c1b3d7c5SThomas E. Spanjaard ata_raid_config_changed(rdp, 1); 547*c1b3d7c5SThomas E. Spanjaard if (!(rdp->status & AR_S_READY)) { 548*c1b3d7c5SThomas E. Spanjaard ata_free_request(request); 549*c1b3d7c5SThomas E. Spanjaard bbp->b_flags |= B_ERROR; 550*c1b3d7c5SThomas E. Spanjaard bbp->b_error = EIO; 551*c1b3d7c5SThomas E. Spanjaard biodone(bp); 552*c1b3d7c5SThomas E. Spanjaard return; 553*c1b3d7c5SThomas E. Spanjaard } 554*c1b3d7c5SThomas E. Spanjaard if (rdp->status & AR_S_DEGRADED) { 555*c1b3d7c5SThomas E. Spanjaard /* do the XOR game if possible */ 556*c1b3d7c5SThomas E. Spanjaard } 557*c1b3d7c5SThomas E. Spanjaard else { 558*c1b3d7c5SThomas E. Spanjaard request->this = drv; 559*c1b3d7c5SThomas E. Spanjaard request->dev = rdp->disks[request->this].dev; 560*c1b3d7c5SThomas E. Spanjaard if (bbp->b_cmd == BUF_CMD_READ) { 561*c1b3d7c5SThomas E. Spanjaard ata_raid_send_request(request); 562*c1b3d7c5SThomas E. Spanjaard } 563*c1b3d7c5SThomas E. Spanjaard if (bbp->b_cmd == BUF_CMD_WRITE) { 564*c1b3d7c5SThomas E. Spanjaard ata_raid_send_request(request); 565*c1b3d7c5SThomas E. Spanjaard // sikre at l�s-modify-skriv til hver disk er atomarisk. 566*c1b3d7c5SThomas E. Spanjaard // par kopi af request 567*c1b3d7c5SThomas E. Spanjaard // l�se orgdata fra drv 568*c1b3d7c5SThomas E. Spanjaard // skriv nydata til drv 569*c1b3d7c5SThomas E. Spanjaard // l�se parorgdata fra par 570*c1b3d7c5SThomas E. Spanjaard // skriv orgdata xor parorgdata xor nydata til par 571*c1b3d7c5SThomas E. Spanjaard } 572*c1b3d7c5SThomas E. Spanjaard } 573*c1b3d7c5SThomas E. Spanjaard break; 574*c1b3d7c5SThomas E. Spanjaard 575*c1b3d7c5SThomas E. Spanjaard default: 576*c1b3d7c5SThomas E. Spanjaard printf("ar%d: unknown array type in ata_raid_strategy\n", rdp->lun); 577*c1b3d7c5SThomas E. Spanjaard } 578*c1b3d7c5SThomas E. Spanjaard } 579*c1b3d7c5SThomas E. Spanjaard } 580*c1b3d7c5SThomas E. Spanjaard 581*c1b3d7c5SThomas E. Spanjaard static void 582*c1b3d7c5SThomas E. Spanjaard ata_raid_done(struct ata_request *request) 583*c1b3d7c5SThomas E. Spanjaard { 584*c1b3d7c5SThomas E. Spanjaard struct ar_softc *rdp = request->driver; 585*c1b3d7c5SThomas E. Spanjaard struct ata_composite *composite = NULL; 586*c1b3d7c5SThomas E. Spanjaard struct bio *bp = request->bio; 587*c1b3d7c5SThomas E. Spanjaard struct buf *bbp = bp->bio_buf; 588*c1b3d7c5SThomas E. Spanjaard int i, mirror, finished = 0; 589*c1b3d7c5SThomas E. Spanjaard 590*c1b3d7c5SThomas E. Spanjaard switch (rdp->type) { 591*c1b3d7c5SThomas E. Spanjaard case AR_T_JBOD: 592*c1b3d7c5SThomas E. Spanjaard case AR_T_SPAN: 593*c1b3d7c5SThomas E. Spanjaard case AR_T_RAID0: 594*c1b3d7c5SThomas E. Spanjaard if (request->result) { 595*c1b3d7c5SThomas E. Spanjaard rdp->disks[request->this].flags &= ~AR_DF_ONLINE; 596*c1b3d7c5SThomas E. Spanjaard ata_raid_config_changed(rdp, 1); 597*c1b3d7c5SThomas E. Spanjaard bbp->b_error = request->result; 598*c1b3d7c5SThomas E. Spanjaard finished = 1; 599*c1b3d7c5SThomas E. Spanjaard } 600*c1b3d7c5SThomas E. Spanjaard else { 601*c1b3d7c5SThomas E. Spanjaard bbp->b_resid -= request->donecount; 602*c1b3d7c5SThomas E. Spanjaard if (!bbp->b_resid) 603*c1b3d7c5SThomas E. Spanjaard finished = 1; 604*c1b3d7c5SThomas E. Spanjaard } 605*c1b3d7c5SThomas E. Spanjaard break; 606*c1b3d7c5SThomas E. Spanjaard 607*c1b3d7c5SThomas E. Spanjaard case AR_T_RAID1: 608*c1b3d7c5SThomas E. Spanjaard case AR_T_RAID01: 609*c1b3d7c5SThomas E. Spanjaard if (request->this < rdp->width) 610*c1b3d7c5SThomas E. Spanjaard mirror = request->this + rdp->width; 611*c1b3d7c5SThomas E. Spanjaard else 612*c1b3d7c5SThomas E. Spanjaard mirror = request->this - rdp->width; 613*c1b3d7c5SThomas E. Spanjaard if (request->result) { 614*c1b3d7c5SThomas E. Spanjaard rdp->disks[request->this].flags &= ~AR_DF_ONLINE; 615*c1b3d7c5SThomas E. Spanjaard ata_raid_config_changed(rdp, 1); 616*c1b3d7c5SThomas E. Spanjaard } 617*c1b3d7c5SThomas E. Spanjaard if (rdp->status & AR_S_READY) { 618*c1b3d7c5SThomas E. Spanjaard u_int64_t blk = 0; 619*c1b3d7c5SThomas E. Spanjaard 620*c1b3d7c5SThomas E. Spanjaard if (rdp->status & AR_S_REBUILDING) 621*c1b3d7c5SThomas E. Spanjaard blk = ((request->u.ata.lba / rdp->interleave) * rdp->width) * 622*c1b3d7c5SThomas E. Spanjaard rdp->interleave + (rdp->interleave * 623*c1b3d7c5SThomas E. Spanjaard (request->this % rdp->width)) + 624*c1b3d7c5SThomas E. Spanjaard request->u.ata.lba % rdp->interleave; 625*c1b3d7c5SThomas E. Spanjaard 626*c1b3d7c5SThomas E. Spanjaard if (bbp->b_cmd == BUF_CMD_READ) { 627*c1b3d7c5SThomas E. Spanjaard 628*c1b3d7c5SThomas E. Spanjaard /* is this a rebuild composite */ 629*c1b3d7c5SThomas E. Spanjaard if ((composite = request->composite)) { 630*c1b3d7c5SThomas E. Spanjaard spin_lock_wr(&composite->lock); 631*c1b3d7c5SThomas E. Spanjaard 632*c1b3d7c5SThomas E. Spanjaard /* handle the read part of a rebuild composite */ 633*c1b3d7c5SThomas E. Spanjaard if (request->flags & ATA_R_READ) { 634*c1b3d7c5SThomas E. Spanjaard 635*c1b3d7c5SThomas E. Spanjaard /* if read failed array is now broken */ 636*c1b3d7c5SThomas E. Spanjaard if (request->result) { 637*c1b3d7c5SThomas E. Spanjaard rdp->disks[request->this].flags &= ~AR_DF_ONLINE; 638*c1b3d7c5SThomas E. Spanjaard ata_raid_config_changed(rdp, 1); 639*c1b3d7c5SThomas E. Spanjaard bbp->b_error = request->result; 640*c1b3d7c5SThomas E. Spanjaard rdp->rebuild_lba = blk; 641*c1b3d7c5SThomas E. Spanjaard finished = 1; 642*c1b3d7c5SThomas E. Spanjaard } 643*c1b3d7c5SThomas E. Spanjaard 644*c1b3d7c5SThomas E. Spanjaard /* good data, update how far we've gotten */ 645*c1b3d7c5SThomas E. Spanjaard else { 646*c1b3d7c5SThomas E. Spanjaard bbp->b_resid -= request->donecount; 647*c1b3d7c5SThomas E. Spanjaard composite->residual -= request->donecount; 648*c1b3d7c5SThomas E. Spanjaard if (!composite->residual) { 649*c1b3d7c5SThomas E. Spanjaard if (composite->wr_done & (1 << mirror)) 650*c1b3d7c5SThomas E. Spanjaard finished = 1; 651*c1b3d7c5SThomas E. Spanjaard } 652*c1b3d7c5SThomas E. Spanjaard } 653*c1b3d7c5SThomas E. Spanjaard } 654*c1b3d7c5SThomas E. Spanjaard 655*c1b3d7c5SThomas E. Spanjaard /* handle the write part of a rebuild composite */ 656*c1b3d7c5SThomas E. Spanjaard else if (request->flags & ATA_R_WRITE) { 657*c1b3d7c5SThomas E. Spanjaard if (composite->rd_done & (1 << mirror)) { 658*c1b3d7c5SThomas E. Spanjaard if (request->result) { 659*c1b3d7c5SThomas E. Spanjaard printf("DOH! rebuild failed\n"); /* XXX SOS */ 660*c1b3d7c5SThomas E. Spanjaard rdp->rebuild_lba = blk; 661*c1b3d7c5SThomas E. Spanjaard } 662*c1b3d7c5SThomas E. Spanjaard if (!composite->residual) 663*c1b3d7c5SThomas E. Spanjaard finished = 1; 664*c1b3d7c5SThomas E. Spanjaard } 665*c1b3d7c5SThomas E. Spanjaard } 666*c1b3d7c5SThomas E. Spanjaard spin_unlock_wr(&composite->lock); 667*c1b3d7c5SThomas E. Spanjaard } 668*c1b3d7c5SThomas E. Spanjaard 669*c1b3d7c5SThomas E. Spanjaard /* if read failed retry on the mirror */ 670*c1b3d7c5SThomas E. Spanjaard else if (request->result) { 671*c1b3d7c5SThomas E. Spanjaard request->dev = rdp->disks[mirror].dev; 672*c1b3d7c5SThomas E. Spanjaard request->flags &= ~ATA_R_TIMEOUT; 673*c1b3d7c5SThomas E. Spanjaard ata_raid_send_request(request); 674*c1b3d7c5SThomas E. Spanjaard return; 675*c1b3d7c5SThomas E. Spanjaard } 676*c1b3d7c5SThomas E. Spanjaard 677*c1b3d7c5SThomas E. Spanjaard /* we have good data */ 678*c1b3d7c5SThomas E. Spanjaard else { 679*c1b3d7c5SThomas E. Spanjaard bbp->b_resid -= request->donecount; 680*c1b3d7c5SThomas E. Spanjaard if (!bbp->b_resid) 681*c1b3d7c5SThomas E. Spanjaard finished = 1; 682*c1b3d7c5SThomas E. Spanjaard } 683*c1b3d7c5SThomas E. Spanjaard } 684*c1b3d7c5SThomas E. Spanjaard else if (bbp->b_cmd == BUF_CMD_WRITE) { 685*c1b3d7c5SThomas E. Spanjaard /* do we have a mirror or rebuild to deal with ? */ 686*c1b3d7c5SThomas E. Spanjaard if ((composite = request->composite)) { 687*c1b3d7c5SThomas E. Spanjaard spin_lock_wr(&composite->lock); 688*c1b3d7c5SThomas E. Spanjaard if (composite->wr_done & (1 << mirror)) { 689*c1b3d7c5SThomas E. Spanjaard if (request->result) { 690*c1b3d7c5SThomas E. Spanjaard if (composite->request[mirror]->result) { 691*c1b3d7c5SThomas E. Spanjaard printf("DOH! all disks failed and got here\n"); 692*c1b3d7c5SThomas E. Spanjaard bbp->b_error = EIO; 693*c1b3d7c5SThomas E. Spanjaard } 694*c1b3d7c5SThomas E. Spanjaard if (rdp->status & AR_S_REBUILDING) { 695*c1b3d7c5SThomas E. Spanjaard rdp->rebuild_lba = blk; 696*c1b3d7c5SThomas E. Spanjaard printf("DOH! rebuild failed\n"); /* XXX SOS */ 697*c1b3d7c5SThomas E. Spanjaard } 698*c1b3d7c5SThomas E. Spanjaard bbp->b_resid -= 699*c1b3d7c5SThomas E. Spanjaard composite->request[mirror]->donecount; 700*c1b3d7c5SThomas E. Spanjaard composite->residual -= 701*c1b3d7c5SThomas E. Spanjaard composite->request[mirror]->donecount; 702*c1b3d7c5SThomas E. Spanjaard } 703*c1b3d7c5SThomas E. Spanjaard else { 704*c1b3d7c5SThomas E. Spanjaard bbp->b_resid -= request->donecount; 705*c1b3d7c5SThomas E. Spanjaard composite->residual -= request->donecount; 706*c1b3d7c5SThomas E. Spanjaard } 707*c1b3d7c5SThomas E. Spanjaard if (!composite->residual) 708*c1b3d7c5SThomas E. Spanjaard finished = 1; 709*c1b3d7c5SThomas E. Spanjaard } 710*c1b3d7c5SThomas E. Spanjaard spin_unlock_wr(&composite->lock); 711*c1b3d7c5SThomas E. Spanjaard } 712*c1b3d7c5SThomas E. Spanjaard /* no mirror we are done */ 713*c1b3d7c5SThomas E. Spanjaard else { 714*c1b3d7c5SThomas E. Spanjaard bbp->b_resid -= request->donecount; 715*c1b3d7c5SThomas E. Spanjaard if (!bbp->b_resid) 716*c1b3d7c5SThomas E. Spanjaard finished = 1; 717*c1b3d7c5SThomas E. Spanjaard } 718*c1b3d7c5SThomas E. Spanjaard } 719*c1b3d7c5SThomas E. Spanjaard } 720*c1b3d7c5SThomas E. Spanjaard else { 721*c1b3d7c5SThomas E. Spanjaard /* XXX TGEN bbp->b_flags |= B_ERROR; */ 722*c1b3d7c5SThomas E. Spanjaard bbp->b_error = request->result; 723*c1b3d7c5SThomas E. Spanjaard biodone(bp); 724*c1b3d7c5SThomas E. Spanjaard } 725*c1b3d7c5SThomas E. Spanjaard break; 726*c1b3d7c5SThomas E. Spanjaard 727*c1b3d7c5SThomas E. Spanjaard case AR_T_RAID5: 728*c1b3d7c5SThomas E. Spanjaard if (request->result) { 729*c1b3d7c5SThomas E. Spanjaard rdp->disks[request->this].flags &= ~AR_DF_ONLINE; 730*c1b3d7c5SThomas E. Spanjaard ata_raid_config_changed(rdp, 1); 731*c1b3d7c5SThomas E. Spanjaard if (rdp->status & AR_S_READY) { 732*c1b3d7c5SThomas E. Spanjaard if (bbp->b_cmd == BUF_CMD_READ) { 733*c1b3d7c5SThomas E. Spanjaard /* do the XOR game to recover data */ 734*c1b3d7c5SThomas E. Spanjaard } 735*c1b3d7c5SThomas E. Spanjaard if (bbp->b_cmd == BUF_CMD_WRITE) { 736*c1b3d7c5SThomas E. Spanjaard /* if the parity failed we're OK sortof */ 737*c1b3d7c5SThomas E. Spanjaard /* otherwise wee need to do the XOR long dance */ 738*c1b3d7c5SThomas E. Spanjaard } 739*c1b3d7c5SThomas E. Spanjaard finished = 1; 740*c1b3d7c5SThomas E. Spanjaard } 741*c1b3d7c5SThomas E. Spanjaard else { 742*c1b3d7c5SThomas E. Spanjaard /* XXX TGEN bbp->b_flags |= B_ERROR; */ 743*c1b3d7c5SThomas E. Spanjaard bbp->b_error = request->result; 744*c1b3d7c5SThomas E. Spanjaard biodone(bp); 745*c1b3d7c5SThomas E. Spanjaard } 746*c1b3d7c5SThomas E. Spanjaard } 747*c1b3d7c5SThomas E. Spanjaard else { 748*c1b3d7c5SThomas E. Spanjaard // did we have an XOR game going ?? 749*c1b3d7c5SThomas E. Spanjaard bbp->b_resid -= request->donecount; 750*c1b3d7c5SThomas E. Spanjaard if (!bbp->b_resid) 751*c1b3d7c5SThomas E. Spanjaard finished = 1; 752*c1b3d7c5SThomas E. Spanjaard } 753*c1b3d7c5SThomas E. Spanjaard break; 754*c1b3d7c5SThomas E. Spanjaard 755*c1b3d7c5SThomas E. Spanjaard default: 756*c1b3d7c5SThomas E. Spanjaard printf("ar%d: unknown array type in ata_raid_done\n", rdp->lun); 757*c1b3d7c5SThomas E. Spanjaard } 758*c1b3d7c5SThomas E. Spanjaard 759*c1b3d7c5SThomas E. Spanjaard if (finished) { 760*c1b3d7c5SThomas E. Spanjaard if ((rdp->status & AR_S_REBUILDING) && 761*c1b3d7c5SThomas E. Spanjaard rdp->rebuild_lba >= rdp->total_sectors) { 762*c1b3d7c5SThomas E. Spanjaard int disk; 763*c1b3d7c5SThomas E. Spanjaard 764*c1b3d7c5SThomas E. Spanjaard for (disk = 0; disk < rdp->total_disks; disk++) { 765*c1b3d7c5SThomas E. Spanjaard if ((rdp->disks[disk].flags & 766*c1b3d7c5SThomas E. Spanjaard (AR_DF_PRESENT | AR_DF_ASSIGNED | AR_DF_SPARE)) == 767*c1b3d7c5SThomas E. Spanjaard (AR_DF_PRESENT | AR_DF_ASSIGNED | AR_DF_SPARE)) { 768*c1b3d7c5SThomas E. Spanjaard rdp->disks[disk].flags &= ~AR_DF_SPARE; 769*c1b3d7c5SThomas E. Spanjaard rdp->disks[disk].flags |= AR_DF_ONLINE; 770*c1b3d7c5SThomas E. Spanjaard } 771*c1b3d7c5SThomas E. Spanjaard } 772*c1b3d7c5SThomas E. Spanjaard rdp->status &= ~AR_S_REBUILDING; 773*c1b3d7c5SThomas E. Spanjaard ata_raid_config_changed(rdp, 1); 774*c1b3d7c5SThomas E. Spanjaard } 775*c1b3d7c5SThomas E. Spanjaard if (!bbp->b_resid) 776*c1b3d7c5SThomas E. Spanjaard biodone(bp); 777*c1b3d7c5SThomas E. Spanjaard } 778*c1b3d7c5SThomas E. Spanjaard 779*c1b3d7c5SThomas E. Spanjaard if (composite) { 780*c1b3d7c5SThomas E. Spanjaard if (finished) { 781*c1b3d7c5SThomas E. Spanjaard /* we are done with this composite, free all resources */ 782*c1b3d7c5SThomas E. Spanjaard for (i = 0; i < 32; i++) { 783*c1b3d7c5SThomas E. Spanjaard if (composite->rd_needed & (1 << i) || 784*c1b3d7c5SThomas E. Spanjaard composite->wr_needed & (1 << i)) { 785*c1b3d7c5SThomas E. Spanjaard ata_free_request(composite->request[i]); 786*c1b3d7c5SThomas E. Spanjaard } 787*c1b3d7c5SThomas E. Spanjaard } 788*c1b3d7c5SThomas E. Spanjaard spin_uninit(&composite->lock); 789*c1b3d7c5SThomas E. Spanjaard ata_free_composite(composite); 790*c1b3d7c5SThomas E. Spanjaard } 791*c1b3d7c5SThomas E. Spanjaard } 792*c1b3d7c5SThomas E. Spanjaard else 793*c1b3d7c5SThomas E. Spanjaard ata_free_request(request); 794*c1b3d7c5SThomas E. Spanjaard } 795*c1b3d7c5SThomas E. Spanjaard 796*c1b3d7c5SThomas E. Spanjaard static int 797*c1b3d7c5SThomas E. Spanjaard ata_raid_dump(struct dev_dump_args *ap) 798*c1b3d7c5SThomas E. Spanjaard { 799*c1b3d7c5SThomas E. Spanjaard struct ar_softc *rdp = ap->a_head.a_dev->si_drv1; 800*c1b3d7c5SThomas E. Spanjaard struct bio bp; 801*c1b3d7c5SThomas E. Spanjaard struct buf bbp; 802*c1b3d7c5SThomas E. Spanjaard struct dev_strategy_args dsap; 803*c1b3d7c5SThomas E. Spanjaard vm_paddr_t addr = 0; 804*c1b3d7c5SThomas E. Spanjaard long blkcnt; 805*c1b3d7c5SThomas E. Spanjaard int dumppages = MAXDUMPPGS; 806*c1b3d7c5SThomas E. Spanjaard int error = 0; 807*c1b3d7c5SThomas E. Spanjaard int disk = 0; 808*c1b3d7c5SThomas E. Spanjaard int i; 809*c1b3d7c5SThomas E. Spanjaard 810*c1b3d7c5SThomas E. Spanjaard #if 0 811*c1b3d7c5SThomas E. Spanjaard /* XXX TGEN Figure out if we need to support this as well. */ 812*c1b3d7c5SThomas E. Spanjaard /* XXX TGEN Seems like we don't, ata_raid_dump isn't called recursively. */ 813*c1b3d7c5SThomas E. Spanjaard /* length zero is special and really means flush buffers to media */ 814*c1b3d7c5SThomas E. Spanjaard if (!length) { 815*c1b3d7c5SThomas E. Spanjaard for (disk = 0, error = 0; disk < rdp->total_disks; disk++) 816*c1b3d7c5SThomas E. Spanjaard if (rdp->disks[disk].dev) 817*c1b3d7c5SThomas E. Spanjaard error |= ata_controlcmd(rdp->disks[disk].dev, 818*c1b3d7c5SThomas E. Spanjaard ATA_FLUSHCACHE, 0, 0, 0); 819*c1b3d7c5SThomas E. Spanjaard return (error ? EIO : 0); 820*c1b3d7c5SThomas E. Spanjaard } 821*c1b3d7c5SThomas E. Spanjaard #endif /* 0 */ 822*c1b3d7c5SThomas E. Spanjaard 823*c1b3d7c5SThomas E. Spanjaard blkcnt = howmany(PAGE_SIZE, ap->a_secsize); 824*c1b3d7c5SThomas E. Spanjaard 825*c1b3d7c5SThomas E. Spanjaard while (ap->a_count > 0) { 826*c1b3d7c5SThomas E. Spanjaard caddr_t va = NULL; 827*c1b3d7c5SThomas E. Spanjaard 828*c1b3d7c5SThomas E. Spanjaard if ((ap->a_count / blkcnt) < dumppages) 829*c1b3d7c5SThomas E. Spanjaard dumppages = ap->a_count / blkcnt; 830*c1b3d7c5SThomas E. Spanjaard 831*c1b3d7c5SThomas E. Spanjaard for (i = 0; i < dumppages; ++i) { 832*c1b3d7c5SThomas E. Spanjaard vm_paddr_t a = addr + (i * PAGE_SIZE); 833*c1b3d7c5SThomas E. Spanjaard if (is_physical_memory(a)) 834*c1b3d7c5SThomas E. Spanjaard va = pmap_kenter_temporary(trunc_page(a), i); 835*c1b3d7c5SThomas E. Spanjaard else 836*c1b3d7c5SThomas E. Spanjaard va = pmap_kenter_temporary(trunc_page(0), i); 837*c1b3d7c5SThomas E. Spanjaard } 838*c1b3d7c5SThomas E. Spanjaard 839*c1b3d7c5SThomas E. Spanjaard bzero(&bp, sizeof(struct bio)); 840*c1b3d7c5SThomas E. Spanjaard bzero(&bbp, sizeof(struct buf)); 841*c1b3d7c5SThomas E. Spanjaard bzero(&dsap, sizeof(struct dev_strategy_args)); 842*c1b3d7c5SThomas E. Spanjaard bp.bio_buf = &bbp; 843*c1b3d7c5SThomas E. Spanjaard /* bio_offset is byte granularity, convert block granularity a_blkno */ 844*c1b3d7c5SThomas E. Spanjaard bp.bio_offset = (off_t)(ap->a_blkno << DEV_BSHIFT); 845*c1b3d7c5SThomas E. Spanjaard bbp.b_bcount = PAGE_SIZE * dumppages; 846*c1b3d7c5SThomas E. Spanjaard bbp.b_data = va; 847*c1b3d7c5SThomas E. Spanjaard bbp.b_cmd = BUF_CMD_WRITE; 848*c1b3d7c5SThomas E. Spanjaard /* XXX TGEN With the previous bzero probably not efficient. */ 849*c1b3d7c5SThomas E. Spanjaard dsap.a_head = ap->a_head; 850*c1b3d7c5SThomas E. Spanjaard dsap.a_bio = &bp; 851*c1b3d7c5SThomas E. Spanjaard ata_raid_strategy(&dsap); 852*c1b3d7c5SThomas E. Spanjaard if (bbp.b_error) 853*c1b3d7c5SThomas E. Spanjaard return bbp.b_error; 854*c1b3d7c5SThomas E. Spanjaard 855*c1b3d7c5SThomas E. Spanjaard if (dumpstatus(addr, (off_t)ap->a_count * DEV_BSIZE) < 0) 856*c1b3d7c5SThomas E. Spanjaard return EINTR; 857*c1b3d7c5SThomas E. Spanjaard 858*c1b3d7c5SThomas E. Spanjaard ap->a_blkno += blkcnt * dumppages; 859*c1b3d7c5SThomas E. Spanjaard ap->a_count -= blkcnt * dumppages; 860*c1b3d7c5SThomas E. Spanjaard addr += PAGE_SIZE * dumppages; 861*c1b3d7c5SThomas E. Spanjaard } 862*c1b3d7c5SThomas E. Spanjaard 863*c1b3d7c5SThomas E. Spanjaard /* flush subdisk buffers to media */ 864*c1b3d7c5SThomas E. Spanjaard for (disk = 0; disk < rdp->total_disks; disk++) 865*c1b3d7c5SThomas E. Spanjaard if (rdp->disks[disk].dev) 866*c1b3d7c5SThomas E. Spanjaard error |= ata_controlcmd(rdp->disks[disk].dev, ATA_FLUSHCACHE, 0, 0, 867*c1b3d7c5SThomas E. Spanjaard 0); 868*c1b3d7c5SThomas E. Spanjaard return (error ? EIO : 0); 869*c1b3d7c5SThomas E. Spanjaard } 870*c1b3d7c5SThomas E. Spanjaard 871*c1b3d7c5SThomas E. Spanjaard static void 872*c1b3d7c5SThomas E. Spanjaard ata_raid_config_changed(struct ar_softc *rdp, int writeback) 873*c1b3d7c5SThomas E. Spanjaard { 874*c1b3d7c5SThomas E. Spanjaard int disk, count, status; 875*c1b3d7c5SThomas E. Spanjaard 876*c1b3d7c5SThomas E. Spanjaard spin_lock_wr(&rdp->lock); 877*c1b3d7c5SThomas E. Spanjaard /* set default all working mode */ 878*c1b3d7c5SThomas E. Spanjaard status = rdp->status; 879*c1b3d7c5SThomas E. Spanjaard rdp->status &= ~AR_S_DEGRADED; 880*c1b3d7c5SThomas E. Spanjaard rdp->status |= AR_S_READY; 881*c1b3d7c5SThomas E. Spanjaard 882*c1b3d7c5SThomas E. Spanjaard /* make sure all lost drives are accounted for */ 883*c1b3d7c5SThomas E. Spanjaard for (disk = 0; disk < rdp->total_disks; disk++) { 884*c1b3d7c5SThomas E. Spanjaard if (!(rdp->disks[disk].flags & AR_DF_PRESENT)) 885*c1b3d7c5SThomas E. Spanjaard rdp->disks[disk].flags &= ~AR_DF_ONLINE; 886*c1b3d7c5SThomas E. Spanjaard } 887*c1b3d7c5SThomas E. Spanjaard 888*c1b3d7c5SThomas E. Spanjaard /* depending on RAID type figure out our health status */ 889*c1b3d7c5SThomas E. Spanjaard switch (rdp->type) { 890*c1b3d7c5SThomas E. Spanjaard case AR_T_JBOD: 891*c1b3d7c5SThomas E. Spanjaard case AR_T_SPAN: 892*c1b3d7c5SThomas E. Spanjaard case AR_T_RAID0: 893*c1b3d7c5SThomas E. Spanjaard for (disk = 0; disk < rdp->total_disks; disk++) 894*c1b3d7c5SThomas E. Spanjaard if (!(rdp->disks[disk].flags & AR_DF_ONLINE)) 895*c1b3d7c5SThomas E. Spanjaard rdp->status &= ~AR_S_READY; 896*c1b3d7c5SThomas E. Spanjaard break; 897*c1b3d7c5SThomas E. Spanjaard 898*c1b3d7c5SThomas E. Spanjaard case AR_T_RAID1: 899*c1b3d7c5SThomas E. Spanjaard case AR_T_RAID01: 900*c1b3d7c5SThomas E. Spanjaard for (disk = 0; disk < rdp->width; disk++) { 901*c1b3d7c5SThomas E. Spanjaard if (!(rdp->disks[disk].flags & AR_DF_ONLINE) && 902*c1b3d7c5SThomas E. Spanjaard !(rdp->disks[disk + rdp->width].flags & AR_DF_ONLINE)) { 903*c1b3d7c5SThomas E. Spanjaard rdp->status &= ~AR_S_READY; 904*c1b3d7c5SThomas E. Spanjaard } 905*c1b3d7c5SThomas E. Spanjaard else if (((rdp->disks[disk].flags & AR_DF_ONLINE) && 906*c1b3d7c5SThomas E. Spanjaard !(rdp->disks[disk + rdp->width].flags & AR_DF_ONLINE)) || 907*c1b3d7c5SThomas E. Spanjaard (!(rdp->disks[disk].flags & AR_DF_ONLINE) && 908*c1b3d7c5SThomas E. Spanjaard (rdp->disks [disk + rdp->width].flags & AR_DF_ONLINE))) { 909*c1b3d7c5SThomas E. Spanjaard rdp->status |= AR_S_DEGRADED; 910*c1b3d7c5SThomas E. Spanjaard } 911*c1b3d7c5SThomas E. Spanjaard } 912*c1b3d7c5SThomas E. Spanjaard break; 913*c1b3d7c5SThomas E. Spanjaard 914*c1b3d7c5SThomas E. Spanjaard case AR_T_RAID5: 915*c1b3d7c5SThomas E. Spanjaard for (count = 0, disk = 0; disk < rdp->total_disks; disk++) { 916*c1b3d7c5SThomas E. Spanjaard if (!(rdp->disks[disk].flags & AR_DF_ONLINE)) 917*c1b3d7c5SThomas E. Spanjaard count++; 918*c1b3d7c5SThomas E. Spanjaard } 919*c1b3d7c5SThomas E. Spanjaard if (count) { 920*c1b3d7c5SThomas E. Spanjaard if (count > 1) 921*c1b3d7c5SThomas E. Spanjaard rdp->status &= ~AR_S_READY; 922*c1b3d7c5SThomas E. Spanjaard else 923*c1b3d7c5SThomas E. Spanjaard rdp->status |= AR_S_DEGRADED; 924*c1b3d7c5SThomas E. Spanjaard } 925*c1b3d7c5SThomas E. Spanjaard break; 926*c1b3d7c5SThomas E. Spanjaard default: 927*c1b3d7c5SThomas E. Spanjaard rdp->status &= ~AR_S_READY; 928*c1b3d7c5SThomas E. Spanjaard } 929*c1b3d7c5SThomas E. Spanjaard 930*c1b3d7c5SThomas E. Spanjaard if (rdp->status != status) { 931*c1b3d7c5SThomas E. Spanjaard if (!(rdp->status & AR_S_READY)) { 932*c1b3d7c5SThomas E. Spanjaard printf("ar%d: FAILURE - %s array broken\n", 933*c1b3d7c5SThomas E. Spanjaard rdp->lun, ata_raid_type(rdp)); 934*c1b3d7c5SThomas E. Spanjaard } 935*c1b3d7c5SThomas E. Spanjaard else if (rdp->status & AR_S_DEGRADED) { 936*c1b3d7c5SThomas E. Spanjaard if (rdp->type & (AR_T_RAID1 | AR_T_RAID01)) 937*c1b3d7c5SThomas E. Spanjaard printf("ar%d: WARNING - mirror", rdp->lun); 938*c1b3d7c5SThomas E. Spanjaard else 939*c1b3d7c5SThomas E. Spanjaard printf("ar%d: WARNING - parity", rdp->lun); 940*c1b3d7c5SThomas E. Spanjaard printf(" protection lost. %s array in DEGRADED mode\n", 941*c1b3d7c5SThomas E. Spanjaard ata_raid_type(rdp)); 942*c1b3d7c5SThomas E. Spanjaard } 943*c1b3d7c5SThomas E. Spanjaard } 944*c1b3d7c5SThomas E. Spanjaard spin_unlock_wr(&rdp->lock); 945*c1b3d7c5SThomas E. Spanjaard if (writeback) 946*c1b3d7c5SThomas E. Spanjaard ata_raid_write_metadata(rdp); 947*c1b3d7c5SThomas E. Spanjaard 948*c1b3d7c5SThomas E. Spanjaard } 949*c1b3d7c5SThomas E. Spanjaard 950*c1b3d7c5SThomas E. Spanjaard static int 951*c1b3d7c5SThomas E. Spanjaard ata_raid_status(struct ata_ioc_raid_config *config) 952*c1b3d7c5SThomas E. Spanjaard { 953*c1b3d7c5SThomas E. Spanjaard struct ar_softc *rdp; 954*c1b3d7c5SThomas E. Spanjaard int i; 955*c1b3d7c5SThomas E. Spanjaard 956*c1b3d7c5SThomas E. Spanjaard if (!(rdp = ata_raid_arrays[config->lun])) 957*c1b3d7c5SThomas E. Spanjaard return ENXIO; 958*c1b3d7c5SThomas E. Spanjaard 959*c1b3d7c5SThomas E. Spanjaard config->type = rdp->type; 960*c1b3d7c5SThomas E. Spanjaard config->total_disks = rdp->total_disks; 961*c1b3d7c5SThomas E. Spanjaard for (i = 0; i < rdp->total_disks; i++ ) { 962*c1b3d7c5SThomas E. Spanjaard if ((rdp->disks[i].flags & AR_DF_PRESENT) && rdp->disks[i].dev) 963*c1b3d7c5SThomas E. Spanjaard config->disks[i] = device_get_unit(rdp->disks[i].dev); 964*c1b3d7c5SThomas E. Spanjaard else 965*c1b3d7c5SThomas E. Spanjaard config->disks[i] = -1; 966*c1b3d7c5SThomas E. Spanjaard } 967*c1b3d7c5SThomas E. Spanjaard config->interleave = rdp->interleave; 968*c1b3d7c5SThomas E. Spanjaard config->status = rdp->status; 969*c1b3d7c5SThomas E. Spanjaard config->progress = 100 * rdp->rebuild_lba / rdp->total_sectors; 970*c1b3d7c5SThomas E. Spanjaard return 0; 971*c1b3d7c5SThomas E. Spanjaard } 972*c1b3d7c5SThomas E. Spanjaard 973*c1b3d7c5SThomas E. Spanjaard static int 974*c1b3d7c5SThomas E. Spanjaard ata_raid_create(struct ata_ioc_raid_config *config) 975*c1b3d7c5SThomas E. Spanjaard { 976*c1b3d7c5SThomas E. Spanjaard struct ar_softc *rdp; 977*c1b3d7c5SThomas E. Spanjaard device_t subdisk; 978*c1b3d7c5SThomas E. Spanjaard int array, disk; 979*c1b3d7c5SThomas E. Spanjaard int ctlr = 0, disk_size = 0, total_disks = 0; 980*c1b3d7c5SThomas E. Spanjaard 981*c1b3d7c5SThomas E. Spanjaard for (array = 0; array < MAX_ARRAYS; array++) { 982*c1b3d7c5SThomas E. Spanjaard if (!ata_raid_arrays[array]) 983*c1b3d7c5SThomas E. Spanjaard break; 984*c1b3d7c5SThomas E. Spanjaard } 985*c1b3d7c5SThomas E. Spanjaard if (array >= MAX_ARRAYS) 986*c1b3d7c5SThomas E. Spanjaard return ENOSPC; 987*c1b3d7c5SThomas E. Spanjaard 988*c1b3d7c5SThomas E. Spanjaard if (!(rdp = (struct ar_softc*)malloc(sizeof(struct ar_softc), M_AR, 989*c1b3d7c5SThomas E. Spanjaard M_NOWAIT | M_ZERO))) { 990*c1b3d7c5SThomas E. Spanjaard printf("ar%d: no memory for metadata storage\n", array); 991*c1b3d7c5SThomas E. Spanjaard return ENOMEM; 992*c1b3d7c5SThomas E. Spanjaard } 993*c1b3d7c5SThomas E. Spanjaard 994*c1b3d7c5SThomas E. Spanjaard for (disk = 0; disk < config->total_disks; disk++) { 995*c1b3d7c5SThomas E. Spanjaard if ((subdisk = devclass_get_device(ata_raid_sub_devclass, 996*c1b3d7c5SThomas E. Spanjaard config->disks[disk]))) { 997*c1b3d7c5SThomas E. Spanjaard struct ata_raid_subdisk *ars = device_get_softc(subdisk); 998*c1b3d7c5SThomas E. Spanjaard 999*c1b3d7c5SThomas E. Spanjaard /* is device already assigned to another array ? */ 1000*c1b3d7c5SThomas E. Spanjaard if (ars->raid[rdp->volume]) { 1001*c1b3d7c5SThomas E. Spanjaard config->disks[disk] = -1; 1002*c1b3d7c5SThomas E. Spanjaard free(rdp, M_AR); 1003*c1b3d7c5SThomas E. Spanjaard return EBUSY; 1004*c1b3d7c5SThomas E. Spanjaard } 1005*c1b3d7c5SThomas E. Spanjaard rdp->disks[disk].dev = device_get_parent(subdisk); 1006*c1b3d7c5SThomas E. Spanjaard 1007*c1b3d7c5SThomas E. Spanjaard switch (pci_get_vendor(GRANDPARENT(rdp->disks[disk].dev))) { 1008*c1b3d7c5SThomas E. Spanjaard case ATA_HIGHPOINT_ID: 1009*c1b3d7c5SThomas E. Spanjaard /* 1010*c1b3d7c5SThomas E. Spanjaard * we need some way to decide if it should be v2 or v3 1011*c1b3d7c5SThomas E. Spanjaard * for now just use v2 since the v3 BIOS knows how to 1012*c1b3d7c5SThomas E. Spanjaard * handle that as well. 1013*c1b3d7c5SThomas E. Spanjaard */ 1014*c1b3d7c5SThomas E. Spanjaard ctlr = AR_F_HPTV2_RAID; 1015*c1b3d7c5SThomas E. Spanjaard rdp->disks[disk].sectors = HPTV3_LBA(rdp->disks[disk].dev); 1016*c1b3d7c5SThomas E. Spanjaard break; 1017*c1b3d7c5SThomas E. Spanjaard 1018*c1b3d7c5SThomas E. Spanjaard case ATA_INTEL_ID: 1019*c1b3d7c5SThomas E. Spanjaard ctlr = AR_F_INTEL_RAID; 1020*c1b3d7c5SThomas E. Spanjaard rdp->disks[disk].sectors = INTEL_LBA(rdp->disks[disk].dev); 1021*c1b3d7c5SThomas E. Spanjaard break; 1022*c1b3d7c5SThomas E. Spanjaard 1023*c1b3d7c5SThomas E. Spanjaard case ATA_ITE_ID: 1024*c1b3d7c5SThomas E. Spanjaard ctlr = AR_F_ITE_RAID; 1025*c1b3d7c5SThomas E. Spanjaard rdp->disks[disk].sectors = ITE_LBA(rdp->disks[disk].dev); 1026*c1b3d7c5SThomas E. Spanjaard break; 1027*c1b3d7c5SThomas E. Spanjaard 1028*c1b3d7c5SThomas E. Spanjaard case ATA_JMICRON_ID: 1029*c1b3d7c5SThomas E. Spanjaard ctlr = AR_F_JMICRON_RAID; 1030*c1b3d7c5SThomas E. Spanjaard rdp->disks[disk].sectors = JMICRON_LBA(rdp->disks[disk].dev); 1031*c1b3d7c5SThomas E. Spanjaard break; 1032*c1b3d7c5SThomas E. Spanjaard 1033*c1b3d7c5SThomas E. Spanjaard case 0: /* XXX SOS cover up for bug in our PCI code */ 1034*c1b3d7c5SThomas E. Spanjaard case ATA_PROMISE_ID: 1035*c1b3d7c5SThomas E. Spanjaard ctlr = AR_F_PROMISE_RAID; 1036*c1b3d7c5SThomas E. Spanjaard rdp->disks[disk].sectors = PROMISE_LBA(rdp->disks[disk].dev); 1037*c1b3d7c5SThomas E. Spanjaard break; 1038*c1b3d7c5SThomas E. Spanjaard 1039*c1b3d7c5SThomas E. Spanjaard case ATA_SIS_ID: 1040*c1b3d7c5SThomas E. Spanjaard ctlr = AR_F_SIS_RAID; 1041*c1b3d7c5SThomas E. Spanjaard rdp->disks[disk].sectors = SIS_LBA(rdp->disks[disk].dev); 1042*c1b3d7c5SThomas E. Spanjaard break; 1043*c1b3d7c5SThomas E. Spanjaard 1044*c1b3d7c5SThomas E. Spanjaard case ATA_ATI_ID: 1045*c1b3d7c5SThomas E. Spanjaard case ATA_VIA_ID: 1046*c1b3d7c5SThomas E. Spanjaard ctlr = AR_F_VIA_RAID; 1047*c1b3d7c5SThomas E. Spanjaard rdp->disks[disk].sectors = VIA_LBA(rdp->disks[disk].dev); 1048*c1b3d7c5SThomas E. Spanjaard break; 1049*c1b3d7c5SThomas E. Spanjaard 1050*c1b3d7c5SThomas E. Spanjaard default: 1051*c1b3d7c5SThomas E. Spanjaard /* XXX SOS 1052*c1b3d7c5SThomas E. Spanjaard * right, so here we are, we have an ATA chip and we want 1053*c1b3d7c5SThomas E. Spanjaard * to create a RAID and store the metadata. 1054*c1b3d7c5SThomas E. Spanjaard * we need to find a way to tell what kind of metadata this 1055*c1b3d7c5SThomas E. Spanjaard * hardware's BIOS might be using (good ideas are welcomed) 1056*c1b3d7c5SThomas E. Spanjaard * for now we just use our own native FreeBSD format. 1057*c1b3d7c5SThomas E. Spanjaard * the only way to get support for the BIOS format is to 1058*c1b3d7c5SThomas E. Spanjaard * setup the RAID from there, in that case we pickup the 1059*c1b3d7c5SThomas E. Spanjaard * metadata format from the disks (if we support it). 1060*c1b3d7c5SThomas E. Spanjaard */ 1061*c1b3d7c5SThomas E. Spanjaard printf("WARNING!! - not able to determine metadata format\n" 1062*c1b3d7c5SThomas E. Spanjaard "WARNING!! - Using FreeBSD PseudoRAID metadata\n" 1063*c1b3d7c5SThomas E. Spanjaard "If that is not what you want, use the BIOS to " 1064*c1b3d7c5SThomas E. Spanjaard "create the array\n"); 1065*c1b3d7c5SThomas E. Spanjaard ctlr = AR_F_FREEBSD_RAID; 1066*c1b3d7c5SThomas E. Spanjaard rdp->disks[disk].sectors = PROMISE_LBA(rdp->disks[disk].dev); 1067*c1b3d7c5SThomas E. Spanjaard break; 1068*c1b3d7c5SThomas E. Spanjaard } 1069*c1b3d7c5SThomas E. Spanjaard 1070*c1b3d7c5SThomas E. Spanjaard /* we need all disks to be of the same format */ 1071*c1b3d7c5SThomas E. Spanjaard if ((rdp->format & AR_F_FORMAT_MASK) && 1072*c1b3d7c5SThomas E. Spanjaard (rdp->format & AR_F_FORMAT_MASK) != (ctlr & AR_F_FORMAT_MASK)) { 1073*c1b3d7c5SThomas E. Spanjaard free(rdp, M_AR); 1074*c1b3d7c5SThomas E. Spanjaard return EXDEV; 1075*c1b3d7c5SThomas E. Spanjaard } 1076*c1b3d7c5SThomas E. Spanjaard else 1077*c1b3d7c5SThomas E. Spanjaard rdp->format = ctlr; 1078*c1b3d7c5SThomas E. Spanjaard 1079*c1b3d7c5SThomas E. Spanjaard /* use the smallest disk of the lots size */ 1080*c1b3d7c5SThomas E. Spanjaard /* gigabyte boundry ??? XXX SOS */ 1081*c1b3d7c5SThomas E. Spanjaard if (disk_size) 1082*c1b3d7c5SThomas E. Spanjaard disk_size = min(rdp->disks[disk].sectors, disk_size); 1083*c1b3d7c5SThomas E. Spanjaard else 1084*c1b3d7c5SThomas E. Spanjaard disk_size = rdp->disks[disk].sectors; 1085*c1b3d7c5SThomas E. Spanjaard rdp->disks[disk].flags = 1086*c1b3d7c5SThomas E. Spanjaard (AR_DF_PRESENT | AR_DF_ASSIGNED | AR_DF_ONLINE); 1087*c1b3d7c5SThomas E. Spanjaard 1088*c1b3d7c5SThomas E. Spanjaard total_disks++; 1089*c1b3d7c5SThomas E. Spanjaard } 1090*c1b3d7c5SThomas E. Spanjaard else { 1091*c1b3d7c5SThomas E. Spanjaard config->disks[disk] = -1; 1092*c1b3d7c5SThomas E. Spanjaard free(rdp, M_AR); 1093*c1b3d7c5SThomas E. Spanjaard return ENXIO; 1094*c1b3d7c5SThomas E. Spanjaard } 1095*c1b3d7c5SThomas E. Spanjaard } 1096*c1b3d7c5SThomas E. Spanjaard 1097*c1b3d7c5SThomas E. Spanjaard if (total_disks != config->total_disks) { 1098*c1b3d7c5SThomas E. Spanjaard free(rdp, M_AR); 1099*c1b3d7c5SThomas E. Spanjaard return ENODEV; 1100*c1b3d7c5SThomas E. Spanjaard } 1101*c1b3d7c5SThomas E. Spanjaard 1102*c1b3d7c5SThomas E. Spanjaard switch (config->type) { 1103*c1b3d7c5SThomas E. Spanjaard case AR_T_JBOD: 1104*c1b3d7c5SThomas E. Spanjaard case AR_T_SPAN: 1105*c1b3d7c5SThomas E. Spanjaard case AR_T_RAID0: 1106*c1b3d7c5SThomas E. Spanjaard break; 1107*c1b3d7c5SThomas E. Spanjaard 1108*c1b3d7c5SThomas E. Spanjaard case AR_T_RAID1: 1109*c1b3d7c5SThomas E. Spanjaard if (total_disks != 2) { 1110*c1b3d7c5SThomas E. Spanjaard free(rdp, M_AR); 1111*c1b3d7c5SThomas E. Spanjaard return EPERM; 1112*c1b3d7c5SThomas E. Spanjaard } 1113*c1b3d7c5SThomas E. Spanjaard break; 1114*c1b3d7c5SThomas E. Spanjaard 1115*c1b3d7c5SThomas E. Spanjaard case AR_T_RAID01: 1116*c1b3d7c5SThomas E. Spanjaard if (total_disks % 2 != 0) { 1117*c1b3d7c5SThomas E. Spanjaard free(rdp, M_AR); 1118*c1b3d7c5SThomas E. Spanjaard return EPERM; 1119*c1b3d7c5SThomas E. Spanjaard } 1120*c1b3d7c5SThomas E. Spanjaard break; 1121*c1b3d7c5SThomas E. Spanjaard 1122*c1b3d7c5SThomas E. Spanjaard case AR_T_RAID5: 1123*c1b3d7c5SThomas E. Spanjaard if (total_disks < 3) { 1124*c1b3d7c5SThomas E. Spanjaard free(rdp, M_AR); 1125*c1b3d7c5SThomas E. Spanjaard return EPERM; 1126*c1b3d7c5SThomas E. Spanjaard } 1127*c1b3d7c5SThomas E. Spanjaard break; 1128*c1b3d7c5SThomas E. Spanjaard 1129*c1b3d7c5SThomas E. Spanjaard default: 1130*c1b3d7c5SThomas E. Spanjaard free(rdp, M_AR); 1131*c1b3d7c5SThomas E. Spanjaard return EOPNOTSUPP; 1132*c1b3d7c5SThomas E. Spanjaard } 1133*c1b3d7c5SThomas E. Spanjaard rdp->type = config->type; 1134*c1b3d7c5SThomas E. Spanjaard rdp->lun = array; 1135*c1b3d7c5SThomas E. Spanjaard if (rdp->type == AR_T_RAID0 || rdp->type == AR_T_RAID01 || 1136*c1b3d7c5SThomas E. Spanjaard rdp->type == AR_T_RAID5) { 1137*c1b3d7c5SThomas E. Spanjaard int bit = 0; 1138*c1b3d7c5SThomas E. Spanjaard 1139*c1b3d7c5SThomas E. Spanjaard while (config->interleave >>= 1) 1140*c1b3d7c5SThomas E. Spanjaard bit++; 1141*c1b3d7c5SThomas E. Spanjaard rdp->interleave = 1 << bit; 1142*c1b3d7c5SThomas E. Spanjaard } 1143*c1b3d7c5SThomas E. Spanjaard rdp->offset_sectors = 0; 1144*c1b3d7c5SThomas E. Spanjaard 1145*c1b3d7c5SThomas E. Spanjaard /* values that depend on metadata format */ 1146*c1b3d7c5SThomas E. Spanjaard switch (rdp->format) { 1147*c1b3d7c5SThomas E. Spanjaard case AR_F_ADAPTEC_RAID: 1148*c1b3d7c5SThomas E. Spanjaard rdp->interleave = min(max(32, rdp->interleave), 128); /*+*/ 1149*c1b3d7c5SThomas E. Spanjaard break; 1150*c1b3d7c5SThomas E. Spanjaard 1151*c1b3d7c5SThomas E. Spanjaard case AR_F_HPTV2_RAID: 1152*c1b3d7c5SThomas E. Spanjaard rdp->interleave = min(max(8, rdp->interleave), 128); /*+*/ 1153*c1b3d7c5SThomas E. Spanjaard rdp->offset_sectors = HPTV2_LBA(x) + 1; 1154*c1b3d7c5SThomas E. Spanjaard break; 1155*c1b3d7c5SThomas E. Spanjaard 1156*c1b3d7c5SThomas E. Spanjaard case AR_F_HPTV3_RAID: 1157*c1b3d7c5SThomas E. Spanjaard rdp->interleave = min(max(32, rdp->interleave), 4096); /*+*/ 1158*c1b3d7c5SThomas E. Spanjaard break; 1159*c1b3d7c5SThomas E. Spanjaard 1160*c1b3d7c5SThomas E. Spanjaard case AR_F_INTEL_RAID: 1161*c1b3d7c5SThomas E. Spanjaard rdp->interleave = min(max(8, rdp->interleave), 256); /*+*/ 1162*c1b3d7c5SThomas E. Spanjaard break; 1163*c1b3d7c5SThomas E. Spanjaard 1164*c1b3d7c5SThomas E. Spanjaard case AR_F_ITE_RAID: 1165*c1b3d7c5SThomas E. Spanjaard rdp->interleave = min(max(2, rdp->interleave), 128); /*+*/ 1166*c1b3d7c5SThomas E. Spanjaard break; 1167*c1b3d7c5SThomas E. Spanjaard 1168*c1b3d7c5SThomas E. Spanjaard case AR_F_JMICRON_RAID: 1169*c1b3d7c5SThomas E. Spanjaard rdp->interleave = min(max(8, rdp->interleave), 256); /*+*/ 1170*c1b3d7c5SThomas E. Spanjaard break; 1171*c1b3d7c5SThomas E. Spanjaard 1172*c1b3d7c5SThomas E. Spanjaard case AR_F_LSIV2_RAID: 1173*c1b3d7c5SThomas E. Spanjaard rdp->interleave = min(max(2, rdp->interleave), 4096); 1174*c1b3d7c5SThomas E. Spanjaard break; 1175*c1b3d7c5SThomas E. Spanjaard 1176*c1b3d7c5SThomas E. Spanjaard case AR_F_LSIV3_RAID: 1177*c1b3d7c5SThomas E. Spanjaard rdp->interleave = min(max(2, rdp->interleave), 256); 1178*c1b3d7c5SThomas E. Spanjaard break; 1179*c1b3d7c5SThomas E. Spanjaard 1180*c1b3d7c5SThomas E. Spanjaard case AR_F_PROMISE_RAID: 1181*c1b3d7c5SThomas E. Spanjaard rdp->interleave = min(max(2, rdp->interleave), 2048); /*+*/ 1182*c1b3d7c5SThomas E. Spanjaard break; 1183*c1b3d7c5SThomas E. Spanjaard 1184*c1b3d7c5SThomas E. Spanjaard case AR_F_SII_RAID: 1185*c1b3d7c5SThomas E. Spanjaard rdp->interleave = min(max(8, rdp->interleave), 256); /*+*/ 1186*c1b3d7c5SThomas E. Spanjaard break; 1187*c1b3d7c5SThomas E. Spanjaard 1188*c1b3d7c5SThomas E. Spanjaard case AR_F_SIS_RAID: 1189*c1b3d7c5SThomas E. Spanjaard rdp->interleave = min(max(32, rdp->interleave), 512); /*+*/ 1190*c1b3d7c5SThomas E. Spanjaard break; 1191*c1b3d7c5SThomas E. Spanjaard 1192*c1b3d7c5SThomas E. Spanjaard case AR_F_VIA_RAID: 1193*c1b3d7c5SThomas E. Spanjaard rdp->interleave = min(max(8, rdp->interleave), 128); /*+*/ 1194*c1b3d7c5SThomas E. Spanjaard break; 1195*c1b3d7c5SThomas E. Spanjaard } 1196*c1b3d7c5SThomas E. Spanjaard 1197*c1b3d7c5SThomas E. Spanjaard rdp->total_disks = total_disks; 1198*c1b3d7c5SThomas E. Spanjaard rdp->width = total_disks / (rdp->type & (AR_RAID1 | AR_T_RAID01) ? 2 : 1); 1199*c1b3d7c5SThomas E. Spanjaard rdp->total_sectors = disk_size * (rdp->width - (rdp->type == AR_RAID5)); 1200*c1b3d7c5SThomas E. Spanjaard rdp->heads = 255; 1201*c1b3d7c5SThomas E. Spanjaard rdp->sectors = 63; 1202*c1b3d7c5SThomas E. Spanjaard rdp->cylinders = rdp->total_sectors / (255 * 63); 1203*c1b3d7c5SThomas E. Spanjaard rdp->rebuild_lba = 0; 1204*c1b3d7c5SThomas E. Spanjaard rdp->status |= AR_S_READY; 1205*c1b3d7c5SThomas E. Spanjaard 1206*c1b3d7c5SThomas E. Spanjaard /* we are committed to this array, grap the subdisks */ 1207*c1b3d7c5SThomas E. Spanjaard for (disk = 0; disk < config->total_disks; disk++) { 1208*c1b3d7c5SThomas E. Spanjaard if ((subdisk = devclass_get_device(ata_raid_sub_devclass, 1209*c1b3d7c5SThomas E. Spanjaard config->disks[disk]))) { 1210*c1b3d7c5SThomas E. Spanjaard struct ata_raid_subdisk *ars = device_get_softc(subdisk); 1211*c1b3d7c5SThomas E. Spanjaard 1212*c1b3d7c5SThomas E. Spanjaard ars->raid[rdp->volume] = rdp; 1213*c1b3d7c5SThomas E. Spanjaard ars->disk_number[rdp->volume] = disk; 1214*c1b3d7c5SThomas E. Spanjaard } 1215*c1b3d7c5SThomas E. Spanjaard } 1216*c1b3d7c5SThomas E. Spanjaard ata_raid_attach(rdp, 1); 1217*c1b3d7c5SThomas E. Spanjaard ata_raid_arrays[array] = rdp; 1218*c1b3d7c5SThomas E. Spanjaard config->lun = array; 1219*c1b3d7c5SThomas E. Spanjaard return 0; 1220*c1b3d7c5SThomas E. Spanjaard } 1221*c1b3d7c5SThomas E. Spanjaard 1222*c1b3d7c5SThomas E. Spanjaard static int 1223*c1b3d7c5SThomas E. Spanjaard ata_raid_delete(int array) 1224*c1b3d7c5SThomas E. Spanjaard { 1225*c1b3d7c5SThomas E. Spanjaard struct ar_softc *rdp; 1226*c1b3d7c5SThomas E. Spanjaard device_t subdisk; 1227*c1b3d7c5SThomas E. Spanjaard int disk; 1228*c1b3d7c5SThomas E. Spanjaard 1229*c1b3d7c5SThomas E. Spanjaard if (!(rdp = ata_raid_arrays[array])) 1230*c1b3d7c5SThomas E. Spanjaard return ENXIO; 1231*c1b3d7c5SThomas E. Spanjaard 1232*c1b3d7c5SThomas E. Spanjaard rdp->status &= ~AR_S_READY; 1233*c1b3d7c5SThomas E. Spanjaard if (rdp->disk) 1234*c1b3d7c5SThomas E. Spanjaard disk_destroy(rdp->disk); 1235*c1b3d7c5SThomas E. Spanjaard 1236*c1b3d7c5SThomas E. Spanjaard for (disk = 0; disk < rdp->total_disks; disk++) { 1237*c1b3d7c5SThomas E. Spanjaard if ((rdp->disks[disk].flags & AR_DF_PRESENT) && rdp->disks[disk].dev) { 1238*c1b3d7c5SThomas E. Spanjaard if ((subdisk = devclass_get_device(ata_raid_sub_devclass, 1239*c1b3d7c5SThomas E. Spanjaard device_get_unit(rdp->disks[disk].dev)))) { 1240*c1b3d7c5SThomas E. Spanjaard struct ata_raid_subdisk *ars = device_get_softc(subdisk); 1241*c1b3d7c5SThomas E. Spanjaard 1242*c1b3d7c5SThomas E. Spanjaard if (ars->raid[rdp->volume] != rdp) /* XXX SOS */ 1243*c1b3d7c5SThomas E. Spanjaard device_printf(subdisk, "DOH! this disk doesn't belong\n"); 1244*c1b3d7c5SThomas E. Spanjaard if (ars->disk_number[rdp->volume] != disk) /* XXX SOS */ 1245*c1b3d7c5SThomas E. Spanjaard device_printf(subdisk, "DOH! this disk number is wrong\n"); 1246*c1b3d7c5SThomas E. Spanjaard ars->raid[rdp->volume] = NULL; 1247*c1b3d7c5SThomas E. Spanjaard ars->disk_number[rdp->volume] = -1; 1248*c1b3d7c5SThomas E. Spanjaard } 1249*c1b3d7c5SThomas E. Spanjaard rdp->disks[disk].flags = 0; 1250*c1b3d7c5SThomas E. Spanjaard } 1251*c1b3d7c5SThomas E. Spanjaard } 1252*c1b3d7c5SThomas E. Spanjaard ata_raid_wipe_metadata(rdp); 1253*c1b3d7c5SThomas E. Spanjaard ata_raid_arrays[array] = NULL; 1254*c1b3d7c5SThomas E. Spanjaard free(rdp, M_AR); 1255*c1b3d7c5SThomas E. Spanjaard return 0; 1256*c1b3d7c5SThomas E. Spanjaard } 1257*c1b3d7c5SThomas E. Spanjaard 1258*c1b3d7c5SThomas E. Spanjaard static int 1259*c1b3d7c5SThomas E. Spanjaard ata_raid_addspare(struct ata_ioc_raid_config *config) 1260*c1b3d7c5SThomas E. Spanjaard { 1261*c1b3d7c5SThomas E. Spanjaard struct ar_softc *rdp; 1262*c1b3d7c5SThomas E. Spanjaard device_t subdisk; 1263*c1b3d7c5SThomas E. Spanjaard int disk; 1264*c1b3d7c5SThomas E. Spanjaard 1265*c1b3d7c5SThomas E. Spanjaard if (!(rdp = ata_raid_arrays[config->lun])) 1266*c1b3d7c5SThomas E. Spanjaard return ENXIO; 1267*c1b3d7c5SThomas E. Spanjaard if (!(rdp->status & AR_S_DEGRADED) || !(rdp->status & AR_S_READY)) 1268*c1b3d7c5SThomas E. Spanjaard return ENXIO; 1269*c1b3d7c5SThomas E. Spanjaard if (rdp->status & AR_S_REBUILDING) 1270*c1b3d7c5SThomas E. Spanjaard return EBUSY; 1271*c1b3d7c5SThomas E. Spanjaard switch (rdp->type) { 1272*c1b3d7c5SThomas E. Spanjaard case AR_T_RAID1: 1273*c1b3d7c5SThomas E. Spanjaard case AR_T_RAID01: 1274*c1b3d7c5SThomas E. Spanjaard case AR_T_RAID5: 1275*c1b3d7c5SThomas E. Spanjaard for (disk = 0; disk < rdp->total_disks; disk++ ) { 1276*c1b3d7c5SThomas E. Spanjaard 1277*c1b3d7c5SThomas E. Spanjaard if (((rdp->disks[disk].flags & (AR_DF_PRESENT | AR_DF_ONLINE)) == 1278*c1b3d7c5SThomas E. Spanjaard (AR_DF_PRESENT | AR_DF_ONLINE)) && rdp->disks[disk].dev) 1279*c1b3d7c5SThomas E. Spanjaard continue; 1280*c1b3d7c5SThomas E. Spanjaard 1281*c1b3d7c5SThomas E. Spanjaard if ((subdisk = devclass_get_device(ata_raid_sub_devclass, 1282*c1b3d7c5SThomas E. Spanjaard config->disks[0] ))) { 1283*c1b3d7c5SThomas E. Spanjaard struct ata_raid_subdisk *ars = device_get_softc(subdisk); 1284*c1b3d7c5SThomas E. Spanjaard 1285*c1b3d7c5SThomas E. Spanjaard if (ars->raid[rdp->volume]) 1286*c1b3d7c5SThomas E. Spanjaard return EBUSY; 1287*c1b3d7c5SThomas E. Spanjaard 1288*c1b3d7c5SThomas E. Spanjaard /* XXX SOS validate size etc etc */ 1289*c1b3d7c5SThomas E. Spanjaard ars->raid[rdp->volume] = rdp; 1290*c1b3d7c5SThomas E. Spanjaard ars->disk_number[rdp->volume] = disk; 1291*c1b3d7c5SThomas E. Spanjaard rdp->disks[disk].dev = device_get_parent(subdisk); 1292*c1b3d7c5SThomas E. Spanjaard rdp->disks[disk].flags = 1293*c1b3d7c5SThomas E. Spanjaard (AR_DF_PRESENT | AR_DF_ASSIGNED | AR_DF_SPARE); 1294*c1b3d7c5SThomas E. Spanjaard 1295*c1b3d7c5SThomas E. Spanjaard device_printf(rdp->disks[disk].dev, 1296*c1b3d7c5SThomas E. Spanjaard "inserted into ar%d disk%d as spare\n", 1297*c1b3d7c5SThomas E. Spanjaard rdp->lun, disk); 1298*c1b3d7c5SThomas E. Spanjaard ata_raid_config_changed(rdp, 1); 1299*c1b3d7c5SThomas E. Spanjaard return 0; 1300*c1b3d7c5SThomas E. Spanjaard } 1301*c1b3d7c5SThomas E. Spanjaard } 1302*c1b3d7c5SThomas E. Spanjaard return ENXIO; 1303*c1b3d7c5SThomas E. Spanjaard 1304*c1b3d7c5SThomas E. Spanjaard default: 1305*c1b3d7c5SThomas E. Spanjaard return EPERM; 1306*c1b3d7c5SThomas E. Spanjaard } 1307*c1b3d7c5SThomas E. Spanjaard } 1308*c1b3d7c5SThomas E. Spanjaard 1309*c1b3d7c5SThomas E. Spanjaard static int 1310*c1b3d7c5SThomas E. Spanjaard ata_raid_rebuild(int array) 1311*c1b3d7c5SThomas E. Spanjaard { 1312*c1b3d7c5SThomas E. Spanjaard struct ar_softc *rdp; 1313*c1b3d7c5SThomas E. Spanjaard int disk, count; 1314*c1b3d7c5SThomas E. Spanjaard 1315*c1b3d7c5SThomas E. Spanjaard if (!(rdp = ata_raid_arrays[array])) 1316*c1b3d7c5SThomas E. Spanjaard return ENXIO; 1317*c1b3d7c5SThomas E. Spanjaard /* XXX SOS we should lock the rdp softc here */ 1318*c1b3d7c5SThomas E. Spanjaard if (!(rdp->status & AR_S_DEGRADED) || !(rdp->status & AR_S_READY)) 1319*c1b3d7c5SThomas E. Spanjaard return ENXIO; 1320*c1b3d7c5SThomas E. Spanjaard if (rdp->status & AR_S_REBUILDING) 1321*c1b3d7c5SThomas E. Spanjaard return EBUSY; 1322*c1b3d7c5SThomas E. Spanjaard 1323*c1b3d7c5SThomas E. Spanjaard switch (rdp->type) { 1324*c1b3d7c5SThomas E. Spanjaard case AR_T_RAID1: 1325*c1b3d7c5SThomas E. Spanjaard case AR_T_RAID01: 1326*c1b3d7c5SThomas E. Spanjaard case AR_T_RAID5: 1327*c1b3d7c5SThomas E. Spanjaard for (count = 0, disk = 0; disk < rdp->total_disks; disk++ ) { 1328*c1b3d7c5SThomas E. Spanjaard if (((rdp->disks[disk].flags & 1329*c1b3d7c5SThomas E. Spanjaard (AR_DF_PRESENT|AR_DF_ASSIGNED|AR_DF_ONLINE|AR_DF_SPARE)) == 1330*c1b3d7c5SThomas E. Spanjaard (AR_DF_PRESENT | AR_DF_ASSIGNED | AR_DF_SPARE)) && 1331*c1b3d7c5SThomas E. Spanjaard rdp->disks[disk].dev) { 1332*c1b3d7c5SThomas E. Spanjaard count++; 1333*c1b3d7c5SThomas E. Spanjaard } 1334*c1b3d7c5SThomas E. Spanjaard } 1335*c1b3d7c5SThomas E. Spanjaard 1336*c1b3d7c5SThomas E. Spanjaard if (count) { 1337*c1b3d7c5SThomas E. Spanjaard rdp->rebuild_lba = 0; 1338*c1b3d7c5SThomas E. Spanjaard rdp->status |= AR_S_REBUILDING; 1339*c1b3d7c5SThomas E. Spanjaard return 0; 1340*c1b3d7c5SThomas E. Spanjaard } 1341*c1b3d7c5SThomas E. Spanjaard return EIO; 1342*c1b3d7c5SThomas E. Spanjaard 1343*c1b3d7c5SThomas E. Spanjaard default: 1344*c1b3d7c5SThomas E. Spanjaard return EPERM; 1345*c1b3d7c5SThomas E. Spanjaard } 1346*c1b3d7c5SThomas E. Spanjaard } 1347*c1b3d7c5SThomas E. Spanjaard 1348*c1b3d7c5SThomas E. Spanjaard static int 1349*c1b3d7c5SThomas E. Spanjaard ata_raid_read_metadata(device_t subdisk) 1350*c1b3d7c5SThomas E. Spanjaard { 1351*c1b3d7c5SThomas E. Spanjaard devclass_t pci_devclass = devclass_find("pci"); 1352*c1b3d7c5SThomas E. Spanjaard devclass_t devclass=device_get_devclass(GRANDPARENT(GRANDPARENT(subdisk))); 1353*c1b3d7c5SThomas E. Spanjaard 1354*c1b3d7c5SThomas E. Spanjaard /* prioritize vendor native metadata layout if possible */ 1355*c1b3d7c5SThomas E. Spanjaard if (devclass == pci_devclass) { 1356*c1b3d7c5SThomas E. Spanjaard switch (pci_get_vendor(GRANDPARENT(device_get_parent(subdisk)))) { 1357*c1b3d7c5SThomas E. Spanjaard case ATA_HIGHPOINT_ID: 1358*c1b3d7c5SThomas E. Spanjaard if (ata_raid_hptv3_read_meta(subdisk, ata_raid_arrays)) 1359*c1b3d7c5SThomas E. Spanjaard return 0; 1360*c1b3d7c5SThomas E. Spanjaard if (ata_raid_hptv2_read_meta(subdisk, ata_raid_arrays)) 1361*c1b3d7c5SThomas E. Spanjaard return 0; 1362*c1b3d7c5SThomas E. Spanjaard break; 1363*c1b3d7c5SThomas E. Spanjaard 1364*c1b3d7c5SThomas E. Spanjaard case ATA_INTEL_ID: 1365*c1b3d7c5SThomas E. Spanjaard if (ata_raid_intel_read_meta(subdisk, ata_raid_arrays)) 1366*c1b3d7c5SThomas E. Spanjaard return 0; 1367*c1b3d7c5SThomas E. Spanjaard break; 1368*c1b3d7c5SThomas E. Spanjaard 1369*c1b3d7c5SThomas E. Spanjaard case ATA_ITE_ID: 1370*c1b3d7c5SThomas E. Spanjaard if (ata_raid_ite_read_meta(subdisk, ata_raid_arrays)) 1371*c1b3d7c5SThomas E. Spanjaard return 0; 1372*c1b3d7c5SThomas E. Spanjaard break; 1373*c1b3d7c5SThomas E. Spanjaard 1374*c1b3d7c5SThomas E. Spanjaard case ATA_JMICRON_ID: 1375*c1b3d7c5SThomas E. Spanjaard if (ata_raid_jmicron_read_meta(subdisk, ata_raid_arrays)) 1376*c1b3d7c5SThomas E. Spanjaard return 0; 1377*c1b3d7c5SThomas E. Spanjaard break; 1378*c1b3d7c5SThomas E. Spanjaard 1379*c1b3d7c5SThomas E. Spanjaard case ATA_NVIDIA_ID: 1380*c1b3d7c5SThomas E. Spanjaard if (ata_raid_nvidia_read_meta(subdisk, ata_raid_arrays)) 1381*c1b3d7c5SThomas E. Spanjaard return 0; 1382*c1b3d7c5SThomas E. Spanjaard break; 1383*c1b3d7c5SThomas E. Spanjaard 1384*c1b3d7c5SThomas E. Spanjaard case 0: /* XXX SOS cover up for bug in our PCI code */ 1385*c1b3d7c5SThomas E. Spanjaard case ATA_PROMISE_ID: 1386*c1b3d7c5SThomas E. Spanjaard if (ata_raid_promise_read_meta(subdisk, ata_raid_arrays, 0)) 1387*c1b3d7c5SThomas E. Spanjaard return 0; 1388*c1b3d7c5SThomas E. Spanjaard break; 1389*c1b3d7c5SThomas E. Spanjaard 1390*c1b3d7c5SThomas E. Spanjaard case ATA_ATI_ID: 1391*c1b3d7c5SThomas E. Spanjaard case ATA_SILICON_IMAGE_ID: 1392*c1b3d7c5SThomas E. Spanjaard if (ata_raid_sii_read_meta(subdisk, ata_raid_arrays)) 1393*c1b3d7c5SThomas E. Spanjaard return 0; 1394*c1b3d7c5SThomas E. Spanjaard break; 1395*c1b3d7c5SThomas E. Spanjaard 1396*c1b3d7c5SThomas E. Spanjaard case ATA_SIS_ID: 1397*c1b3d7c5SThomas E. Spanjaard if (ata_raid_sis_read_meta(subdisk, ata_raid_arrays)) 1398*c1b3d7c5SThomas E. Spanjaard return 0; 1399*c1b3d7c5SThomas E. Spanjaard break; 1400*c1b3d7c5SThomas E. Spanjaard 1401*c1b3d7c5SThomas E. Spanjaard case ATA_VIA_ID: 1402*c1b3d7c5SThomas E. Spanjaard if (ata_raid_via_read_meta(subdisk, ata_raid_arrays)) 1403*c1b3d7c5SThomas E. Spanjaard return 0; 1404*c1b3d7c5SThomas E. Spanjaard break; 1405*c1b3d7c5SThomas E. Spanjaard } 1406*c1b3d7c5SThomas E. Spanjaard } 1407*c1b3d7c5SThomas E. Spanjaard 1408*c1b3d7c5SThomas E. Spanjaard /* handle controllers that have multiple layout possibilities */ 1409*c1b3d7c5SThomas E. Spanjaard /* NOTE: the order of these are not insignificant */ 1410*c1b3d7c5SThomas E. Spanjaard 1411*c1b3d7c5SThomas E. Spanjaard /* Adaptec HostRAID */ 1412*c1b3d7c5SThomas E. Spanjaard if (ata_raid_adaptec_read_meta(subdisk, ata_raid_arrays)) 1413*c1b3d7c5SThomas E. Spanjaard return 0; 1414*c1b3d7c5SThomas E. Spanjaard 1415*c1b3d7c5SThomas E. Spanjaard /* LSILogic v3 and v2 */ 1416*c1b3d7c5SThomas E. Spanjaard if (ata_raid_lsiv3_read_meta(subdisk, ata_raid_arrays)) 1417*c1b3d7c5SThomas E. Spanjaard return 0; 1418*c1b3d7c5SThomas E. Spanjaard if (ata_raid_lsiv2_read_meta(subdisk, ata_raid_arrays)) 1419*c1b3d7c5SThomas E. Spanjaard return 0; 1420*c1b3d7c5SThomas E. Spanjaard 1421*c1b3d7c5SThomas E. Spanjaard /* if none of the above matched, try FreeBSD native format */ 1422*c1b3d7c5SThomas E. Spanjaard return ata_raid_promise_read_meta(subdisk, ata_raid_arrays, 1); 1423*c1b3d7c5SThomas E. Spanjaard } 1424*c1b3d7c5SThomas E. Spanjaard 1425*c1b3d7c5SThomas E. Spanjaard static int 1426*c1b3d7c5SThomas E. Spanjaard ata_raid_write_metadata(struct ar_softc *rdp) 1427*c1b3d7c5SThomas E. Spanjaard { 1428*c1b3d7c5SThomas E. Spanjaard switch (rdp->format) { 1429*c1b3d7c5SThomas E. Spanjaard case AR_F_FREEBSD_RAID: 1430*c1b3d7c5SThomas E. Spanjaard case AR_F_PROMISE_RAID: 1431*c1b3d7c5SThomas E. Spanjaard return ata_raid_promise_write_meta(rdp); 1432*c1b3d7c5SThomas E. Spanjaard 1433*c1b3d7c5SThomas E. Spanjaard case AR_F_HPTV3_RAID: 1434*c1b3d7c5SThomas E. Spanjaard case AR_F_HPTV2_RAID: 1435*c1b3d7c5SThomas E. Spanjaard /* 1436*c1b3d7c5SThomas E. Spanjaard * always write HPT v2 metadata, the v3 BIOS knows it as well. 1437*c1b3d7c5SThomas E. Spanjaard * this is handy since we cannot know what version BIOS is on there 1438*c1b3d7c5SThomas E. Spanjaard */ 1439*c1b3d7c5SThomas E. Spanjaard return ata_raid_hptv2_write_meta(rdp); 1440*c1b3d7c5SThomas E. Spanjaard 1441*c1b3d7c5SThomas E. Spanjaard case AR_F_INTEL_RAID: 1442*c1b3d7c5SThomas E. Spanjaard return ata_raid_intel_write_meta(rdp); 1443*c1b3d7c5SThomas E. Spanjaard 1444*c1b3d7c5SThomas E. Spanjaard case AR_F_JMICRON_RAID: 1445*c1b3d7c5SThomas E. Spanjaard return ata_raid_jmicron_write_meta(rdp); 1446*c1b3d7c5SThomas E. Spanjaard 1447*c1b3d7c5SThomas E. Spanjaard case AR_F_SIS_RAID: 1448*c1b3d7c5SThomas E. Spanjaard return ata_raid_sis_write_meta(rdp); 1449*c1b3d7c5SThomas E. Spanjaard 1450*c1b3d7c5SThomas E. Spanjaard case AR_F_VIA_RAID: 1451*c1b3d7c5SThomas E. Spanjaard return ata_raid_via_write_meta(rdp); 1452*c1b3d7c5SThomas E. Spanjaard #if 0 1453*c1b3d7c5SThomas E. Spanjaard case AR_F_HPTV3_RAID: 1454*c1b3d7c5SThomas E. Spanjaard return ata_raid_hptv3_write_meta(rdp); 1455*c1b3d7c5SThomas E. Spanjaard 1456*c1b3d7c5SThomas E. Spanjaard case AR_F_ADAPTEC_RAID: 1457*c1b3d7c5SThomas E. Spanjaard return ata_raid_adaptec_write_meta(rdp); 1458*c1b3d7c5SThomas E. Spanjaard 1459*c1b3d7c5SThomas E. Spanjaard case AR_F_ITE_RAID: 1460*c1b3d7c5SThomas E. Spanjaard return ata_raid_ite_write_meta(rdp); 1461*c1b3d7c5SThomas E. Spanjaard 1462*c1b3d7c5SThomas E. Spanjaard case AR_F_LSIV2_RAID: 1463*c1b3d7c5SThomas E. Spanjaard return ata_raid_lsiv2_write_meta(rdp); 1464*c1b3d7c5SThomas E. Spanjaard 1465*c1b3d7c5SThomas E. Spanjaard case AR_F_LSIV3_RAID: 1466*c1b3d7c5SThomas E. Spanjaard return ata_raid_lsiv3_write_meta(rdp); 1467*c1b3d7c5SThomas E. Spanjaard 1468*c1b3d7c5SThomas E. Spanjaard case AR_F_NVIDIA_RAID: 1469*c1b3d7c5SThomas E. Spanjaard return ata_raid_nvidia_write_meta(rdp); 1470*c1b3d7c5SThomas E. Spanjaard 1471*c1b3d7c5SThomas E. Spanjaard case AR_F_SII_RAID: 1472*c1b3d7c5SThomas E. Spanjaard return ata_raid_sii_write_meta(rdp); 1473*c1b3d7c5SThomas E. Spanjaard 1474*c1b3d7c5SThomas E. Spanjaard #endif 1475*c1b3d7c5SThomas E. Spanjaard default: 1476*c1b3d7c5SThomas E. Spanjaard printf("ar%d: writing of %s metadata is NOT supported yet\n", 1477*c1b3d7c5SThomas E. Spanjaard rdp->lun, ata_raid_format(rdp)); 1478*c1b3d7c5SThomas E. Spanjaard } 1479*c1b3d7c5SThomas E. Spanjaard return -1; 1480*c1b3d7c5SThomas E. Spanjaard } 1481*c1b3d7c5SThomas E. Spanjaard 1482*c1b3d7c5SThomas E. Spanjaard static int 1483*c1b3d7c5SThomas E. Spanjaard ata_raid_wipe_metadata(struct ar_softc *rdp) 1484*c1b3d7c5SThomas E. Spanjaard { 1485*c1b3d7c5SThomas E. Spanjaard int disk, error = 0; 1486*c1b3d7c5SThomas E. Spanjaard u_int64_t lba; 1487*c1b3d7c5SThomas E. Spanjaard u_int32_t size; 1488*c1b3d7c5SThomas E. Spanjaard u_int8_t *meta; 1489*c1b3d7c5SThomas E. Spanjaard 1490*c1b3d7c5SThomas E. Spanjaard for (disk = 0; disk < rdp->total_disks; disk++) { 1491*c1b3d7c5SThomas E. Spanjaard if (rdp->disks[disk].dev) { 1492*c1b3d7c5SThomas E. Spanjaard switch (rdp->format) { 1493*c1b3d7c5SThomas E. Spanjaard case AR_F_ADAPTEC_RAID: 1494*c1b3d7c5SThomas E. Spanjaard lba = ADP_LBA(rdp->disks[disk].dev); 1495*c1b3d7c5SThomas E. Spanjaard size = sizeof(struct adaptec_raid_conf); 1496*c1b3d7c5SThomas E. Spanjaard break; 1497*c1b3d7c5SThomas E. Spanjaard 1498*c1b3d7c5SThomas E. Spanjaard case AR_F_HPTV2_RAID: 1499*c1b3d7c5SThomas E. Spanjaard lba = HPTV2_LBA(rdp->disks[disk].dev); 1500*c1b3d7c5SThomas E. Spanjaard size = sizeof(struct hptv2_raid_conf); 1501*c1b3d7c5SThomas E. Spanjaard break; 1502*c1b3d7c5SThomas E. Spanjaard 1503*c1b3d7c5SThomas E. Spanjaard case AR_F_HPTV3_RAID: 1504*c1b3d7c5SThomas E. Spanjaard lba = HPTV3_LBA(rdp->disks[disk].dev); 1505*c1b3d7c5SThomas E. Spanjaard size = sizeof(struct hptv3_raid_conf); 1506*c1b3d7c5SThomas E. Spanjaard break; 1507*c1b3d7c5SThomas E. Spanjaard 1508*c1b3d7c5SThomas E. Spanjaard case AR_F_INTEL_RAID: 1509*c1b3d7c5SThomas E. Spanjaard lba = INTEL_LBA(rdp->disks[disk].dev); 1510*c1b3d7c5SThomas E. Spanjaard size = 3 * 512; /* XXX SOS */ 1511*c1b3d7c5SThomas E. Spanjaard break; 1512*c1b3d7c5SThomas E. Spanjaard 1513*c1b3d7c5SThomas E. Spanjaard case AR_F_ITE_RAID: 1514*c1b3d7c5SThomas E. Spanjaard lba = ITE_LBA(rdp->disks[disk].dev); 1515*c1b3d7c5SThomas E. Spanjaard size = sizeof(struct ite_raid_conf); 1516*c1b3d7c5SThomas E. Spanjaard break; 1517*c1b3d7c5SThomas E. Spanjaard 1518*c1b3d7c5SThomas E. Spanjaard case AR_F_JMICRON_RAID: 1519*c1b3d7c5SThomas E. Spanjaard lba = JMICRON_LBA(rdp->disks[disk].dev); 1520*c1b3d7c5SThomas E. Spanjaard size = sizeof(struct jmicron_raid_conf); 1521*c1b3d7c5SThomas E. Spanjaard break; 1522*c1b3d7c5SThomas E. Spanjaard 1523*c1b3d7c5SThomas E. Spanjaard case AR_F_LSIV2_RAID: 1524*c1b3d7c5SThomas E. Spanjaard lba = LSIV2_LBA(rdp->disks[disk].dev); 1525*c1b3d7c5SThomas E. Spanjaard size = sizeof(struct lsiv2_raid_conf); 1526*c1b3d7c5SThomas E. Spanjaard break; 1527*c1b3d7c5SThomas E. Spanjaard 1528*c1b3d7c5SThomas E. Spanjaard case AR_F_LSIV3_RAID: 1529*c1b3d7c5SThomas E. Spanjaard lba = LSIV3_LBA(rdp->disks[disk].dev); 1530*c1b3d7c5SThomas E. Spanjaard size = sizeof(struct lsiv3_raid_conf); 1531*c1b3d7c5SThomas E. Spanjaard break; 1532*c1b3d7c5SThomas E. Spanjaard 1533*c1b3d7c5SThomas E. Spanjaard case AR_F_NVIDIA_RAID: 1534*c1b3d7c5SThomas E. Spanjaard lba = NVIDIA_LBA(rdp->disks[disk].dev); 1535*c1b3d7c5SThomas E. Spanjaard size = sizeof(struct nvidia_raid_conf); 1536*c1b3d7c5SThomas E. Spanjaard break; 1537*c1b3d7c5SThomas E. Spanjaard 1538*c1b3d7c5SThomas E. Spanjaard case AR_F_FREEBSD_RAID: 1539*c1b3d7c5SThomas E. Spanjaard case AR_F_PROMISE_RAID: 1540*c1b3d7c5SThomas E. Spanjaard lba = PROMISE_LBA(rdp->disks[disk].dev); 1541*c1b3d7c5SThomas E. Spanjaard size = sizeof(struct promise_raid_conf); 1542*c1b3d7c5SThomas E. Spanjaard break; 1543*c1b3d7c5SThomas E. Spanjaard 1544*c1b3d7c5SThomas E. Spanjaard case AR_F_SII_RAID: 1545*c1b3d7c5SThomas E. Spanjaard lba = SII_LBA(rdp->disks[disk].dev); 1546*c1b3d7c5SThomas E. Spanjaard size = sizeof(struct sii_raid_conf); 1547*c1b3d7c5SThomas E. Spanjaard break; 1548*c1b3d7c5SThomas E. Spanjaard 1549*c1b3d7c5SThomas E. Spanjaard case AR_F_SIS_RAID: 1550*c1b3d7c5SThomas E. Spanjaard lba = SIS_LBA(rdp->disks[disk].dev); 1551*c1b3d7c5SThomas E. Spanjaard size = sizeof(struct sis_raid_conf); 1552*c1b3d7c5SThomas E. Spanjaard break; 1553*c1b3d7c5SThomas E. Spanjaard 1554*c1b3d7c5SThomas E. Spanjaard case AR_F_VIA_RAID: 1555*c1b3d7c5SThomas E. Spanjaard lba = VIA_LBA(rdp->disks[disk].dev); 1556*c1b3d7c5SThomas E. Spanjaard size = sizeof(struct via_raid_conf); 1557*c1b3d7c5SThomas E. Spanjaard break; 1558*c1b3d7c5SThomas E. Spanjaard 1559*c1b3d7c5SThomas E. Spanjaard default: 1560*c1b3d7c5SThomas E. Spanjaard printf("ar%d: wiping of %s metadata is NOT supported yet\n", 1561*c1b3d7c5SThomas E. Spanjaard rdp->lun, ata_raid_format(rdp)); 1562*c1b3d7c5SThomas E. Spanjaard return ENXIO; 1563*c1b3d7c5SThomas E. Spanjaard } 1564*c1b3d7c5SThomas E. Spanjaard if (!(meta = malloc(size, M_AR, M_NOWAIT | M_ZERO))) 1565*c1b3d7c5SThomas E. Spanjaard return ENOMEM; 1566*c1b3d7c5SThomas E. Spanjaard if (ata_raid_rw(rdp->disks[disk].dev, lba, meta, size, 1567*c1b3d7c5SThomas E. Spanjaard ATA_R_WRITE | ATA_R_DIRECT)) { 1568*c1b3d7c5SThomas E. Spanjaard device_printf(rdp->disks[disk].dev, "wipe metadata failed\n"); 1569*c1b3d7c5SThomas E. Spanjaard error = EIO; 1570*c1b3d7c5SThomas E. Spanjaard } 1571*c1b3d7c5SThomas E. Spanjaard free(meta, M_AR); 1572*c1b3d7c5SThomas E. Spanjaard } 1573*c1b3d7c5SThomas E. Spanjaard } 1574*c1b3d7c5SThomas E. Spanjaard return error; 1575*c1b3d7c5SThomas E. Spanjaard } 1576*c1b3d7c5SThomas E. Spanjaard 1577*c1b3d7c5SThomas E. Spanjaard /* Adaptec HostRAID Metadata */ 1578*c1b3d7c5SThomas E. Spanjaard static int 1579*c1b3d7c5SThomas E. Spanjaard ata_raid_adaptec_read_meta(device_t dev, struct ar_softc **raidp) 1580*c1b3d7c5SThomas E. Spanjaard { 1581*c1b3d7c5SThomas E. Spanjaard struct ata_raid_subdisk *ars = device_get_softc(dev); 1582*c1b3d7c5SThomas E. Spanjaard device_t parent = device_get_parent(dev); 1583*c1b3d7c5SThomas E. Spanjaard struct adaptec_raid_conf *meta; 1584*c1b3d7c5SThomas E. Spanjaard struct ar_softc *raid; 1585*c1b3d7c5SThomas E. Spanjaard int array, disk, retval = 0; 1586*c1b3d7c5SThomas E. Spanjaard 1587*c1b3d7c5SThomas E. Spanjaard if (!(meta = (struct adaptec_raid_conf *) 1588*c1b3d7c5SThomas E. Spanjaard malloc(sizeof(struct adaptec_raid_conf), M_AR, M_NOWAIT | M_ZERO))) 1589*c1b3d7c5SThomas E. Spanjaard return ENOMEM; 1590*c1b3d7c5SThomas E. Spanjaard 1591*c1b3d7c5SThomas E. Spanjaard if (ata_raid_rw(parent, ADP_LBA(parent), 1592*c1b3d7c5SThomas E. Spanjaard meta, sizeof(struct adaptec_raid_conf), ATA_R_READ)) { 1593*c1b3d7c5SThomas E. Spanjaard if (testing || bootverbose) 1594*c1b3d7c5SThomas E. Spanjaard device_printf(parent, "Adaptec read metadata failed\n"); 1595*c1b3d7c5SThomas E. Spanjaard goto adaptec_out; 1596*c1b3d7c5SThomas E. Spanjaard } 1597*c1b3d7c5SThomas E. Spanjaard 1598*c1b3d7c5SThomas E. Spanjaard /* check if this is a Adaptec RAID struct */ 1599*c1b3d7c5SThomas E. Spanjaard if (meta->magic_0 != ADP_MAGIC_0 || meta->magic_3 != ADP_MAGIC_3) { 1600*c1b3d7c5SThomas E. Spanjaard if (testing || bootverbose) 1601*c1b3d7c5SThomas E. Spanjaard device_printf(parent, "Adaptec check1 failed\n"); 1602*c1b3d7c5SThomas E. Spanjaard goto adaptec_out; 1603*c1b3d7c5SThomas E. Spanjaard } 1604*c1b3d7c5SThomas E. Spanjaard 1605*c1b3d7c5SThomas E. Spanjaard if (testing || bootverbose) 1606*c1b3d7c5SThomas E. Spanjaard ata_raid_adaptec_print_meta(meta); 1607*c1b3d7c5SThomas E. Spanjaard 1608*c1b3d7c5SThomas E. Spanjaard /* now convert Adaptec metadata into our generic form */ 1609*c1b3d7c5SThomas E. Spanjaard for (array = 0; array < MAX_ARRAYS; array++) { 1610*c1b3d7c5SThomas E. Spanjaard if (!raidp[array]) { 1611*c1b3d7c5SThomas E. Spanjaard raidp[array] = 1612*c1b3d7c5SThomas E. Spanjaard (struct ar_softc *)malloc(sizeof(struct ar_softc), M_AR, 1613*c1b3d7c5SThomas E. Spanjaard M_NOWAIT | M_ZERO); 1614*c1b3d7c5SThomas E. Spanjaard if (!raidp[array]) { 1615*c1b3d7c5SThomas E. Spanjaard device_printf(parent, "failed to allocate metadata storage\n"); 1616*c1b3d7c5SThomas E. Spanjaard goto adaptec_out; 1617*c1b3d7c5SThomas E. Spanjaard } 1618*c1b3d7c5SThomas E. Spanjaard } 1619*c1b3d7c5SThomas E. Spanjaard raid = raidp[array]; 1620*c1b3d7c5SThomas E. Spanjaard if (raid->format && (raid->format != AR_F_ADAPTEC_RAID)) 1621*c1b3d7c5SThomas E. Spanjaard continue; 1622*c1b3d7c5SThomas E. Spanjaard 1623*c1b3d7c5SThomas E. Spanjaard if (raid->magic_0 && raid->magic_0 != meta->configs[0].magic_0) 1624*c1b3d7c5SThomas E. Spanjaard continue; 1625*c1b3d7c5SThomas E. Spanjaard 1626*c1b3d7c5SThomas E. Spanjaard if (!meta->generation || be32toh(meta->generation) > raid->generation) { 1627*c1b3d7c5SThomas E. Spanjaard switch (meta->configs[0].type) { 1628*c1b3d7c5SThomas E. Spanjaard case ADP_T_RAID0: 1629*c1b3d7c5SThomas E. Spanjaard raid->magic_0 = meta->configs[0].magic_0; 1630*c1b3d7c5SThomas E. Spanjaard raid->type = AR_T_RAID0; 1631*c1b3d7c5SThomas E. Spanjaard raid->interleave = 1 << (meta->configs[0].stripe_shift >> 1); 1632*c1b3d7c5SThomas E. Spanjaard raid->width = be16toh(meta->configs[0].total_disks); 1633*c1b3d7c5SThomas E. Spanjaard break; 1634*c1b3d7c5SThomas E. Spanjaard 1635*c1b3d7c5SThomas E. Spanjaard case ADP_T_RAID1: 1636*c1b3d7c5SThomas E. Spanjaard raid->magic_0 = meta->configs[0].magic_0; 1637*c1b3d7c5SThomas E. Spanjaard raid->type = AR_T_RAID1; 1638*c1b3d7c5SThomas E. Spanjaard raid->width = be16toh(meta->configs[0].total_disks) / 2; 1639*c1b3d7c5SThomas E. Spanjaard break; 1640*c1b3d7c5SThomas E. Spanjaard 1641*c1b3d7c5SThomas E. Spanjaard default: 1642*c1b3d7c5SThomas E. Spanjaard device_printf(parent, "Adaptec unknown RAID type 0x%02x\n", 1643*c1b3d7c5SThomas E. Spanjaard meta->configs[0].type); 1644*c1b3d7c5SThomas E. Spanjaard free(raidp[array], M_AR); 1645*c1b3d7c5SThomas E. Spanjaard raidp[array] = NULL; 1646*c1b3d7c5SThomas E. Spanjaard goto adaptec_out; 1647*c1b3d7c5SThomas E. Spanjaard } 1648*c1b3d7c5SThomas E. Spanjaard 1649*c1b3d7c5SThomas E. Spanjaard raid->format = AR_F_ADAPTEC_RAID; 1650*c1b3d7c5SThomas E. Spanjaard raid->generation = be32toh(meta->generation); 1651*c1b3d7c5SThomas E. Spanjaard raid->total_disks = be16toh(meta->configs[0].total_disks); 1652*c1b3d7c5SThomas E. Spanjaard raid->total_sectors = be32toh(meta->configs[0].sectors); 1653*c1b3d7c5SThomas E. Spanjaard raid->heads = 255; 1654*c1b3d7c5SThomas E. Spanjaard raid->sectors = 63; 1655*c1b3d7c5SThomas E. Spanjaard raid->cylinders = raid->total_sectors / (63 * 255); 1656*c1b3d7c5SThomas E. Spanjaard raid->offset_sectors = 0; 1657*c1b3d7c5SThomas E. Spanjaard raid->rebuild_lba = 0; 1658*c1b3d7c5SThomas E. Spanjaard raid->lun = array; 1659*c1b3d7c5SThomas E. Spanjaard strncpy(raid->name, meta->configs[0].name, 1660*c1b3d7c5SThomas E. Spanjaard min(sizeof(raid->name), sizeof(meta->configs[0].name))); 1661*c1b3d7c5SThomas E. Spanjaard 1662*c1b3d7c5SThomas E. Spanjaard /* clear out any old info */ 1663*c1b3d7c5SThomas E. Spanjaard if (raid->generation) { 1664*c1b3d7c5SThomas E. Spanjaard for (disk = 0; disk < raid->total_disks; disk++) { 1665*c1b3d7c5SThomas E. Spanjaard raid->disks[disk].dev = NULL; 1666*c1b3d7c5SThomas E. Spanjaard raid->disks[disk].flags = 0; 1667*c1b3d7c5SThomas E. Spanjaard } 1668*c1b3d7c5SThomas E. Spanjaard } 1669*c1b3d7c5SThomas E. Spanjaard } 1670*c1b3d7c5SThomas E. Spanjaard if (be32toh(meta->generation) >= raid->generation) { 1671*c1b3d7c5SThomas E. Spanjaard struct ata_device *atadev = device_get_softc(parent); 1672*c1b3d7c5SThomas E. Spanjaard struct ata_channel *ch = device_get_softc(GRANDPARENT(dev)); 1673*c1b3d7c5SThomas E. Spanjaard int disk_number = (ch->unit << !(ch->flags & ATA_NO_SLAVE)) + 1674*c1b3d7c5SThomas E. Spanjaard ATA_DEV(atadev->unit); 1675*c1b3d7c5SThomas E. Spanjaard 1676*c1b3d7c5SThomas E. Spanjaard raid->disks[disk_number].dev = parent; 1677*c1b3d7c5SThomas E. Spanjaard raid->disks[disk_number].sectors = 1678*c1b3d7c5SThomas E. Spanjaard be32toh(meta->configs[disk_number + 1].sectors); 1679*c1b3d7c5SThomas E. Spanjaard raid->disks[disk_number].flags = 1680*c1b3d7c5SThomas E. Spanjaard (AR_DF_ONLINE | AR_DF_PRESENT | AR_DF_ASSIGNED); 1681*c1b3d7c5SThomas E. Spanjaard ars->raid[raid->volume] = raid; 1682*c1b3d7c5SThomas E. Spanjaard ars->disk_number[raid->volume] = disk_number; 1683*c1b3d7c5SThomas E. Spanjaard retval = 1; 1684*c1b3d7c5SThomas E. Spanjaard } 1685*c1b3d7c5SThomas E. Spanjaard break; 1686*c1b3d7c5SThomas E. Spanjaard } 1687*c1b3d7c5SThomas E. Spanjaard 1688*c1b3d7c5SThomas E. Spanjaard adaptec_out: 1689*c1b3d7c5SThomas E. Spanjaard free(meta, M_AR); 1690*c1b3d7c5SThomas E. Spanjaard return retval; 1691*c1b3d7c5SThomas E. Spanjaard } 1692*c1b3d7c5SThomas E. Spanjaard 1693*c1b3d7c5SThomas E. Spanjaard /* Highpoint V2 RocketRAID Metadata */ 1694*c1b3d7c5SThomas E. Spanjaard static int 1695*c1b3d7c5SThomas E. Spanjaard ata_raid_hptv2_read_meta(device_t dev, struct ar_softc **raidp) 1696*c1b3d7c5SThomas E. Spanjaard { 1697*c1b3d7c5SThomas E. Spanjaard struct ata_raid_subdisk *ars = device_get_softc(dev); 1698*c1b3d7c5SThomas E. Spanjaard device_t parent = device_get_parent(dev); 1699*c1b3d7c5SThomas E. Spanjaard struct hptv2_raid_conf *meta; 1700*c1b3d7c5SThomas E. Spanjaard struct ar_softc *raid = NULL; 1701*c1b3d7c5SThomas E. Spanjaard int array, disk_number = 0, retval = 0; 1702*c1b3d7c5SThomas E. Spanjaard 1703*c1b3d7c5SThomas E. Spanjaard if (!(meta = (struct hptv2_raid_conf *) 1704*c1b3d7c5SThomas E. Spanjaard malloc(sizeof(struct hptv2_raid_conf), M_AR, M_NOWAIT | M_ZERO))) 1705*c1b3d7c5SThomas E. Spanjaard return ENOMEM; 1706*c1b3d7c5SThomas E. Spanjaard 1707*c1b3d7c5SThomas E. Spanjaard if (ata_raid_rw(parent, HPTV2_LBA(parent), 1708*c1b3d7c5SThomas E. Spanjaard meta, sizeof(struct hptv2_raid_conf), ATA_R_READ)) { 1709*c1b3d7c5SThomas E. Spanjaard if (testing || bootverbose) 1710*c1b3d7c5SThomas E. Spanjaard device_printf(parent, "HighPoint (v2) read metadata failed\n"); 1711*c1b3d7c5SThomas E. Spanjaard goto hptv2_out; 1712*c1b3d7c5SThomas E. Spanjaard } 1713*c1b3d7c5SThomas E. Spanjaard 1714*c1b3d7c5SThomas E. Spanjaard /* check if this is a HighPoint v2 RAID struct */ 1715*c1b3d7c5SThomas E. Spanjaard if (meta->magic != HPTV2_MAGIC_OK && meta->magic != HPTV2_MAGIC_BAD) { 1716*c1b3d7c5SThomas E. Spanjaard if (testing || bootverbose) 1717*c1b3d7c5SThomas E. Spanjaard device_printf(parent, "HighPoint (v2) check1 failed\n"); 1718*c1b3d7c5SThomas E. Spanjaard goto hptv2_out; 1719*c1b3d7c5SThomas E. Spanjaard } 1720*c1b3d7c5SThomas E. Spanjaard 1721*c1b3d7c5SThomas E. Spanjaard /* is this disk defined, or an old leftover/spare ? */ 1722*c1b3d7c5SThomas E. Spanjaard if (!meta->magic_0) { 1723*c1b3d7c5SThomas E. Spanjaard if (testing || bootverbose) 1724*c1b3d7c5SThomas E. Spanjaard device_printf(parent, "HighPoint (v2) check2 failed\n"); 1725*c1b3d7c5SThomas E. Spanjaard goto hptv2_out; 1726*c1b3d7c5SThomas E. Spanjaard } 1727*c1b3d7c5SThomas E. Spanjaard 1728*c1b3d7c5SThomas E. Spanjaard if (testing || bootverbose) 1729*c1b3d7c5SThomas E. Spanjaard ata_raid_hptv2_print_meta(meta); 1730*c1b3d7c5SThomas E. Spanjaard 1731*c1b3d7c5SThomas E. Spanjaard /* now convert HighPoint (v2) metadata into our generic form */ 1732*c1b3d7c5SThomas E. Spanjaard for (array = 0; array < MAX_ARRAYS; array++) { 1733*c1b3d7c5SThomas E. Spanjaard if (!raidp[array]) { 1734*c1b3d7c5SThomas E. Spanjaard raidp[array] = 1735*c1b3d7c5SThomas E. Spanjaard (struct ar_softc *)malloc(sizeof(struct ar_softc), M_AR, 1736*c1b3d7c5SThomas E. Spanjaard M_NOWAIT | M_ZERO); 1737*c1b3d7c5SThomas E. Spanjaard if (!raidp[array]) { 1738*c1b3d7c5SThomas E. Spanjaard device_printf(parent, "failed to allocate metadata storage\n"); 1739*c1b3d7c5SThomas E. Spanjaard goto hptv2_out; 1740*c1b3d7c5SThomas E. Spanjaard } 1741*c1b3d7c5SThomas E. Spanjaard } 1742*c1b3d7c5SThomas E. Spanjaard raid = raidp[array]; 1743*c1b3d7c5SThomas E. Spanjaard if (raid->format && (raid->format != AR_F_HPTV2_RAID)) 1744*c1b3d7c5SThomas E. Spanjaard continue; 1745*c1b3d7c5SThomas E. Spanjaard 1746*c1b3d7c5SThomas E. Spanjaard switch (meta->type) { 1747*c1b3d7c5SThomas E. Spanjaard case HPTV2_T_RAID0: 1748*c1b3d7c5SThomas E. Spanjaard if ((meta->order & (HPTV2_O_RAID0|HPTV2_O_OK)) == 1749*c1b3d7c5SThomas E. Spanjaard (HPTV2_O_RAID0|HPTV2_O_OK)) 1750*c1b3d7c5SThomas E. Spanjaard goto highpoint_raid1; 1751*c1b3d7c5SThomas E. Spanjaard if (meta->order & (HPTV2_O_RAID0 | HPTV2_O_RAID1)) 1752*c1b3d7c5SThomas E. Spanjaard goto highpoint_raid01; 1753*c1b3d7c5SThomas E. Spanjaard if (raid->magic_0 && raid->magic_0 != meta->magic_0) 1754*c1b3d7c5SThomas E. Spanjaard continue; 1755*c1b3d7c5SThomas E. Spanjaard raid->magic_0 = meta->magic_0; 1756*c1b3d7c5SThomas E. Spanjaard raid->type = AR_T_RAID0; 1757*c1b3d7c5SThomas E. Spanjaard raid->interleave = 1 << meta->stripe_shift; 1758*c1b3d7c5SThomas E. Spanjaard disk_number = meta->disk_number; 1759*c1b3d7c5SThomas E. Spanjaard if (!(meta->order & HPTV2_O_OK)) 1760*c1b3d7c5SThomas E. Spanjaard meta->magic = 0; /* mark bad */ 1761*c1b3d7c5SThomas E. Spanjaard break; 1762*c1b3d7c5SThomas E. Spanjaard 1763*c1b3d7c5SThomas E. Spanjaard case HPTV2_T_RAID1: 1764*c1b3d7c5SThomas E. Spanjaard highpoint_raid1: 1765*c1b3d7c5SThomas E. Spanjaard if (raid->magic_0 && raid->magic_0 != meta->magic_0) 1766*c1b3d7c5SThomas E. Spanjaard continue; 1767*c1b3d7c5SThomas E. Spanjaard raid->magic_0 = meta->magic_0; 1768*c1b3d7c5SThomas E. Spanjaard raid->type = AR_T_RAID1; 1769*c1b3d7c5SThomas E. Spanjaard disk_number = (meta->disk_number > 0); 1770*c1b3d7c5SThomas E. Spanjaard break; 1771*c1b3d7c5SThomas E. Spanjaard 1772*c1b3d7c5SThomas E. Spanjaard case HPTV2_T_RAID01_RAID0: 1773*c1b3d7c5SThomas E. Spanjaard highpoint_raid01: 1774*c1b3d7c5SThomas E. Spanjaard if (meta->order & HPTV2_O_RAID0) { 1775*c1b3d7c5SThomas E. Spanjaard if ((raid->magic_0 && raid->magic_0 != meta->magic_0) || 1776*c1b3d7c5SThomas E. Spanjaard (raid->magic_1 && raid->magic_1 != meta->magic_1)) 1777*c1b3d7c5SThomas E. Spanjaard continue; 1778*c1b3d7c5SThomas E. Spanjaard raid->magic_0 = meta->magic_0; 1779*c1b3d7c5SThomas E. Spanjaard raid->magic_1 = meta->magic_1; 1780*c1b3d7c5SThomas E. Spanjaard raid->type = AR_T_RAID01; 1781*c1b3d7c5SThomas E. Spanjaard raid->interleave = 1 << meta->stripe_shift; 1782*c1b3d7c5SThomas E. Spanjaard disk_number = meta->disk_number; 1783*c1b3d7c5SThomas E. Spanjaard } 1784*c1b3d7c5SThomas E. Spanjaard else { 1785*c1b3d7c5SThomas E. Spanjaard if (raid->magic_1 && raid->magic_1 != meta->magic_1) 1786*c1b3d7c5SThomas E. Spanjaard continue; 1787*c1b3d7c5SThomas E. Spanjaard raid->magic_1 = meta->magic_1; 1788*c1b3d7c5SThomas E. Spanjaard raid->type = AR_T_RAID01; 1789*c1b3d7c5SThomas E. Spanjaard raid->interleave = 1 << meta->stripe_shift; 1790*c1b3d7c5SThomas E. Spanjaard disk_number = meta->disk_number + meta->array_width; 1791*c1b3d7c5SThomas E. Spanjaard if (!(meta->order & HPTV2_O_RAID1)) 1792*c1b3d7c5SThomas E. Spanjaard meta->magic = 0; /* mark bad */ 1793*c1b3d7c5SThomas E. Spanjaard } 1794*c1b3d7c5SThomas E. Spanjaard break; 1795*c1b3d7c5SThomas E. Spanjaard 1796*c1b3d7c5SThomas E. Spanjaard case HPTV2_T_SPAN: 1797*c1b3d7c5SThomas E. Spanjaard if (raid->magic_0 && raid->magic_0 != meta->magic_0) 1798*c1b3d7c5SThomas E. Spanjaard continue; 1799*c1b3d7c5SThomas E. Spanjaard raid->magic_0 = meta->magic_0; 1800*c1b3d7c5SThomas E. Spanjaard raid->type = AR_T_SPAN; 1801*c1b3d7c5SThomas E. Spanjaard disk_number = meta->disk_number; 1802*c1b3d7c5SThomas E. Spanjaard break; 1803*c1b3d7c5SThomas E. Spanjaard 1804*c1b3d7c5SThomas E. Spanjaard default: 1805*c1b3d7c5SThomas E. Spanjaard device_printf(parent, "Highpoint (v2) unknown RAID type 0x%02x\n", 1806*c1b3d7c5SThomas E. Spanjaard meta->type); 1807*c1b3d7c5SThomas E. Spanjaard free(raidp[array], M_AR); 1808*c1b3d7c5SThomas E. Spanjaard raidp[array] = NULL; 1809*c1b3d7c5SThomas E. Spanjaard goto hptv2_out; 1810*c1b3d7c5SThomas E. Spanjaard } 1811*c1b3d7c5SThomas E. Spanjaard 1812*c1b3d7c5SThomas E. Spanjaard raid->format |= AR_F_HPTV2_RAID; 1813*c1b3d7c5SThomas E. Spanjaard raid->disks[disk_number].dev = parent; 1814*c1b3d7c5SThomas E. Spanjaard raid->disks[disk_number].flags = (AR_DF_PRESENT | AR_DF_ASSIGNED); 1815*c1b3d7c5SThomas E. Spanjaard raid->lun = array; 1816*c1b3d7c5SThomas E. Spanjaard strncpy(raid->name, meta->name_1, 1817*c1b3d7c5SThomas E. Spanjaard min(sizeof(raid->name), sizeof(meta->name_1))); 1818*c1b3d7c5SThomas E. Spanjaard if (meta->magic == HPTV2_MAGIC_OK) { 1819*c1b3d7c5SThomas E. Spanjaard raid->disks[disk_number].flags |= AR_DF_ONLINE; 1820*c1b3d7c5SThomas E. Spanjaard raid->width = meta->array_width; 1821*c1b3d7c5SThomas E. Spanjaard raid->total_sectors = meta->total_sectors; 1822*c1b3d7c5SThomas E. Spanjaard raid->heads = 255; 1823*c1b3d7c5SThomas E. Spanjaard raid->sectors = 63; 1824*c1b3d7c5SThomas E. Spanjaard raid->cylinders = raid->total_sectors / (63 * 255); 1825*c1b3d7c5SThomas E. Spanjaard raid->offset_sectors = HPTV2_LBA(parent) + 1; 1826*c1b3d7c5SThomas E. Spanjaard raid->rebuild_lba = meta->rebuild_lba; 1827*c1b3d7c5SThomas E. Spanjaard raid->disks[disk_number].sectors = 1828*c1b3d7c5SThomas E. Spanjaard raid->total_sectors / raid->width; 1829*c1b3d7c5SThomas E. Spanjaard } 1830*c1b3d7c5SThomas E. Spanjaard else 1831*c1b3d7c5SThomas E. Spanjaard raid->disks[disk_number].flags &= ~AR_DF_ONLINE; 1832*c1b3d7c5SThomas E. Spanjaard 1833*c1b3d7c5SThomas E. Spanjaard if ((raid->type & AR_T_RAID0) && (raid->total_disks < raid->width)) 1834*c1b3d7c5SThomas E. Spanjaard raid->total_disks = raid->width; 1835*c1b3d7c5SThomas E. Spanjaard if (disk_number >= raid->total_disks) 1836*c1b3d7c5SThomas E. Spanjaard raid->total_disks = disk_number + 1; 1837*c1b3d7c5SThomas E. Spanjaard ars->raid[raid->volume] = raid; 1838*c1b3d7c5SThomas E. Spanjaard ars->disk_number[raid->volume] = disk_number; 1839*c1b3d7c5SThomas E. Spanjaard retval = 1; 1840*c1b3d7c5SThomas E. Spanjaard break; 1841*c1b3d7c5SThomas E. Spanjaard } 1842*c1b3d7c5SThomas E. Spanjaard 1843*c1b3d7c5SThomas E. Spanjaard hptv2_out: 1844*c1b3d7c5SThomas E. Spanjaard free(meta, M_AR); 1845*c1b3d7c5SThomas E. Spanjaard return retval; 1846*c1b3d7c5SThomas E. Spanjaard } 1847*c1b3d7c5SThomas E. Spanjaard 1848*c1b3d7c5SThomas E. Spanjaard static int 1849*c1b3d7c5SThomas E. Spanjaard ata_raid_hptv2_write_meta(struct ar_softc *rdp) 1850*c1b3d7c5SThomas E. Spanjaard { 1851*c1b3d7c5SThomas E. Spanjaard struct hptv2_raid_conf *meta; 1852*c1b3d7c5SThomas E. Spanjaard struct timeval timestamp; 1853*c1b3d7c5SThomas E. Spanjaard int disk, error = 0; 1854*c1b3d7c5SThomas E. Spanjaard 1855*c1b3d7c5SThomas E. Spanjaard if (!(meta = (struct hptv2_raid_conf *) 1856*c1b3d7c5SThomas E. Spanjaard malloc(sizeof(struct hptv2_raid_conf), M_AR, M_NOWAIT | M_ZERO))) { 1857*c1b3d7c5SThomas E. Spanjaard printf("ar%d: failed to allocate metadata storage\n", rdp->lun); 1858*c1b3d7c5SThomas E. Spanjaard return ENOMEM; 1859*c1b3d7c5SThomas E. Spanjaard } 1860*c1b3d7c5SThomas E. Spanjaard 1861*c1b3d7c5SThomas E. Spanjaard microtime(×tamp); 1862*c1b3d7c5SThomas E. Spanjaard rdp->magic_0 = timestamp.tv_sec + 2; 1863*c1b3d7c5SThomas E. Spanjaard rdp->magic_1 = timestamp.tv_sec; 1864*c1b3d7c5SThomas E. Spanjaard 1865*c1b3d7c5SThomas E. Spanjaard for (disk = 0; disk < rdp->total_disks; disk++) { 1866*c1b3d7c5SThomas E. Spanjaard if ((rdp->disks[disk].flags & (AR_DF_PRESENT | AR_DF_ONLINE)) == 1867*c1b3d7c5SThomas E. Spanjaard (AR_DF_PRESENT | AR_DF_ONLINE)) 1868*c1b3d7c5SThomas E. Spanjaard meta->magic = HPTV2_MAGIC_OK; 1869*c1b3d7c5SThomas E. Spanjaard if (rdp->disks[disk].flags & AR_DF_ASSIGNED) { 1870*c1b3d7c5SThomas E. Spanjaard meta->magic_0 = rdp->magic_0; 1871*c1b3d7c5SThomas E. Spanjaard if (strlen(rdp->name)) 1872*c1b3d7c5SThomas E. Spanjaard strncpy(meta->name_1, rdp->name, sizeof(meta->name_1)); 1873*c1b3d7c5SThomas E. Spanjaard else 1874*c1b3d7c5SThomas E. Spanjaard strcpy(meta->name_1, "FreeBSD"); 1875*c1b3d7c5SThomas E. Spanjaard } 1876*c1b3d7c5SThomas E. Spanjaard meta->disk_number = disk; 1877*c1b3d7c5SThomas E. Spanjaard 1878*c1b3d7c5SThomas E. Spanjaard switch (rdp->type) { 1879*c1b3d7c5SThomas E. Spanjaard case AR_T_RAID0: 1880*c1b3d7c5SThomas E. Spanjaard meta->type = HPTV2_T_RAID0; 1881*c1b3d7c5SThomas E. Spanjaard strcpy(meta->name_2, "RAID 0"); 1882*c1b3d7c5SThomas E. Spanjaard if (rdp->disks[disk].flags & AR_DF_ONLINE) 1883*c1b3d7c5SThomas E. Spanjaard meta->order = HPTV2_O_OK; 1884*c1b3d7c5SThomas E. Spanjaard break; 1885*c1b3d7c5SThomas E. Spanjaard 1886*c1b3d7c5SThomas E. Spanjaard case AR_T_RAID1: 1887*c1b3d7c5SThomas E. Spanjaard meta->type = HPTV2_T_RAID0; 1888*c1b3d7c5SThomas E. Spanjaard strcpy(meta->name_2, "RAID 1"); 1889*c1b3d7c5SThomas E. Spanjaard meta->disk_number = (disk < rdp->width) ? disk : disk + 5; 1890*c1b3d7c5SThomas E. Spanjaard meta->order = HPTV2_O_RAID0 | HPTV2_O_OK; 1891*c1b3d7c5SThomas E. Spanjaard break; 1892*c1b3d7c5SThomas E. Spanjaard 1893*c1b3d7c5SThomas E. Spanjaard case AR_T_RAID01: 1894*c1b3d7c5SThomas E. Spanjaard meta->type = HPTV2_T_RAID01_RAID0; 1895*c1b3d7c5SThomas E. Spanjaard strcpy(meta->name_2, "RAID 0+1"); 1896*c1b3d7c5SThomas E. Spanjaard if (rdp->disks[disk].flags & AR_DF_ONLINE) { 1897*c1b3d7c5SThomas E. Spanjaard if (disk < rdp->width) { 1898*c1b3d7c5SThomas E. Spanjaard meta->order = (HPTV2_O_RAID0 | HPTV2_O_RAID1); 1899*c1b3d7c5SThomas E. Spanjaard meta->magic_0 = rdp->magic_0 - 1; 1900*c1b3d7c5SThomas E. Spanjaard } 1901*c1b3d7c5SThomas E. Spanjaard else { 1902*c1b3d7c5SThomas E. Spanjaard meta->order = HPTV2_O_RAID1; 1903*c1b3d7c5SThomas E. Spanjaard meta->disk_number -= rdp->width; 1904*c1b3d7c5SThomas E. Spanjaard } 1905*c1b3d7c5SThomas E. Spanjaard } 1906*c1b3d7c5SThomas E. Spanjaard else 1907*c1b3d7c5SThomas E. Spanjaard meta->magic_0 = rdp->magic_0 - 1; 1908*c1b3d7c5SThomas E. Spanjaard meta->magic_1 = rdp->magic_1; 1909*c1b3d7c5SThomas E. Spanjaard break; 1910*c1b3d7c5SThomas E. Spanjaard 1911*c1b3d7c5SThomas E. Spanjaard case AR_T_SPAN: 1912*c1b3d7c5SThomas E. Spanjaard meta->type = HPTV2_T_SPAN; 1913*c1b3d7c5SThomas E. Spanjaard strcpy(meta->name_2, "SPAN"); 1914*c1b3d7c5SThomas E. Spanjaard break; 1915*c1b3d7c5SThomas E. Spanjaard default: 1916*c1b3d7c5SThomas E. Spanjaard free(meta, M_AR); 1917*c1b3d7c5SThomas E. Spanjaard return ENODEV; 1918*c1b3d7c5SThomas E. Spanjaard } 1919*c1b3d7c5SThomas E. Spanjaard 1920*c1b3d7c5SThomas E. Spanjaard meta->array_width = rdp->width; 1921*c1b3d7c5SThomas E. Spanjaard meta->stripe_shift = (rdp->width > 1) ? (ffs(rdp->interleave)-1) : 0; 1922*c1b3d7c5SThomas E. Spanjaard meta->total_sectors = rdp->total_sectors; 1923*c1b3d7c5SThomas E. Spanjaard meta->rebuild_lba = rdp->rebuild_lba; 1924*c1b3d7c5SThomas E. Spanjaard if (testing || bootverbose) 1925*c1b3d7c5SThomas E. Spanjaard ata_raid_hptv2_print_meta(meta); 1926*c1b3d7c5SThomas E. Spanjaard if (rdp->disks[disk].dev) { 1927*c1b3d7c5SThomas E. Spanjaard if (ata_raid_rw(rdp->disks[disk].dev, 1928*c1b3d7c5SThomas E. Spanjaard HPTV2_LBA(rdp->disks[disk].dev), meta, 1929*c1b3d7c5SThomas E. Spanjaard sizeof(struct promise_raid_conf), 1930*c1b3d7c5SThomas E. Spanjaard ATA_R_WRITE | ATA_R_DIRECT)) { 1931*c1b3d7c5SThomas E. Spanjaard device_printf(rdp->disks[disk].dev, "write metadata failed\n"); 1932*c1b3d7c5SThomas E. Spanjaard error = EIO; 1933*c1b3d7c5SThomas E. Spanjaard } 1934*c1b3d7c5SThomas E. Spanjaard } 1935*c1b3d7c5SThomas E. Spanjaard } 1936*c1b3d7c5SThomas E. Spanjaard free(meta, M_AR); 1937*c1b3d7c5SThomas E. Spanjaard return error; 1938*c1b3d7c5SThomas E. Spanjaard } 1939*c1b3d7c5SThomas E. Spanjaard 1940*c1b3d7c5SThomas E. Spanjaard /* Highpoint V3 RocketRAID Metadata */ 1941*c1b3d7c5SThomas E. Spanjaard static int 1942*c1b3d7c5SThomas E. Spanjaard ata_raid_hptv3_read_meta(device_t dev, struct ar_softc **raidp) 1943*c1b3d7c5SThomas E. Spanjaard { 1944*c1b3d7c5SThomas E. Spanjaard struct ata_raid_subdisk *ars = device_get_softc(dev); 1945*c1b3d7c5SThomas E. Spanjaard device_t parent = device_get_parent(dev); 1946*c1b3d7c5SThomas E. Spanjaard struct hptv3_raid_conf *meta; 1947*c1b3d7c5SThomas E. Spanjaard struct ar_softc *raid = NULL; 1948*c1b3d7c5SThomas E. Spanjaard int array, disk_number, retval = 0; 1949*c1b3d7c5SThomas E. Spanjaard 1950*c1b3d7c5SThomas E. Spanjaard if (!(meta = (struct hptv3_raid_conf *) 1951*c1b3d7c5SThomas E. Spanjaard malloc(sizeof(struct hptv3_raid_conf), M_AR, M_NOWAIT | M_ZERO))) 1952*c1b3d7c5SThomas E. Spanjaard return ENOMEM; 1953*c1b3d7c5SThomas E. Spanjaard 1954*c1b3d7c5SThomas E. Spanjaard if (ata_raid_rw(parent, HPTV3_LBA(parent), 1955*c1b3d7c5SThomas E. Spanjaard meta, sizeof(struct hptv3_raid_conf), ATA_R_READ)) { 1956*c1b3d7c5SThomas E. Spanjaard if (testing || bootverbose) 1957*c1b3d7c5SThomas E. Spanjaard device_printf(parent, "HighPoint (v3) read metadata failed\n"); 1958*c1b3d7c5SThomas E. Spanjaard goto hptv3_out; 1959*c1b3d7c5SThomas E. Spanjaard } 1960*c1b3d7c5SThomas E. Spanjaard 1961*c1b3d7c5SThomas E. Spanjaard /* check if this is a HighPoint v3 RAID struct */ 1962*c1b3d7c5SThomas E. Spanjaard if (meta->magic != HPTV3_MAGIC) { 1963*c1b3d7c5SThomas E. Spanjaard if (testing || bootverbose) 1964*c1b3d7c5SThomas E. Spanjaard device_printf(parent, "HighPoint (v3) check1 failed\n"); 1965*c1b3d7c5SThomas E. Spanjaard goto hptv3_out; 1966*c1b3d7c5SThomas E. Spanjaard } 1967*c1b3d7c5SThomas E. Spanjaard 1968*c1b3d7c5SThomas E. Spanjaard /* check if there are any config_entries */ 1969*c1b3d7c5SThomas E. Spanjaard if (meta->config_entries < 1) { 1970*c1b3d7c5SThomas E. Spanjaard if (testing || bootverbose) 1971*c1b3d7c5SThomas E. Spanjaard device_printf(parent, "HighPoint (v3) check2 failed\n"); 1972*c1b3d7c5SThomas E. Spanjaard goto hptv3_out; 1973*c1b3d7c5SThomas E. Spanjaard } 1974*c1b3d7c5SThomas E. Spanjaard 1975*c1b3d7c5SThomas E. Spanjaard if (testing || bootverbose) 1976*c1b3d7c5SThomas E. Spanjaard ata_raid_hptv3_print_meta(meta); 1977*c1b3d7c5SThomas E. Spanjaard 1978*c1b3d7c5SThomas E. Spanjaard /* now convert HighPoint (v3) metadata into our generic form */ 1979*c1b3d7c5SThomas E. Spanjaard for (array = 0; array < MAX_ARRAYS; array++) { 1980*c1b3d7c5SThomas E. Spanjaard if (!raidp[array]) { 1981*c1b3d7c5SThomas E. Spanjaard raidp[array] = 1982*c1b3d7c5SThomas E. Spanjaard (struct ar_softc *)malloc(sizeof(struct ar_softc), M_AR, 1983*c1b3d7c5SThomas E. Spanjaard M_NOWAIT | M_ZERO); 1984*c1b3d7c5SThomas E. Spanjaard if (!raidp[array]) { 1985*c1b3d7c5SThomas E. Spanjaard device_printf(parent, "failed to allocate metadata storage\n"); 1986*c1b3d7c5SThomas E. Spanjaard goto hptv3_out; 1987*c1b3d7c5SThomas E. Spanjaard } 1988*c1b3d7c5SThomas E. Spanjaard } 1989*c1b3d7c5SThomas E. Spanjaard raid = raidp[array]; 1990*c1b3d7c5SThomas E. Spanjaard if (raid->format && (raid->format != AR_F_HPTV3_RAID)) 1991*c1b3d7c5SThomas E. Spanjaard continue; 1992*c1b3d7c5SThomas E. Spanjaard 1993*c1b3d7c5SThomas E. Spanjaard if ((raid->format & AR_F_HPTV3_RAID) && raid->magic_0 != meta->magic_0) 1994*c1b3d7c5SThomas E. Spanjaard continue; 1995*c1b3d7c5SThomas E. Spanjaard 1996*c1b3d7c5SThomas E. Spanjaard switch (meta->configs[0].type) { 1997*c1b3d7c5SThomas E. Spanjaard case HPTV3_T_RAID0: 1998*c1b3d7c5SThomas E. Spanjaard raid->type = AR_T_RAID0; 1999*c1b3d7c5SThomas E. Spanjaard raid->width = meta->configs[0].total_disks; 2000*c1b3d7c5SThomas E. Spanjaard disk_number = meta->configs[0].disk_number; 2001*c1b3d7c5SThomas E. Spanjaard break; 2002*c1b3d7c5SThomas E. Spanjaard 2003*c1b3d7c5SThomas E. Spanjaard case HPTV3_T_RAID1: 2004*c1b3d7c5SThomas E. Spanjaard raid->type = AR_T_RAID1; 2005*c1b3d7c5SThomas E. Spanjaard raid->width = meta->configs[0].total_disks / 2; 2006*c1b3d7c5SThomas E. Spanjaard disk_number = meta->configs[0].disk_number; 2007*c1b3d7c5SThomas E. Spanjaard break; 2008*c1b3d7c5SThomas E. Spanjaard 2009*c1b3d7c5SThomas E. Spanjaard case HPTV3_T_RAID5: 2010*c1b3d7c5SThomas E. Spanjaard raid->type = AR_T_RAID5; 2011*c1b3d7c5SThomas E. Spanjaard raid->width = meta->configs[0].total_disks; 2012*c1b3d7c5SThomas E. Spanjaard disk_number = meta->configs[0].disk_number; 2013*c1b3d7c5SThomas E. Spanjaard break; 2014*c1b3d7c5SThomas E. Spanjaard 2015*c1b3d7c5SThomas E. Spanjaard case HPTV3_T_SPAN: 2016*c1b3d7c5SThomas E. Spanjaard raid->type = AR_T_SPAN; 2017*c1b3d7c5SThomas E. Spanjaard raid->width = meta->configs[0].total_disks; 2018*c1b3d7c5SThomas E. Spanjaard disk_number = meta->configs[0].disk_number; 2019*c1b3d7c5SThomas E. Spanjaard break; 2020*c1b3d7c5SThomas E. Spanjaard 2021*c1b3d7c5SThomas E. Spanjaard default: 2022*c1b3d7c5SThomas E. Spanjaard device_printf(parent, "Highpoint (v3) unknown RAID type 0x%02x\n", 2023*c1b3d7c5SThomas E. Spanjaard meta->configs[0].type); 2024*c1b3d7c5SThomas E. Spanjaard free(raidp[array], M_AR); 2025*c1b3d7c5SThomas E. Spanjaard raidp[array] = NULL; 2026*c1b3d7c5SThomas E. Spanjaard goto hptv3_out; 2027*c1b3d7c5SThomas E. Spanjaard } 2028*c1b3d7c5SThomas E. Spanjaard if (meta->config_entries == 2) { 2029*c1b3d7c5SThomas E. Spanjaard switch (meta->configs[1].type) { 2030*c1b3d7c5SThomas E. Spanjaard case HPTV3_T_RAID1: 2031*c1b3d7c5SThomas E. Spanjaard if (raid->type == AR_T_RAID0) { 2032*c1b3d7c5SThomas E. Spanjaard raid->type = AR_T_RAID01; 2033*c1b3d7c5SThomas E. Spanjaard disk_number = meta->configs[1].disk_number + 2034*c1b3d7c5SThomas E. Spanjaard (meta->configs[0].disk_number << 1); 2035*c1b3d7c5SThomas E. Spanjaard break; 2036*c1b3d7c5SThomas E. Spanjaard } 2037*c1b3d7c5SThomas E. Spanjaard default: 2038*c1b3d7c5SThomas E. Spanjaard device_printf(parent, "Highpoint (v3) unknown level 2 0x%02x\n", 2039*c1b3d7c5SThomas E. Spanjaard meta->configs[1].type); 2040*c1b3d7c5SThomas E. Spanjaard free(raidp[array], M_AR); 2041*c1b3d7c5SThomas E. Spanjaard raidp[array] = NULL; 2042*c1b3d7c5SThomas E. Spanjaard goto hptv3_out; 2043*c1b3d7c5SThomas E. Spanjaard } 2044*c1b3d7c5SThomas E. Spanjaard } 2045*c1b3d7c5SThomas E. Spanjaard 2046*c1b3d7c5SThomas E. Spanjaard raid->magic_0 = meta->magic_0; 2047*c1b3d7c5SThomas E. Spanjaard raid->format = AR_F_HPTV3_RAID; 2048*c1b3d7c5SThomas E. Spanjaard raid->generation = meta->timestamp; 2049*c1b3d7c5SThomas E. Spanjaard raid->interleave = 1 << meta->configs[0].stripe_shift; 2050*c1b3d7c5SThomas E. Spanjaard raid->total_disks = meta->configs[0].total_disks + 2051*c1b3d7c5SThomas E. Spanjaard meta->configs[1].total_disks; 2052*c1b3d7c5SThomas E. Spanjaard raid->total_sectors = meta->configs[0].total_sectors + 2053*c1b3d7c5SThomas E. Spanjaard ((u_int64_t)meta->configs_high[0].total_sectors << 32); 2054*c1b3d7c5SThomas E. Spanjaard raid->heads = 255; 2055*c1b3d7c5SThomas E. Spanjaard raid->sectors = 63; 2056*c1b3d7c5SThomas E. Spanjaard raid->cylinders = raid->total_sectors / (63 * 255); 2057*c1b3d7c5SThomas E. Spanjaard raid->offset_sectors = 0; 2058*c1b3d7c5SThomas E. Spanjaard raid->rebuild_lba = meta->configs[0].rebuild_lba + 2059*c1b3d7c5SThomas E. Spanjaard ((u_int64_t)meta->configs_high[0].rebuild_lba << 32); 2060*c1b3d7c5SThomas E. Spanjaard raid->lun = array; 2061*c1b3d7c5SThomas E. Spanjaard strncpy(raid->name, meta->name, 2062*c1b3d7c5SThomas E. Spanjaard min(sizeof(raid->name), sizeof(meta->name))); 2063*c1b3d7c5SThomas E. Spanjaard raid->disks[disk_number].sectors = raid->total_sectors / 2064*c1b3d7c5SThomas E. Spanjaard (raid->type == AR_T_RAID5 ? raid->width - 1 : raid->width); 2065*c1b3d7c5SThomas E. Spanjaard raid->disks[disk_number].dev = parent; 2066*c1b3d7c5SThomas E. Spanjaard raid->disks[disk_number].flags = 2067*c1b3d7c5SThomas E. Spanjaard (AR_DF_PRESENT | AR_DF_ASSIGNED | AR_DF_ONLINE); 2068*c1b3d7c5SThomas E. Spanjaard ars->raid[raid->volume] = raid; 2069*c1b3d7c5SThomas E. Spanjaard ars->disk_number[raid->volume] = disk_number; 2070*c1b3d7c5SThomas E. Spanjaard retval = 1; 2071*c1b3d7c5SThomas E. Spanjaard break; 2072*c1b3d7c5SThomas E. Spanjaard } 2073*c1b3d7c5SThomas E. Spanjaard 2074*c1b3d7c5SThomas E. Spanjaard hptv3_out: 2075*c1b3d7c5SThomas E. Spanjaard free(meta, M_AR); 2076*c1b3d7c5SThomas E. Spanjaard return retval; 2077*c1b3d7c5SThomas E. Spanjaard } 2078*c1b3d7c5SThomas E. Spanjaard 2079*c1b3d7c5SThomas E. Spanjaard /* Intel MatrixRAID Metadata */ 2080*c1b3d7c5SThomas E. Spanjaard static int 2081*c1b3d7c5SThomas E. Spanjaard ata_raid_intel_read_meta(device_t dev, struct ar_softc **raidp) 2082*c1b3d7c5SThomas E. Spanjaard { 2083*c1b3d7c5SThomas E. Spanjaard struct ata_raid_subdisk *ars = device_get_softc(dev); 2084*c1b3d7c5SThomas E. Spanjaard device_t parent = device_get_parent(dev); 2085*c1b3d7c5SThomas E. Spanjaard struct intel_raid_conf *meta; 2086*c1b3d7c5SThomas E. Spanjaard struct intel_raid_mapping *map; 2087*c1b3d7c5SThomas E. Spanjaard struct ar_softc *raid = NULL; 2088*c1b3d7c5SThomas E. Spanjaard u_int32_t checksum, *ptr; 2089*c1b3d7c5SThomas E. Spanjaard int array, count, disk, volume = 1, retval = 0; 2090*c1b3d7c5SThomas E. Spanjaard char *tmp; 2091*c1b3d7c5SThomas E. Spanjaard 2092*c1b3d7c5SThomas E. Spanjaard if (!(meta = (struct intel_raid_conf *) 2093*c1b3d7c5SThomas E. Spanjaard malloc(1536, M_AR, M_NOWAIT | M_ZERO))) 2094*c1b3d7c5SThomas E. Spanjaard return ENOMEM; 2095*c1b3d7c5SThomas E. Spanjaard 2096*c1b3d7c5SThomas E. Spanjaard if (ata_raid_rw(parent, INTEL_LBA(parent), meta, 1024, ATA_R_READ)) { 2097*c1b3d7c5SThomas E. Spanjaard if (testing || bootverbose) 2098*c1b3d7c5SThomas E. Spanjaard device_printf(parent, "Intel read metadata failed\n"); 2099*c1b3d7c5SThomas E. Spanjaard goto intel_out; 2100*c1b3d7c5SThomas E. Spanjaard } 2101*c1b3d7c5SThomas E. Spanjaard tmp = (char *)meta; 2102*c1b3d7c5SThomas E. Spanjaard bcopy(tmp, tmp+1024, 512); 2103*c1b3d7c5SThomas E. Spanjaard bcopy(tmp+512, tmp, 1024); 2104*c1b3d7c5SThomas E. Spanjaard bzero(tmp+1024, 512); 2105*c1b3d7c5SThomas E. Spanjaard 2106*c1b3d7c5SThomas E. Spanjaard /* check if this is a Intel RAID struct */ 2107*c1b3d7c5SThomas E. Spanjaard if (strncmp(meta->intel_id, INTEL_MAGIC, strlen(INTEL_MAGIC))) { 2108*c1b3d7c5SThomas E. Spanjaard if (testing || bootverbose) 2109*c1b3d7c5SThomas E. Spanjaard device_printf(parent, "Intel check1 failed\n"); 2110*c1b3d7c5SThomas E. Spanjaard goto intel_out; 2111*c1b3d7c5SThomas E. Spanjaard } 2112*c1b3d7c5SThomas E. Spanjaard 2113*c1b3d7c5SThomas E. Spanjaard for (checksum = 0, ptr = (u_int32_t *)meta, count = 0; 2114*c1b3d7c5SThomas E. Spanjaard count < (meta->config_size / sizeof(u_int32_t)); count++) { 2115*c1b3d7c5SThomas E. Spanjaard checksum += *ptr++; 2116*c1b3d7c5SThomas E. Spanjaard } 2117*c1b3d7c5SThomas E. Spanjaard checksum -= meta->checksum; 2118*c1b3d7c5SThomas E. Spanjaard if (checksum != meta->checksum) { 2119*c1b3d7c5SThomas E. Spanjaard if (testing || bootverbose) 2120*c1b3d7c5SThomas E. Spanjaard device_printf(parent, "Intel check2 failed\n"); 2121*c1b3d7c5SThomas E. Spanjaard goto intel_out; 2122*c1b3d7c5SThomas E. Spanjaard } 2123*c1b3d7c5SThomas E. Spanjaard 2124*c1b3d7c5SThomas E. Spanjaard if (testing || bootverbose) 2125*c1b3d7c5SThomas E. Spanjaard ata_raid_intel_print_meta(meta); 2126*c1b3d7c5SThomas E. Spanjaard 2127*c1b3d7c5SThomas E. Spanjaard map = (struct intel_raid_mapping *)&meta->disk[meta->total_disks]; 2128*c1b3d7c5SThomas E. Spanjaard 2129*c1b3d7c5SThomas E. Spanjaard /* now convert Intel metadata into our generic form */ 2130*c1b3d7c5SThomas E. Spanjaard for (array = 0; array < MAX_ARRAYS; array++) { 2131*c1b3d7c5SThomas E. Spanjaard if (!raidp[array]) { 2132*c1b3d7c5SThomas E. Spanjaard raidp[array] = 2133*c1b3d7c5SThomas E. Spanjaard (struct ar_softc *)malloc(sizeof(struct ar_softc), M_AR, 2134*c1b3d7c5SThomas E. Spanjaard M_NOWAIT | M_ZERO); 2135*c1b3d7c5SThomas E. Spanjaard if (!raidp[array]) { 2136*c1b3d7c5SThomas E. Spanjaard device_printf(parent, "failed to allocate metadata storage\n"); 2137*c1b3d7c5SThomas E. Spanjaard goto intel_out; 2138*c1b3d7c5SThomas E. Spanjaard } 2139*c1b3d7c5SThomas E. Spanjaard } 2140*c1b3d7c5SThomas E. Spanjaard raid = raidp[array]; 2141*c1b3d7c5SThomas E. Spanjaard if (raid->format && (raid->format != AR_F_INTEL_RAID)) 2142*c1b3d7c5SThomas E. Spanjaard continue; 2143*c1b3d7c5SThomas E. Spanjaard 2144*c1b3d7c5SThomas E. Spanjaard if ((raid->format & AR_F_INTEL_RAID) && 2145*c1b3d7c5SThomas E. Spanjaard (raid->magic_0 != meta->config_id)) 2146*c1b3d7c5SThomas E. Spanjaard continue; 2147*c1b3d7c5SThomas E. Spanjaard 2148*c1b3d7c5SThomas E. Spanjaard /* 2149*c1b3d7c5SThomas E. Spanjaard * update our knowledge about the array config based on generation 2150*c1b3d7c5SThomas E. Spanjaard * NOTE: there can be multiple volumes on a disk set 2151*c1b3d7c5SThomas E. Spanjaard */ 2152*c1b3d7c5SThomas E. Spanjaard if (!meta->generation || meta->generation > raid->generation) { 2153*c1b3d7c5SThomas E. Spanjaard switch (map->type) { 2154*c1b3d7c5SThomas E. Spanjaard case INTEL_T_RAID0: 2155*c1b3d7c5SThomas E. Spanjaard raid->type = AR_T_RAID0; 2156*c1b3d7c5SThomas E. Spanjaard raid->width = map->total_disks; 2157*c1b3d7c5SThomas E. Spanjaard break; 2158*c1b3d7c5SThomas E. Spanjaard 2159*c1b3d7c5SThomas E. Spanjaard case INTEL_T_RAID1: 2160*c1b3d7c5SThomas E. Spanjaard if (map->total_disks == 4) 2161*c1b3d7c5SThomas E. Spanjaard raid->type = AR_T_RAID01; 2162*c1b3d7c5SThomas E. Spanjaard else 2163*c1b3d7c5SThomas E. Spanjaard raid->type = AR_T_RAID1; 2164*c1b3d7c5SThomas E. Spanjaard raid->width = map->total_disks / 2; 2165*c1b3d7c5SThomas E. Spanjaard break; 2166*c1b3d7c5SThomas E. Spanjaard 2167*c1b3d7c5SThomas E. Spanjaard case INTEL_T_RAID5: 2168*c1b3d7c5SThomas E. Spanjaard raid->type = AR_T_RAID5; 2169*c1b3d7c5SThomas E. Spanjaard raid->width = map->total_disks; 2170*c1b3d7c5SThomas E. Spanjaard break; 2171*c1b3d7c5SThomas E. Spanjaard 2172*c1b3d7c5SThomas E. Spanjaard default: 2173*c1b3d7c5SThomas E. Spanjaard device_printf(parent, "Intel unknown RAID type 0x%02x\n", 2174*c1b3d7c5SThomas E. Spanjaard map->type); 2175*c1b3d7c5SThomas E. Spanjaard free(raidp[array], M_AR); 2176*c1b3d7c5SThomas E. Spanjaard raidp[array] = NULL; 2177*c1b3d7c5SThomas E. Spanjaard goto intel_out; 2178*c1b3d7c5SThomas E. Spanjaard } 2179*c1b3d7c5SThomas E. Spanjaard 2180*c1b3d7c5SThomas E. Spanjaard switch (map->status) { 2181*c1b3d7c5SThomas E. Spanjaard case INTEL_S_READY: 2182*c1b3d7c5SThomas E. Spanjaard raid->status = AR_S_READY; 2183*c1b3d7c5SThomas E. Spanjaard break; 2184*c1b3d7c5SThomas E. Spanjaard case INTEL_S_DEGRADED: 2185*c1b3d7c5SThomas E. Spanjaard raid->status |= AR_S_DEGRADED; 2186*c1b3d7c5SThomas E. Spanjaard break; 2187*c1b3d7c5SThomas E. Spanjaard case INTEL_S_DISABLED: 2188*c1b3d7c5SThomas E. Spanjaard case INTEL_S_FAILURE: 2189*c1b3d7c5SThomas E. Spanjaard raid->status = 0; 2190*c1b3d7c5SThomas E. Spanjaard } 2191*c1b3d7c5SThomas E. Spanjaard 2192*c1b3d7c5SThomas E. Spanjaard raid->magic_0 = meta->config_id; 2193*c1b3d7c5SThomas E. Spanjaard raid->format = AR_F_INTEL_RAID; 2194*c1b3d7c5SThomas E. Spanjaard raid->generation = meta->generation; 2195*c1b3d7c5SThomas E. Spanjaard raid->interleave = map->stripe_sectors; 2196*c1b3d7c5SThomas E. Spanjaard raid->total_disks = map->total_disks; 2197*c1b3d7c5SThomas E. Spanjaard raid->total_sectors = map->total_sectors; 2198*c1b3d7c5SThomas E. Spanjaard raid->heads = 255; 2199*c1b3d7c5SThomas E. Spanjaard raid->sectors = 63; 2200*c1b3d7c5SThomas E. Spanjaard raid->cylinders = raid->total_sectors / (63 * 255); 2201*c1b3d7c5SThomas E. Spanjaard raid->offset_sectors = map->offset; 2202*c1b3d7c5SThomas E. Spanjaard raid->rebuild_lba = 0; 2203*c1b3d7c5SThomas E. Spanjaard raid->lun = array; 2204*c1b3d7c5SThomas E. Spanjaard raid->volume = volume - 1; 2205*c1b3d7c5SThomas E. Spanjaard strncpy(raid->name, map->name, 2206*c1b3d7c5SThomas E. Spanjaard min(sizeof(raid->name), sizeof(map->name))); 2207*c1b3d7c5SThomas E. Spanjaard 2208*c1b3d7c5SThomas E. Spanjaard /* clear out any old info */ 2209*c1b3d7c5SThomas E. Spanjaard for (disk = 0; disk < raid->total_disks; disk++) { 2210*c1b3d7c5SThomas E. Spanjaard raid->disks[disk].dev = NULL; 2211*c1b3d7c5SThomas E. Spanjaard bcopy(meta->disk[map->disk_idx[disk]].serial, 2212*c1b3d7c5SThomas E. Spanjaard raid->disks[disk].serial, 2213*c1b3d7c5SThomas E. Spanjaard sizeof(raid->disks[disk].serial)); 2214*c1b3d7c5SThomas E. Spanjaard raid->disks[disk].sectors = 2215*c1b3d7c5SThomas E. Spanjaard meta->disk[map->disk_idx[disk]].sectors; 2216*c1b3d7c5SThomas E. Spanjaard raid->disks[disk].flags = 0; 2217*c1b3d7c5SThomas E. Spanjaard if (meta->disk[map->disk_idx[disk]].flags & INTEL_F_ONLINE) 2218*c1b3d7c5SThomas E. Spanjaard raid->disks[disk].flags |= AR_DF_ONLINE; 2219*c1b3d7c5SThomas E. Spanjaard if (meta->disk[map->disk_idx[disk]].flags & INTEL_F_ASSIGNED) 2220*c1b3d7c5SThomas E. Spanjaard raid->disks[disk].flags |= AR_DF_ASSIGNED; 2221*c1b3d7c5SThomas E. Spanjaard if (meta->disk[map->disk_idx[disk]].flags & INTEL_F_SPARE) { 2222*c1b3d7c5SThomas E. Spanjaard raid->disks[disk].flags &= ~(AR_DF_ONLINE | AR_DF_ASSIGNED); 2223*c1b3d7c5SThomas E. Spanjaard raid->disks[disk].flags |= AR_DF_SPARE; 2224*c1b3d7c5SThomas E. Spanjaard } 2225*c1b3d7c5SThomas E. Spanjaard if (meta->disk[map->disk_idx[disk]].flags & INTEL_F_DOWN) 2226*c1b3d7c5SThomas E. Spanjaard raid->disks[disk].flags &= ~AR_DF_ONLINE; 2227*c1b3d7c5SThomas E. Spanjaard } 2228*c1b3d7c5SThomas E. Spanjaard } 2229*c1b3d7c5SThomas E. Spanjaard if (meta->generation >= raid->generation) { 2230*c1b3d7c5SThomas E. Spanjaard for (disk = 0; disk < raid->total_disks; disk++) { 2231*c1b3d7c5SThomas E. Spanjaard struct ata_device *atadev = device_get_softc(parent); 2232*c1b3d7c5SThomas E. Spanjaard 2233*c1b3d7c5SThomas E. Spanjaard if (!strncmp(raid->disks[disk].serial, atadev->param.serial, 2234*c1b3d7c5SThomas E. Spanjaard sizeof(raid->disks[disk].serial))) { 2235*c1b3d7c5SThomas E. Spanjaard raid->disks[disk].dev = parent; 2236*c1b3d7c5SThomas E. Spanjaard raid->disks[disk].flags |= (AR_DF_PRESENT | AR_DF_ONLINE); 2237*c1b3d7c5SThomas E. Spanjaard ars->raid[raid->volume] = raid; 2238*c1b3d7c5SThomas E. Spanjaard ars->disk_number[raid->volume] = disk; 2239*c1b3d7c5SThomas E. Spanjaard retval = 1; 2240*c1b3d7c5SThomas E. Spanjaard } 2241*c1b3d7c5SThomas E. Spanjaard } 2242*c1b3d7c5SThomas E. Spanjaard } 2243*c1b3d7c5SThomas E. Spanjaard else 2244*c1b3d7c5SThomas E. Spanjaard goto intel_out; 2245*c1b3d7c5SThomas E. Spanjaard 2246*c1b3d7c5SThomas E. Spanjaard if (retval) { 2247*c1b3d7c5SThomas E. Spanjaard if (volume < meta->total_volumes) { 2248*c1b3d7c5SThomas E. Spanjaard map = (struct intel_raid_mapping *) 2249*c1b3d7c5SThomas E. Spanjaard &map->disk_idx[map->total_disks]; 2250*c1b3d7c5SThomas E. Spanjaard volume++; 2251*c1b3d7c5SThomas E. Spanjaard retval = 0; 2252*c1b3d7c5SThomas E. Spanjaard continue; 2253*c1b3d7c5SThomas E. Spanjaard } 2254*c1b3d7c5SThomas E. Spanjaard break; 2255*c1b3d7c5SThomas E. Spanjaard } 2256*c1b3d7c5SThomas E. Spanjaard else { 2257*c1b3d7c5SThomas E. Spanjaard free(raidp[array], M_AR); 2258*c1b3d7c5SThomas E. Spanjaard raidp[array] = NULL; 2259*c1b3d7c5SThomas E. Spanjaard if (volume == 2) 2260*c1b3d7c5SThomas E. Spanjaard retval = 1; 2261*c1b3d7c5SThomas E. Spanjaard } 2262*c1b3d7c5SThomas E. Spanjaard } 2263*c1b3d7c5SThomas E. Spanjaard 2264*c1b3d7c5SThomas E. Spanjaard intel_out: 2265*c1b3d7c5SThomas E. Spanjaard free(meta, M_AR); 2266*c1b3d7c5SThomas E. Spanjaard return retval; 2267*c1b3d7c5SThomas E. Spanjaard } 2268*c1b3d7c5SThomas E. Spanjaard 2269*c1b3d7c5SThomas E. Spanjaard static int 2270*c1b3d7c5SThomas E. Spanjaard ata_raid_intel_write_meta(struct ar_softc *rdp) 2271*c1b3d7c5SThomas E. Spanjaard { 2272*c1b3d7c5SThomas E. Spanjaard struct intel_raid_conf *meta; 2273*c1b3d7c5SThomas E. Spanjaard struct intel_raid_mapping *map; 2274*c1b3d7c5SThomas E. Spanjaard struct timeval timestamp; 2275*c1b3d7c5SThomas E. Spanjaard u_int32_t checksum, *ptr; 2276*c1b3d7c5SThomas E. Spanjaard int count, disk, error = 0; 2277*c1b3d7c5SThomas E. Spanjaard char *tmp; 2278*c1b3d7c5SThomas E. Spanjaard 2279*c1b3d7c5SThomas E. Spanjaard if (!(meta = (struct intel_raid_conf *) 2280*c1b3d7c5SThomas E. Spanjaard malloc(1536, M_AR, M_NOWAIT | M_ZERO))) { 2281*c1b3d7c5SThomas E. Spanjaard printf("ar%d: failed to allocate metadata storage\n", rdp->lun); 2282*c1b3d7c5SThomas E. Spanjaard return ENOMEM; 2283*c1b3d7c5SThomas E. Spanjaard } 2284*c1b3d7c5SThomas E. Spanjaard 2285*c1b3d7c5SThomas E. Spanjaard rdp->generation++; 2286*c1b3d7c5SThomas E. Spanjaard microtime(×tamp); 2287*c1b3d7c5SThomas E. Spanjaard 2288*c1b3d7c5SThomas E. Spanjaard bcopy(INTEL_MAGIC, meta->intel_id, sizeof(meta->intel_id)); 2289*c1b3d7c5SThomas E. Spanjaard bcopy(INTEL_VERSION_1100, meta->version, sizeof(meta->version)); 2290*c1b3d7c5SThomas E. Spanjaard meta->config_id = timestamp.tv_sec; 2291*c1b3d7c5SThomas E. Spanjaard meta->generation = rdp->generation; 2292*c1b3d7c5SThomas E. Spanjaard meta->total_disks = rdp->total_disks; 2293*c1b3d7c5SThomas E. Spanjaard meta->total_volumes = 1; /* XXX SOS */ 2294*c1b3d7c5SThomas E. Spanjaard for (disk = 0; disk < rdp->total_disks; disk++) { 2295*c1b3d7c5SThomas E. Spanjaard if (rdp->disks[disk].dev) { 2296*c1b3d7c5SThomas E. Spanjaard struct ata_channel *ch = 2297*c1b3d7c5SThomas E. Spanjaard device_get_softc(device_get_parent(rdp->disks[disk].dev)); 2298*c1b3d7c5SThomas E. Spanjaard struct ata_device *atadev = 2299*c1b3d7c5SThomas E. Spanjaard device_get_softc(rdp->disks[disk].dev); 2300*c1b3d7c5SThomas E. Spanjaard 2301*c1b3d7c5SThomas E. Spanjaard bcopy(atadev->param.serial, meta->disk[disk].serial, 2302*c1b3d7c5SThomas E. Spanjaard sizeof(rdp->disks[disk].serial)); 2303*c1b3d7c5SThomas E. Spanjaard meta->disk[disk].sectors = rdp->disks[disk].sectors; 2304*c1b3d7c5SThomas E. Spanjaard meta->disk[disk].id = (ch->unit << 16) | ATA_DEV(atadev->unit); 2305*c1b3d7c5SThomas E. Spanjaard } 2306*c1b3d7c5SThomas E. Spanjaard else 2307*c1b3d7c5SThomas E. Spanjaard meta->disk[disk].sectors = rdp->total_sectors / rdp->width; 2308*c1b3d7c5SThomas E. Spanjaard meta->disk[disk].flags = 0; 2309*c1b3d7c5SThomas E. Spanjaard if (rdp->disks[disk].flags & AR_DF_SPARE) 2310*c1b3d7c5SThomas E. Spanjaard meta->disk[disk].flags |= INTEL_F_SPARE; 2311*c1b3d7c5SThomas E. Spanjaard else { 2312*c1b3d7c5SThomas E. Spanjaard if (rdp->disks[disk].flags & AR_DF_ONLINE) 2313*c1b3d7c5SThomas E. Spanjaard meta->disk[disk].flags |= INTEL_F_ONLINE; 2314*c1b3d7c5SThomas E. Spanjaard else 2315*c1b3d7c5SThomas E. Spanjaard meta->disk[disk].flags |= INTEL_F_DOWN; 2316*c1b3d7c5SThomas E. Spanjaard if (rdp->disks[disk].flags & AR_DF_ASSIGNED) 2317*c1b3d7c5SThomas E. Spanjaard meta->disk[disk].flags |= INTEL_F_ASSIGNED; 2318*c1b3d7c5SThomas E. Spanjaard } 2319*c1b3d7c5SThomas E. Spanjaard } 2320*c1b3d7c5SThomas E. Spanjaard map = (struct intel_raid_mapping *)&meta->disk[meta->total_disks]; 2321*c1b3d7c5SThomas E. Spanjaard 2322*c1b3d7c5SThomas E. Spanjaard bcopy(rdp->name, map->name, sizeof(rdp->name)); 2323*c1b3d7c5SThomas E. Spanjaard map->total_sectors = rdp->total_sectors; 2324*c1b3d7c5SThomas E. Spanjaard map->state = 12; /* XXX SOS */ 2325*c1b3d7c5SThomas E. Spanjaard map->offset = rdp->offset_sectors; 2326*c1b3d7c5SThomas E. Spanjaard map->stripe_count = rdp->total_sectors / (rdp->interleave*rdp->total_disks); 2327*c1b3d7c5SThomas E. Spanjaard map->stripe_sectors = rdp->interleave; 2328*c1b3d7c5SThomas E. Spanjaard map->disk_sectors = rdp->total_sectors / rdp->width; 2329*c1b3d7c5SThomas E. Spanjaard map->status = INTEL_S_READY; /* XXX SOS */ 2330*c1b3d7c5SThomas E. Spanjaard switch (rdp->type) { 2331*c1b3d7c5SThomas E. Spanjaard case AR_T_RAID0: 2332*c1b3d7c5SThomas E. Spanjaard map->type = INTEL_T_RAID0; 2333*c1b3d7c5SThomas E. Spanjaard break; 2334*c1b3d7c5SThomas E. Spanjaard case AR_T_RAID1: 2335*c1b3d7c5SThomas E. Spanjaard map->type = INTEL_T_RAID1; 2336*c1b3d7c5SThomas E. Spanjaard break; 2337*c1b3d7c5SThomas E. Spanjaard case AR_T_RAID01: 2338*c1b3d7c5SThomas E. Spanjaard map->type = INTEL_T_RAID1; 2339*c1b3d7c5SThomas E. Spanjaard break; 2340*c1b3d7c5SThomas E. Spanjaard case AR_T_RAID5: 2341*c1b3d7c5SThomas E. Spanjaard map->type = INTEL_T_RAID5; 2342*c1b3d7c5SThomas E. Spanjaard break; 2343*c1b3d7c5SThomas E. Spanjaard default: 2344*c1b3d7c5SThomas E. Spanjaard free(meta, M_AR); 2345*c1b3d7c5SThomas E. Spanjaard return ENODEV; 2346*c1b3d7c5SThomas E. Spanjaard } 2347*c1b3d7c5SThomas E. Spanjaard map->total_disks = rdp->total_disks; 2348*c1b3d7c5SThomas E. Spanjaard map->magic[0] = 0x02; 2349*c1b3d7c5SThomas E. Spanjaard map->magic[1] = 0xff; 2350*c1b3d7c5SThomas E. Spanjaard map->magic[2] = 0x01; 2351*c1b3d7c5SThomas E. Spanjaard for (disk = 0; disk < rdp->total_disks; disk++) 2352*c1b3d7c5SThomas E. Spanjaard map->disk_idx[disk] = disk; 2353*c1b3d7c5SThomas E. Spanjaard 2354*c1b3d7c5SThomas E. Spanjaard meta->config_size = (char *)&map->disk_idx[disk] - (char *)meta; 2355*c1b3d7c5SThomas E. Spanjaard for (checksum = 0, ptr = (u_int32_t *)meta, count = 0; 2356*c1b3d7c5SThomas E. Spanjaard count < (meta->config_size / sizeof(u_int32_t)); count++) { 2357*c1b3d7c5SThomas E. Spanjaard checksum += *ptr++; 2358*c1b3d7c5SThomas E. Spanjaard } 2359*c1b3d7c5SThomas E. Spanjaard meta->checksum = checksum; 2360*c1b3d7c5SThomas E. Spanjaard 2361*c1b3d7c5SThomas E. Spanjaard if (testing || bootverbose) 2362*c1b3d7c5SThomas E. Spanjaard ata_raid_intel_print_meta(meta); 2363*c1b3d7c5SThomas E. Spanjaard 2364*c1b3d7c5SThomas E. Spanjaard tmp = (char *)meta; 2365*c1b3d7c5SThomas E. Spanjaard bcopy(tmp, tmp+1024, 512); 2366*c1b3d7c5SThomas E. Spanjaard bcopy(tmp+512, tmp, 1024); 2367*c1b3d7c5SThomas E. Spanjaard bzero(tmp+1024, 512); 2368*c1b3d7c5SThomas E. Spanjaard 2369*c1b3d7c5SThomas E. Spanjaard for (disk = 0; disk < rdp->total_disks; disk++) { 2370*c1b3d7c5SThomas E. Spanjaard if (rdp->disks[disk].dev) { 2371*c1b3d7c5SThomas E. Spanjaard if (ata_raid_rw(rdp->disks[disk].dev, 2372*c1b3d7c5SThomas E. Spanjaard INTEL_LBA(rdp->disks[disk].dev), 2373*c1b3d7c5SThomas E. Spanjaard meta, 1024, ATA_R_WRITE | ATA_R_DIRECT)) { 2374*c1b3d7c5SThomas E. Spanjaard device_printf(rdp->disks[disk].dev, "write metadata failed\n"); 2375*c1b3d7c5SThomas E. Spanjaard error = EIO; 2376*c1b3d7c5SThomas E. Spanjaard } 2377*c1b3d7c5SThomas E. Spanjaard } 2378*c1b3d7c5SThomas E. Spanjaard } 2379*c1b3d7c5SThomas E. Spanjaard free(meta, M_AR); 2380*c1b3d7c5SThomas E. Spanjaard return error; 2381*c1b3d7c5SThomas E. Spanjaard } 2382*c1b3d7c5SThomas E. Spanjaard 2383*c1b3d7c5SThomas E. Spanjaard 2384*c1b3d7c5SThomas E. Spanjaard /* Integrated Technology Express Metadata */ 2385*c1b3d7c5SThomas E. Spanjaard static int 2386*c1b3d7c5SThomas E. Spanjaard ata_raid_ite_read_meta(device_t dev, struct ar_softc **raidp) 2387*c1b3d7c5SThomas E. Spanjaard { 2388*c1b3d7c5SThomas E. Spanjaard struct ata_raid_subdisk *ars = device_get_softc(dev); 2389*c1b3d7c5SThomas E. Spanjaard device_t parent = device_get_parent(dev); 2390*c1b3d7c5SThomas E. Spanjaard struct ite_raid_conf *meta; 2391*c1b3d7c5SThomas E. Spanjaard struct ar_softc *raid = NULL; 2392*c1b3d7c5SThomas E. Spanjaard int array, disk_number, count, retval = 0; 2393*c1b3d7c5SThomas E. Spanjaard u_int16_t *ptr; 2394*c1b3d7c5SThomas E. Spanjaard 2395*c1b3d7c5SThomas E. Spanjaard if (!(meta = (struct ite_raid_conf *) 2396*c1b3d7c5SThomas E. Spanjaard malloc(sizeof(struct ite_raid_conf), M_AR, M_NOWAIT | M_ZERO))) 2397*c1b3d7c5SThomas E. Spanjaard return ENOMEM; 2398*c1b3d7c5SThomas E. Spanjaard 2399*c1b3d7c5SThomas E. Spanjaard if (ata_raid_rw(parent, ITE_LBA(parent), 2400*c1b3d7c5SThomas E. Spanjaard meta, sizeof(struct ite_raid_conf), ATA_R_READ)) { 2401*c1b3d7c5SThomas E. Spanjaard if (testing || bootverbose) 2402*c1b3d7c5SThomas E. Spanjaard device_printf(parent, "ITE read metadata failed\n"); 2403*c1b3d7c5SThomas E. Spanjaard goto ite_out; 2404*c1b3d7c5SThomas E. Spanjaard } 2405*c1b3d7c5SThomas E. Spanjaard 2406*c1b3d7c5SThomas E. Spanjaard /* check if this is a ITE RAID struct */ 2407*c1b3d7c5SThomas E. Spanjaard for (ptr = (u_int16_t *)meta->ite_id, count = 0; 2408*c1b3d7c5SThomas E. Spanjaard count < sizeof(meta->ite_id)/sizeof(uint16_t); count++) 2409*c1b3d7c5SThomas E. Spanjaard ptr[count] = be16toh(ptr[count]); 2410*c1b3d7c5SThomas E. Spanjaard 2411*c1b3d7c5SThomas E. Spanjaard if (strncmp(meta->ite_id, ITE_MAGIC, strlen(ITE_MAGIC))) { 2412*c1b3d7c5SThomas E. Spanjaard if (testing || bootverbose) 2413*c1b3d7c5SThomas E. Spanjaard device_printf(parent, "ITE check1 failed\n"); 2414*c1b3d7c5SThomas E. Spanjaard goto ite_out; 2415*c1b3d7c5SThomas E. Spanjaard } 2416*c1b3d7c5SThomas E. Spanjaard 2417*c1b3d7c5SThomas E. Spanjaard if (testing || bootverbose) 2418*c1b3d7c5SThomas E. Spanjaard ata_raid_ite_print_meta(meta); 2419*c1b3d7c5SThomas E. Spanjaard 2420*c1b3d7c5SThomas E. Spanjaard /* now convert ITE metadata into our generic form */ 2421*c1b3d7c5SThomas E. Spanjaard for (array = 0; array < MAX_ARRAYS; array++) { 2422*c1b3d7c5SThomas E. Spanjaard if ((raid = raidp[array])) { 2423*c1b3d7c5SThomas E. Spanjaard if (raid->format != AR_F_ITE_RAID) 2424*c1b3d7c5SThomas E. Spanjaard continue; 2425*c1b3d7c5SThomas E. Spanjaard if (raid->magic_0 != *((u_int64_t *)meta->timestamp_0)) 2426*c1b3d7c5SThomas E. Spanjaard continue; 2427*c1b3d7c5SThomas E. Spanjaard } 2428*c1b3d7c5SThomas E. Spanjaard 2429*c1b3d7c5SThomas E. Spanjaard /* if we dont have a disks timestamp the RAID is invalidated */ 2430*c1b3d7c5SThomas E. Spanjaard if (*((u_int64_t *)meta->timestamp_1) == 0) 2431*c1b3d7c5SThomas E. Spanjaard goto ite_out; 2432*c1b3d7c5SThomas E. Spanjaard 2433*c1b3d7c5SThomas E. Spanjaard if (!raid) { 2434*c1b3d7c5SThomas E. Spanjaard raidp[array] = (struct ar_softc *)malloc(sizeof(struct ar_softc), 2435*c1b3d7c5SThomas E. Spanjaard M_AR, M_NOWAIT | M_ZERO); 2436*c1b3d7c5SThomas E. Spanjaard if (!(raid = raidp[array])) { 2437*c1b3d7c5SThomas E. Spanjaard device_printf(parent, "failed to allocate metadata storage\n"); 2438*c1b3d7c5SThomas E. Spanjaard goto ite_out; 2439*c1b3d7c5SThomas E. Spanjaard } 2440*c1b3d7c5SThomas E. Spanjaard } 2441*c1b3d7c5SThomas E. Spanjaard 2442*c1b3d7c5SThomas E. Spanjaard switch (meta->type) { 2443*c1b3d7c5SThomas E. Spanjaard case ITE_T_RAID0: 2444*c1b3d7c5SThomas E. Spanjaard raid->type = AR_T_RAID0; 2445*c1b3d7c5SThomas E. Spanjaard raid->width = meta->array_width; 2446*c1b3d7c5SThomas E. Spanjaard raid->total_disks = meta->array_width; 2447*c1b3d7c5SThomas E. Spanjaard disk_number = meta->disk_number; 2448*c1b3d7c5SThomas E. Spanjaard break; 2449*c1b3d7c5SThomas E. Spanjaard 2450*c1b3d7c5SThomas E. Spanjaard case ITE_T_RAID1: 2451*c1b3d7c5SThomas E. Spanjaard raid->type = AR_T_RAID1; 2452*c1b3d7c5SThomas E. Spanjaard raid->width = 1; 2453*c1b3d7c5SThomas E. Spanjaard raid->total_disks = 2; 2454*c1b3d7c5SThomas E. Spanjaard disk_number = meta->disk_number; 2455*c1b3d7c5SThomas E. Spanjaard break; 2456*c1b3d7c5SThomas E. Spanjaard 2457*c1b3d7c5SThomas E. Spanjaard case ITE_T_RAID01: 2458*c1b3d7c5SThomas E. Spanjaard raid->type = AR_T_RAID01; 2459*c1b3d7c5SThomas E. Spanjaard raid->width = meta->array_width; 2460*c1b3d7c5SThomas E. Spanjaard raid->total_disks = 4; 2461*c1b3d7c5SThomas E. Spanjaard disk_number = ((meta->disk_number & 0x02) >> 1) | 2462*c1b3d7c5SThomas E. Spanjaard ((meta->disk_number & 0x01) << 1); 2463*c1b3d7c5SThomas E. Spanjaard break; 2464*c1b3d7c5SThomas E. Spanjaard 2465*c1b3d7c5SThomas E. Spanjaard case ITE_T_SPAN: 2466*c1b3d7c5SThomas E. Spanjaard raid->type = AR_T_SPAN; 2467*c1b3d7c5SThomas E. Spanjaard raid->width = 1; 2468*c1b3d7c5SThomas E. Spanjaard raid->total_disks = meta->array_width; 2469*c1b3d7c5SThomas E. Spanjaard disk_number = meta->disk_number; 2470*c1b3d7c5SThomas E. Spanjaard break; 2471*c1b3d7c5SThomas E. Spanjaard 2472*c1b3d7c5SThomas E. Spanjaard default: 2473*c1b3d7c5SThomas E. Spanjaard device_printf(parent, "ITE unknown RAID type 0x%02x\n", meta->type); 2474*c1b3d7c5SThomas E. Spanjaard free(raidp[array], M_AR); 2475*c1b3d7c5SThomas E. Spanjaard raidp[array] = NULL; 2476*c1b3d7c5SThomas E. Spanjaard goto ite_out; 2477*c1b3d7c5SThomas E. Spanjaard } 2478*c1b3d7c5SThomas E. Spanjaard 2479*c1b3d7c5SThomas E. Spanjaard raid->magic_0 = *((u_int64_t *)meta->timestamp_0); 2480*c1b3d7c5SThomas E. Spanjaard raid->format = AR_F_ITE_RAID; 2481*c1b3d7c5SThomas E. Spanjaard raid->generation = 0; 2482*c1b3d7c5SThomas E. Spanjaard raid->interleave = meta->stripe_sectors; 2483*c1b3d7c5SThomas E. Spanjaard raid->total_sectors = meta->total_sectors; 2484*c1b3d7c5SThomas E. Spanjaard raid->heads = 255; 2485*c1b3d7c5SThomas E. Spanjaard raid->sectors = 63; 2486*c1b3d7c5SThomas E. Spanjaard raid->cylinders = raid->total_sectors / (63 * 255); 2487*c1b3d7c5SThomas E. Spanjaard raid->offset_sectors = 0; 2488*c1b3d7c5SThomas E. Spanjaard raid->rebuild_lba = 0; 2489*c1b3d7c5SThomas E. Spanjaard raid->lun = array; 2490*c1b3d7c5SThomas E. Spanjaard 2491*c1b3d7c5SThomas E. Spanjaard raid->disks[disk_number].dev = parent; 2492*c1b3d7c5SThomas E. Spanjaard raid->disks[disk_number].sectors = raid->total_sectors / raid->width; 2493*c1b3d7c5SThomas E. Spanjaard raid->disks[disk_number].flags = 2494*c1b3d7c5SThomas E. Spanjaard (AR_DF_PRESENT | AR_DF_ASSIGNED | AR_DF_ONLINE); 2495*c1b3d7c5SThomas E. Spanjaard ars->raid[raid->volume] = raid; 2496*c1b3d7c5SThomas E. Spanjaard ars->disk_number[raid->volume] = disk_number; 2497*c1b3d7c5SThomas E. Spanjaard retval = 1; 2498*c1b3d7c5SThomas E. Spanjaard break; 2499*c1b3d7c5SThomas E. Spanjaard } 2500*c1b3d7c5SThomas E. Spanjaard ite_out: 2501*c1b3d7c5SThomas E. Spanjaard free(meta, M_AR); 2502*c1b3d7c5SThomas E. Spanjaard return retval; 2503*c1b3d7c5SThomas E. Spanjaard } 2504*c1b3d7c5SThomas E. Spanjaard 2505*c1b3d7c5SThomas E. Spanjaard /* JMicron Technology Corp Metadata */ 2506*c1b3d7c5SThomas E. Spanjaard static int 2507*c1b3d7c5SThomas E. Spanjaard ata_raid_jmicron_read_meta(device_t dev, struct ar_softc **raidp) 2508*c1b3d7c5SThomas E. Spanjaard { 2509*c1b3d7c5SThomas E. Spanjaard struct ata_raid_subdisk *ars = device_get_softc(dev); 2510*c1b3d7c5SThomas E. Spanjaard device_t parent = device_get_parent(dev); 2511*c1b3d7c5SThomas E. Spanjaard struct jmicron_raid_conf *meta; 2512*c1b3d7c5SThomas E. Spanjaard struct ar_softc *raid = NULL; 2513*c1b3d7c5SThomas E. Spanjaard u_int16_t checksum, *ptr; 2514*c1b3d7c5SThomas E. Spanjaard u_int64_t disk_size; 2515*c1b3d7c5SThomas E. Spanjaard int count, array, disk, total_disks, retval = 0; 2516*c1b3d7c5SThomas E. Spanjaard 2517*c1b3d7c5SThomas E. Spanjaard if (!(meta = (struct jmicron_raid_conf *) 2518*c1b3d7c5SThomas E. Spanjaard malloc(sizeof(struct jmicron_raid_conf), M_AR, M_NOWAIT | M_ZERO))) 2519*c1b3d7c5SThomas E. Spanjaard return ENOMEM; 2520*c1b3d7c5SThomas E. Spanjaard 2521*c1b3d7c5SThomas E. Spanjaard if (ata_raid_rw(parent, JMICRON_LBA(parent), 2522*c1b3d7c5SThomas E. Spanjaard meta, sizeof(struct jmicron_raid_conf), ATA_R_READ)) { 2523*c1b3d7c5SThomas E. Spanjaard if (testing || bootverbose) 2524*c1b3d7c5SThomas E. Spanjaard device_printf(parent, 2525*c1b3d7c5SThomas E. Spanjaard "JMicron read metadata failed\n"); 2526*c1b3d7c5SThomas E. Spanjaard } 2527*c1b3d7c5SThomas E. Spanjaard 2528*c1b3d7c5SThomas E. Spanjaard /* check for JMicron signature */ 2529*c1b3d7c5SThomas E. Spanjaard if (strncmp(meta->signature, JMICRON_MAGIC, 2)) { 2530*c1b3d7c5SThomas E. Spanjaard if (testing || bootverbose) 2531*c1b3d7c5SThomas E. Spanjaard device_printf(parent, "JMicron check1 failed\n"); 2532*c1b3d7c5SThomas E. Spanjaard goto jmicron_out; 2533*c1b3d7c5SThomas E. Spanjaard } 2534*c1b3d7c5SThomas E. Spanjaard 2535*c1b3d7c5SThomas E. Spanjaard /* calculate checksum and compare for valid */ 2536*c1b3d7c5SThomas E. Spanjaard for (checksum = 0, ptr = (u_int16_t *)meta, count = 0; count < 64; count++) 2537*c1b3d7c5SThomas E. Spanjaard checksum += *ptr++; 2538*c1b3d7c5SThomas E. Spanjaard if (checksum) { 2539*c1b3d7c5SThomas E. Spanjaard if (testing || bootverbose) 2540*c1b3d7c5SThomas E. Spanjaard device_printf(parent, "JMicron check2 failed\n"); 2541*c1b3d7c5SThomas E. Spanjaard goto jmicron_out; 2542*c1b3d7c5SThomas E. Spanjaard } 2543*c1b3d7c5SThomas E. Spanjaard 2544*c1b3d7c5SThomas E. Spanjaard if (testing || bootverbose) 2545*c1b3d7c5SThomas E. Spanjaard ata_raid_jmicron_print_meta(meta); 2546*c1b3d7c5SThomas E. Spanjaard 2547*c1b3d7c5SThomas E. Spanjaard /* now convert JMicron meta into our generic form */ 2548*c1b3d7c5SThomas E. Spanjaard for (array = 0; array < MAX_ARRAYS; array++) { 2549*c1b3d7c5SThomas E. Spanjaard jmicron_next: 2550*c1b3d7c5SThomas E. Spanjaard if (!raidp[array]) { 2551*c1b3d7c5SThomas E. Spanjaard raidp[array] = 2552*c1b3d7c5SThomas E. Spanjaard (struct ar_softc *)malloc(sizeof(struct ar_softc), M_AR, 2553*c1b3d7c5SThomas E. Spanjaard M_NOWAIT | M_ZERO); 2554*c1b3d7c5SThomas E. Spanjaard if (!raidp[array]) { 2555*c1b3d7c5SThomas E. Spanjaard device_printf(parent, "failed to allocate metadata storage\n"); 2556*c1b3d7c5SThomas E. Spanjaard goto jmicron_out; 2557*c1b3d7c5SThomas E. Spanjaard } 2558*c1b3d7c5SThomas E. Spanjaard } 2559*c1b3d7c5SThomas E. Spanjaard raid = raidp[array]; 2560*c1b3d7c5SThomas E. Spanjaard if (raid->format && (raid->format != AR_F_JMICRON_RAID)) 2561*c1b3d7c5SThomas E. Spanjaard continue; 2562*c1b3d7c5SThomas E. Spanjaard 2563*c1b3d7c5SThomas E. Spanjaard for (total_disks = 0, disk = 0; disk < JM_MAX_DISKS; disk++) { 2564*c1b3d7c5SThomas E. Spanjaard if (meta->disks[disk]) { 2565*c1b3d7c5SThomas E. Spanjaard if (raid->format == AR_F_JMICRON_RAID) { 2566*c1b3d7c5SThomas E. Spanjaard if (bcmp(&meta->disks[disk], 2567*c1b3d7c5SThomas E. Spanjaard raid->disks[disk].serial, sizeof(u_int32_t))) { 2568*c1b3d7c5SThomas E. Spanjaard array++; 2569*c1b3d7c5SThomas E. Spanjaard goto jmicron_next; 2570*c1b3d7c5SThomas E. Spanjaard } 2571*c1b3d7c5SThomas E. Spanjaard } 2572*c1b3d7c5SThomas E. Spanjaard else 2573*c1b3d7c5SThomas E. Spanjaard bcopy(&meta->disks[disk], 2574*c1b3d7c5SThomas E. Spanjaard raid->disks[disk].serial, sizeof(u_int32_t)); 2575*c1b3d7c5SThomas E. Spanjaard total_disks++; 2576*c1b3d7c5SThomas E. Spanjaard } 2577*c1b3d7c5SThomas E. Spanjaard } 2578*c1b3d7c5SThomas E. Spanjaard /* handle spares XXX SOS */ 2579*c1b3d7c5SThomas E. Spanjaard 2580*c1b3d7c5SThomas E. Spanjaard switch (meta->type) { 2581*c1b3d7c5SThomas E. Spanjaard case JM_T_RAID0: 2582*c1b3d7c5SThomas E. Spanjaard raid->type = AR_T_RAID0; 2583*c1b3d7c5SThomas E. Spanjaard raid->width = total_disks; 2584*c1b3d7c5SThomas E. Spanjaard break; 2585*c1b3d7c5SThomas E. Spanjaard 2586*c1b3d7c5SThomas E. Spanjaard case JM_T_RAID1: 2587*c1b3d7c5SThomas E. Spanjaard raid->type = AR_T_RAID1; 2588*c1b3d7c5SThomas E. Spanjaard raid->width = 1; 2589*c1b3d7c5SThomas E. Spanjaard break; 2590*c1b3d7c5SThomas E. Spanjaard 2591*c1b3d7c5SThomas E. Spanjaard case JM_T_RAID01: 2592*c1b3d7c5SThomas E. Spanjaard raid->type = AR_T_RAID01; 2593*c1b3d7c5SThomas E. Spanjaard raid->width = total_disks / 2; 2594*c1b3d7c5SThomas E. Spanjaard break; 2595*c1b3d7c5SThomas E. Spanjaard 2596*c1b3d7c5SThomas E. Spanjaard case JM_T_RAID5: 2597*c1b3d7c5SThomas E. Spanjaard raid->type = AR_T_RAID5; 2598*c1b3d7c5SThomas E. Spanjaard raid->width = total_disks; 2599*c1b3d7c5SThomas E. Spanjaard break; 2600*c1b3d7c5SThomas E. Spanjaard 2601*c1b3d7c5SThomas E. Spanjaard case JM_T_JBOD: 2602*c1b3d7c5SThomas E. Spanjaard raid->type = AR_T_SPAN; 2603*c1b3d7c5SThomas E. Spanjaard raid->width = 1; 2604*c1b3d7c5SThomas E. Spanjaard break; 2605*c1b3d7c5SThomas E. Spanjaard 2606*c1b3d7c5SThomas E. Spanjaard default: 2607*c1b3d7c5SThomas E. Spanjaard device_printf(parent, 2608*c1b3d7c5SThomas E. Spanjaard "JMicron unknown RAID type 0x%02x\n", meta->type); 2609*c1b3d7c5SThomas E. Spanjaard free(raidp[array], M_AR); 2610*c1b3d7c5SThomas E. Spanjaard raidp[array] = NULL; 2611*c1b3d7c5SThomas E. Spanjaard goto jmicron_out; 2612*c1b3d7c5SThomas E. Spanjaard } 2613*c1b3d7c5SThomas E. Spanjaard disk_size = (meta->disk_sectors_high << 16) + meta->disk_sectors_low; 2614*c1b3d7c5SThomas E. Spanjaard raid->format = AR_F_JMICRON_RAID; 2615*c1b3d7c5SThomas E. Spanjaard strncpy(raid->name, meta->name, sizeof(meta->name)); 2616*c1b3d7c5SThomas E. Spanjaard raid->generation = 0; 2617*c1b3d7c5SThomas E. Spanjaard raid->interleave = 2 << meta->stripe_shift; 2618*c1b3d7c5SThomas E. Spanjaard raid->total_disks = total_disks; 2619*c1b3d7c5SThomas E. Spanjaard raid->total_sectors = disk_size * (raid->width-(raid->type==AR_RAID5)); 2620*c1b3d7c5SThomas E. Spanjaard raid->heads = 255; 2621*c1b3d7c5SThomas E. Spanjaard raid->sectors = 63; 2622*c1b3d7c5SThomas E. Spanjaard raid->cylinders = raid->total_sectors / (63 * 255); 2623*c1b3d7c5SThomas E. Spanjaard raid->offset_sectors = meta->offset * 16; 2624*c1b3d7c5SThomas E. Spanjaard raid->rebuild_lba = 0; 2625*c1b3d7c5SThomas E. Spanjaard raid->lun = array; 2626*c1b3d7c5SThomas E. Spanjaard 2627*c1b3d7c5SThomas E. Spanjaard for (disk = 0; disk < raid->total_disks; disk++) { 2628*c1b3d7c5SThomas E. Spanjaard if (meta->disks[disk] == meta->disk_id) { 2629*c1b3d7c5SThomas E. Spanjaard raid->disks[disk].dev = parent; 2630*c1b3d7c5SThomas E. Spanjaard raid->disks[disk].sectors = disk_size; 2631*c1b3d7c5SThomas E. Spanjaard raid->disks[disk].flags = 2632*c1b3d7c5SThomas E. Spanjaard (AR_DF_ONLINE | AR_DF_PRESENT | AR_DF_ASSIGNED); 2633*c1b3d7c5SThomas E. Spanjaard ars->raid[raid->volume] = raid; 2634*c1b3d7c5SThomas E. Spanjaard ars->disk_number[raid->volume] = disk; 2635*c1b3d7c5SThomas E. Spanjaard retval = 1; 2636*c1b3d7c5SThomas E. Spanjaard break; 2637*c1b3d7c5SThomas E. Spanjaard } 2638*c1b3d7c5SThomas E. Spanjaard } 2639*c1b3d7c5SThomas E. Spanjaard break; 2640*c1b3d7c5SThomas E. Spanjaard } 2641*c1b3d7c5SThomas E. Spanjaard jmicron_out: 2642*c1b3d7c5SThomas E. Spanjaard free(meta, M_AR); 2643*c1b3d7c5SThomas E. Spanjaard return retval; 2644*c1b3d7c5SThomas E. Spanjaard } 2645*c1b3d7c5SThomas E. Spanjaard 2646*c1b3d7c5SThomas E. Spanjaard static int 2647*c1b3d7c5SThomas E. Spanjaard ata_raid_jmicron_write_meta(struct ar_softc *rdp) 2648*c1b3d7c5SThomas E. Spanjaard { 2649*c1b3d7c5SThomas E. Spanjaard struct jmicron_raid_conf *meta; 2650*c1b3d7c5SThomas E. Spanjaard u_int64_t disk_sectors; 2651*c1b3d7c5SThomas E. Spanjaard int disk, error = 0; 2652*c1b3d7c5SThomas E. Spanjaard 2653*c1b3d7c5SThomas E. Spanjaard if (!(meta = (struct jmicron_raid_conf *) 2654*c1b3d7c5SThomas E. Spanjaard malloc(sizeof(struct jmicron_raid_conf), M_AR, M_NOWAIT | M_ZERO))) { 2655*c1b3d7c5SThomas E. Spanjaard printf("ar%d: failed to allocate metadata storage\n", rdp->lun); 2656*c1b3d7c5SThomas E. Spanjaard return ENOMEM; 2657*c1b3d7c5SThomas E. Spanjaard } 2658*c1b3d7c5SThomas E. Spanjaard 2659*c1b3d7c5SThomas E. Spanjaard rdp->generation++; 2660*c1b3d7c5SThomas E. Spanjaard switch (rdp->type) { 2661*c1b3d7c5SThomas E. Spanjaard case AR_T_JBOD: 2662*c1b3d7c5SThomas E. Spanjaard meta->type = JM_T_JBOD; 2663*c1b3d7c5SThomas E. Spanjaard break; 2664*c1b3d7c5SThomas E. Spanjaard 2665*c1b3d7c5SThomas E. Spanjaard case AR_T_RAID0: 2666*c1b3d7c5SThomas E. Spanjaard meta->type = JM_T_RAID0; 2667*c1b3d7c5SThomas E. Spanjaard break; 2668*c1b3d7c5SThomas E. Spanjaard 2669*c1b3d7c5SThomas E. Spanjaard case AR_T_RAID1: 2670*c1b3d7c5SThomas E. Spanjaard meta->type = JM_T_RAID1; 2671*c1b3d7c5SThomas E. Spanjaard break; 2672*c1b3d7c5SThomas E. Spanjaard 2673*c1b3d7c5SThomas E. Spanjaard case AR_T_RAID5: 2674*c1b3d7c5SThomas E. Spanjaard meta->type = JM_T_RAID5; 2675*c1b3d7c5SThomas E. Spanjaard break; 2676*c1b3d7c5SThomas E. Spanjaard 2677*c1b3d7c5SThomas E. Spanjaard case AR_T_RAID01: 2678*c1b3d7c5SThomas E. Spanjaard meta->type = JM_T_RAID01; 2679*c1b3d7c5SThomas E. Spanjaard break; 2680*c1b3d7c5SThomas E. Spanjaard 2681*c1b3d7c5SThomas E. Spanjaard default: 2682*c1b3d7c5SThomas E. Spanjaard free(meta, M_AR); 2683*c1b3d7c5SThomas E. Spanjaard return ENODEV; 2684*c1b3d7c5SThomas E. Spanjaard } 2685*c1b3d7c5SThomas E. Spanjaard bcopy(JMICRON_MAGIC, meta->signature, sizeof(JMICRON_MAGIC)); 2686*c1b3d7c5SThomas E. Spanjaard meta->version = JMICRON_VERSION; 2687*c1b3d7c5SThomas E. Spanjaard meta->offset = rdp->offset_sectors / 16; 2688*c1b3d7c5SThomas E. Spanjaard disk_sectors = rdp->total_sectors / (rdp->width - (rdp->type == AR_RAID5)); 2689*c1b3d7c5SThomas E. Spanjaard meta->disk_sectors_low = disk_sectors & 0xffff; 2690*c1b3d7c5SThomas E. Spanjaard meta->disk_sectors_high = disk_sectors >> 16; 2691*c1b3d7c5SThomas E. Spanjaard strncpy(meta->name, rdp->name, sizeof(meta->name)); 2692*c1b3d7c5SThomas E. Spanjaard meta->stripe_shift = ffs(rdp->interleave) - 2; 2693*c1b3d7c5SThomas E. Spanjaard 2694*c1b3d7c5SThomas E. Spanjaard for (disk = 0; disk < rdp->total_disks; disk++) { 2695*c1b3d7c5SThomas E. Spanjaard if (rdp->disks[disk].serial[0]) 2696*c1b3d7c5SThomas E. Spanjaard bcopy(rdp->disks[disk].serial,&meta->disks[disk],sizeof(u_int32_t)); 2697*c1b3d7c5SThomas E. Spanjaard else 2698*c1b3d7c5SThomas E. Spanjaard meta->disks[disk] = (u_int32_t)(uintptr_t)rdp->disks[disk].dev; 2699*c1b3d7c5SThomas E. Spanjaard } 2700*c1b3d7c5SThomas E. Spanjaard 2701*c1b3d7c5SThomas E. Spanjaard for (disk = 0; disk < rdp->total_disks; disk++) { 2702*c1b3d7c5SThomas E. Spanjaard if (rdp->disks[disk].dev) { 2703*c1b3d7c5SThomas E. Spanjaard u_int16_t checksum = 0, *ptr; 2704*c1b3d7c5SThomas E. Spanjaard int count; 2705*c1b3d7c5SThomas E. Spanjaard 2706*c1b3d7c5SThomas E. Spanjaard meta->disk_id = meta->disks[disk]; 2707*c1b3d7c5SThomas E. Spanjaard meta->checksum = 0; 2708*c1b3d7c5SThomas E. Spanjaard for (ptr = (u_int16_t *)meta, count = 0; count < 64; count++) 2709*c1b3d7c5SThomas E. Spanjaard checksum += *ptr++; 2710*c1b3d7c5SThomas E. Spanjaard meta->checksum -= checksum; 2711*c1b3d7c5SThomas E. Spanjaard 2712*c1b3d7c5SThomas E. Spanjaard if (testing || bootverbose) 2713*c1b3d7c5SThomas E. Spanjaard ata_raid_jmicron_print_meta(meta); 2714*c1b3d7c5SThomas E. Spanjaard 2715*c1b3d7c5SThomas E. Spanjaard if (ata_raid_rw(rdp->disks[disk].dev, 2716*c1b3d7c5SThomas E. Spanjaard JMICRON_LBA(rdp->disks[disk].dev), 2717*c1b3d7c5SThomas E. Spanjaard meta, sizeof(struct jmicron_raid_conf), 2718*c1b3d7c5SThomas E. Spanjaard ATA_R_WRITE | ATA_R_DIRECT)) { 2719*c1b3d7c5SThomas E. Spanjaard device_printf(rdp->disks[disk].dev, "write metadata failed\n"); 2720*c1b3d7c5SThomas E. Spanjaard error = EIO; 2721*c1b3d7c5SThomas E. Spanjaard } 2722*c1b3d7c5SThomas E. Spanjaard } 2723*c1b3d7c5SThomas E. Spanjaard } 2724*c1b3d7c5SThomas E. Spanjaard /* handle spares XXX SOS */ 2725*c1b3d7c5SThomas E. Spanjaard 2726*c1b3d7c5SThomas E. Spanjaard free(meta, M_AR); 2727*c1b3d7c5SThomas E. Spanjaard return error; 2728*c1b3d7c5SThomas E. Spanjaard } 2729*c1b3d7c5SThomas E. Spanjaard 2730*c1b3d7c5SThomas E. Spanjaard /* LSILogic V2 MegaRAID Metadata */ 2731*c1b3d7c5SThomas E. Spanjaard static int 2732*c1b3d7c5SThomas E. Spanjaard ata_raid_lsiv2_read_meta(device_t dev, struct ar_softc **raidp) 2733*c1b3d7c5SThomas E. Spanjaard { 2734*c1b3d7c5SThomas E. Spanjaard struct ata_raid_subdisk *ars = device_get_softc(dev); 2735*c1b3d7c5SThomas E. Spanjaard device_t parent = device_get_parent(dev); 2736*c1b3d7c5SThomas E. Spanjaard struct lsiv2_raid_conf *meta; 2737*c1b3d7c5SThomas E. Spanjaard struct ar_softc *raid = NULL; 2738*c1b3d7c5SThomas E. Spanjaard int array, retval = 0; 2739*c1b3d7c5SThomas E. Spanjaard 2740*c1b3d7c5SThomas E. Spanjaard if (!(meta = (struct lsiv2_raid_conf *) 2741*c1b3d7c5SThomas E. Spanjaard malloc(sizeof(struct lsiv2_raid_conf), M_AR, M_NOWAIT | M_ZERO))) 2742*c1b3d7c5SThomas E. Spanjaard return ENOMEM; 2743*c1b3d7c5SThomas E. Spanjaard 2744*c1b3d7c5SThomas E. Spanjaard if (ata_raid_rw(parent, LSIV2_LBA(parent), 2745*c1b3d7c5SThomas E. Spanjaard meta, sizeof(struct lsiv2_raid_conf), ATA_R_READ)) { 2746*c1b3d7c5SThomas E. Spanjaard if (testing || bootverbose) 2747*c1b3d7c5SThomas E. Spanjaard device_printf(parent, "LSI (v2) read metadata failed\n"); 2748*c1b3d7c5SThomas E. Spanjaard goto lsiv2_out; 2749*c1b3d7c5SThomas E. Spanjaard } 2750*c1b3d7c5SThomas E. Spanjaard 2751*c1b3d7c5SThomas E. Spanjaard /* check if this is a LSI RAID struct */ 2752*c1b3d7c5SThomas E. Spanjaard if (strncmp(meta->lsi_id, LSIV2_MAGIC, strlen(LSIV2_MAGIC))) { 2753*c1b3d7c5SThomas E. Spanjaard if (testing || bootverbose) 2754*c1b3d7c5SThomas E. Spanjaard device_printf(parent, "LSI (v2) check1 failed\n"); 2755*c1b3d7c5SThomas E. Spanjaard goto lsiv2_out; 2756*c1b3d7c5SThomas E. Spanjaard } 2757*c1b3d7c5SThomas E. Spanjaard 2758*c1b3d7c5SThomas E. Spanjaard if (testing || bootverbose) 2759*c1b3d7c5SThomas E. Spanjaard ata_raid_lsiv2_print_meta(meta); 2760*c1b3d7c5SThomas E. Spanjaard 2761*c1b3d7c5SThomas E. Spanjaard /* now convert LSI (v2) config meta into our generic form */ 2762*c1b3d7c5SThomas E. Spanjaard for (array = 0; array < MAX_ARRAYS; array++) { 2763*c1b3d7c5SThomas E. Spanjaard int raid_entry, conf_entry; 2764*c1b3d7c5SThomas E. Spanjaard 2765*c1b3d7c5SThomas E. Spanjaard if (!raidp[array + meta->raid_number]) { 2766*c1b3d7c5SThomas E. Spanjaard raidp[array + meta->raid_number] = 2767*c1b3d7c5SThomas E. Spanjaard (struct ar_softc *)malloc(sizeof(struct ar_softc), M_AR, 2768*c1b3d7c5SThomas E. Spanjaard M_NOWAIT | M_ZERO); 2769*c1b3d7c5SThomas E. Spanjaard if (!raidp[array + meta->raid_number]) { 2770*c1b3d7c5SThomas E. Spanjaard device_printf(parent, "failed to allocate metadata storage\n"); 2771*c1b3d7c5SThomas E. Spanjaard goto lsiv2_out; 2772*c1b3d7c5SThomas E. Spanjaard } 2773*c1b3d7c5SThomas E. Spanjaard } 2774*c1b3d7c5SThomas E. Spanjaard raid = raidp[array + meta->raid_number]; 2775*c1b3d7c5SThomas E. Spanjaard if (raid->format && (raid->format != AR_F_LSIV2_RAID)) 2776*c1b3d7c5SThomas E. Spanjaard continue; 2777*c1b3d7c5SThomas E. Spanjaard 2778*c1b3d7c5SThomas E. Spanjaard if (raid->magic_0 && 2779*c1b3d7c5SThomas E. Spanjaard ((raid->magic_0 != meta->timestamp) || 2780*c1b3d7c5SThomas E. Spanjaard (raid->magic_1 != meta->raid_number))) 2781*c1b3d7c5SThomas E. Spanjaard continue; 2782*c1b3d7c5SThomas E. Spanjaard 2783*c1b3d7c5SThomas E. Spanjaard array += meta->raid_number; 2784*c1b3d7c5SThomas E. Spanjaard 2785*c1b3d7c5SThomas E. Spanjaard raid_entry = meta->raid_number; 2786*c1b3d7c5SThomas E. Spanjaard conf_entry = (meta->configs[raid_entry].raid.config_offset >> 4) + 2787*c1b3d7c5SThomas E. Spanjaard meta->disk_number - 1; 2788*c1b3d7c5SThomas E. Spanjaard 2789*c1b3d7c5SThomas E. Spanjaard switch (meta->configs[raid_entry].raid.type) { 2790*c1b3d7c5SThomas E. Spanjaard case LSIV2_T_RAID0: 2791*c1b3d7c5SThomas E. Spanjaard raid->magic_0 = meta->timestamp; 2792*c1b3d7c5SThomas E. Spanjaard raid->magic_1 = meta->raid_number; 2793*c1b3d7c5SThomas E. Spanjaard raid->type = AR_T_RAID0; 2794*c1b3d7c5SThomas E. Spanjaard raid->interleave = meta->configs[raid_entry].raid.stripe_sectors; 2795*c1b3d7c5SThomas E. Spanjaard raid->width = meta->configs[raid_entry].raid.array_width; 2796*c1b3d7c5SThomas E. Spanjaard break; 2797*c1b3d7c5SThomas E. Spanjaard 2798*c1b3d7c5SThomas E. Spanjaard case LSIV2_T_RAID1: 2799*c1b3d7c5SThomas E. Spanjaard raid->magic_0 = meta->timestamp; 2800*c1b3d7c5SThomas E. Spanjaard raid->magic_1 = meta->raid_number; 2801*c1b3d7c5SThomas E. Spanjaard raid->type = AR_T_RAID1; 2802*c1b3d7c5SThomas E. Spanjaard raid->width = meta->configs[raid_entry].raid.array_width; 2803*c1b3d7c5SThomas E. Spanjaard break; 2804*c1b3d7c5SThomas E. Spanjaard 2805*c1b3d7c5SThomas E. Spanjaard case LSIV2_T_RAID0 | LSIV2_T_RAID1: 2806*c1b3d7c5SThomas E. Spanjaard raid->magic_0 = meta->timestamp; 2807*c1b3d7c5SThomas E. Spanjaard raid->magic_1 = meta->raid_number; 2808*c1b3d7c5SThomas E. Spanjaard raid->type = AR_T_RAID01; 2809*c1b3d7c5SThomas E. Spanjaard raid->interleave = meta->configs[raid_entry].raid.stripe_sectors; 2810*c1b3d7c5SThomas E. Spanjaard raid->width = meta->configs[raid_entry].raid.array_width; 2811*c1b3d7c5SThomas E. Spanjaard break; 2812*c1b3d7c5SThomas E. Spanjaard 2813*c1b3d7c5SThomas E. Spanjaard default: 2814*c1b3d7c5SThomas E. Spanjaard device_printf(parent, "LSI v2 unknown RAID type 0x%02x\n", 2815*c1b3d7c5SThomas E. Spanjaard meta->configs[raid_entry].raid.type); 2816*c1b3d7c5SThomas E. Spanjaard free(raidp[array], M_AR); 2817*c1b3d7c5SThomas E. Spanjaard raidp[array] = NULL; 2818*c1b3d7c5SThomas E. Spanjaard goto lsiv2_out; 2819*c1b3d7c5SThomas E. Spanjaard } 2820*c1b3d7c5SThomas E. Spanjaard 2821*c1b3d7c5SThomas E. Spanjaard raid->format = AR_F_LSIV2_RAID; 2822*c1b3d7c5SThomas E. Spanjaard raid->generation = 0; 2823*c1b3d7c5SThomas E. Spanjaard raid->total_disks = meta->configs[raid_entry].raid.disk_count; 2824*c1b3d7c5SThomas E. Spanjaard raid->total_sectors = meta->configs[raid_entry].raid.total_sectors; 2825*c1b3d7c5SThomas E. Spanjaard raid->heads = 255; 2826*c1b3d7c5SThomas E. Spanjaard raid->sectors = 63; 2827*c1b3d7c5SThomas E. Spanjaard raid->cylinders = raid->total_sectors / (63 * 255); 2828*c1b3d7c5SThomas E. Spanjaard raid->offset_sectors = 0; 2829*c1b3d7c5SThomas E. Spanjaard raid->rebuild_lba = 0; 2830*c1b3d7c5SThomas E. Spanjaard raid->lun = array; 2831*c1b3d7c5SThomas E. Spanjaard 2832*c1b3d7c5SThomas E. Spanjaard if (meta->configs[conf_entry].disk.device != LSIV2_D_NONE) { 2833*c1b3d7c5SThomas E. Spanjaard raid->disks[meta->disk_number].dev = parent; 2834*c1b3d7c5SThomas E. Spanjaard raid->disks[meta->disk_number].sectors = 2835*c1b3d7c5SThomas E. Spanjaard meta->configs[conf_entry].disk.disk_sectors; 2836*c1b3d7c5SThomas E. Spanjaard raid->disks[meta->disk_number].flags = 2837*c1b3d7c5SThomas E. Spanjaard (AR_DF_ONLINE | AR_DF_PRESENT | AR_DF_ASSIGNED); 2838*c1b3d7c5SThomas E. Spanjaard ars->raid[raid->volume] = raid; 2839*c1b3d7c5SThomas E. Spanjaard ars->disk_number[raid->volume] = meta->disk_number; 2840*c1b3d7c5SThomas E. Spanjaard retval = 1; 2841*c1b3d7c5SThomas E. Spanjaard } 2842*c1b3d7c5SThomas E. Spanjaard else 2843*c1b3d7c5SThomas E. Spanjaard raid->disks[meta->disk_number].flags &= ~AR_DF_ONLINE; 2844*c1b3d7c5SThomas E. Spanjaard 2845*c1b3d7c5SThomas E. Spanjaard break; 2846*c1b3d7c5SThomas E. Spanjaard } 2847*c1b3d7c5SThomas E. Spanjaard 2848*c1b3d7c5SThomas E. Spanjaard lsiv2_out: 2849*c1b3d7c5SThomas E. Spanjaard free(meta, M_AR); 2850*c1b3d7c5SThomas E. Spanjaard return retval; 2851*c1b3d7c5SThomas E. Spanjaard } 2852*c1b3d7c5SThomas E. Spanjaard 2853*c1b3d7c5SThomas E. Spanjaard /* LSILogic V3 MegaRAID Metadata */ 2854*c1b3d7c5SThomas E. Spanjaard static int 2855*c1b3d7c5SThomas E. Spanjaard ata_raid_lsiv3_read_meta(device_t dev, struct ar_softc **raidp) 2856*c1b3d7c5SThomas E. Spanjaard { 2857*c1b3d7c5SThomas E. Spanjaard struct ata_raid_subdisk *ars = device_get_softc(dev); 2858*c1b3d7c5SThomas E. Spanjaard device_t parent = device_get_parent(dev); 2859*c1b3d7c5SThomas E. Spanjaard struct lsiv3_raid_conf *meta; 2860*c1b3d7c5SThomas E. Spanjaard struct ar_softc *raid = NULL; 2861*c1b3d7c5SThomas E. Spanjaard u_int8_t checksum, *ptr; 2862*c1b3d7c5SThomas E. Spanjaard int array, entry, count, disk_number, retval = 0; 2863*c1b3d7c5SThomas E. Spanjaard 2864*c1b3d7c5SThomas E. Spanjaard if (!(meta = (struct lsiv3_raid_conf *) 2865*c1b3d7c5SThomas E. Spanjaard malloc(sizeof(struct lsiv3_raid_conf), M_AR, M_NOWAIT | M_ZERO))) 2866*c1b3d7c5SThomas E. Spanjaard return ENOMEM; 2867*c1b3d7c5SThomas E. Spanjaard 2868*c1b3d7c5SThomas E. Spanjaard if (ata_raid_rw(parent, LSIV3_LBA(parent), 2869*c1b3d7c5SThomas E. Spanjaard meta, sizeof(struct lsiv3_raid_conf), ATA_R_READ)) { 2870*c1b3d7c5SThomas E. Spanjaard if (testing || bootverbose) 2871*c1b3d7c5SThomas E. Spanjaard device_printf(parent, "LSI (v3) read metadata failed\n"); 2872*c1b3d7c5SThomas E. Spanjaard goto lsiv3_out; 2873*c1b3d7c5SThomas E. Spanjaard } 2874*c1b3d7c5SThomas E. Spanjaard 2875*c1b3d7c5SThomas E. Spanjaard /* check if this is a LSI RAID struct */ 2876*c1b3d7c5SThomas E. Spanjaard if (strncmp(meta->lsi_id, LSIV3_MAGIC, strlen(LSIV3_MAGIC))) { 2877*c1b3d7c5SThomas E. Spanjaard if (testing || bootverbose) 2878*c1b3d7c5SThomas E. Spanjaard device_printf(parent, "LSI (v3) check1 failed\n"); 2879*c1b3d7c5SThomas E. Spanjaard goto lsiv3_out; 2880*c1b3d7c5SThomas E. Spanjaard } 2881*c1b3d7c5SThomas E. Spanjaard 2882*c1b3d7c5SThomas E. Spanjaard /* check if the checksum is OK */ 2883*c1b3d7c5SThomas E. Spanjaard for (checksum = 0, ptr = meta->lsi_id, count = 0; count < 512; count++) 2884*c1b3d7c5SThomas E. Spanjaard checksum += *ptr++; 2885*c1b3d7c5SThomas E. Spanjaard if (checksum) { 2886*c1b3d7c5SThomas E. Spanjaard if (testing || bootverbose) 2887*c1b3d7c5SThomas E. Spanjaard device_printf(parent, "LSI (v3) check2 failed\n"); 2888*c1b3d7c5SThomas E. Spanjaard goto lsiv3_out; 2889*c1b3d7c5SThomas E. Spanjaard } 2890*c1b3d7c5SThomas E. Spanjaard 2891*c1b3d7c5SThomas E. Spanjaard if (testing || bootverbose) 2892*c1b3d7c5SThomas E. Spanjaard ata_raid_lsiv3_print_meta(meta); 2893*c1b3d7c5SThomas E. Spanjaard 2894*c1b3d7c5SThomas E. Spanjaard /* now convert LSI (v3) config meta into our generic form */ 2895*c1b3d7c5SThomas E. Spanjaard for (array = 0, entry = 0; array < MAX_ARRAYS && entry < 8;) { 2896*c1b3d7c5SThomas E. Spanjaard if (!raidp[array]) { 2897*c1b3d7c5SThomas E. Spanjaard raidp[array] = 2898*c1b3d7c5SThomas E. Spanjaard (struct ar_softc *)malloc(sizeof(struct ar_softc), M_AR, 2899*c1b3d7c5SThomas E. Spanjaard M_NOWAIT | M_ZERO); 2900*c1b3d7c5SThomas E. Spanjaard if (!raidp[array]) { 2901*c1b3d7c5SThomas E. Spanjaard device_printf(parent, "failed to allocate metadata storage\n"); 2902*c1b3d7c5SThomas E. Spanjaard goto lsiv3_out; 2903*c1b3d7c5SThomas E. Spanjaard } 2904*c1b3d7c5SThomas E. Spanjaard } 2905*c1b3d7c5SThomas E. Spanjaard raid = raidp[array]; 2906*c1b3d7c5SThomas E. Spanjaard if (raid->format && (raid->format != AR_F_LSIV3_RAID)) { 2907*c1b3d7c5SThomas E. Spanjaard array++; 2908*c1b3d7c5SThomas E. Spanjaard continue; 2909*c1b3d7c5SThomas E. Spanjaard } 2910*c1b3d7c5SThomas E. Spanjaard 2911*c1b3d7c5SThomas E. Spanjaard if ((raid->format == AR_F_LSIV3_RAID) && 2912*c1b3d7c5SThomas E. Spanjaard (raid->magic_0 != meta->timestamp)) { 2913*c1b3d7c5SThomas E. Spanjaard array++; 2914*c1b3d7c5SThomas E. Spanjaard continue; 2915*c1b3d7c5SThomas E. Spanjaard } 2916*c1b3d7c5SThomas E. Spanjaard 2917*c1b3d7c5SThomas E. Spanjaard switch (meta->raid[entry].total_disks) { 2918*c1b3d7c5SThomas E. Spanjaard case 0: 2919*c1b3d7c5SThomas E. Spanjaard entry++; 2920*c1b3d7c5SThomas E. Spanjaard continue; 2921*c1b3d7c5SThomas E. Spanjaard case 1: 2922*c1b3d7c5SThomas E. Spanjaard if (meta->raid[entry].device == meta->device) { 2923*c1b3d7c5SThomas E. Spanjaard disk_number = 0; 2924*c1b3d7c5SThomas E. Spanjaard break; 2925*c1b3d7c5SThomas E. Spanjaard } 2926*c1b3d7c5SThomas E. Spanjaard if (raid->format) 2927*c1b3d7c5SThomas E. Spanjaard array++; 2928*c1b3d7c5SThomas E. Spanjaard entry++; 2929*c1b3d7c5SThomas E. Spanjaard continue; 2930*c1b3d7c5SThomas E. Spanjaard case 2: 2931*c1b3d7c5SThomas E. Spanjaard disk_number = (meta->device & (LSIV3_D_DEVICE|LSIV3_D_CHANNEL))?1:0; 2932*c1b3d7c5SThomas E. Spanjaard break; 2933*c1b3d7c5SThomas E. Spanjaard default: 2934*c1b3d7c5SThomas E. Spanjaard device_printf(parent, "lsiv3 > 2 disk support untested!!\n"); 2935*c1b3d7c5SThomas E. Spanjaard disk_number = (meta->device & LSIV3_D_DEVICE ? 1 : 0) + 2936*c1b3d7c5SThomas E. Spanjaard (meta->device & LSIV3_D_CHANNEL ? 2 : 0); 2937*c1b3d7c5SThomas E. Spanjaard break; 2938*c1b3d7c5SThomas E. Spanjaard } 2939*c1b3d7c5SThomas E. Spanjaard 2940*c1b3d7c5SThomas E. Spanjaard switch (meta->raid[entry].type) { 2941*c1b3d7c5SThomas E. Spanjaard case LSIV3_T_RAID0: 2942*c1b3d7c5SThomas E. Spanjaard raid->type = AR_T_RAID0; 2943*c1b3d7c5SThomas E. Spanjaard raid->width = meta->raid[entry].total_disks; 2944*c1b3d7c5SThomas E. Spanjaard break; 2945*c1b3d7c5SThomas E. Spanjaard 2946*c1b3d7c5SThomas E. Spanjaard case LSIV3_T_RAID1: 2947*c1b3d7c5SThomas E. Spanjaard raid->type = AR_T_RAID1; 2948*c1b3d7c5SThomas E. Spanjaard raid->width = meta->raid[entry].array_width; 2949*c1b3d7c5SThomas E. Spanjaard break; 2950*c1b3d7c5SThomas E. Spanjaard 2951*c1b3d7c5SThomas E. Spanjaard default: 2952*c1b3d7c5SThomas E. Spanjaard device_printf(parent, "LSI v3 unknown RAID type 0x%02x\n", 2953*c1b3d7c5SThomas E. Spanjaard meta->raid[entry].type); 2954*c1b3d7c5SThomas E. Spanjaard free(raidp[array], M_AR); 2955*c1b3d7c5SThomas E. Spanjaard raidp[array] = NULL; 2956*c1b3d7c5SThomas E. Spanjaard entry++; 2957*c1b3d7c5SThomas E. Spanjaard continue; 2958*c1b3d7c5SThomas E. Spanjaard } 2959*c1b3d7c5SThomas E. Spanjaard 2960*c1b3d7c5SThomas E. Spanjaard raid->magic_0 = meta->timestamp; 2961*c1b3d7c5SThomas E. Spanjaard raid->format = AR_F_LSIV3_RAID; 2962*c1b3d7c5SThomas E. Spanjaard raid->generation = 0; 2963*c1b3d7c5SThomas E. Spanjaard raid->interleave = meta->raid[entry].stripe_pages * 8; 2964*c1b3d7c5SThomas E. Spanjaard raid->total_disks = meta->raid[entry].total_disks; 2965*c1b3d7c5SThomas E. Spanjaard raid->total_sectors = raid->width * meta->raid[entry].sectors; 2966*c1b3d7c5SThomas E. Spanjaard raid->heads = 255; 2967*c1b3d7c5SThomas E. Spanjaard raid->sectors = 63; 2968*c1b3d7c5SThomas E. Spanjaard raid->cylinders = raid->total_sectors / (63 * 255); 2969*c1b3d7c5SThomas E. Spanjaard raid->offset_sectors = meta->raid[entry].offset; 2970*c1b3d7c5SThomas E. Spanjaard raid->rebuild_lba = 0; 2971*c1b3d7c5SThomas E. Spanjaard raid->lun = array; 2972*c1b3d7c5SThomas E. Spanjaard 2973*c1b3d7c5SThomas E. Spanjaard raid->disks[disk_number].dev = parent; 2974*c1b3d7c5SThomas E. Spanjaard raid->disks[disk_number].sectors = raid->total_sectors / raid->width; 2975*c1b3d7c5SThomas E. Spanjaard raid->disks[disk_number].flags = 2976*c1b3d7c5SThomas E. Spanjaard (AR_DF_PRESENT | AR_DF_ASSIGNED | AR_DF_ONLINE); 2977*c1b3d7c5SThomas E. Spanjaard ars->raid[raid->volume] = raid; 2978*c1b3d7c5SThomas E. Spanjaard ars->disk_number[raid->volume] = disk_number; 2979*c1b3d7c5SThomas E. Spanjaard retval = 1; 2980*c1b3d7c5SThomas E. Spanjaard entry++; 2981*c1b3d7c5SThomas E. Spanjaard array++; 2982*c1b3d7c5SThomas E. Spanjaard } 2983*c1b3d7c5SThomas E. Spanjaard 2984*c1b3d7c5SThomas E. Spanjaard lsiv3_out: 2985*c1b3d7c5SThomas E. Spanjaard free(meta, M_AR); 2986*c1b3d7c5SThomas E. Spanjaard return retval; 2987*c1b3d7c5SThomas E. Spanjaard } 2988*c1b3d7c5SThomas E. Spanjaard 2989*c1b3d7c5SThomas E. Spanjaard /* nVidia MediaShield Metadata */ 2990*c1b3d7c5SThomas E. Spanjaard static int 2991*c1b3d7c5SThomas E. Spanjaard ata_raid_nvidia_read_meta(device_t dev, struct ar_softc **raidp) 2992*c1b3d7c5SThomas E. Spanjaard { 2993*c1b3d7c5SThomas E. Spanjaard struct ata_raid_subdisk *ars = device_get_softc(dev); 2994*c1b3d7c5SThomas E. Spanjaard device_t parent = device_get_parent(dev); 2995*c1b3d7c5SThomas E. Spanjaard struct nvidia_raid_conf *meta; 2996*c1b3d7c5SThomas E. Spanjaard struct ar_softc *raid = NULL; 2997*c1b3d7c5SThomas E. Spanjaard u_int32_t checksum, *ptr; 2998*c1b3d7c5SThomas E. Spanjaard int array, count, retval = 0; 2999*c1b3d7c5SThomas E. Spanjaard 3000*c1b3d7c5SThomas E. Spanjaard if (!(meta = (struct nvidia_raid_conf *) 3001*c1b3d7c5SThomas E. Spanjaard malloc(sizeof(struct nvidia_raid_conf), M_AR, M_NOWAIT | M_ZERO))) 3002*c1b3d7c5SThomas E. Spanjaard return ENOMEM; 3003*c1b3d7c5SThomas E. Spanjaard 3004*c1b3d7c5SThomas E. Spanjaard if (ata_raid_rw(parent, NVIDIA_LBA(parent), 3005*c1b3d7c5SThomas E. Spanjaard meta, sizeof(struct nvidia_raid_conf), ATA_R_READ)) { 3006*c1b3d7c5SThomas E. Spanjaard if (testing || bootverbose) 3007*c1b3d7c5SThomas E. Spanjaard device_printf(parent, "nVidia read metadata failed\n"); 3008*c1b3d7c5SThomas E. Spanjaard goto nvidia_out; 3009*c1b3d7c5SThomas E. Spanjaard } 3010*c1b3d7c5SThomas E. Spanjaard 3011*c1b3d7c5SThomas E. Spanjaard /* check if this is a nVidia RAID struct */ 3012*c1b3d7c5SThomas E. Spanjaard if (strncmp(meta->nvidia_id, NV_MAGIC, strlen(NV_MAGIC))) { 3013*c1b3d7c5SThomas E. Spanjaard if (testing || bootverbose) 3014*c1b3d7c5SThomas E. Spanjaard device_printf(parent, "nVidia check1 failed\n"); 3015*c1b3d7c5SThomas E. Spanjaard goto nvidia_out; 3016*c1b3d7c5SThomas E. Spanjaard } 3017*c1b3d7c5SThomas E. Spanjaard 3018*c1b3d7c5SThomas E. Spanjaard /* check if the checksum is OK */ 3019*c1b3d7c5SThomas E. Spanjaard for (checksum = 0, ptr = (u_int32_t*)meta, count = 0; 3020*c1b3d7c5SThomas E. Spanjaard count < meta->config_size; count++) 3021*c1b3d7c5SThomas E. Spanjaard checksum += *ptr++; 3022*c1b3d7c5SThomas E. Spanjaard if (checksum) { 3023*c1b3d7c5SThomas E. Spanjaard if (testing || bootverbose) 3024*c1b3d7c5SThomas E. Spanjaard device_printf(parent, "nVidia check2 failed\n"); 3025*c1b3d7c5SThomas E. Spanjaard goto nvidia_out; 3026*c1b3d7c5SThomas E. Spanjaard } 3027*c1b3d7c5SThomas E. Spanjaard 3028*c1b3d7c5SThomas E. Spanjaard if (testing || bootverbose) 3029*c1b3d7c5SThomas E. Spanjaard ata_raid_nvidia_print_meta(meta); 3030*c1b3d7c5SThomas E. Spanjaard 3031*c1b3d7c5SThomas E. Spanjaard /* now convert nVidia meta into our generic form */ 3032*c1b3d7c5SThomas E. Spanjaard for (array = 0; array < MAX_ARRAYS; array++) { 3033*c1b3d7c5SThomas E. Spanjaard if (!raidp[array]) { 3034*c1b3d7c5SThomas E. Spanjaard raidp[array] = 3035*c1b3d7c5SThomas E. Spanjaard (struct ar_softc *)malloc(sizeof(struct ar_softc), M_AR, 3036*c1b3d7c5SThomas E. Spanjaard M_NOWAIT | M_ZERO); 3037*c1b3d7c5SThomas E. Spanjaard if (!raidp[array]) { 3038*c1b3d7c5SThomas E. Spanjaard device_printf(parent, "failed to allocate metadata storage\n"); 3039*c1b3d7c5SThomas E. Spanjaard goto nvidia_out; 3040*c1b3d7c5SThomas E. Spanjaard } 3041*c1b3d7c5SThomas E. Spanjaard } 3042*c1b3d7c5SThomas E. Spanjaard raid = raidp[array]; 3043*c1b3d7c5SThomas E. Spanjaard if (raid->format && (raid->format != AR_F_NVIDIA_RAID)) 3044*c1b3d7c5SThomas E. Spanjaard continue; 3045*c1b3d7c5SThomas E. Spanjaard 3046*c1b3d7c5SThomas E. Spanjaard if (raid->format == AR_F_NVIDIA_RAID && 3047*c1b3d7c5SThomas E. Spanjaard ((raid->magic_0 != meta->magic_1) || 3048*c1b3d7c5SThomas E. Spanjaard (raid->magic_1 != meta->magic_2))) { 3049*c1b3d7c5SThomas E. Spanjaard continue; 3050*c1b3d7c5SThomas E. Spanjaard } 3051*c1b3d7c5SThomas E. Spanjaard 3052*c1b3d7c5SThomas E. Spanjaard switch (meta->type) { 3053*c1b3d7c5SThomas E. Spanjaard case NV_T_SPAN: 3054*c1b3d7c5SThomas E. Spanjaard raid->type = AR_T_SPAN; 3055*c1b3d7c5SThomas E. Spanjaard break; 3056*c1b3d7c5SThomas E. Spanjaard 3057*c1b3d7c5SThomas E. Spanjaard case NV_T_RAID0: 3058*c1b3d7c5SThomas E. Spanjaard raid->type = AR_T_RAID0; 3059*c1b3d7c5SThomas E. Spanjaard break; 3060*c1b3d7c5SThomas E. Spanjaard 3061*c1b3d7c5SThomas E. Spanjaard case NV_T_RAID1: 3062*c1b3d7c5SThomas E. Spanjaard raid->type = AR_T_RAID1; 3063*c1b3d7c5SThomas E. Spanjaard break; 3064*c1b3d7c5SThomas E. Spanjaard 3065*c1b3d7c5SThomas E. Spanjaard case NV_T_RAID5: 3066*c1b3d7c5SThomas E. Spanjaard raid->type = AR_T_RAID5; 3067*c1b3d7c5SThomas E. Spanjaard break; 3068*c1b3d7c5SThomas E. Spanjaard 3069*c1b3d7c5SThomas E. Spanjaard case NV_T_RAID01: 3070*c1b3d7c5SThomas E. Spanjaard raid->type = AR_T_RAID01; 3071*c1b3d7c5SThomas E. Spanjaard break; 3072*c1b3d7c5SThomas E. Spanjaard 3073*c1b3d7c5SThomas E. Spanjaard default: 3074*c1b3d7c5SThomas E. Spanjaard device_printf(parent, "nVidia unknown RAID type 0x%02x\n", 3075*c1b3d7c5SThomas E. Spanjaard meta->type); 3076*c1b3d7c5SThomas E. Spanjaard free(raidp[array], M_AR); 3077*c1b3d7c5SThomas E. Spanjaard raidp[array] = NULL; 3078*c1b3d7c5SThomas E. Spanjaard goto nvidia_out; 3079*c1b3d7c5SThomas E. Spanjaard } 3080*c1b3d7c5SThomas E. Spanjaard raid->magic_0 = meta->magic_1; 3081*c1b3d7c5SThomas E. Spanjaard raid->magic_1 = meta->magic_2; 3082*c1b3d7c5SThomas E. Spanjaard raid->format = AR_F_NVIDIA_RAID; 3083*c1b3d7c5SThomas E. Spanjaard raid->generation = 0; 3084*c1b3d7c5SThomas E. Spanjaard raid->interleave = meta->stripe_sectors; 3085*c1b3d7c5SThomas E. Spanjaard raid->width = meta->array_width; 3086*c1b3d7c5SThomas E. Spanjaard raid->total_disks = meta->total_disks; 3087*c1b3d7c5SThomas E. Spanjaard raid->total_sectors = meta->total_sectors; 3088*c1b3d7c5SThomas E. Spanjaard raid->heads = 255; 3089*c1b3d7c5SThomas E. Spanjaard raid->sectors = 63; 3090*c1b3d7c5SThomas E. Spanjaard raid->cylinders = raid->total_sectors / (63 * 255); 3091*c1b3d7c5SThomas E. Spanjaard raid->offset_sectors = 0; 3092*c1b3d7c5SThomas E. Spanjaard raid->rebuild_lba = meta->rebuild_lba; 3093*c1b3d7c5SThomas E. Spanjaard raid->lun = array; 3094*c1b3d7c5SThomas E. Spanjaard raid->status = AR_S_READY; 3095*c1b3d7c5SThomas E. Spanjaard if (meta->status & NV_S_DEGRADED) 3096*c1b3d7c5SThomas E. Spanjaard raid->status |= AR_S_DEGRADED; 3097*c1b3d7c5SThomas E. Spanjaard 3098*c1b3d7c5SThomas E. Spanjaard raid->disks[meta->disk_number].dev = parent; 3099*c1b3d7c5SThomas E. Spanjaard raid->disks[meta->disk_number].sectors = 3100*c1b3d7c5SThomas E. Spanjaard raid->total_sectors / raid->width; 3101*c1b3d7c5SThomas E. Spanjaard raid->disks[meta->disk_number].flags = 3102*c1b3d7c5SThomas E. Spanjaard (AR_DF_PRESENT | AR_DF_ASSIGNED | AR_DF_ONLINE); 3103*c1b3d7c5SThomas E. Spanjaard ars->raid[raid->volume] = raid; 3104*c1b3d7c5SThomas E. Spanjaard ars->disk_number[raid->volume] = meta->disk_number; 3105*c1b3d7c5SThomas E. Spanjaard retval = 1; 3106*c1b3d7c5SThomas E. Spanjaard break; 3107*c1b3d7c5SThomas E. Spanjaard } 3108*c1b3d7c5SThomas E. Spanjaard 3109*c1b3d7c5SThomas E. Spanjaard nvidia_out: 3110*c1b3d7c5SThomas E. Spanjaard free(meta, M_AR); 3111*c1b3d7c5SThomas E. Spanjaard return retval; 3112*c1b3d7c5SThomas E. Spanjaard } 3113*c1b3d7c5SThomas E. Spanjaard 3114*c1b3d7c5SThomas E. Spanjaard /* Promise FastTrak Metadata */ 3115*c1b3d7c5SThomas E. Spanjaard static int 3116*c1b3d7c5SThomas E. Spanjaard ata_raid_promise_read_meta(device_t dev, struct ar_softc **raidp, int native) 3117*c1b3d7c5SThomas E. Spanjaard { 3118*c1b3d7c5SThomas E. Spanjaard struct ata_raid_subdisk *ars = device_get_softc(dev); 3119*c1b3d7c5SThomas E. Spanjaard device_t parent = device_get_parent(dev); 3120*c1b3d7c5SThomas E. Spanjaard struct promise_raid_conf *meta; 3121*c1b3d7c5SThomas E. Spanjaard struct ar_softc *raid; 3122*c1b3d7c5SThomas E. Spanjaard u_int32_t checksum, *ptr; 3123*c1b3d7c5SThomas E. Spanjaard int array, count, disk, disksum = 0, retval = 0; 3124*c1b3d7c5SThomas E. Spanjaard 3125*c1b3d7c5SThomas E. Spanjaard if (!(meta = (struct promise_raid_conf *) 3126*c1b3d7c5SThomas E. Spanjaard malloc(sizeof(struct promise_raid_conf), M_AR, M_NOWAIT | M_ZERO))) 3127*c1b3d7c5SThomas E. Spanjaard return ENOMEM; 3128*c1b3d7c5SThomas E. Spanjaard 3129*c1b3d7c5SThomas E. Spanjaard if (ata_raid_rw(parent, PROMISE_LBA(parent), 3130*c1b3d7c5SThomas E. Spanjaard meta, sizeof(struct promise_raid_conf), ATA_R_READ)) { 3131*c1b3d7c5SThomas E. Spanjaard if (testing || bootverbose) 3132*c1b3d7c5SThomas E. Spanjaard device_printf(parent, "%s read metadata failed\n", 3133*c1b3d7c5SThomas E. Spanjaard native ? "FreeBSD" : "Promise"); 3134*c1b3d7c5SThomas E. Spanjaard goto promise_out; 3135*c1b3d7c5SThomas E. Spanjaard } 3136*c1b3d7c5SThomas E. Spanjaard 3137*c1b3d7c5SThomas E. Spanjaard /* check the signature */ 3138*c1b3d7c5SThomas E. Spanjaard if (native) { 3139*c1b3d7c5SThomas E. Spanjaard if (strncmp(meta->promise_id, ATA_MAGIC, strlen(ATA_MAGIC))) { 3140*c1b3d7c5SThomas E. Spanjaard if (testing || bootverbose) 3141*c1b3d7c5SThomas E. Spanjaard device_printf(parent, "FreeBSD check1 failed\n"); 3142*c1b3d7c5SThomas E. Spanjaard goto promise_out; 3143*c1b3d7c5SThomas E. Spanjaard } 3144*c1b3d7c5SThomas E. Spanjaard } 3145*c1b3d7c5SThomas E. Spanjaard else { 3146*c1b3d7c5SThomas E. Spanjaard if (strncmp(meta->promise_id, PR_MAGIC, strlen(PR_MAGIC))) { 3147*c1b3d7c5SThomas E. Spanjaard if (testing || bootverbose) 3148*c1b3d7c5SThomas E. Spanjaard device_printf(parent, "Promise check1 failed\n"); 3149*c1b3d7c5SThomas E. Spanjaard goto promise_out; 3150*c1b3d7c5SThomas E. Spanjaard } 3151*c1b3d7c5SThomas E. Spanjaard } 3152*c1b3d7c5SThomas E. Spanjaard 3153*c1b3d7c5SThomas E. Spanjaard /* check if the checksum is OK */ 3154*c1b3d7c5SThomas E. Spanjaard for (checksum = 0, ptr = (u_int32_t *)meta, count = 0; count < 511; count++) 3155*c1b3d7c5SThomas E. Spanjaard checksum += *ptr++; 3156*c1b3d7c5SThomas E. Spanjaard if (checksum != *ptr) { 3157*c1b3d7c5SThomas E. Spanjaard if (testing || bootverbose) 3158*c1b3d7c5SThomas E. Spanjaard device_printf(parent, "%s check2 failed\n", 3159*c1b3d7c5SThomas E. Spanjaard native ? "FreeBSD" : "Promise"); 3160*c1b3d7c5SThomas E. Spanjaard goto promise_out; 3161*c1b3d7c5SThomas E. Spanjaard } 3162*c1b3d7c5SThomas E. Spanjaard 3163*c1b3d7c5SThomas E. Spanjaard /* check on disk integrity status */ 3164*c1b3d7c5SThomas E. Spanjaard if (meta->raid.integrity != PR_I_VALID) { 3165*c1b3d7c5SThomas E. Spanjaard if (testing || bootverbose) 3166*c1b3d7c5SThomas E. Spanjaard device_printf(parent, "%s check3 failed\n", 3167*c1b3d7c5SThomas E. Spanjaard native ? "FreeBSD" : "Promise"); 3168*c1b3d7c5SThomas E. Spanjaard goto promise_out; 3169*c1b3d7c5SThomas E. Spanjaard } 3170*c1b3d7c5SThomas E. Spanjaard 3171*c1b3d7c5SThomas E. Spanjaard if (testing || bootverbose) 3172*c1b3d7c5SThomas E. Spanjaard ata_raid_promise_print_meta(meta); 3173*c1b3d7c5SThomas E. Spanjaard 3174*c1b3d7c5SThomas E. Spanjaard /* now convert Promise metadata into our generic form */ 3175*c1b3d7c5SThomas E. Spanjaard for (array = 0; array < MAX_ARRAYS; array++) { 3176*c1b3d7c5SThomas E. Spanjaard if (!raidp[array]) { 3177*c1b3d7c5SThomas E. Spanjaard raidp[array] = 3178*c1b3d7c5SThomas E. Spanjaard (struct ar_softc *)malloc(sizeof(struct ar_softc), M_AR, 3179*c1b3d7c5SThomas E. Spanjaard M_NOWAIT | M_ZERO); 3180*c1b3d7c5SThomas E. Spanjaard if (!raidp[array]) { 3181*c1b3d7c5SThomas E. Spanjaard device_printf(parent, "failed to allocate metadata storage\n"); 3182*c1b3d7c5SThomas E. Spanjaard goto promise_out; 3183*c1b3d7c5SThomas E. Spanjaard } 3184*c1b3d7c5SThomas E. Spanjaard } 3185*c1b3d7c5SThomas E. Spanjaard raid = raidp[array]; 3186*c1b3d7c5SThomas E. Spanjaard if (raid->format && 3187*c1b3d7c5SThomas E. Spanjaard (raid->format != (native ? AR_F_FREEBSD_RAID : AR_F_PROMISE_RAID))) 3188*c1b3d7c5SThomas E. Spanjaard continue; 3189*c1b3d7c5SThomas E. Spanjaard 3190*c1b3d7c5SThomas E. Spanjaard if ((raid->format == (native ? AR_F_FREEBSD_RAID : AR_F_PROMISE_RAID))&& 3191*c1b3d7c5SThomas E. Spanjaard !(meta->raid.magic_1 == (raid->magic_1))) 3192*c1b3d7c5SThomas E. Spanjaard continue; 3193*c1b3d7c5SThomas E. Spanjaard 3194*c1b3d7c5SThomas E. Spanjaard /* update our knowledge about the array config based on generation */ 3195*c1b3d7c5SThomas E. Spanjaard if (!meta->raid.generation || meta->raid.generation > raid->generation){ 3196*c1b3d7c5SThomas E. Spanjaard switch (meta->raid.type) { 3197*c1b3d7c5SThomas E. Spanjaard case PR_T_SPAN: 3198*c1b3d7c5SThomas E. Spanjaard raid->type = AR_T_SPAN; 3199*c1b3d7c5SThomas E. Spanjaard break; 3200*c1b3d7c5SThomas E. Spanjaard 3201*c1b3d7c5SThomas E. Spanjaard case PR_T_JBOD: 3202*c1b3d7c5SThomas E. Spanjaard raid->type = AR_T_JBOD; 3203*c1b3d7c5SThomas E. Spanjaard break; 3204*c1b3d7c5SThomas E. Spanjaard 3205*c1b3d7c5SThomas E. Spanjaard case PR_T_RAID0: 3206*c1b3d7c5SThomas E. Spanjaard raid->type = AR_T_RAID0; 3207*c1b3d7c5SThomas E. Spanjaard break; 3208*c1b3d7c5SThomas E. Spanjaard 3209*c1b3d7c5SThomas E. Spanjaard case PR_T_RAID1: 3210*c1b3d7c5SThomas E. Spanjaard raid->type = AR_T_RAID1; 3211*c1b3d7c5SThomas E. Spanjaard if (meta->raid.array_width > 1) 3212*c1b3d7c5SThomas E. Spanjaard raid->type = AR_T_RAID01; 3213*c1b3d7c5SThomas E. Spanjaard break; 3214*c1b3d7c5SThomas E. Spanjaard 3215*c1b3d7c5SThomas E. Spanjaard case PR_T_RAID5: 3216*c1b3d7c5SThomas E. Spanjaard raid->type = AR_T_RAID5; 3217*c1b3d7c5SThomas E. Spanjaard break; 3218*c1b3d7c5SThomas E. Spanjaard 3219*c1b3d7c5SThomas E. Spanjaard default: 3220*c1b3d7c5SThomas E. Spanjaard device_printf(parent, "%s unknown RAID type 0x%02x\n", 3221*c1b3d7c5SThomas E. Spanjaard native ? "FreeBSD" : "Promise", meta->raid.type); 3222*c1b3d7c5SThomas E. Spanjaard free(raidp[array], M_AR); 3223*c1b3d7c5SThomas E. Spanjaard raidp[array] = NULL; 3224*c1b3d7c5SThomas E. Spanjaard goto promise_out; 3225*c1b3d7c5SThomas E. Spanjaard } 3226*c1b3d7c5SThomas E. Spanjaard raid->magic_1 = meta->raid.magic_1; 3227*c1b3d7c5SThomas E. Spanjaard raid->format = (native ? AR_F_FREEBSD_RAID : AR_F_PROMISE_RAID); 3228*c1b3d7c5SThomas E. Spanjaard raid->generation = meta->raid.generation; 3229*c1b3d7c5SThomas E. Spanjaard raid->interleave = 1 << meta->raid.stripe_shift; 3230*c1b3d7c5SThomas E. Spanjaard raid->width = meta->raid.array_width; 3231*c1b3d7c5SThomas E. Spanjaard raid->total_disks = meta->raid.total_disks; 3232*c1b3d7c5SThomas E. Spanjaard raid->heads = meta->raid.heads + 1; 3233*c1b3d7c5SThomas E. Spanjaard raid->sectors = meta->raid.sectors; 3234*c1b3d7c5SThomas E. Spanjaard raid->cylinders = meta->raid.cylinders + 1; 3235*c1b3d7c5SThomas E. Spanjaard raid->total_sectors = meta->raid.total_sectors; 3236*c1b3d7c5SThomas E. Spanjaard raid->offset_sectors = 0; 3237*c1b3d7c5SThomas E. Spanjaard raid->rebuild_lba = meta->raid.rebuild_lba; 3238*c1b3d7c5SThomas E. Spanjaard raid->lun = array; 3239*c1b3d7c5SThomas E. Spanjaard if ((meta->raid.status & 3240*c1b3d7c5SThomas E. Spanjaard (PR_S_VALID | PR_S_ONLINE | PR_S_INITED | PR_S_READY)) == 3241*c1b3d7c5SThomas E. Spanjaard (PR_S_VALID | PR_S_ONLINE | PR_S_INITED | PR_S_READY)) { 3242*c1b3d7c5SThomas E. Spanjaard raid->status |= AR_S_READY; 3243*c1b3d7c5SThomas E. Spanjaard if (meta->raid.status & PR_S_DEGRADED) 3244*c1b3d7c5SThomas E. Spanjaard raid->status |= AR_S_DEGRADED; 3245*c1b3d7c5SThomas E. Spanjaard } 3246*c1b3d7c5SThomas E. Spanjaard else 3247*c1b3d7c5SThomas E. Spanjaard raid->status &= ~AR_S_READY; 3248*c1b3d7c5SThomas E. Spanjaard 3249*c1b3d7c5SThomas E. Spanjaard /* convert disk flags to our internal types */ 3250*c1b3d7c5SThomas E. Spanjaard for (disk = 0; disk < meta->raid.total_disks; disk++) { 3251*c1b3d7c5SThomas E. Spanjaard raid->disks[disk].dev = NULL; 3252*c1b3d7c5SThomas E. Spanjaard raid->disks[disk].flags = 0; 3253*c1b3d7c5SThomas E. Spanjaard *((u_int64_t *)(raid->disks[disk].serial)) = 3254*c1b3d7c5SThomas E. Spanjaard meta->raid.disk[disk].magic_0; 3255*c1b3d7c5SThomas E. Spanjaard disksum += meta->raid.disk[disk].flags; 3256*c1b3d7c5SThomas E. Spanjaard if (meta->raid.disk[disk].flags & PR_F_ONLINE) 3257*c1b3d7c5SThomas E. Spanjaard raid->disks[disk].flags |= AR_DF_ONLINE; 3258*c1b3d7c5SThomas E. Spanjaard if (meta->raid.disk[disk].flags & PR_F_ASSIGNED) 3259*c1b3d7c5SThomas E. Spanjaard raid->disks[disk].flags |= AR_DF_ASSIGNED; 3260*c1b3d7c5SThomas E. Spanjaard if (meta->raid.disk[disk].flags & PR_F_SPARE) { 3261*c1b3d7c5SThomas E. Spanjaard raid->disks[disk].flags &= ~(AR_DF_ONLINE | AR_DF_ASSIGNED); 3262*c1b3d7c5SThomas E. Spanjaard raid->disks[disk].flags |= AR_DF_SPARE; 3263*c1b3d7c5SThomas E. Spanjaard } 3264*c1b3d7c5SThomas E. Spanjaard if (meta->raid.disk[disk].flags & (PR_F_REDIR | PR_F_DOWN)) 3265*c1b3d7c5SThomas E. Spanjaard raid->disks[disk].flags &= ~AR_DF_ONLINE; 3266*c1b3d7c5SThomas E. Spanjaard } 3267*c1b3d7c5SThomas E. Spanjaard if (!disksum) { 3268*c1b3d7c5SThomas E. Spanjaard device_printf(parent, "%s subdisks has no flags\n", 3269*c1b3d7c5SThomas E. Spanjaard native ? "FreeBSD" : "Promise"); 3270*c1b3d7c5SThomas E. Spanjaard free(raidp[array], M_AR); 3271*c1b3d7c5SThomas E. Spanjaard raidp[array] = NULL; 3272*c1b3d7c5SThomas E. Spanjaard goto promise_out; 3273*c1b3d7c5SThomas E. Spanjaard } 3274*c1b3d7c5SThomas E. Spanjaard } 3275*c1b3d7c5SThomas E. Spanjaard if (meta->raid.generation >= raid->generation) { 3276*c1b3d7c5SThomas E. Spanjaard int disk_number = meta->raid.disk_number; 3277*c1b3d7c5SThomas E. Spanjaard 3278*c1b3d7c5SThomas E. Spanjaard if (raid->disks[disk_number].flags && (meta->magic_0 == 3279*c1b3d7c5SThomas E. Spanjaard *((u_int64_t *)(raid->disks[disk_number].serial)))) { 3280*c1b3d7c5SThomas E. Spanjaard raid->disks[disk_number].dev = parent; 3281*c1b3d7c5SThomas E. Spanjaard raid->disks[disk_number].flags |= AR_DF_PRESENT; 3282*c1b3d7c5SThomas E. Spanjaard raid->disks[disk_number].sectors = meta->raid.disk_sectors; 3283*c1b3d7c5SThomas E. Spanjaard if ((raid->disks[disk_number].flags & 3284*c1b3d7c5SThomas E. Spanjaard (AR_DF_PRESENT | AR_DF_ASSIGNED | AR_DF_ONLINE)) == 3285*c1b3d7c5SThomas E. Spanjaard (AR_DF_PRESENT | AR_DF_ASSIGNED | AR_DF_ONLINE)) { 3286*c1b3d7c5SThomas E. Spanjaard ars->raid[raid->volume] = raid; 3287*c1b3d7c5SThomas E. Spanjaard ars->disk_number[raid->volume] = disk_number; 3288*c1b3d7c5SThomas E. Spanjaard retval = 1; 3289*c1b3d7c5SThomas E. Spanjaard } 3290*c1b3d7c5SThomas E. Spanjaard } 3291*c1b3d7c5SThomas E. Spanjaard } 3292*c1b3d7c5SThomas E. Spanjaard break; 3293*c1b3d7c5SThomas E. Spanjaard } 3294*c1b3d7c5SThomas E. Spanjaard 3295*c1b3d7c5SThomas E. Spanjaard promise_out: 3296*c1b3d7c5SThomas E. Spanjaard free(meta, M_AR); 3297*c1b3d7c5SThomas E. Spanjaard return retval; 3298*c1b3d7c5SThomas E. Spanjaard } 3299*c1b3d7c5SThomas E. Spanjaard 3300*c1b3d7c5SThomas E. Spanjaard static int 3301*c1b3d7c5SThomas E. Spanjaard ata_raid_promise_write_meta(struct ar_softc *rdp) 3302*c1b3d7c5SThomas E. Spanjaard { 3303*c1b3d7c5SThomas E. Spanjaard struct promise_raid_conf *meta; 3304*c1b3d7c5SThomas E. Spanjaard struct timeval timestamp; 3305*c1b3d7c5SThomas E. Spanjaard u_int32_t *ckptr; 3306*c1b3d7c5SThomas E. Spanjaard int count, disk, drive, error = 0; 3307*c1b3d7c5SThomas E. Spanjaard 3308*c1b3d7c5SThomas E. Spanjaard if (!(meta = (struct promise_raid_conf *) 3309*c1b3d7c5SThomas E. Spanjaard malloc(sizeof(struct promise_raid_conf), M_AR, M_NOWAIT))) { 3310*c1b3d7c5SThomas E. Spanjaard printf("ar%d: failed to allocate metadata storage\n", rdp->lun); 3311*c1b3d7c5SThomas E. Spanjaard return ENOMEM; 3312*c1b3d7c5SThomas E. Spanjaard } 3313*c1b3d7c5SThomas E. Spanjaard 3314*c1b3d7c5SThomas E. Spanjaard rdp->generation++; 3315*c1b3d7c5SThomas E. Spanjaard microtime(×tamp); 3316*c1b3d7c5SThomas E. Spanjaard 3317*c1b3d7c5SThomas E. Spanjaard for (disk = 0; disk < rdp->total_disks; disk++) { 3318*c1b3d7c5SThomas E. Spanjaard for (count = 0; count < sizeof(struct promise_raid_conf); count++) 3319*c1b3d7c5SThomas E. Spanjaard *(((u_int8_t *)meta) + count) = 255 - (count % 256); 3320*c1b3d7c5SThomas E. Spanjaard meta->dummy_0 = 0x00020000; 3321*c1b3d7c5SThomas E. Spanjaard meta->raid.disk_number = disk; 3322*c1b3d7c5SThomas E. Spanjaard 3323*c1b3d7c5SThomas E. Spanjaard if (rdp->disks[disk].dev) { 3324*c1b3d7c5SThomas E. Spanjaard struct ata_device *atadev = device_get_softc(rdp->disks[disk].dev); 3325*c1b3d7c5SThomas E. Spanjaard struct ata_channel *ch = 3326*c1b3d7c5SThomas E. Spanjaard device_get_softc(device_get_parent(rdp->disks[disk].dev)); 3327*c1b3d7c5SThomas E. Spanjaard 3328*c1b3d7c5SThomas E. Spanjaard meta->raid.channel = ch->unit; 3329*c1b3d7c5SThomas E. Spanjaard meta->raid.device = ATA_DEV(atadev->unit); 3330*c1b3d7c5SThomas E. Spanjaard meta->raid.disk_sectors = rdp->disks[disk].sectors; 3331*c1b3d7c5SThomas E. Spanjaard meta->raid.disk_offset = rdp->offset_sectors; 3332*c1b3d7c5SThomas E. Spanjaard } 3333*c1b3d7c5SThomas E. Spanjaard else { 3334*c1b3d7c5SThomas E. Spanjaard meta->raid.channel = 0; 3335*c1b3d7c5SThomas E. Spanjaard meta->raid.device = 0; 3336*c1b3d7c5SThomas E. Spanjaard meta->raid.disk_sectors = 0; 3337*c1b3d7c5SThomas E. Spanjaard meta->raid.disk_offset = 0; 3338*c1b3d7c5SThomas E. Spanjaard } 3339*c1b3d7c5SThomas E. Spanjaard meta->magic_0 = PR_MAGIC0(meta->raid) | timestamp.tv_sec; 3340*c1b3d7c5SThomas E. Spanjaard meta->magic_1 = timestamp.tv_sec >> 16; 3341*c1b3d7c5SThomas E. Spanjaard meta->magic_2 = timestamp.tv_sec; 3342*c1b3d7c5SThomas E. Spanjaard meta->raid.integrity = PR_I_VALID; 3343*c1b3d7c5SThomas E. Spanjaard meta->raid.magic_0 = meta->magic_0; 3344*c1b3d7c5SThomas E. Spanjaard meta->raid.rebuild_lba = rdp->rebuild_lba; 3345*c1b3d7c5SThomas E. Spanjaard meta->raid.generation = rdp->generation; 3346*c1b3d7c5SThomas E. Spanjaard 3347*c1b3d7c5SThomas E. Spanjaard if (rdp->status & AR_S_READY) { 3348*c1b3d7c5SThomas E. Spanjaard meta->raid.flags = (PR_F_VALID | PR_F_ASSIGNED | PR_F_ONLINE); 3349*c1b3d7c5SThomas E. Spanjaard meta->raid.status = 3350*c1b3d7c5SThomas E. Spanjaard (PR_S_VALID | PR_S_ONLINE | PR_S_INITED | PR_S_READY); 3351*c1b3d7c5SThomas E. Spanjaard if (rdp->status & AR_S_DEGRADED) 3352*c1b3d7c5SThomas E. Spanjaard meta->raid.status |= PR_S_DEGRADED; 3353*c1b3d7c5SThomas E. Spanjaard else 3354*c1b3d7c5SThomas E. Spanjaard meta->raid.status |= PR_S_FUNCTIONAL; 3355*c1b3d7c5SThomas E. Spanjaard } 3356*c1b3d7c5SThomas E. Spanjaard else { 3357*c1b3d7c5SThomas E. Spanjaard meta->raid.flags = PR_F_DOWN; 3358*c1b3d7c5SThomas E. Spanjaard meta->raid.status = 0; 3359*c1b3d7c5SThomas E. Spanjaard } 3360*c1b3d7c5SThomas E. Spanjaard 3361*c1b3d7c5SThomas E. Spanjaard switch (rdp->type) { 3362*c1b3d7c5SThomas E. Spanjaard case AR_T_RAID0: 3363*c1b3d7c5SThomas E. Spanjaard meta->raid.type = PR_T_RAID0; 3364*c1b3d7c5SThomas E. Spanjaard break; 3365*c1b3d7c5SThomas E. Spanjaard case AR_T_RAID1: 3366*c1b3d7c5SThomas E. Spanjaard meta->raid.type = PR_T_RAID1; 3367*c1b3d7c5SThomas E. Spanjaard break; 3368*c1b3d7c5SThomas E. Spanjaard case AR_T_RAID01: 3369*c1b3d7c5SThomas E. Spanjaard meta->raid.type = PR_T_RAID1; 3370*c1b3d7c5SThomas E. Spanjaard break; 3371*c1b3d7c5SThomas E. Spanjaard case AR_T_RAID5: 3372*c1b3d7c5SThomas E. Spanjaard meta->raid.type = PR_T_RAID5; 3373*c1b3d7c5SThomas E. Spanjaard break; 3374*c1b3d7c5SThomas E. Spanjaard case AR_T_SPAN: 3375*c1b3d7c5SThomas E. Spanjaard meta->raid.type = PR_T_SPAN; 3376*c1b3d7c5SThomas E. Spanjaard break; 3377*c1b3d7c5SThomas E. Spanjaard case AR_T_JBOD: 3378*c1b3d7c5SThomas E. Spanjaard meta->raid.type = PR_T_JBOD; 3379*c1b3d7c5SThomas E. Spanjaard break; 3380*c1b3d7c5SThomas E. Spanjaard default: 3381*c1b3d7c5SThomas E. Spanjaard free(meta, M_AR); 3382*c1b3d7c5SThomas E. Spanjaard return ENODEV; 3383*c1b3d7c5SThomas E. Spanjaard } 3384*c1b3d7c5SThomas E. Spanjaard 3385*c1b3d7c5SThomas E. Spanjaard meta->raid.total_disks = rdp->total_disks; 3386*c1b3d7c5SThomas E. Spanjaard meta->raid.stripe_shift = ffs(rdp->interleave) - 1; 3387*c1b3d7c5SThomas E. Spanjaard meta->raid.array_width = rdp->width; 3388*c1b3d7c5SThomas E. Spanjaard meta->raid.array_number = rdp->lun; 3389*c1b3d7c5SThomas E. Spanjaard meta->raid.total_sectors = rdp->total_sectors; 3390*c1b3d7c5SThomas E. Spanjaard meta->raid.cylinders = rdp->cylinders - 1; 3391*c1b3d7c5SThomas E. Spanjaard meta->raid.heads = rdp->heads - 1; 3392*c1b3d7c5SThomas E. Spanjaard meta->raid.sectors = rdp->sectors; 3393*c1b3d7c5SThomas E. Spanjaard meta->raid.magic_1 = (u_int64_t)meta->magic_2<<16 | meta->magic_1; 3394*c1b3d7c5SThomas E. Spanjaard 3395*c1b3d7c5SThomas E. Spanjaard bzero(&meta->raid.disk, 8 * 12); 3396*c1b3d7c5SThomas E. Spanjaard for (drive = 0; drive < rdp->total_disks; drive++) { 3397*c1b3d7c5SThomas E. Spanjaard meta->raid.disk[drive].flags = 0; 3398*c1b3d7c5SThomas E. Spanjaard if (rdp->disks[drive].flags & AR_DF_PRESENT) 3399*c1b3d7c5SThomas E. Spanjaard meta->raid.disk[drive].flags |= PR_F_VALID; 3400*c1b3d7c5SThomas E. Spanjaard if (rdp->disks[drive].flags & AR_DF_ASSIGNED) 3401*c1b3d7c5SThomas E. Spanjaard meta->raid.disk[drive].flags |= PR_F_ASSIGNED; 3402*c1b3d7c5SThomas E. Spanjaard if (rdp->disks[drive].flags & AR_DF_ONLINE) 3403*c1b3d7c5SThomas E. Spanjaard meta->raid.disk[drive].flags |= PR_F_ONLINE; 3404*c1b3d7c5SThomas E. Spanjaard else 3405*c1b3d7c5SThomas E. Spanjaard if (rdp->disks[drive].flags & AR_DF_PRESENT) 3406*c1b3d7c5SThomas E. Spanjaard meta->raid.disk[drive].flags = (PR_F_REDIR | PR_F_DOWN); 3407*c1b3d7c5SThomas E. Spanjaard if (rdp->disks[drive].flags & AR_DF_SPARE) 3408*c1b3d7c5SThomas E. Spanjaard meta->raid.disk[drive].flags |= PR_F_SPARE; 3409*c1b3d7c5SThomas E. Spanjaard meta->raid.disk[drive].dummy_0 = 0x0; 3410*c1b3d7c5SThomas E. Spanjaard if (rdp->disks[drive].dev) { 3411*c1b3d7c5SThomas E. Spanjaard struct ata_channel *ch = 3412*c1b3d7c5SThomas E. Spanjaard device_get_softc(device_get_parent(rdp->disks[drive].dev)); 3413*c1b3d7c5SThomas E. Spanjaard struct ata_device *atadev = 3414*c1b3d7c5SThomas E. Spanjaard device_get_softc(rdp->disks[drive].dev); 3415*c1b3d7c5SThomas E. Spanjaard 3416*c1b3d7c5SThomas E. Spanjaard meta->raid.disk[drive].channel = ch->unit; 3417*c1b3d7c5SThomas E. Spanjaard meta->raid.disk[drive].device = ATA_DEV(atadev->unit); 3418*c1b3d7c5SThomas E. Spanjaard } 3419*c1b3d7c5SThomas E. Spanjaard meta->raid.disk[drive].magic_0 = 3420*c1b3d7c5SThomas E. Spanjaard PR_MAGIC0(meta->raid.disk[drive]) | timestamp.tv_sec; 3421*c1b3d7c5SThomas E. Spanjaard } 3422*c1b3d7c5SThomas E. Spanjaard 3423*c1b3d7c5SThomas E. Spanjaard if (rdp->disks[disk].dev) { 3424*c1b3d7c5SThomas E. Spanjaard if ((rdp->disks[disk].flags & (AR_DF_PRESENT | AR_DF_ONLINE)) == 3425*c1b3d7c5SThomas E. Spanjaard (AR_DF_PRESENT | AR_DF_ONLINE)) { 3426*c1b3d7c5SThomas E. Spanjaard if (rdp->format == AR_F_FREEBSD_RAID) 3427*c1b3d7c5SThomas E. Spanjaard bcopy(ATA_MAGIC, meta->promise_id, sizeof(ATA_MAGIC)); 3428*c1b3d7c5SThomas E. Spanjaard else 3429*c1b3d7c5SThomas E. Spanjaard bcopy(PR_MAGIC, meta->promise_id, sizeof(PR_MAGIC)); 3430*c1b3d7c5SThomas E. Spanjaard } 3431*c1b3d7c5SThomas E. Spanjaard else 3432*c1b3d7c5SThomas E. Spanjaard bzero(meta->promise_id, sizeof(meta->promise_id)); 3433*c1b3d7c5SThomas E. Spanjaard meta->checksum = 0; 3434*c1b3d7c5SThomas E. Spanjaard for (ckptr = (int32_t *)meta, count = 0; count < 511; count++) 3435*c1b3d7c5SThomas E. Spanjaard meta->checksum += *ckptr++; 3436*c1b3d7c5SThomas E. Spanjaard if (testing || bootverbose) 3437*c1b3d7c5SThomas E. Spanjaard ata_raid_promise_print_meta(meta); 3438*c1b3d7c5SThomas E. Spanjaard if (ata_raid_rw(rdp->disks[disk].dev, 3439*c1b3d7c5SThomas E. Spanjaard PROMISE_LBA(rdp->disks[disk].dev), 3440*c1b3d7c5SThomas E. Spanjaard meta, sizeof(struct promise_raid_conf), 3441*c1b3d7c5SThomas E. Spanjaard ATA_R_WRITE | ATA_R_DIRECT)) { 3442*c1b3d7c5SThomas E. Spanjaard device_printf(rdp->disks[disk].dev, "write metadata failed\n"); 3443*c1b3d7c5SThomas E. Spanjaard error = EIO; 3444*c1b3d7c5SThomas E. Spanjaard } 3445*c1b3d7c5SThomas E. Spanjaard } 3446*c1b3d7c5SThomas E. Spanjaard } 3447*c1b3d7c5SThomas E. Spanjaard free(meta, M_AR); 3448*c1b3d7c5SThomas E. Spanjaard return error; 3449*c1b3d7c5SThomas E. Spanjaard } 3450*c1b3d7c5SThomas E. Spanjaard 3451*c1b3d7c5SThomas E. Spanjaard /* Silicon Image Medley Metadata */ 3452*c1b3d7c5SThomas E. Spanjaard static int 3453*c1b3d7c5SThomas E. Spanjaard ata_raid_sii_read_meta(device_t dev, struct ar_softc **raidp) 3454*c1b3d7c5SThomas E. Spanjaard { 3455*c1b3d7c5SThomas E. Spanjaard struct ata_raid_subdisk *ars = device_get_softc(dev); 3456*c1b3d7c5SThomas E. Spanjaard device_t parent = device_get_parent(dev); 3457*c1b3d7c5SThomas E. Spanjaard struct sii_raid_conf *meta; 3458*c1b3d7c5SThomas E. Spanjaard struct ar_softc *raid = NULL; 3459*c1b3d7c5SThomas E. Spanjaard u_int16_t checksum, *ptr; 3460*c1b3d7c5SThomas E. Spanjaard int array, count, disk, retval = 0; 3461*c1b3d7c5SThomas E. Spanjaard 3462*c1b3d7c5SThomas E. Spanjaard if (!(meta = (struct sii_raid_conf *) 3463*c1b3d7c5SThomas E. Spanjaard malloc(sizeof(struct sii_raid_conf), M_AR, M_NOWAIT | M_ZERO))) 3464*c1b3d7c5SThomas E. Spanjaard return ENOMEM; 3465*c1b3d7c5SThomas E. Spanjaard 3466*c1b3d7c5SThomas E. Spanjaard if (ata_raid_rw(parent, SII_LBA(parent), 3467*c1b3d7c5SThomas E. Spanjaard meta, sizeof(struct sii_raid_conf), ATA_R_READ)) { 3468*c1b3d7c5SThomas E. Spanjaard if (testing || bootverbose) 3469*c1b3d7c5SThomas E. Spanjaard device_printf(parent, "Silicon Image read metadata failed\n"); 3470*c1b3d7c5SThomas E. Spanjaard goto sii_out; 3471*c1b3d7c5SThomas E. Spanjaard } 3472*c1b3d7c5SThomas E. Spanjaard 3473*c1b3d7c5SThomas E. Spanjaard /* check if this is a Silicon Image (Medley) RAID struct */ 3474*c1b3d7c5SThomas E. Spanjaard for (checksum = 0, ptr = (u_int16_t *)meta, count = 0; count < 160; count++) 3475*c1b3d7c5SThomas E. Spanjaard checksum += *ptr++; 3476*c1b3d7c5SThomas E. Spanjaard if (checksum) { 3477*c1b3d7c5SThomas E. Spanjaard if (testing || bootverbose) 3478*c1b3d7c5SThomas E. Spanjaard device_printf(parent, "Silicon Image check1 failed\n"); 3479*c1b3d7c5SThomas E. Spanjaard goto sii_out; 3480*c1b3d7c5SThomas E. Spanjaard } 3481*c1b3d7c5SThomas E. Spanjaard 3482*c1b3d7c5SThomas E. Spanjaard for (checksum = 0, ptr = (u_int16_t *)meta, count = 0; count < 256; count++) 3483*c1b3d7c5SThomas E. Spanjaard checksum += *ptr++; 3484*c1b3d7c5SThomas E. Spanjaard if (checksum != meta->checksum_1) { 3485*c1b3d7c5SThomas E. Spanjaard if (testing || bootverbose) 3486*c1b3d7c5SThomas E. Spanjaard device_printf(parent, "Silicon Image check2 failed\n"); 3487*c1b3d7c5SThomas E. Spanjaard goto sii_out; 3488*c1b3d7c5SThomas E. Spanjaard } 3489*c1b3d7c5SThomas E. Spanjaard 3490*c1b3d7c5SThomas E. Spanjaard /* check verison */ 3491*c1b3d7c5SThomas E. Spanjaard if (meta->version_major != 0x0002 || 3492*c1b3d7c5SThomas E. Spanjaard (meta->version_minor != 0x0000 && meta->version_minor != 0x0001)) { 3493*c1b3d7c5SThomas E. Spanjaard if (testing || bootverbose) 3494*c1b3d7c5SThomas E. Spanjaard device_printf(parent, "Silicon Image check3 failed\n"); 3495*c1b3d7c5SThomas E. Spanjaard goto sii_out; 3496*c1b3d7c5SThomas E. Spanjaard } 3497*c1b3d7c5SThomas E. Spanjaard 3498*c1b3d7c5SThomas E. Spanjaard if (testing || bootverbose) 3499*c1b3d7c5SThomas E. Spanjaard ata_raid_sii_print_meta(meta); 3500*c1b3d7c5SThomas E. Spanjaard 3501*c1b3d7c5SThomas E. Spanjaard /* now convert Silicon Image meta into our generic form */ 3502*c1b3d7c5SThomas E. Spanjaard for (array = 0; array < MAX_ARRAYS; array++) { 3503*c1b3d7c5SThomas E. Spanjaard if (!raidp[array]) { 3504*c1b3d7c5SThomas E. Spanjaard raidp[array] = 3505*c1b3d7c5SThomas E. Spanjaard (struct ar_softc *)malloc(sizeof(struct ar_softc), M_AR, 3506*c1b3d7c5SThomas E. Spanjaard M_NOWAIT | M_ZERO); 3507*c1b3d7c5SThomas E. Spanjaard if (!raidp[array]) { 3508*c1b3d7c5SThomas E. Spanjaard device_printf(parent, "failed to allocate metadata storage\n"); 3509*c1b3d7c5SThomas E. Spanjaard goto sii_out; 3510*c1b3d7c5SThomas E. Spanjaard } 3511*c1b3d7c5SThomas E. Spanjaard } 3512*c1b3d7c5SThomas E. Spanjaard raid = raidp[array]; 3513*c1b3d7c5SThomas E. Spanjaard if (raid->format && (raid->format != AR_F_SII_RAID)) 3514*c1b3d7c5SThomas E. Spanjaard continue; 3515*c1b3d7c5SThomas E. Spanjaard 3516*c1b3d7c5SThomas E. Spanjaard if (raid->format == AR_F_SII_RAID && 3517*c1b3d7c5SThomas E. Spanjaard (raid->magic_0 != *((u_int64_t *)meta->timestamp))) { 3518*c1b3d7c5SThomas E. Spanjaard continue; 3519*c1b3d7c5SThomas E. Spanjaard } 3520*c1b3d7c5SThomas E. Spanjaard 3521*c1b3d7c5SThomas E. Spanjaard /* update our knowledge about the array config based on generation */ 3522*c1b3d7c5SThomas E. Spanjaard if (!meta->generation || meta->generation > raid->generation) { 3523*c1b3d7c5SThomas E. Spanjaard switch (meta->type) { 3524*c1b3d7c5SThomas E. Spanjaard case SII_T_RAID0: 3525*c1b3d7c5SThomas E. Spanjaard raid->type = AR_T_RAID0; 3526*c1b3d7c5SThomas E. Spanjaard break; 3527*c1b3d7c5SThomas E. Spanjaard 3528*c1b3d7c5SThomas E. Spanjaard case SII_T_RAID1: 3529*c1b3d7c5SThomas E. Spanjaard raid->type = AR_T_RAID1; 3530*c1b3d7c5SThomas E. Spanjaard break; 3531*c1b3d7c5SThomas E. Spanjaard 3532*c1b3d7c5SThomas E. Spanjaard case SII_T_RAID01: 3533*c1b3d7c5SThomas E. Spanjaard raid->type = AR_T_RAID01; 3534*c1b3d7c5SThomas E. Spanjaard break; 3535*c1b3d7c5SThomas E. Spanjaard 3536*c1b3d7c5SThomas E. Spanjaard case SII_T_SPARE: 3537*c1b3d7c5SThomas E. Spanjaard device_printf(parent, "Silicon Image SPARE disk\n"); 3538*c1b3d7c5SThomas E. Spanjaard free(raidp[array], M_AR); 3539*c1b3d7c5SThomas E. Spanjaard raidp[array] = NULL; 3540*c1b3d7c5SThomas E. Spanjaard goto sii_out; 3541*c1b3d7c5SThomas E. Spanjaard 3542*c1b3d7c5SThomas E. Spanjaard default: 3543*c1b3d7c5SThomas E. Spanjaard device_printf(parent,"Silicon Image unknown RAID type 0x%02x\n", 3544*c1b3d7c5SThomas E. Spanjaard meta->type); 3545*c1b3d7c5SThomas E. Spanjaard free(raidp[array], M_AR); 3546*c1b3d7c5SThomas E. Spanjaard raidp[array] = NULL; 3547*c1b3d7c5SThomas E. Spanjaard goto sii_out; 3548*c1b3d7c5SThomas E. Spanjaard } 3549*c1b3d7c5SThomas E. Spanjaard raid->magic_0 = *((u_int64_t *)meta->timestamp); 3550*c1b3d7c5SThomas E. Spanjaard raid->format = AR_F_SII_RAID; 3551*c1b3d7c5SThomas E. Spanjaard raid->generation = meta->generation; 3552*c1b3d7c5SThomas E. Spanjaard raid->interleave = meta->stripe_sectors; 3553*c1b3d7c5SThomas E. Spanjaard raid->width = (meta->raid0_disks != 0xff) ? meta->raid0_disks : 1; 3554*c1b3d7c5SThomas E. Spanjaard raid->total_disks = 3555*c1b3d7c5SThomas E. Spanjaard ((meta->raid0_disks != 0xff) ? meta->raid0_disks : 0) + 3556*c1b3d7c5SThomas E. Spanjaard ((meta->raid1_disks != 0xff) ? meta->raid1_disks : 0); 3557*c1b3d7c5SThomas E. Spanjaard raid->total_sectors = meta->total_sectors; 3558*c1b3d7c5SThomas E. Spanjaard raid->heads = 255; 3559*c1b3d7c5SThomas E. Spanjaard raid->sectors = 63; 3560*c1b3d7c5SThomas E. Spanjaard raid->cylinders = raid->total_sectors / (63 * 255); 3561*c1b3d7c5SThomas E. Spanjaard raid->offset_sectors = 0; 3562*c1b3d7c5SThomas E. Spanjaard raid->rebuild_lba = meta->rebuild_lba; 3563*c1b3d7c5SThomas E. Spanjaard raid->lun = array; 3564*c1b3d7c5SThomas E. Spanjaard strncpy(raid->name, meta->name, 3565*c1b3d7c5SThomas E. Spanjaard min(sizeof(raid->name), sizeof(meta->name))); 3566*c1b3d7c5SThomas E. Spanjaard 3567*c1b3d7c5SThomas E. Spanjaard /* clear out any old info */ 3568*c1b3d7c5SThomas E. Spanjaard if (raid->generation) { 3569*c1b3d7c5SThomas E. Spanjaard for (disk = 0; disk < raid->total_disks; disk++) { 3570*c1b3d7c5SThomas E. Spanjaard raid->disks[disk].dev = NULL; 3571*c1b3d7c5SThomas E. Spanjaard raid->disks[disk].flags = 0; 3572*c1b3d7c5SThomas E. Spanjaard } 3573*c1b3d7c5SThomas E. Spanjaard } 3574*c1b3d7c5SThomas E. Spanjaard } 3575*c1b3d7c5SThomas E. Spanjaard if (meta->generation >= raid->generation) { 3576*c1b3d7c5SThomas E. Spanjaard /* XXX SOS add check for the right physical disk by serial# */ 3577*c1b3d7c5SThomas E. Spanjaard if (meta->status & SII_S_READY) { 3578*c1b3d7c5SThomas E. Spanjaard int disk_number = (raid->type == AR_T_RAID01) ? 3579*c1b3d7c5SThomas E. Spanjaard meta->raid1_ident + (meta->raid0_ident << 1) : 3580*c1b3d7c5SThomas E. Spanjaard meta->disk_number; 3581*c1b3d7c5SThomas E. Spanjaard 3582*c1b3d7c5SThomas E. Spanjaard raid->disks[disk_number].dev = parent; 3583*c1b3d7c5SThomas E. Spanjaard raid->disks[disk_number].sectors = 3584*c1b3d7c5SThomas E. Spanjaard raid->total_sectors / raid->width; 3585*c1b3d7c5SThomas E. Spanjaard raid->disks[disk_number].flags = 3586*c1b3d7c5SThomas E. Spanjaard (AR_DF_ONLINE | AR_DF_PRESENT | AR_DF_ASSIGNED); 3587*c1b3d7c5SThomas E. Spanjaard ars->raid[raid->volume] = raid; 3588*c1b3d7c5SThomas E. Spanjaard ars->disk_number[raid->volume] = disk_number; 3589*c1b3d7c5SThomas E. Spanjaard retval = 1; 3590*c1b3d7c5SThomas E. Spanjaard } 3591*c1b3d7c5SThomas E. Spanjaard } 3592*c1b3d7c5SThomas E. Spanjaard break; 3593*c1b3d7c5SThomas E. Spanjaard } 3594*c1b3d7c5SThomas E. Spanjaard 3595*c1b3d7c5SThomas E. Spanjaard sii_out: 3596*c1b3d7c5SThomas E. Spanjaard free(meta, M_AR); 3597*c1b3d7c5SThomas E. Spanjaard return retval; 3598*c1b3d7c5SThomas E. Spanjaard } 3599*c1b3d7c5SThomas E. Spanjaard 3600*c1b3d7c5SThomas E. Spanjaard /* Silicon Integrated Systems Metadata */ 3601*c1b3d7c5SThomas E. Spanjaard static int 3602*c1b3d7c5SThomas E. Spanjaard ata_raid_sis_read_meta(device_t dev, struct ar_softc **raidp) 3603*c1b3d7c5SThomas E. Spanjaard { 3604*c1b3d7c5SThomas E. Spanjaard struct ata_raid_subdisk *ars = device_get_softc(dev); 3605*c1b3d7c5SThomas E. Spanjaard device_t parent = device_get_parent(dev); 3606*c1b3d7c5SThomas E. Spanjaard struct sis_raid_conf *meta; 3607*c1b3d7c5SThomas E. Spanjaard struct ar_softc *raid = NULL; 3608*c1b3d7c5SThomas E. Spanjaard int array, disk_number, drive, retval = 0; 3609*c1b3d7c5SThomas E. Spanjaard 3610*c1b3d7c5SThomas E. Spanjaard if (!(meta = (struct sis_raid_conf *) 3611*c1b3d7c5SThomas E. Spanjaard malloc(sizeof(struct sis_raid_conf), M_AR, M_NOWAIT | M_ZERO))) 3612*c1b3d7c5SThomas E. Spanjaard return ENOMEM; 3613*c1b3d7c5SThomas E. Spanjaard 3614*c1b3d7c5SThomas E. Spanjaard if (ata_raid_rw(parent, SIS_LBA(parent), 3615*c1b3d7c5SThomas E. Spanjaard meta, sizeof(struct sis_raid_conf), ATA_R_READ)) { 3616*c1b3d7c5SThomas E. Spanjaard if (testing || bootverbose) 3617*c1b3d7c5SThomas E. Spanjaard device_printf(parent, 3618*c1b3d7c5SThomas E. Spanjaard "Silicon Integrated Systems read metadata failed\n"); 3619*c1b3d7c5SThomas E. Spanjaard } 3620*c1b3d7c5SThomas E. Spanjaard 3621*c1b3d7c5SThomas E. Spanjaard /* check for SiS magic */ 3622*c1b3d7c5SThomas E. Spanjaard if (meta->magic != SIS_MAGIC) { 3623*c1b3d7c5SThomas E. Spanjaard if (testing || bootverbose) 3624*c1b3d7c5SThomas E. Spanjaard device_printf(parent, 3625*c1b3d7c5SThomas E. Spanjaard "Silicon Integrated Systems check1 failed\n"); 3626*c1b3d7c5SThomas E. Spanjaard goto sis_out; 3627*c1b3d7c5SThomas E. Spanjaard } 3628*c1b3d7c5SThomas E. Spanjaard 3629*c1b3d7c5SThomas E. Spanjaard if (testing || bootverbose) 3630*c1b3d7c5SThomas E. Spanjaard ata_raid_sis_print_meta(meta); 3631*c1b3d7c5SThomas E. Spanjaard 3632*c1b3d7c5SThomas E. Spanjaard /* now convert SiS meta into our generic form */ 3633*c1b3d7c5SThomas E. Spanjaard for (array = 0; array < MAX_ARRAYS; array++) { 3634*c1b3d7c5SThomas E. Spanjaard if (!raidp[array]) { 3635*c1b3d7c5SThomas E. Spanjaard raidp[array] = 3636*c1b3d7c5SThomas E. Spanjaard (struct ar_softc *)malloc(sizeof(struct ar_softc), M_AR, 3637*c1b3d7c5SThomas E. Spanjaard M_NOWAIT | M_ZERO); 3638*c1b3d7c5SThomas E. Spanjaard if (!raidp[array]) { 3639*c1b3d7c5SThomas E. Spanjaard device_printf(parent, "failed to allocate metadata storage\n"); 3640*c1b3d7c5SThomas E. Spanjaard goto sis_out; 3641*c1b3d7c5SThomas E. Spanjaard } 3642*c1b3d7c5SThomas E. Spanjaard } 3643*c1b3d7c5SThomas E. Spanjaard 3644*c1b3d7c5SThomas E. Spanjaard raid = raidp[array]; 3645*c1b3d7c5SThomas E. Spanjaard if (raid->format && (raid->format != AR_F_SIS_RAID)) 3646*c1b3d7c5SThomas E. Spanjaard continue; 3647*c1b3d7c5SThomas E. Spanjaard 3648*c1b3d7c5SThomas E. Spanjaard if ((raid->format == AR_F_SIS_RAID) && 3649*c1b3d7c5SThomas E. Spanjaard ((raid->magic_0 != meta->controller_pci_id) || 3650*c1b3d7c5SThomas E. Spanjaard (raid->magic_1 != meta->timestamp))) { 3651*c1b3d7c5SThomas E. Spanjaard continue; 3652*c1b3d7c5SThomas E. Spanjaard } 3653*c1b3d7c5SThomas E. Spanjaard 3654*c1b3d7c5SThomas E. Spanjaard switch (meta->type_total_disks & SIS_T_MASK) { 3655*c1b3d7c5SThomas E. Spanjaard case SIS_T_JBOD: 3656*c1b3d7c5SThomas E. Spanjaard raid->type = AR_T_JBOD; 3657*c1b3d7c5SThomas E. Spanjaard raid->width = (meta->type_total_disks & SIS_D_MASK); 3658*c1b3d7c5SThomas E. Spanjaard raid->total_sectors += SIS_LBA(parent); 3659*c1b3d7c5SThomas E. Spanjaard break; 3660*c1b3d7c5SThomas E. Spanjaard 3661*c1b3d7c5SThomas E. Spanjaard case SIS_T_RAID0: 3662*c1b3d7c5SThomas E. Spanjaard raid->type = AR_T_RAID0; 3663*c1b3d7c5SThomas E. Spanjaard raid->width = (meta->type_total_disks & SIS_D_MASK); 3664*c1b3d7c5SThomas E. Spanjaard if (!raid->total_sectors || 3665*c1b3d7c5SThomas E. Spanjaard (raid->total_sectors > (raid->width * SIS_LBA(parent)))) 3666*c1b3d7c5SThomas E. Spanjaard raid->total_sectors = raid->width * SIS_LBA(parent); 3667*c1b3d7c5SThomas E. Spanjaard break; 3668*c1b3d7c5SThomas E. Spanjaard 3669*c1b3d7c5SThomas E. Spanjaard case SIS_T_RAID1: 3670*c1b3d7c5SThomas E. Spanjaard raid->type = AR_T_RAID1; 3671*c1b3d7c5SThomas E. Spanjaard raid->width = 1; 3672*c1b3d7c5SThomas E. Spanjaard if (!raid->total_sectors || (raid->total_sectors > SIS_LBA(parent))) 3673*c1b3d7c5SThomas E. Spanjaard raid->total_sectors = SIS_LBA(parent); 3674*c1b3d7c5SThomas E. Spanjaard break; 3675*c1b3d7c5SThomas E. Spanjaard 3676*c1b3d7c5SThomas E. Spanjaard default: 3677*c1b3d7c5SThomas E. Spanjaard device_printf(parent, "Silicon Integrated Systems " 3678*c1b3d7c5SThomas E. Spanjaard "unknown RAID type 0x%08x\n", meta->magic); 3679*c1b3d7c5SThomas E. Spanjaard free(raidp[array], M_AR); 3680*c1b3d7c5SThomas E. Spanjaard raidp[array] = NULL; 3681*c1b3d7c5SThomas E. Spanjaard goto sis_out; 3682*c1b3d7c5SThomas E. Spanjaard } 3683*c1b3d7c5SThomas E. Spanjaard raid->magic_0 = meta->controller_pci_id; 3684*c1b3d7c5SThomas E. Spanjaard raid->magic_1 = meta->timestamp; 3685*c1b3d7c5SThomas E. Spanjaard raid->format = AR_F_SIS_RAID; 3686*c1b3d7c5SThomas E. Spanjaard raid->generation = 0; 3687*c1b3d7c5SThomas E. Spanjaard raid->interleave = meta->stripe_sectors; 3688*c1b3d7c5SThomas E. Spanjaard raid->total_disks = (meta->type_total_disks & SIS_D_MASK); 3689*c1b3d7c5SThomas E. Spanjaard raid->heads = 255; 3690*c1b3d7c5SThomas E. Spanjaard raid->sectors = 63; 3691*c1b3d7c5SThomas E. Spanjaard raid->cylinders = raid->total_sectors / (63 * 255); 3692*c1b3d7c5SThomas E. Spanjaard raid->offset_sectors = 0; 3693*c1b3d7c5SThomas E. Spanjaard raid->rebuild_lba = 0; 3694*c1b3d7c5SThomas E. Spanjaard raid->lun = array; 3695*c1b3d7c5SThomas E. Spanjaard /* XXX SOS if total_disks > 2 this doesn't float */ 3696*c1b3d7c5SThomas E. Spanjaard if (((meta->disks & SIS_D_MASTER) >> 4) == meta->disk_number) 3697*c1b3d7c5SThomas E. Spanjaard disk_number = 0; 3698*c1b3d7c5SThomas E. Spanjaard else 3699*c1b3d7c5SThomas E. Spanjaard disk_number = 1; 3700*c1b3d7c5SThomas E. Spanjaard 3701*c1b3d7c5SThomas E. Spanjaard for (drive = 0; drive < raid->total_disks; drive++) { 3702*c1b3d7c5SThomas E. Spanjaard raid->disks[drive].sectors = raid->total_sectors/raid->width; 3703*c1b3d7c5SThomas E. Spanjaard if (drive == disk_number) { 3704*c1b3d7c5SThomas E. Spanjaard raid->disks[disk_number].dev = parent; 3705*c1b3d7c5SThomas E. Spanjaard raid->disks[disk_number].flags = 3706*c1b3d7c5SThomas E. Spanjaard (AR_DF_ONLINE | AR_DF_PRESENT | AR_DF_ASSIGNED); 3707*c1b3d7c5SThomas E. Spanjaard ars->raid[raid->volume] = raid; 3708*c1b3d7c5SThomas E. Spanjaard ars->disk_number[raid->volume] = disk_number; 3709*c1b3d7c5SThomas E. Spanjaard } 3710*c1b3d7c5SThomas E. Spanjaard } 3711*c1b3d7c5SThomas E. Spanjaard retval = 1; 3712*c1b3d7c5SThomas E. Spanjaard break; 3713*c1b3d7c5SThomas E. Spanjaard } 3714*c1b3d7c5SThomas E. Spanjaard 3715*c1b3d7c5SThomas E. Spanjaard sis_out: 3716*c1b3d7c5SThomas E. Spanjaard free(meta, M_AR); 3717*c1b3d7c5SThomas E. Spanjaard return retval; 3718*c1b3d7c5SThomas E. Spanjaard } 3719*c1b3d7c5SThomas E. Spanjaard 3720*c1b3d7c5SThomas E. Spanjaard static int 3721*c1b3d7c5SThomas E. Spanjaard ata_raid_sis_write_meta(struct ar_softc *rdp) 3722*c1b3d7c5SThomas E. Spanjaard { 3723*c1b3d7c5SThomas E. Spanjaard struct sis_raid_conf *meta; 3724*c1b3d7c5SThomas E. Spanjaard struct timeval timestamp; 3725*c1b3d7c5SThomas E. Spanjaard int disk, error = 0; 3726*c1b3d7c5SThomas E. Spanjaard 3727*c1b3d7c5SThomas E. Spanjaard if (!(meta = (struct sis_raid_conf *) 3728*c1b3d7c5SThomas E. Spanjaard malloc(sizeof(struct sis_raid_conf), M_AR, M_NOWAIT | M_ZERO))) { 3729*c1b3d7c5SThomas E. Spanjaard printf("ar%d: failed to allocate metadata storage\n", rdp->lun); 3730*c1b3d7c5SThomas E. Spanjaard return ENOMEM; 3731*c1b3d7c5SThomas E. Spanjaard } 3732*c1b3d7c5SThomas E. Spanjaard 3733*c1b3d7c5SThomas E. Spanjaard rdp->generation++; 3734*c1b3d7c5SThomas E. Spanjaard microtime(×tamp); 3735*c1b3d7c5SThomas E. Spanjaard 3736*c1b3d7c5SThomas E. Spanjaard meta->magic = SIS_MAGIC; 3737*c1b3d7c5SThomas E. Spanjaard /* XXX SOS if total_disks > 2 this doesn't float */ 3738*c1b3d7c5SThomas E. Spanjaard for (disk = 0; disk < rdp->total_disks; disk++) { 3739*c1b3d7c5SThomas E. Spanjaard if (rdp->disks[disk].dev) { 3740*c1b3d7c5SThomas E. Spanjaard struct ata_channel *ch = 3741*c1b3d7c5SThomas E. Spanjaard device_get_softc(device_get_parent(rdp->disks[disk].dev)); 3742*c1b3d7c5SThomas E. Spanjaard struct ata_device *atadev = device_get_softc(rdp->disks[disk].dev); 3743*c1b3d7c5SThomas E. Spanjaard int disk_number = 1 + ATA_DEV(atadev->unit) + (ch->unit << 1); 3744*c1b3d7c5SThomas E. Spanjaard 3745*c1b3d7c5SThomas E. Spanjaard meta->disks |= disk_number << ((1 - disk) << 2); 3746*c1b3d7c5SThomas E. Spanjaard } 3747*c1b3d7c5SThomas E. Spanjaard } 3748*c1b3d7c5SThomas E. Spanjaard switch (rdp->type) { 3749*c1b3d7c5SThomas E. Spanjaard case AR_T_JBOD: 3750*c1b3d7c5SThomas E. Spanjaard meta->type_total_disks = SIS_T_JBOD; 3751*c1b3d7c5SThomas E. Spanjaard break; 3752*c1b3d7c5SThomas E. Spanjaard 3753*c1b3d7c5SThomas E. Spanjaard case AR_T_RAID0: 3754*c1b3d7c5SThomas E. Spanjaard meta->type_total_disks = SIS_T_RAID0; 3755*c1b3d7c5SThomas E. Spanjaard break; 3756*c1b3d7c5SThomas E. Spanjaard 3757*c1b3d7c5SThomas E. Spanjaard case AR_T_RAID1: 3758*c1b3d7c5SThomas E. Spanjaard meta->type_total_disks = SIS_T_RAID1; 3759*c1b3d7c5SThomas E. Spanjaard break; 3760*c1b3d7c5SThomas E. Spanjaard 3761*c1b3d7c5SThomas E. Spanjaard default: 3762*c1b3d7c5SThomas E. Spanjaard free(meta, M_AR); 3763*c1b3d7c5SThomas E. Spanjaard return ENODEV; 3764*c1b3d7c5SThomas E. Spanjaard } 3765*c1b3d7c5SThomas E. Spanjaard meta->type_total_disks |= (rdp->total_disks & SIS_D_MASK); 3766*c1b3d7c5SThomas E. Spanjaard meta->stripe_sectors = rdp->interleave; 3767*c1b3d7c5SThomas E. Spanjaard meta->timestamp = timestamp.tv_sec; 3768*c1b3d7c5SThomas E. Spanjaard 3769*c1b3d7c5SThomas E. Spanjaard for (disk = 0; disk < rdp->total_disks; disk++) { 3770*c1b3d7c5SThomas E. Spanjaard if (rdp->disks[disk].dev) { 3771*c1b3d7c5SThomas E. Spanjaard struct ata_channel *ch = 3772*c1b3d7c5SThomas E. Spanjaard device_get_softc(device_get_parent(rdp->disks[disk].dev)); 3773*c1b3d7c5SThomas E. Spanjaard struct ata_device *atadev = device_get_softc(rdp->disks[disk].dev); 3774*c1b3d7c5SThomas E. Spanjaard 3775*c1b3d7c5SThomas E. Spanjaard meta->controller_pci_id = 3776*c1b3d7c5SThomas E. Spanjaard (pci_get_vendor(GRANDPARENT(rdp->disks[disk].dev)) << 16) | 3777*c1b3d7c5SThomas E. Spanjaard pci_get_device(GRANDPARENT(rdp->disks[disk].dev)); 3778*c1b3d7c5SThomas E. Spanjaard bcopy(atadev->param.model, meta->model, sizeof(meta->model)); 3779*c1b3d7c5SThomas E. Spanjaard 3780*c1b3d7c5SThomas E. Spanjaard /* XXX SOS if total_disks > 2 this may not float */ 3781*c1b3d7c5SThomas E. Spanjaard meta->disk_number = 1 + ATA_DEV(atadev->unit) + (ch->unit << 1); 3782*c1b3d7c5SThomas E. Spanjaard 3783*c1b3d7c5SThomas E. Spanjaard if (testing || bootverbose) 3784*c1b3d7c5SThomas E. Spanjaard ata_raid_sis_print_meta(meta); 3785*c1b3d7c5SThomas E. Spanjaard 3786*c1b3d7c5SThomas E. Spanjaard if (ata_raid_rw(rdp->disks[disk].dev, 3787*c1b3d7c5SThomas E. Spanjaard SIS_LBA(rdp->disks[disk].dev), 3788*c1b3d7c5SThomas E. Spanjaard meta, sizeof(struct sis_raid_conf), 3789*c1b3d7c5SThomas E. Spanjaard ATA_R_WRITE | ATA_R_DIRECT)) { 3790*c1b3d7c5SThomas E. Spanjaard device_printf(rdp->disks[disk].dev, "write metadata failed\n"); 3791*c1b3d7c5SThomas E. Spanjaard error = EIO; 3792*c1b3d7c5SThomas E. Spanjaard } 3793*c1b3d7c5SThomas E. Spanjaard } 3794*c1b3d7c5SThomas E. Spanjaard } 3795*c1b3d7c5SThomas E. Spanjaard free(meta, M_AR); 3796*c1b3d7c5SThomas E. Spanjaard return error; 3797*c1b3d7c5SThomas E. Spanjaard } 3798*c1b3d7c5SThomas E. Spanjaard 3799*c1b3d7c5SThomas E. Spanjaard /* VIA Tech V-RAID Metadata */ 3800*c1b3d7c5SThomas E. Spanjaard static int 3801*c1b3d7c5SThomas E. Spanjaard ata_raid_via_read_meta(device_t dev, struct ar_softc **raidp) 3802*c1b3d7c5SThomas E. Spanjaard { 3803*c1b3d7c5SThomas E. Spanjaard struct ata_raid_subdisk *ars = device_get_softc(dev); 3804*c1b3d7c5SThomas E. Spanjaard device_t parent = device_get_parent(dev); 3805*c1b3d7c5SThomas E. Spanjaard struct via_raid_conf *meta; 3806*c1b3d7c5SThomas E. Spanjaard struct ar_softc *raid = NULL; 3807*c1b3d7c5SThomas E. Spanjaard u_int8_t checksum, *ptr; 3808*c1b3d7c5SThomas E. Spanjaard int array, count, disk, retval = 0; 3809*c1b3d7c5SThomas E. Spanjaard 3810*c1b3d7c5SThomas E. Spanjaard if (!(meta = (struct via_raid_conf *) 3811*c1b3d7c5SThomas E. Spanjaard malloc(sizeof(struct via_raid_conf), M_AR, M_NOWAIT | M_ZERO))) 3812*c1b3d7c5SThomas E. Spanjaard return ENOMEM; 3813*c1b3d7c5SThomas E. Spanjaard 3814*c1b3d7c5SThomas E. Spanjaard if (ata_raid_rw(parent, VIA_LBA(parent), 3815*c1b3d7c5SThomas E. Spanjaard meta, sizeof(struct via_raid_conf), ATA_R_READ)) { 3816*c1b3d7c5SThomas E. Spanjaard if (testing || bootverbose) 3817*c1b3d7c5SThomas E. Spanjaard device_printf(parent, "VIA read metadata failed\n"); 3818*c1b3d7c5SThomas E. Spanjaard goto via_out; 3819*c1b3d7c5SThomas E. Spanjaard } 3820*c1b3d7c5SThomas E. Spanjaard 3821*c1b3d7c5SThomas E. Spanjaard /* check if this is a VIA RAID struct */ 3822*c1b3d7c5SThomas E. Spanjaard if (meta->magic != VIA_MAGIC) { 3823*c1b3d7c5SThomas E. Spanjaard if (testing || bootverbose) 3824*c1b3d7c5SThomas E. Spanjaard device_printf(parent, "VIA check1 failed\n"); 3825*c1b3d7c5SThomas E. Spanjaard goto via_out; 3826*c1b3d7c5SThomas E. Spanjaard } 3827*c1b3d7c5SThomas E. Spanjaard 3828*c1b3d7c5SThomas E. Spanjaard /* calculate checksum and compare for valid */ 3829*c1b3d7c5SThomas E. Spanjaard for (checksum = 0, ptr = (u_int8_t *)meta, count = 0; count < 50; count++) 3830*c1b3d7c5SThomas E. Spanjaard checksum += *ptr++; 3831*c1b3d7c5SThomas E. Spanjaard if (checksum != meta->checksum) { 3832*c1b3d7c5SThomas E. Spanjaard if (testing || bootverbose) 3833*c1b3d7c5SThomas E. Spanjaard device_printf(parent, "VIA check2 failed\n"); 3834*c1b3d7c5SThomas E. Spanjaard goto via_out; 3835*c1b3d7c5SThomas E. Spanjaard } 3836*c1b3d7c5SThomas E. Spanjaard 3837*c1b3d7c5SThomas E. Spanjaard if (testing || bootverbose) 3838*c1b3d7c5SThomas E. Spanjaard ata_raid_via_print_meta(meta); 3839*c1b3d7c5SThomas E. Spanjaard 3840*c1b3d7c5SThomas E. Spanjaard /* now convert VIA meta into our generic form */ 3841*c1b3d7c5SThomas E. Spanjaard for (array = 0; array < MAX_ARRAYS; array++) { 3842*c1b3d7c5SThomas E. Spanjaard if (!raidp[array]) { 3843*c1b3d7c5SThomas E. Spanjaard raidp[array] = 3844*c1b3d7c5SThomas E. Spanjaard (struct ar_softc *)malloc(sizeof(struct ar_softc), M_AR, 3845*c1b3d7c5SThomas E. Spanjaard M_NOWAIT | M_ZERO); 3846*c1b3d7c5SThomas E. Spanjaard if (!raidp[array]) { 3847*c1b3d7c5SThomas E. Spanjaard device_printf(parent, "failed to allocate metadata storage\n"); 3848*c1b3d7c5SThomas E. Spanjaard goto via_out; 3849*c1b3d7c5SThomas E. Spanjaard } 3850*c1b3d7c5SThomas E. Spanjaard } 3851*c1b3d7c5SThomas E. Spanjaard raid = raidp[array]; 3852*c1b3d7c5SThomas E. Spanjaard if (raid->format && (raid->format != AR_F_VIA_RAID)) 3853*c1b3d7c5SThomas E. Spanjaard continue; 3854*c1b3d7c5SThomas E. Spanjaard 3855*c1b3d7c5SThomas E. Spanjaard if (raid->format == AR_F_VIA_RAID && (raid->magic_0 != meta->disks[0])) 3856*c1b3d7c5SThomas E. Spanjaard continue; 3857*c1b3d7c5SThomas E. Spanjaard 3858*c1b3d7c5SThomas E. Spanjaard switch (meta->type & VIA_T_MASK) { 3859*c1b3d7c5SThomas E. Spanjaard case VIA_T_RAID0: 3860*c1b3d7c5SThomas E. Spanjaard raid->type = AR_T_RAID0; 3861*c1b3d7c5SThomas E. Spanjaard raid->width = meta->stripe_layout & VIA_L_DISKS; 3862*c1b3d7c5SThomas E. Spanjaard if (!raid->total_sectors || 3863*c1b3d7c5SThomas E. Spanjaard (raid->total_sectors > (raid->width * meta->disk_sectors))) 3864*c1b3d7c5SThomas E. Spanjaard raid->total_sectors = raid->width * meta->disk_sectors; 3865*c1b3d7c5SThomas E. Spanjaard break; 3866*c1b3d7c5SThomas E. Spanjaard 3867*c1b3d7c5SThomas E. Spanjaard case VIA_T_RAID1: 3868*c1b3d7c5SThomas E. Spanjaard raid->type = AR_T_RAID1; 3869*c1b3d7c5SThomas E. Spanjaard raid->width = 1; 3870*c1b3d7c5SThomas E. Spanjaard raid->total_sectors = meta->disk_sectors; 3871*c1b3d7c5SThomas E. Spanjaard break; 3872*c1b3d7c5SThomas E. Spanjaard 3873*c1b3d7c5SThomas E. Spanjaard case VIA_T_RAID01: 3874*c1b3d7c5SThomas E. Spanjaard raid->type = AR_T_RAID01; 3875*c1b3d7c5SThomas E. Spanjaard raid->width = meta->stripe_layout & VIA_L_DISKS; 3876*c1b3d7c5SThomas E. Spanjaard if (!raid->total_sectors || 3877*c1b3d7c5SThomas E. Spanjaard (raid->total_sectors > (raid->width * meta->disk_sectors))) 3878*c1b3d7c5SThomas E. Spanjaard raid->total_sectors = raid->width * meta->disk_sectors; 3879*c1b3d7c5SThomas E. Spanjaard break; 3880*c1b3d7c5SThomas E. Spanjaard 3881*c1b3d7c5SThomas E. Spanjaard case VIA_T_RAID5: 3882*c1b3d7c5SThomas E. Spanjaard raid->type = AR_T_RAID5; 3883*c1b3d7c5SThomas E. Spanjaard raid->width = meta->stripe_layout & VIA_L_DISKS; 3884*c1b3d7c5SThomas E. Spanjaard if (!raid->total_sectors || 3885*c1b3d7c5SThomas E. Spanjaard (raid->total_sectors > ((raid->width - 1)*meta->disk_sectors))) 3886*c1b3d7c5SThomas E. Spanjaard raid->total_sectors = (raid->width - 1) * meta->disk_sectors; 3887*c1b3d7c5SThomas E. Spanjaard break; 3888*c1b3d7c5SThomas E. Spanjaard 3889*c1b3d7c5SThomas E. Spanjaard case VIA_T_SPAN: 3890*c1b3d7c5SThomas E. Spanjaard raid->type = AR_T_SPAN; 3891*c1b3d7c5SThomas E. Spanjaard raid->width = 1; 3892*c1b3d7c5SThomas E. Spanjaard raid->total_sectors += meta->disk_sectors; 3893*c1b3d7c5SThomas E. Spanjaard break; 3894*c1b3d7c5SThomas E. Spanjaard 3895*c1b3d7c5SThomas E. Spanjaard default: 3896*c1b3d7c5SThomas E. Spanjaard device_printf(parent,"VIA unknown RAID type 0x%02x\n", meta->type); 3897*c1b3d7c5SThomas E. Spanjaard free(raidp[array], M_AR); 3898*c1b3d7c5SThomas E. Spanjaard raidp[array] = NULL; 3899*c1b3d7c5SThomas E. Spanjaard goto via_out; 3900*c1b3d7c5SThomas E. Spanjaard } 3901*c1b3d7c5SThomas E. Spanjaard raid->magic_0 = meta->disks[0]; 3902*c1b3d7c5SThomas E. Spanjaard raid->format = AR_F_VIA_RAID; 3903*c1b3d7c5SThomas E. Spanjaard raid->generation = 0; 3904*c1b3d7c5SThomas E. Spanjaard raid->interleave = 3905*c1b3d7c5SThomas E. Spanjaard 0x08 << ((meta->stripe_layout & VIA_L_MASK) >> VIA_L_SHIFT); 3906*c1b3d7c5SThomas E. Spanjaard for (count = 0, disk = 0; disk < 8; disk++) 3907*c1b3d7c5SThomas E. Spanjaard if (meta->disks[disk]) 3908*c1b3d7c5SThomas E. Spanjaard count++; 3909*c1b3d7c5SThomas E. Spanjaard raid->total_disks = count; 3910*c1b3d7c5SThomas E. Spanjaard raid->heads = 255; 3911*c1b3d7c5SThomas E. Spanjaard raid->sectors = 63; 3912*c1b3d7c5SThomas E. Spanjaard raid->cylinders = raid->total_sectors / (63 * 255); 3913*c1b3d7c5SThomas E. Spanjaard raid->offset_sectors = 0; 3914*c1b3d7c5SThomas E. Spanjaard raid->rebuild_lba = 0; 3915*c1b3d7c5SThomas E. Spanjaard raid->lun = array; 3916*c1b3d7c5SThomas E. Spanjaard 3917*c1b3d7c5SThomas E. Spanjaard for (disk = 0; disk < raid->total_disks; disk++) { 3918*c1b3d7c5SThomas E. Spanjaard if (meta->disks[disk] == meta->disk_id) { 3919*c1b3d7c5SThomas E. Spanjaard raid->disks[disk].dev = parent; 3920*c1b3d7c5SThomas E. Spanjaard bcopy(&meta->disk_id, raid->disks[disk].serial, 3921*c1b3d7c5SThomas E. Spanjaard sizeof(u_int32_t)); 3922*c1b3d7c5SThomas E. Spanjaard raid->disks[disk].sectors = meta->disk_sectors; 3923*c1b3d7c5SThomas E. Spanjaard raid->disks[disk].flags = 3924*c1b3d7c5SThomas E. Spanjaard (AR_DF_ONLINE | AR_DF_PRESENT | AR_DF_ASSIGNED); 3925*c1b3d7c5SThomas E. Spanjaard ars->raid[raid->volume] = raid; 3926*c1b3d7c5SThomas E. Spanjaard ars->disk_number[raid->volume] = disk; 3927*c1b3d7c5SThomas E. Spanjaard retval = 1; 3928*c1b3d7c5SThomas E. Spanjaard break; 3929*c1b3d7c5SThomas E. Spanjaard } 3930*c1b3d7c5SThomas E. Spanjaard } 3931*c1b3d7c5SThomas E. Spanjaard break; 3932*c1b3d7c5SThomas E. Spanjaard } 3933*c1b3d7c5SThomas E. Spanjaard 3934*c1b3d7c5SThomas E. Spanjaard via_out: 3935*c1b3d7c5SThomas E. Spanjaard free(meta, M_AR); 3936*c1b3d7c5SThomas E. Spanjaard return retval; 3937*c1b3d7c5SThomas E. Spanjaard } 3938*c1b3d7c5SThomas E. Spanjaard 3939*c1b3d7c5SThomas E. Spanjaard static int 3940*c1b3d7c5SThomas E. Spanjaard ata_raid_via_write_meta(struct ar_softc *rdp) 3941*c1b3d7c5SThomas E. Spanjaard { 3942*c1b3d7c5SThomas E. Spanjaard struct via_raid_conf *meta; 3943*c1b3d7c5SThomas E. Spanjaard int disk, error = 0; 3944*c1b3d7c5SThomas E. Spanjaard 3945*c1b3d7c5SThomas E. Spanjaard if (!(meta = (struct via_raid_conf *) 3946*c1b3d7c5SThomas E. Spanjaard malloc(sizeof(struct via_raid_conf), M_AR, M_NOWAIT | M_ZERO))) { 3947*c1b3d7c5SThomas E. Spanjaard printf("ar%d: failed to allocate metadata storage\n", rdp->lun); 3948*c1b3d7c5SThomas E. Spanjaard return ENOMEM; 3949*c1b3d7c5SThomas E. Spanjaard } 3950*c1b3d7c5SThomas E. Spanjaard 3951*c1b3d7c5SThomas E. Spanjaard rdp->generation++; 3952*c1b3d7c5SThomas E. Spanjaard 3953*c1b3d7c5SThomas E. Spanjaard meta->magic = VIA_MAGIC; 3954*c1b3d7c5SThomas E. Spanjaard meta->dummy_0 = 0x02; 3955*c1b3d7c5SThomas E. Spanjaard switch (rdp->type) { 3956*c1b3d7c5SThomas E. Spanjaard case AR_T_SPAN: 3957*c1b3d7c5SThomas E. Spanjaard meta->type = VIA_T_SPAN; 3958*c1b3d7c5SThomas E. Spanjaard meta->stripe_layout = (rdp->total_disks & VIA_L_DISKS); 3959*c1b3d7c5SThomas E. Spanjaard break; 3960*c1b3d7c5SThomas E. Spanjaard 3961*c1b3d7c5SThomas E. Spanjaard case AR_T_RAID0: 3962*c1b3d7c5SThomas E. Spanjaard meta->type = VIA_T_RAID0; 3963*c1b3d7c5SThomas E. Spanjaard meta->stripe_layout = ((rdp->interleave >> 1) & VIA_L_MASK); 3964*c1b3d7c5SThomas E. Spanjaard meta->stripe_layout |= (rdp->total_disks & VIA_L_DISKS); 3965*c1b3d7c5SThomas E. Spanjaard break; 3966*c1b3d7c5SThomas E. Spanjaard 3967*c1b3d7c5SThomas E. Spanjaard case AR_T_RAID1: 3968*c1b3d7c5SThomas E. Spanjaard meta->type = VIA_T_RAID1; 3969*c1b3d7c5SThomas E. Spanjaard meta->stripe_layout = (rdp->total_disks & VIA_L_DISKS); 3970*c1b3d7c5SThomas E. Spanjaard break; 3971*c1b3d7c5SThomas E. Spanjaard 3972*c1b3d7c5SThomas E. Spanjaard case AR_T_RAID5: 3973*c1b3d7c5SThomas E. Spanjaard meta->type = VIA_T_RAID5; 3974*c1b3d7c5SThomas E. Spanjaard meta->stripe_layout = ((rdp->interleave >> 1) & VIA_L_MASK); 3975*c1b3d7c5SThomas E. Spanjaard meta->stripe_layout |= (rdp->total_disks & VIA_L_DISKS); 3976*c1b3d7c5SThomas E. Spanjaard break; 3977*c1b3d7c5SThomas E. Spanjaard 3978*c1b3d7c5SThomas E. Spanjaard case AR_T_RAID01: 3979*c1b3d7c5SThomas E. Spanjaard meta->type = VIA_T_RAID01; 3980*c1b3d7c5SThomas E. Spanjaard meta->stripe_layout = ((rdp->interleave >> 1) & VIA_L_MASK); 3981*c1b3d7c5SThomas E. Spanjaard meta->stripe_layout |= (rdp->width & VIA_L_DISKS); 3982*c1b3d7c5SThomas E. Spanjaard break; 3983*c1b3d7c5SThomas E. Spanjaard 3984*c1b3d7c5SThomas E. Spanjaard default: 3985*c1b3d7c5SThomas E. Spanjaard free(meta, M_AR); 3986*c1b3d7c5SThomas E. Spanjaard return ENODEV; 3987*c1b3d7c5SThomas E. Spanjaard } 3988*c1b3d7c5SThomas E. Spanjaard meta->type |= VIA_T_BOOTABLE; /* XXX SOS */ 3989*c1b3d7c5SThomas E. Spanjaard meta->disk_sectors = 3990*c1b3d7c5SThomas E. Spanjaard rdp->total_sectors / (rdp->width - (rdp->type == AR_RAID5)); 3991*c1b3d7c5SThomas E. Spanjaard for (disk = 0; disk < rdp->total_disks; disk++) 3992*c1b3d7c5SThomas E. Spanjaard meta->disks[disk] = (u_int32_t)(uintptr_t)rdp->disks[disk].dev; 3993*c1b3d7c5SThomas E. Spanjaard 3994*c1b3d7c5SThomas E. Spanjaard for (disk = 0; disk < rdp->total_disks; disk++) { 3995*c1b3d7c5SThomas E. Spanjaard if (rdp->disks[disk].dev) { 3996*c1b3d7c5SThomas E. Spanjaard u_int8_t *ptr; 3997*c1b3d7c5SThomas E. Spanjaard int count; 3998*c1b3d7c5SThomas E. Spanjaard 3999*c1b3d7c5SThomas E. Spanjaard meta->disk_index = disk * sizeof(u_int32_t); 4000*c1b3d7c5SThomas E. Spanjaard if (rdp->type == AR_T_RAID01) 4001*c1b3d7c5SThomas E. Spanjaard meta->disk_index = ((meta->disk_index & 0x08) << 2) | 4002*c1b3d7c5SThomas E. Spanjaard (meta->disk_index & ~0x08); 4003*c1b3d7c5SThomas E. Spanjaard meta->disk_id = meta->disks[disk]; 4004*c1b3d7c5SThomas E. Spanjaard meta->checksum = 0; 4005*c1b3d7c5SThomas E. Spanjaard for (ptr = (u_int8_t *)meta, count = 0; count < 50; count++) 4006*c1b3d7c5SThomas E. Spanjaard meta->checksum += *ptr++; 4007*c1b3d7c5SThomas E. Spanjaard 4008*c1b3d7c5SThomas E. Spanjaard if (testing || bootverbose) 4009*c1b3d7c5SThomas E. Spanjaard ata_raid_via_print_meta(meta); 4010*c1b3d7c5SThomas E. Spanjaard 4011*c1b3d7c5SThomas E. Spanjaard if (ata_raid_rw(rdp->disks[disk].dev, 4012*c1b3d7c5SThomas E. Spanjaard VIA_LBA(rdp->disks[disk].dev), 4013*c1b3d7c5SThomas E. Spanjaard meta, sizeof(struct via_raid_conf), 4014*c1b3d7c5SThomas E. Spanjaard ATA_R_WRITE | ATA_R_DIRECT)) { 4015*c1b3d7c5SThomas E. Spanjaard device_printf(rdp->disks[disk].dev, "write metadata failed\n"); 4016*c1b3d7c5SThomas E. Spanjaard error = EIO; 4017*c1b3d7c5SThomas E. Spanjaard } 4018*c1b3d7c5SThomas E. Spanjaard } 4019*c1b3d7c5SThomas E. Spanjaard } 4020*c1b3d7c5SThomas E. Spanjaard free(meta, M_AR); 4021*c1b3d7c5SThomas E. Spanjaard return error; 4022*c1b3d7c5SThomas E. Spanjaard } 4023*c1b3d7c5SThomas E. Spanjaard 4024*c1b3d7c5SThomas E. Spanjaard static struct ata_request * 4025*c1b3d7c5SThomas E. Spanjaard ata_raid_init_request(struct ar_softc *rdp, struct bio *bio) 4026*c1b3d7c5SThomas E. Spanjaard { 4027*c1b3d7c5SThomas E. Spanjaard struct ata_request *request; 4028*c1b3d7c5SThomas E. Spanjaard 4029*c1b3d7c5SThomas E. Spanjaard if (!(request = ata_alloc_request())) { 4030*c1b3d7c5SThomas E. Spanjaard printf("FAILURE - out of memory in ata_raid_init_request\n"); 4031*c1b3d7c5SThomas E. Spanjaard return NULL; 4032*c1b3d7c5SThomas E. Spanjaard } 4033*c1b3d7c5SThomas E. Spanjaard request->timeout = 5; 4034*c1b3d7c5SThomas E. Spanjaard request->retries = 2; 4035*c1b3d7c5SThomas E. Spanjaard request->callback = ata_raid_done; 4036*c1b3d7c5SThomas E. Spanjaard request->driver = rdp; 4037*c1b3d7c5SThomas E. Spanjaard request->bio = bio; 4038*c1b3d7c5SThomas E. Spanjaard switch (request->bio->bio_buf->b_cmd) { 4039*c1b3d7c5SThomas E. Spanjaard case BUF_CMD_READ: 4040*c1b3d7c5SThomas E. Spanjaard request->flags = ATA_R_READ; 4041*c1b3d7c5SThomas E. Spanjaard break; 4042*c1b3d7c5SThomas E. Spanjaard case BUF_CMD_WRITE: 4043*c1b3d7c5SThomas E. Spanjaard request->flags = ATA_R_WRITE; 4044*c1b3d7c5SThomas E. Spanjaard break; 4045*c1b3d7c5SThomas E. Spanjaard } 4046*c1b3d7c5SThomas E. Spanjaard return request; 4047*c1b3d7c5SThomas E. Spanjaard } 4048*c1b3d7c5SThomas E. Spanjaard 4049*c1b3d7c5SThomas E. Spanjaard static int 4050*c1b3d7c5SThomas E. Spanjaard ata_raid_send_request(struct ata_request *request) 4051*c1b3d7c5SThomas E. Spanjaard { 4052*c1b3d7c5SThomas E. Spanjaard struct ata_device *atadev = device_get_softc(request->dev); 4053*c1b3d7c5SThomas E. Spanjaard 4054*c1b3d7c5SThomas E. Spanjaard request->transfersize = min(request->bytecount, atadev->max_iosize); 4055*c1b3d7c5SThomas E. Spanjaard if (request->flags & ATA_R_READ) { 4056*c1b3d7c5SThomas E. Spanjaard if (atadev->mode >= ATA_DMA) { 4057*c1b3d7c5SThomas E. Spanjaard request->flags |= ATA_R_DMA; 4058*c1b3d7c5SThomas E. Spanjaard request->u.ata.command = ATA_READ_DMA; 4059*c1b3d7c5SThomas E. Spanjaard } 4060*c1b3d7c5SThomas E. Spanjaard else if (atadev->max_iosize > DEV_BSIZE) 4061*c1b3d7c5SThomas E. Spanjaard request->u.ata.command = ATA_READ_MUL; 4062*c1b3d7c5SThomas E. Spanjaard else 4063*c1b3d7c5SThomas E. Spanjaard request->u.ata.command = ATA_READ; 4064*c1b3d7c5SThomas E. Spanjaard } 4065*c1b3d7c5SThomas E. Spanjaard else if (request->flags & ATA_R_WRITE) { 4066*c1b3d7c5SThomas E. Spanjaard if (atadev->mode >= ATA_DMA) { 4067*c1b3d7c5SThomas E. Spanjaard request->flags |= ATA_R_DMA; 4068*c1b3d7c5SThomas E. Spanjaard request->u.ata.command = ATA_WRITE_DMA; 4069*c1b3d7c5SThomas E. Spanjaard } 4070*c1b3d7c5SThomas E. Spanjaard else if (atadev->max_iosize > DEV_BSIZE) 4071*c1b3d7c5SThomas E. Spanjaard request->u.ata.command = ATA_WRITE_MUL; 4072*c1b3d7c5SThomas E. Spanjaard else 4073*c1b3d7c5SThomas E. Spanjaard request->u.ata.command = ATA_WRITE; 4074*c1b3d7c5SThomas E. Spanjaard } 4075*c1b3d7c5SThomas E. Spanjaard else { 4076*c1b3d7c5SThomas E. Spanjaard device_printf(request->dev, "FAILURE - unknown IO operation\n"); 4077*c1b3d7c5SThomas E. Spanjaard ata_free_request(request); 4078*c1b3d7c5SThomas E. Spanjaard return EIO; 4079*c1b3d7c5SThomas E. Spanjaard } 4080*c1b3d7c5SThomas E. Spanjaard request->flags |= (ATA_R_ORDERED | ATA_R_THREAD); 4081*c1b3d7c5SThomas E. Spanjaard ata_queue_request(request); 4082*c1b3d7c5SThomas E. Spanjaard return 0; 4083*c1b3d7c5SThomas E. Spanjaard } 4084*c1b3d7c5SThomas E. Spanjaard 4085*c1b3d7c5SThomas E. Spanjaard static int 4086*c1b3d7c5SThomas E. Spanjaard ata_raid_rw(device_t dev, u_int64_t lba, void *data, u_int bcount, int flags) 4087*c1b3d7c5SThomas E. Spanjaard { 4088*c1b3d7c5SThomas E. Spanjaard struct ata_device *atadev = device_get_softc(dev); 4089*c1b3d7c5SThomas E. Spanjaard struct ata_request *request; 4090*c1b3d7c5SThomas E. Spanjaard int error; 4091*c1b3d7c5SThomas E. Spanjaard 4092*c1b3d7c5SThomas E. Spanjaard if (bcount % DEV_BSIZE) { 4093*c1b3d7c5SThomas E. Spanjaard device_printf(dev, "FAILURE - transfers must be modulo sectorsize\n"); 4094*c1b3d7c5SThomas E. Spanjaard return ENOMEM; 4095*c1b3d7c5SThomas E. Spanjaard } 4096*c1b3d7c5SThomas E. Spanjaard 4097*c1b3d7c5SThomas E. Spanjaard if (!(request = ata_alloc_request())) { 4098*c1b3d7c5SThomas E. Spanjaard device_printf(dev, "FAILURE - out of memory in ata_raid_rw\n"); 4099*c1b3d7c5SThomas E. Spanjaard return ENOMEM; 4100*c1b3d7c5SThomas E. Spanjaard } 4101*c1b3d7c5SThomas E. Spanjaard 4102*c1b3d7c5SThomas E. Spanjaard /* setup request */ 4103*c1b3d7c5SThomas E. Spanjaard request->dev = dev; 4104*c1b3d7c5SThomas E. Spanjaard request->timeout = 10; 4105*c1b3d7c5SThomas E. Spanjaard request->retries = 0; 4106*c1b3d7c5SThomas E. Spanjaard request->data = data; 4107*c1b3d7c5SThomas E. Spanjaard request->bytecount = bcount; 4108*c1b3d7c5SThomas E. Spanjaard request->transfersize = DEV_BSIZE; 4109*c1b3d7c5SThomas E. Spanjaard request->u.ata.lba = lba; 4110*c1b3d7c5SThomas E. Spanjaard request->u.ata.count = request->bytecount / DEV_BSIZE; 4111*c1b3d7c5SThomas E. Spanjaard request->flags = flags; 4112*c1b3d7c5SThomas E. Spanjaard 4113*c1b3d7c5SThomas E. Spanjaard if (flags & ATA_R_READ) { 4114*c1b3d7c5SThomas E. Spanjaard if (atadev->mode >= ATA_DMA) { 4115*c1b3d7c5SThomas E. Spanjaard request->u.ata.command = ATA_READ_DMA; 4116*c1b3d7c5SThomas E. Spanjaard request->flags |= ATA_R_DMA; 4117*c1b3d7c5SThomas E. Spanjaard } 4118*c1b3d7c5SThomas E. Spanjaard else 4119*c1b3d7c5SThomas E. Spanjaard request->u.ata.command = ATA_READ; 4120*c1b3d7c5SThomas E. Spanjaard ata_queue_request(request); 4121*c1b3d7c5SThomas E. Spanjaard } 4122*c1b3d7c5SThomas E. Spanjaard else if (flags & ATA_R_WRITE) { 4123*c1b3d7c5SThomas E. Spanjaard if (atadev->mode >= ATA_DMA) { 4124*c1b3d7c5SThomas E. Spanjaard request->u.ata.command = ATA_WRITE_DMA; 4125*c1b3d7c5SThomas E. Spanjaard request->flags |= ATA_R_DMA; 4126*c1b3d7c5SThomas E. Spanjaard } 4127*c1b3d7c5SThomas E. Spanjaard else 4128*c1b3d7c5SThomas E. Spanjaard request->u.ata.command = ATA_WRITE; 4129*c1b3d7c5SThomas E. Spanjaard ata_queue_request(request); 4130*c1b3d7c5SThomas E. Spanjaard } 4131*c1b3d7c5SThomas E. Spanjaard else { 4132*c1b3d7c5SThomas E. Spanjaard device_printf(dev, "FAILURE - unknown IO operation\n"); 4133*c1b3d7c5SThomas E. Spanjaard request->result = EIO; 4134*c1b3d7c5SThomas E. Spanjaard } 4135*c1b3d7c5SThomas E. Spanjaard error = request->result; 4136*c1b3d7c5SThomas E. Spanjaard ata_free_request(request); 4137*c1b3d7c5SThomas E. Spanjaard return error; 4138*c1b3d7c5SThomas E. Spanjaard } 4139*c1b3d7c5SThomas E. Spanjaard 4140*c1b3d7c5SThomas E. Spanjaard /* 4141*c1b3d7c5SThomas E. Spanjaard * module handeling 4142*c1b3d7c5SThomas E. Spanjaard */ 4143*c1b3d7c5SThomas E. Spanjaard static int 4144*c1b3d7c5SThomas E. Spanjaard ata_raid_subdisk_probe(device_t dev) 4145*c1b3d7c5SThomas E. Spanjaard { 4146*c1b3d7c5SThomas E. Spanjaard device_quiet(dev); 4147*c1b3d7c5SThomas E. Spanjaard return 0; 4148*c1b3d7c5SThomas E. Spanjaard } 4149*c1b3d7c5SThomas E. Spanjaard 4150*c1b3d7c5SThomas E. Spanjaard static int 4151*c1b3d7c5SThomas E. Spanjaard ata_raid_subdisk_attach(device_t dev) 4152*c1b3d7c5SThomas E. Spanjaard { 4153*c1b3d7c5SThomas E. Spanjaard struct ata_raid_subdisk *ars = device_get_softc(dev); 4154*c1b3d7c5SThomas E. Spanjaard int volume; 4155*c1b3d7c5SThomas E. Spanjaard 4156*c1b3d7c5SThomas E. Spanjaard for (volume = 0; volume < MAX_VOLUMES; volume++) { 4157*c1b3d7c5SThomas E. Spanjaard ars->raid[volume] = NULL; 4158*c1b3d7c5SThomas E. Spanjaard ars->disk_number[volume] = -1; 4159*c1b3d7c5SThomas E. Spanjaard } 4160*c1b3d7c5SThomas E. Spanjaard ata_raid_read_metadata(dev); 4161*c1b3d7c5SThomas E. Spanjaard return 0; 4162*c1b3d7c5SThomas E. Spanjaard } 4163*c1b3d7c5SThomas E. Spanjaard 4164*c1b3d7c5SThomas E. Spanjaard static int 4165*c1b3d7c5SThomas E. Spanjaard ata_raid_subdisk_detach(device_t dev) 4166*c1b3d7c5SThomas E. Spanjaard { 4167*c1b3d7c5SThomas E. Spanjaard struct ata_raid_subdisk *ars = device_get_softc(dev); 4168*c1b3d7c5SThomas E. Spanjaard int volume; 4169*c1b3d7c5SThomas E. Spanjaard 4170*c1b3d7c5SThomas E. Spanjaard for (volume = 0; volume < MAX_VOLUMES; volume++) { 4171*c1b3d7c5SThomas E. Spanjaard if (ars->raid[volume]) { 4172*c1b3d7c5SThomas E. Spanjaard ars->raid[volume]->disks[ars->disk_number[volume]].flags &= 4173*c1b3d7c5SThomas E. Spanjaard ~(AR_DF_PRESENT | AR_DF_ONLINE); 4174*c1b3d7c5SThomas E. Spanjaard ars->raid[volume]->disks[ars->disk_number[volume]].dev = NULL; 4175*c1b3d7c5SThomas E. Spanjaard ata_raid_config_changed(ars->raid[volume], 1); 4176*c1b3d7c5SThomas E. Spanjaard ars->raid[volume] = NULL; 4177*c1b3d7c5SThomas E. Spanjaard ars->disk_number[volume] = -1; 4178*c1b3d7c5SThomas E. Spanjaard } 4179*c1b3d7c5SThomas E. Spanjaard } 4180*c1b3d7c5SThomas E. Spanjaard return 0; 4181*c1b3d7c5SThomas E. Spanjaard } 4182*c1b3d7c5SThomas E. Spanjaard 4183*c1b3d7c5SThomas E. Spanjaard static device_method_t ata_raid_sub_methods[] = { 4184*c1b3d7c5SThomas E. Spanjaard /* device interface */ 4185*c1b3d7c5SThomas E. Spanjaard DEVMETHOD(device_probe, ata_raid_subdisk_probe), 4186*c1b3d7c5SThomas E. Spanjaard DEVMETHOD(device_attach, ata_raid_subdisk_attach), 4187*c1b3d7c5SThomas E. Spanjaard DEVMETHOD(device_detach, ata_raid_subdisk_detach), 4188*c1b3d7c5SThomas E. Spanjaard { 0, 0 } 4189*c1b3d7c5SThomas E. Spanjaard }; 4190*c1b3d7c5SThomas E. Spanjaard 4191*c1b3d7c5SThomas E. Spanjaard static driver_t ata_raid_sub_driver = { 4192*c1b3d7c5SThomas E. Spanjaard "subdisk", 4193*c1b3d7c5SThomas E. Spanjaard ata_raid_sub_methods, 4194*c1b3d7c5SThomas E. Spanjaard sizeof(struct ata_raid_subdisk) 4195*c1b3d7c5SThomas E. Spanjaard }; 4196*c1b3d7c5SThomas E. Spanjaard 4197*c1b3d7c5SThomas E. Spanjaard DRIVER_MODULE(subdisk, ad, ata_raid_sub_driver, ata_raid_sub_devclass, NULL, NULL); 4198*c1b3d7c5SThomas E. Spanjaard 4199*c1b3d7c5SThomas E. Spanjaard static int 4200*c1b3d7c5SThomas E. Spanjaard ata_raid_module_event_handler(module_t mod, int what, void *arg) 4201*c1b3d7c5SThomas E. Spanjaard { 4202*c1b3d7c5SThomas E. Spanjaard int i; 4203*c1b3d7c5SThomas E. Spanjaard 4204*c1b3d7c5SThomas E. Spanjaard switch (what) { 4205*c1b3d7c5SThomas E. Spanjaard case MOD_LOAD: 4206*c1b3d7c5SThomas E. Spanjaard if (testing || bootverbose) 4207*c1b3d7c5SThomas E. Spanjaard printf("ATA PseudoRAID loaded\n"); 4208*c1b3d7c5SThomas E. Spanjaard #if 0 4209*c1b3d7c5SThomas E. Spanjaard /* setup table to hold metadata for all ATA PseudoRAID arrays */ 4210*c1b3d7c5SThomas E. Spanjaard ata_raid_arrays = malloc(sizeof(struct ar_soft *) * MAX_ARRAYS, 4211*c1b3d7c5SThomas E. Spanjaard M_AR, M_NOWAIT | M_ZERO); 4212*c1b3d7c5SThomas E. Spanjaard if (!ata_raid_arrays) { 4213*c1b3d7c5SThomas E. Spanjaard printf("ataraid: no memory for metadata storage\n"); 4214*c1b3d7c5SThomas E. Spanjaard return ENOMEM; 4215*c1b3d7c5SThomas E. Spanjaard } 4216*c1b3d7c5SThomas E. Spanjaard #endif 4217*c1b3d7c5SThomas E. Spanjaard /* attach found PseudoRAID arrays */ 4218*c1b3d7c5SThomas E. Spanjaard for (i = 0; i < MAX_ARRAYS; i++) { 4219*c1b3d7c5SThomas E. Spanjaard struct ar_softc *rdp = ata_raid_arrays[i]; 4220*c1b3d7c5SThomas E. Spanjaard 4221*c1b3d7c5SThomas E. Spanjaard if (!rdp || !rdp->format) 4222*c1b3d7c5SThomas E. Spanjaard continue; 4223*c1b3d7c5SThomas E. Spanjaard if (testing || bootverbose) 4224*c1b3d7c5SThomas E. Spanjaard ata_raid_print_meta(rdp); 4225*c1b3d7c5SThomas E. Spanjaard ata_raid_attach(rdp, 0); 4226*c1b3d7c5SThomas E. Spanjaard } 4227*c1b3d7c5SThomas E. Spanjaard ata_raid_ioctl_func = ata_raid_ioctl; 4228*c1b3d7c5SThomas E. Spanjaard return 0; 4229*c1b3d7c5SThomas E. Spanjaard 4230*c1b3d7c5SThomas E. Spanjaard case MOD_UNLOAD: 4231*c1b3d7c5SThomas E. Spanjaard /* detach found PseudoRAID arrays */ 4232*c1b3d7c5SThomas E. Spanjaard for (i = 0; i < MAX_ARRAYS; i++) { 4233*c1b3d7c5SThomas E. Spanjaard struct ar_softc *rdp = ata_raid_arrays[i]; 4234*c1b3d7c5SThomas E. Spanjaard 4235*c1b3d7c5SThomas E. Spanjaard if (!rdp || !rdp->status) 4236*c1b3d7c5SThomas E. Spanjaard continue; 4237*c1b3d7c5SThomas E. Spanjaard if (rdp->disk) 4238*c1b3d7c5SThomas E. Spanjaard disk_destroy(rdp->disk); 4239*c1b3d7c5SThomas E. Spanjaard } 4240*c1b3d7c5SThomas E. Spanjaard if (testing || bootverbose) 4241*c1b3d7c5SThomas E. Spanjaard printf("ATA PseudoRAID unloaded\n"); 4242*c1b3d7c5SThomas E. Spanjaard #if 0 4243*c1b3d7c5SThomas E. Spanjaard free(ata_raid_arrays, M_AR); 4244*c1b3d7c5SThomas E. Spanjaard #endif 4245*c1b3d7c5SThomas E. Spanjaard ata_raid_ioctl_func = NULL; 4246*c1b3d7c5SThomas E. Spanjaard return 0; 4247*c1b3d7c5SThomas E. Spanjaard 4248*c1b3d7c5SThomas E. Spanjaard default: 4249*c1b3d7c5SThomas E. Spanjaard return EOPNOTSUPP; 4250*c1b3d7c5SThomas E. Spanjaard } 4251*c1b3d7c5SThomas E. Spanjaard } 4252*c1b3d7c5SThomas E. Spanjaard 4253*c1b3d7c5SThomas E. Spanjaard static moduledata_t ata_raid_moduledata = 4254*c1b3d7c5SThomas E. Spanjaard { "ataraid", ata_raid_module_event_handler, NULL }; 4255*c1b3d7c5SThomas E. Spanjaard DECLARE_MODULE(ata, ata_raid_moduledata, SI_SUB_RAID, SI_ORDER_FIRST); 4256*c1b3d7c5SThomas E. Spanjaard MODULE_VERSION(ataraid, 1); 4257*c1b3d7c5SThomas E. Spanjaard MODULE_DEPEND(ataraid, ata, 1, 1, 1); 4258*c1b3d7c5SThomas E. Spanjaard MODULE_DEPEND(ataraid, ad, 1, 1, 1); 4259*c1b3d7c5SThomas E. Spanjaard 4260*c1b3d7c5SThomas E. Spanjaard static char * 4261*c1b3d7c5SThomas E. Spanjaard ata_raid_format(struct ar_softc *rdp) 4262*c1b3d7c5SThomas E. Spanjaard { 4263*c1b3d7c5SThomas E. Spanjaard switch (rdp->format) { 4264*c1b3d7c5SThomas E. Spanjaard case AR_F_FREEBSD_RAID: return "FreeBSD PseudoRAID"; 4265*c1b3d7c5SThomas E. Spanjaard case AR_F_ADAPTEC_RAID: return "Adaptec HostRAID"; 4266*c1b3d7c5SThomas E. Spanjaard case AR_F_HPTV2_RAID: return "HighPoint v2 RocketRAID"; 4267*c1b3d7c5SThomas E. Spanjaard case AR_F_HPTV3_RAID: return "HighPoint v3 RocketRAID"; 4268*c1b3d7c5SThomas E. Spanjaard case AR_F_INTEL_RAID: return "Intel MatrixRAID"; 4269*c1b3d7c5SThomas E. Spanjaard case AR_F_ITE_RAID: return "Integrated Technology Express"; 4270*c1b3d7c5SThomas E. Spanjaard case AR_F_JMICRON_RAID: return "JMicron Technology Corp"; 4271*c1b3d7c5SThomas E. Spanjaard case AR_F_LSIV2_RAID: return "LSILogic v2 MegaRAID"; 4272*c1b3d7c5SThomas E. Spanjaard case AR_F_LSIV3_RAID: return "LSILogic v3 MegaRAID"; 4273*c1b3d7c5SThomas E. Spanjaard case AR_F_NVIDIA_RAID: return "nVidia MediaShield"; 4274*c1b3d7c5SThomas E. Spanjaard case AR_F_PROMISE_RAID: return "Promise Fasttrak"; 4275*c1b3d7c5SThomas E. Spanjaard case AR_F_SII_RAID: return "Silicon Image Medley"; 4276*c1b3d7c5SThomas E. Spanjaard case AR_F_SIS_RAID: return "Silicon Integrated Systems"; 4277*c1b3d7c5SThomas E. Spanjaard case AR_F_VIA_RAID: return "VIA Tech V-RAID"; 4278*c1b3d7c5SThomas E. Spanjaard default: return "UNKNOWN"; 4279*c1b3d7c5SThomas E. Spanjaard } 4280*c1b3d7c5SThomas E. Spanjaard } 4281*c1b3d7c5SThomas E. Spanjaard 4282*c1b3d7c5SThomas E. Spanjaard static char * 4283*c1b3d7c5SThomas E. Spanjaard ata_raid_type(struct ar_softc *rdp) 4284*c1b3d7c5SThomas E. Spanjaard { 4285*c1b3d7c5SThomas E. Spanjaard switch (rdp->type) { 4286*c1b3d7c5SThomas E. Spanjaard case AR_T_JBOD: return "JBOD"; 4287*c1b3d7c5SThomas E. Spanjaard case AR_T_SPAN: return "SPAN"; 4288*c1b3d7c5SThomas E. Spanjaard case AR_T_RAID0: return "RAID0"; 4289*c1b3d7c5SThomas E. Spanjaard case AR_T_RAID1: return "RAID1"; 4290*c1b3d7c5SThomas E. Spanjaard case AR_T_RAID3: return "RAID3"; 4291*c1b3d7c5SThomas E. Spanjaard case AR_T_RAID4: return "RAID4"; 4292*c1b3d7c5SThomas E. Spanjaard case AR_T_RAID5: return "RAID5"; 4293*c1b3d7c5SThomas E. Spanjaard case AR_T_RAID01: return "RAID0+1"; 4294*c1b3d7c5SThomas E. Spanjaard default: return "UNKNOWN"; 4295*c1b3d7c5SThomas E. Spanjaard } 4296*c1b3d7c5SThomas E. Spanjaard } 4297*c1b3d7c5SThomas E. Spanjaard 4298*c1b3d7c5SThomas E. Spanjaard static char * 4299*c1b3d7c5SThomas E. Spanjaard ata_raid_flags(struct ar_softc *rdp) 4300*c1b3d7c5SThomas E. Spanjaard { 4301*c1b3d7c5SThomas E. Spanjaard switch (rdp->status & (AR_S_READY | AR_S_DEGRADED | AR_S_REBUILDING)) { 4302*c1b3d7c5SThomas E. Spanjaard case AR_S_READY: return "READY"; 4303*c1b3d7c5SThomas E. Spanjaard case AR_S_READY | AR_S_DEGRADED: return "DEGRADED"; 4304*c1b3d7c5SThomas E. Spanjaard case AR_S_READY | AR_S_REBUILDING: 4305*c1b3d7c5SThomas E. Spanjaard case AR_S_READY | AR_S_DEGRADED | AR_S_REBUILDING: return "REBUILDING"; 4306*c1b3d7c5SThomas E. Spanjaard default: return "BROKEN"; 4307*c1b3d7c5SThomas E. Spanjaard } 4308*c1b3d7c5SThomas E. Spanjaard } 4309*c1b3d7c5SThomas E. Spanjaard 4310*c1b3d7c5SThomas E. Spanjaard /* debugging gunk */ 4311*c1b3d7c5SThomas E. Spanjaard static void 4312*c1b3d7c5SThomas E. Spanjaard ata_raid_print_meta(struct ar_softc *raid) 4313*c1b3d7c5SThomas E. Spanjaard { 4314*c1b3d7c5SThomas E. Spanjaard int i; 4315*c1b3d7c5SThomas E. Spanjaard 4316*c1b3d7c5SThomas E. Spanjaard printf("********** ATA PseudoRAID ar%d Metadata **********\n", raid->lun); 4317*c1b3d7c5SThomas E. Spanjaard printf("=================================================\n"); 4318*c1b3d7c5SThomas E. Spanjaard printf("format %s\n", ata_raid_format(raid)); 4319*c1b3d7c5SThomas E. Spanjaard printf("type %s\n", ata_raid_type(raid)); 4320*c1b3d7c5SThomas E. Spanjaard printf("flags 0x%02x %b\n", raid->status, raid->status, 4321*c1b3d7c5SThomas E. Spanjaard "\20\3REBUILDING\2DEGRADED\1READY\n"); 4322*c1b3d7c5SThomas E. Spanjaard printf("magic_0 0x%016jx\n", raid->magic_0); 4323*c1b3d7c5SThomas E. Spanjaard printf("magic_1 0x%016jx\n",raid->magic_1); 4324*c1b3d7c5SThomas E. Spanjaard printf("generation %u\n", raid->generation); 4325*c1b3d7c5SThomas E. Spanjaard printf("total_sectors %ju\n", raid->total_sectors); 4326*c1b3d7c5SThomas E. Spanjaard printf("offset_sectors %ju\n", raid->offset_sectors); 4327*c1b3d7c5SThomas E. Spanjaard printf("heads %u\n", raid->heads); 4328*c1b3d7c5SThomas E. Spanjaard printf("sectors %u\n", raid->sectors); 4329*c1b3d7c5SThomas E. Spanjaard printf("cylinders %u\n", raid->cylinders); 4330*c1b3d7c5SThomas E. Spanjaard printf("width %u\n", raid->width); 4331*c1b3d7c5SThomas E. Spanjaard printf("interleave %u\n", raid->interleave); 4332*c1b3d7c5SThomas E. Spanjaard printf("total_disks %u\n", raid->total_disks); 4333*c1b3d7c5SThomas E. Spanjaard for (i = 0; i < raid->total_disks; i++) { 4334*c1b3d7c5SThomas E. Spanjaard printf(" disk %d: flags = 0x%02x %b\n", i, raid->disks[i].flags, 4335*c1b3d7c5SThomas E. Spanjaard raid->disks[i].flags, "\20\4ONLINE\3SPARE\2ASSIGNED\1PRESENT\n"); 4336*c1b3d7c5SThomas E. Spanjaard if (raid->disks[i].dev) { 4337*c1b3d7c5SThomas E. Spanjaard printf(" "); 4338*c1b3d7c5SThomas E. Spanjaard device_printf(raid->disks[i].dev, " sectors %jd\n", 4339*c1b3d7c5SThomas E. Spanjaard raid->disks[i].sectors); 4340*c1b3d7c5SThomas E. Spanjaard } 4341*c1b3d7c5SThomas E. Spanjaard } 4342*c1b3d7c5SThomas E. Spanjaard printf("=================================================\n"); 4343*c1b3d7c5SThomas E. Spanjaard } 4344*c1b3d7c5SThomas E. Spanjaard 4345*c1b3d7c5SThomas E. Spanjaard static char * 4346*c1b3d7c5SThomas E. Spanjaard ata_raid_adaptec_type(int type) 4347*c1b3d7c5SThomas E. Spanjaard { 4348*c1b3d7c5SThomas E. Spanjaard static char buffer[16]; 4349*c1b3d7c5SThomas E. Spanjaard 4350*c1b3d7c5SThomas E. Spanjaard switch (type) { 4351*c1b3d7c5SThomas E. Spanjaard case ADP_T_RAID0: return "RAID0"; 4352*c1b3d7c5SThomas E. Spanjaard case ADP_T_RAID1: return "RAID1"; 4353*c1b3d7c5SThomas E. Spanjaard default: sprintf(buffer, "UNKNOWN 0x%02x", type); 4354*c1b3d7c5SThomas E. Spanjaard return buffer; 4355*c1b3d7c5SThomas E. Spanjaard } 4356*c1b3d7c5SThomas E. Spanjaard } 4357*c1b3d7c5SThomas E. Spanjaard 4358*c1b3d7c5SThomas E. Spanjaard static void 4359*c1b3d7c5SThomas E. Spanjaard ata_raid_adaptec_print_meta(struct adaptec_raid_conf *meta) 4360*c1b3d7c5SThomas E. Spanjaard { 4361*c1b3d7c5SThomas E. Spanjaard int i; 4362*c1b3d7c5SThomas E. Spanjaard 4363*c1b3d7c5SThomas E. Spanjaard printf("********* ATA Adaptec HostRAID Metadata *********\n"); 4364*c1b3d7c5SThomas E. Spanjaard printf("magic_0 <0x%08x>\n", be32toh(meta->magic_0)); 4365*c1b3d7c5SThomas E. Spanjaard printf("generation 0x%08x\n", be32toh(meta->generation)); 4366*c1b3d7c5SThomas E. Spanjaard printf("dummy_0 0x%04x\n", be16toh(meta->dummy_0)); 4367*c1b3d7c5SThomas E. Spanjaard printf("total_configs %u\n", be16toh(meta->total_configs)); 4368*c1b3d7c5SThomas E. Spanjaard printf("dummy_1 0x%04x\n", be16toh(meta->dummy_1)); 4369*c1b3d7c5SThomas E. Spanjaard printf("checksum 0x%04x\n", be16toh(meta->checksum)); 4370*c1b3d7c5SThomas E. Spanjaard printf("dummy_2 0x%08x\n", be32toh(meta->dummy_2)); 4371*c1b3d7c5SThomas E. Spanjaard printf("dummy_3 0x%08x\n", be32toh(meta->dummy_3)); 4372*c1b3d7c5SThomas E. Spanjaard printf("flags 0x%08x\n", be32toh(meta->flags)); 4373*c1b3d7c5SThomas E. Spanjaard printf("timestamp 0x%08x\n", be32toh(meta->timestamp)); 4374*c1b3d7c5SThomas E. Spanjaard printf("dummy_4 0x%08x 0x%08x 0x%08x 0x%08x\n", 4375*c1b3d7c5SThomas E. Spanjaard be32toh(meta->dummy_4[0]), be32toh(meta->dummy_4[1]), 4376*c1b3d7c5SThomas E. Spanjaard be32toh(meta->dummy_4[2]), be32toh(meta->dummy_4[3])); 4377*c1b3d7c5SThomas E. Spanjaard printf("dummy_5 0x%08x 0x%08x 0x%08x 0x%08x\n", 4378*c1b3d7c5SThomas E. Spanjaard be32toh(meta->dummy_5[0]), be32toh(meta->dummy_5[1]), 4379*c1b3d7c5SThomas E. Spanjaard be32toh(meta->dummy_5[2]), be32toh(meta->dummy_5[3])); 4380*c1b3d7c5SThomas E. Spanjaard 4381*c1b3d7c5SThomas E. Spanjaard for (i = 0; i < be16toh(meta->total_configs); i++) { 4382*c1b3d7c5SThomas E. Spanjaard printf(" %d total_disks %u\n", i, 4383*c1b3d7c5SThomas E. Spanjaard be16toh(meta->configs[i].disk_number)); 4384*c1b3d7c5SThomas E. Spanjaard printf(" %d generation %u\n", i, 4385*c1b3d7c5SThomas E. Spanjaard be16toh(meta->configs[i].generation)); 4386*c1b3d7c5SThomas E. Spanjaard printf(" %d magic_0 0x%08x\n", i, 4387*c1b3d7c5SThomas E. Spanjaard be32toh(meta->configs[i].magic_0)); 4388*c1b3d7c5SThomas E. Spanjaard printf(" %d dummy_0 0x%02x\n", i, meta->configs[i].dummy_0); 4389*c1b3d7c5SThomas E. Spanjaard printf(" %d type %s\n", i, 4390*c1b3d7c5SThomas E. Spanjaard ata_raid_adaptec_type(meta->configs[i].type)); 4391*c1b3d7c5SThomas E. Spanjaard printf(" %d dummy_1 0x%02x\n", i, meta->configs[i].dummy_1); 4392*c1b3d7c5SThomas E. Spanjaard printf(" %d flags %d\n", i, 4393*c1b3d7c5SThomas E. Spanjaard be32toh(meta->configs[i].flags)); 4394*c1b3d7c5SThomas E. Spanjaard printf(" %d dummy_2 0x%02x\n", i, meta->configs[i].dummy_2); 4395*c1b3d7c5SThomas E. Spanjaard printf(" %d dummy_3 0x%02x\n", i, meta->configs[i].dummy_3); 4396*c1b3d7c5SThomas E. Spanjaard printf(" %d dummy_4 0x%02x\n", i, meta->configs[i].dummy_4); 4397*c1b3d7c5SThomas E. Spanjaard printf(" %d dummy_5 0x%02x\n", i, meta->configs[i].dummy_5); 4398*c1b3d7c5SThomas E. Spanjaard printf(" %d disk_number %u\n", i, 4399*c1b3d7c5SThomas E. Spanjaard be32toh(meta->configs[i].disk_number)); 4400*c1b3d7c5SThomas E. Spanjaard printf(" %d dummy_6 0x%08x\n", i, 4401*c1b3d7c5SThomas E. Spanjaard be32toh(meta->configs[i].dummy_6)); 4402*c1b3d7c5SThomas E. Spanjaard printf(" %d sectors %u\n", i, 4403*c1b3d7c5SThomas E. Spanjaard be32toh(meta->configs[i].sectors)); 4404*c1b3d7c5SThomas E. Spanjaard printf(" %d stripe_shift %u\n", i, 4405*c1b3d7c5SThomas E. Spanjaard be16toh(meta->configs[i].stripe_shift)); 4406*c1b3d7c5SThomas E. Spanjaard printf(" %d dummy_7 0x%08x\n", i, 4407*c1b3d7c5SThomas E. Spanjaard be32toh(meta->configs[i].dummy_7)); 4408*c1b3d7c5SThomas E. Spanjaard printf(" %d dummy_8 0x%08x 0x%08x 0x%08x 0x%08x\n", i, 4409*c1b3d7c5SThomas E. Spanjaard be32toh(meta->configs[i].dummy_8[0]), 4410*c1b3d7c5SThomas E. Spanjaard be32toh(meta->configs[i].dummy_8[1]), 4411*c1b3d7c5SThomas E. Spanjaard be32toh(meta->configs[i].dummy_8[2]), 4412*c1b3d7c5SThomas E. Spanjaard be32toh(meta->configs[i].dummy_8[3])); 4413*c1b3d7c5SThomas E. Spanjaard printf(" %d name <%s>\n", i, meta->configs[i].name); 4414*c1b3d7c5SThomas E. Spanjaard } 4415*c1b3d7c5SThomas E. Spanjaard printf("magic_1 <0x%08x>\n", be32toh(meta->magic_1)); 4416*c1b3d7c5SThomas E. Spanjaard printf("magic_2 <0x%08x>\n", be32toh(meta->magic_2)); 4417*c1b3d7c5SThomas E. Spanjaard printf("magic_3 <0x%08x>\n", be32toh(meta->magic_3)); 4418*c1b3d7c5SThomas E. Spanjaard printf("magic_4 <0x%08x>\n", be32toh(meta->magic_4)); 4419*c1b3d7c5SThomas E. Spanjaard printf("=================================================\n"); 4420*c1b3d7c5SThomas E. Spanjaard } 4421*c1b3d7c5SThomas E. Spanjaard 4422*c1b3d7c5SThomas E. Spanjaard static char * 4423*c1b3d7c5SThomas E. Spanjaard ata_raid_hptv2_type(int type) 4424*c1b3d7c5SThomas E. Spanjaard { 4425*c1b3d7c5SThomas E. Spanjaard static char buffer[16]; 4426*c1b3d7c5SThomas E. Spanjaard 4427*c1b3d7c5SThomas E. Spanjaard switch (type) { 4428*c1b3d7c5SThomas E. Spanjaard case HPTV2_T_RAID0: return "RAID0"; 4429*c1b3d7c5SThomas E. Spanjaard case HPTV2_T_RAID1: return "RAID1"; 4430*c1b3d7c5SThomas E. Spanjaard case HPTV2_T_RAID01_RAID0: return "RAID01_RAID0"; 4431*c1b3d7c5SThomas E. Spanjaard case HPTV2_T_SPAN: return "SPAN"; 4432*c1b3d7c5SThomas E. Spanjaard case HPTV2_T_RAID_3: return "RAID3"; 4433*c1b3d7c5SThomas E. Spanjaard case HPTV2_T_RAID_5: return "RAID5"; 4434*c1b3d7c5SThomas E. Spanjaard case HPTV2_T_JBOD: return "JBOD"; 4435*c1b3d7c5SThomas E. Spanjaard case HPTV2_T_RAID01_RAID1: return "RAID01_RAID1"; 4436*c1b3d7c5SThomas E. Spanjaard default: sprintf(buffer, "UNKNOWN 0x%02x", type); 4437*c1b3d7c5SThomas E. Spanjaard return buffer; 4438*c1b3d7c5SThomas E. Spanjaard } 4439*c1b3d7c5SThomas E. Spanjaard } 4440*c1b3d7c5SThomas E. Spanjaard 4441*c1b3d7c5SThomas E. Spanjaard static void 4442*c1b3d7c5SThomas E. Spanjaard ata_raid_hptv2_print_meta(struct hptv2_raid_conf *meta) 4443*c1b3d7c5SThomas E. Spanjaard { 4444*c1b3d7c5SThomas E. Spanjaard int i; 4445*c1b3d7c5SThomas E. Spanjaard 4446*c1b3d7c5SThomas E. Spanjaard printf("****** ATA Highpoint V2 RocketRAID Metadata *****\n"); 4447*c1b3d7c5SThomas E. Spanjaard printf("magic 0x%08x\n", meta->magic); 4448*c1b3d7c5SThomas E. Spanjaard printf("magic_0 0x%08x\n", meta->magic_0); 4449*c1b3d7c5SThomas E. Spanjaard printf("magic_1 0x%08x\n", meta->magic_1); 4450*c1b3d7c5SThomas E. Spanjaard printf("order 0x%08x\n", meta->order); 4451*c1b3d7c5SThomas E. Spanjaard printf("array_width %u\n", meta->array_width); 4452*c1b3d7c5SThomas E. Spanjaard printf("stripe_shift %u\n", meta->stripe_shift); 4453*c1b3d7c5SThomas E. Spanjaard printf("type %s\n", ata_raid_hptv2_type(meta->type)); 4454*c1b3d7c5SThomas E. Spanjaard printf("disk_number %u\n", meta->disk_number); 4455*c1b3d7c5SThomas E. Spanjaard printf("total_sectors %u\n", meta->total_sectors); 4456*c1b3d7c5SThomas E. Spanjaard printf("disk_mode 0x%08x\n", meta->disk_mode); 4457*c1b3d7c5SThomas E. Spanjaard printf("boot_mode 0x%08x\n", meta->boot_mode); 4458*c1b3d7c5SThomas E. Spanjaard printf("boot_disk 0x%02x\n", meta->boot_disk); 4459*c1b3d7c5SThomas E. Spanjaard printf("boot_protect 0x%02x\n", meta->boot_protect); 4460*c1b3d7c5SThomas E. Spanjaard printf("log_entries 0x%02x\n", meta->error_log_entries); 4461*c1b3d7c5SThomas E. Spanjaard printf("log_index 0x%02x\n", meta->error_log_index); 4462*c1b3d7c5SThomas E. Spanjaard if (meta->error_log_entries) { 4463*c1b3d7c5SThomas E. Spanjaard printf(" timestamp reason disk status sectors lba\n"); 4464*c1b3d7c5SThomas E. Spanjaard for (i = meta->error_log_index; 4465*c1b3d7c5SThomas E. Spanjaard i < meta->error_log_index + meta->error_log_entries; i++) 4466*c1b3d7c5SThomas E. Spanjaard printf(" 0x%08x 0x%02x 0x%02x 0x%02x 0x%02x 0x%08x\n", 4467*c1b3d7c5SThomas E. Spanjaard meta->errorlog[i%32].timestamp, 4468*c1b3d7c5SThomas E. Spanjaard meta->errorlog[i%32].reason, 4469*c1b3d7c5SThomas E. Spanjaard meta->errorlog[i%32].disk, meta->errorlog[i%32].status, 4470*c1b3d7c5SThomas E. Spanjaard meta->errorlog[i%32].sectors, meta->errorlog[i%32].lba); 4471*c1b3d7c5SThomas E. Spanjaard } 4472*c1b3d7c5SThomas E. Spanjaard printf("rebuild_lba 0x%08x\n", meta->rebuild_lba); 4473*c1b3d7c5SThomas E. Spanjaard printf("dummy_1 0x%02x\n", meta->dummy_1); 4474*c1b3d7c5SThomas E. Spanjaard printf("name_1 <%.15s>\n", meta->name_1); 4475*c1b3d7c5SThomas E. Spanjaard printf("dummy_2 0x%02x\n", meta->dummy_2); 4476*c1b3d7c5SThomas E. Spanjaard printf("name_2 <%.15s>\n", meta->name_2); 4477*c1b3d7c5SThomas E. Spanjaard printf("=================================================\n"); 4478*c1b3d7c5SThomas E. Spanjaard } 4479*c1b3d7c5SThomas E. Spanjaard 4480*c1b3d7c5SThomas E. Spanjaard static char * 4481*c1b3d7c5SThomas E. Spanjaard ata_raid_hptv3_type(int type) 4482*c1b3d7c5SThomas E. Spanjaard { 4483*c1b3d7c5SThomas E. Spanjaard static char buffer[16]; 4484*c1b3d7c5SThomas E. Spanjaard 4485*c1b3d7c5SThomas E. Spanjaard switch (type) { 4486*c1b3d7c5SThomas E. Spanjaard case HPTV3_T_SPARE: return "SPARE"; 4487*c1b3d7c5SThomas E. Spanjaard case HPTV3_T_JBOD: return "JBOD"; 4488*c1b3d7c5SThomas E. Spanjaard case HPTV3_T_SPAN: return "SPAN"; 4489*c1b3d7c5SThomas E. Spanjaard case HPTV3_T_RAID0: return "RAID0"; 4490*c1b3d7c5SThomas E. Spanjaard case HPTV3_T_RAID1: return "RAID1"; 4491*c1b3d7c5SThomas E. Spanjaard case HPTV3_T_RAID3: return "RAID3"; 4492*c1b3d7c5SThomas E. Spanjaard case HPTV3_T_RAID5: return "RAID5"; 4493*c1b3d7c5SThomas E. Spanjaard default: sprintf(buffer, "UNKNOWN 0x%02x", type); 4494*c1b3d7c5SThomas E. Spanjaard return buffer; 4495*c1b3d7c5SThomas E. Spanjaard } 4496*c1b3d7c5SThomas E. Spanjaard } 4497*c1b3d7c5SThomas E. Spanjaard 4498*c1b3d7c5SThomas E. Spanjaard static void 4499*c1b3d7c5SThomas E. Spanjaard ata_raid_hptv3_print_meta(struct hptv3_raid_conf *meta) 4500*c1b3d7c5SThomas E. Spanjaard { 4501*c1b3d7c5SThomas E. Spanjaard int i; 4502*c1b3d7c5SThomas E. Spanjaard 4503*c1b3d7c5SThomas E. Spanjaard printf("****** ATA Highpoint V3 RocketRAID Metadata *****\n"); 4504*c1b3d7c5SThomas E. Spanjaard printf("magic 0x%08x\n", meta->magic); 4505*c1b3d7c5SThomas E. Spanjaard printf("magic_0 0x%08x\n", meta->magic_0); 4506*c1b3d7c5SThomas E. Spanjaard printf("checksum_0 0x%02x\n", meta->checksum_0); 4507*c1b3d7c5SThomas E. Spanjaard printf("mode 0x%02x\n", meta->mode); 4508*c1b3d7c5SThomas E. Spanjaard printf("user_mode 0x%02x\n", meta->user_mode); 4509*c1b3d7c5SThomas E. Spanjaard printf("config_entries 0x%02x\n", meta->config_entries); 4510*c1b3d7c5SThomas E. Spanjaard for (i = 0; i < meta->config_entries; i++) { 4511*c1b3d7c5SThomas E. Spanjaard printf("config %d:\n", i); 4512*c1b3d7c5SThomas E. Spanjaard printf(" total_sectors %ju\n", 4513*c1b3d7c5SThomas E. Spanjaard meta->configs[0].total_sectors + 4514*c1b3d7c5SThomas E. Spanjaard ((u_int64_t)meta->configs_high[0].total_sectors << 32)); 4515*c1b3d7c5SThomas E. Spanjaard printf(" type %s\n", 4516*c1b3d7c5SThomas E. Spanjaard ata_raid_hptv3_type(meta->configs[i].type)); 4517*c1b3d7c5SThomas E. Spanjaard printf(" total_disks %u\n", meta->configs[i].total_disks); 4518*c1b3d7c5SThomas E. Spanjaard printf(" disk_number %u\n", meta->configs[i].disk_number); 4519*c1b3d7c5SThomas E. Spanjaard printf(" stripe_shift %u\n", meta->configs[i].stripe_shift); 4520*c1b3d7c5SThomas E. Spanjaard printf(" status %b\n", meta->configs[i].status, 4521*c1b3d7c5SThomas E. Spanjaard "\20\2RAID5\1NEED_REBUILD\n"); 4522*c1b3d7c5SThomas E. Spanjaard printf(" critical_disks %u\n", meta->configs[i].critical_disks); 4523*c1b3d7c5SThomas E. Spanjaard printf(" rebuild_lba %ju\n", 4524*c1b3d7c5SThomas E. Spanjaard meta->configs_high[0].rebuild_lba + 4525*c1b3d7c5SThomas E. Spanjaard ((u_int64_t)meta->configs_high[0].rebuild_lba << 32)); 4526*c1b3d7c5SThomas E. Spanjaard } 4527*c1b3d7c5SThomas E. Spanjaard printf("name <%.16s>\n", meta->name); 4528*c1b3d7c5SThomas E. Spanjaard printf("timestamp 0x%08x\n", meta->timestamp); 4529*c1b3d7c5SThomas E. Spanjaard printf("description <%.16s>\n", meta->description); 4530*c1b3d7c5SThomas E. Spanjaard printf("creator <%.16s>\n", meta->creator); 4531*c1b3d7c5SThomas E. Spanjaard printf("checksum_1 0x%02x\n", meta->checksum_1); 4532*c1b3d7c5SThomas E. Spanjaard printf("dummy_0 0x%02x\n", meta->dummy_0); 4533*c1b3d7c5SThomas E. Spanjaard printf("dummy_1 0x%02x\n", meta->dummy_1); 4534*c1b3d7c5SThomas E. Spanjaard printf("flags %b\n", meta->flags, 4535*c1b3d7c5SThomas E. Spanjaard "\20\4RCACHE\3WCACHE\2NCQ\1TCQ\n"); 4536*c1b3d7c5SThomas E. Spanjaard printf("=================================================\n"); 4537*c1b3d7c5SThomas E. Spanjaard } 4538*c1b3d7c5SThomas E. Spanjaard 4539*c1b3d7c5SThomas E. Spanjaard static char * 4540*c1b3d7c5SThomas E. Spanjaard ata_raid_intel_type(int type) 4541*c1b3d7c5SThomas E. Spanjaard { 4542*c1b3d7c5SThomas E. Spanjaard static char buffer[16]; 4543*c1b3d7c5SThomas E. Spanjaard 4544*c1b3d7c5SThomas E. Spanjaard switch (type) { 4545*c1b3d7c5SThomas E. Spanjaard case INTEL_T_RAID0: return "RAID0"; 4546*c1b3d7c5SThomas E. Spanjaard case INTEL_T_RAID1: return "RAID1"; 4547*c1b3d7c5SThomas E. Spanjaard case INTEL_T_RAID5: return "RAID5"; 4548*c1b3d7c5SThomas E. Spanjaard default: sprintf(buffer, "UNKNOWN 0x%02x", type); 4549*c1b3d7c5SThomas E. Spanjaard return buffer; 4550*c1b3d7c5SThomas E. Spanjaard } 4551*c1b3d7c5SThomas E. Spanjaard } 4552*c1b3d7c5SThomas E. Spanjaard 4553*c1b3d7c5SThomas E. Spanjaard static void 4554*c1b3d7c5SThomas E. Spanjaard ata_raid_intel_print_meta(struct intel_raid_conf *meta) 4555*c1b3d7c5SThomas E. Spanjaard { 4556*c1b3d7c5SThomas E. Spanjaard struct intel_raid_mapping *map; 4557*c1b3d7c5SThomas E. Spanjaard int i, j; 4558*c1b3d7c5SThomas E. Spanjaard 4559*c1b3d7c5SThomas E. Spanjaard printf("********* ATA Intel MatrixRAID Metadata *********\n"); 4560*c1b3d7c5SThomas E. Spanjaard printf("intel_id <%.24s>\n", meta->intel_id); 4561*c1b3d7c5SThomas E. Spanjaard printf("version <%.6s>\n", meta->version); 4562*c1b3d7c5SThomas E. Spanjaard printf("checksum 0x%08x\n", meta->checksum); 4563*c1b3d7c5SThomas E. Spanjaard printf("config_size 0x%08x\n", meta->config_size); 4564*c1b3d7c5SThomas E. Spanjaard printf("config_id 0x%08x\n", meta->config_id); 4565*c1b3d7c5SThomas E. Spanjaard printf("generation 0x%08x\n", meta->generation); 4566*c1b3d7c5SThomas E. Spanjaard printf("total_disks %u\n", meta->total_disks); 4567*c1b3d7c5SThomas E. Spanjaard printf("total_volumes %u\n", meta->total_volumes); 4568*c1b3d7c5SThomas E. Spanjaard printf("DISK# serial disk_sectors disk_id flags\n"); 4569*c1b3d7c5SThomas E. Spanjaard for (i = 0; i < meta->total_disks; i++ ) { 4570*c1b3d7c5SThomas E. Spanjaard printf(" %d <%.16s> %u 0x%08x 0x%08x\n", i, 4571*c1b3d7c5SThomas E. Spanjaard meta->disk[i].serial, meta->disk[i].sectors, 4572*c1b3d7c5SThomas E. Spanjaard meta->disk[i].id, meta->disk[i].flags); 4573*c1b3d7c5SThomas E. Spanjaard } 4574*c1b3d7c5SThomas E. Spanjaard map = (struct intel_raid_mapping *)&meta->disk[meta->total_disks]; 4575*c1b3d7c5SThomas E. Spanjaard for (j = 0; j < meta->total_volumes; j++) { 4576*c1b3d7c5SThomas E. Spanjaard printf("name %.16s\n", map->name); 4577*c1b3d7c5SThomas E. Spanjaard printf("total_sectors %ju\n", map->total_sectors); 4578*c1b3d7c5SThomas E. Spanjaard printf("state %u\n", map->state); 4579*c1b3d7c5SThomas E. Spanjaard printf("reserved %u\n", map->reserved); 4580*c1b3d7c5SThomas E. Spanjaard printf("offset %u\n", map->offset); 4581*c1b3d7c5SThomas E. Spanjaard printf("disk_sectors %u\n", map->disk_sectors); 4582*c1b3d7c5SThomas E. Spanjaard printf("stripe_count %u\n", map->stripe_count); 4583*c1b3d7c5SThomas E. Spanjaard printf("stripe_sectors %u\n", map->stripe_sectors); 4584*c1b3d7c5SThomas E. Spanjaard printf("status %u\n", map->status); 4585*c1b3d7c5SThomas E. Spanjaard printf("type %s\n", ata_raid_intel_type(map->type)); 4586*c1b3d7c5SThomas E. Spanjaard printf("total_disks %u\n", map->total_disks); 4587*c1b3d7c5SThomas E. Spanjaard printf("magic[0] 0x%02x\n", map->magic[0]); 4588*c1b3d7c5SThomas E. Spanjaard printf("magic[1] 0x%02x\n", map->magic[1]); 4589*c1b3d7c5SThomas E. Spanjaard printf("magic[2] 0x%02x\n", map->magic[2]); 4590*c1b3d7c5SThomas E. Spanjaard for (i = 0; i < map->total_disks; i++ ) { 4591*c1b3d7c5SThomas E. Spanjaard printf(" disk %d at disk_idx 0x%08x\n", i, map->disk_idx[i]); 4592*c1b3d7c5SThomas E. Spanjaard } 4593*c1b3d7c5SThomas E. Spanjaard map = (struct intel_raid_mapping *)&map->disk_idx[map->total_disks]; 4594*c1b3d7c5SThomas E. Spanjaard } 4595*c1b3d7c5SThomas E. Spanjaard printf("=================================================\n"); 4596*c1b3d7c5SThomas E. Spanjaard } 4597*c1b3d7c5SThomas E. Spanjaard 4598*c1b3d7c5SThomas E. Spanjaard static char * 4599*c1b3d7c5SThomas E. Spanjaard ata_raid_ite_type(int type) 4600*c1b3d7c5SThomas E. Spanjaard { 4601*c1b3d7c5SThomas E. Spanjaard static char buffer[16]; 4602*c1b3d7c5SThomas E. Spanjaard 4603*c1b3d7c5SThomas E. Spanjaard switch (type) { 4604*c1b3d7c5SThomas E. Spanjaard case ITE_T_RAID0: return "RAID0"; 4605*c1b3d7c5SThomas E. Spanjaard case ITE_T_RAID1: return "RAID1"; 4606*c1b3d7c5SThomas E. Spanjaard case ITE_T_RAID01: return "RAID0+1"; 4607*c1b3d7c5SThomas E. Spanjaard case ITE_T_SPAN: return "SPAN"; 4608*c1b3d7c5SThomas E. Spanjaard default: sprintf(buffer, "UNKNOWN 0x%02x", type); 4609*c1b3d7c5SThomas E. Spanjaard return buffer; 4610*c1b3d7c5SThomas E. Spanjaard } 4611*c1b3d7c5SThomas E. Spanjaard } 4612*c1b3d7c5SThomas E. Spanjaard 4613*c1b3d7c5SThomas E. Spanjaard static void 4614*c1b3d7c5SThomas E. Spanjaard ata_raid_ite_print_meta(struct ite_raid_conf *meta) 4615*c1b3d7c5SThomas E. Spanjaard { 4616*c1b3d7c5SThomas E. Spanjaard printf("*** ATA Integrated Technology Express Metadata **\n"); 4617*c1b3d7c5SThomas E. Spanjaard printf("ite_id <%.40s>\n", meta->ite_id); 4618*c1b3d7c5SThomas E. Spanjaard printf("timestamp_0 %04x/%02x/%02x %02x:%02x:%02x.%02x\n", 4619*c1b3d7c5SThomas E. Spanjaard *((u_int16_t *)meta->timestamp_0), meta->timestamp_0[2], 4620*c1b3d7c5SThomas E. Spanjaard meta->timestamp_0[3], meta->timestamp_0[5], meta->timestamp_0[4], 4621*c1b3d7c5SThomas E. Spanjaard meta->timestamp_0[7], meta->timestamp_0[6]); 4622*c1b3d7c5SThomas E. Spanjaard printf("total_sectors %jd\n", meta->total_sectors); 4623*c1b3d7c5SThomas E. Spanjaard printf("type %s\n", ata_raid_ite_type(meta->type)); 4624*c1b3d7c5SThomas E. Spanjaard printf("stripe_1kblocks %u\n", meta->stripe_1kblocks); 4625*c1b3d7c5SThomas E. Spanjaard printf("timestamp_1 %04x/%02x/%02x %02x:%02x:%02x.%02x\n", 4626*c1b3d7c5SThomas E. Spanjaard *((u_int16_t *)meta->timestamp_1), meta->timestamp_1[2], 4627*c1b3d7c5SThomas E. Spanjaard meta->timestamp_1[3], meta->timestamp_1[5], meta->timestamp_1[4], 4628*c1b3d7c5SThomas E. Spanjaard meta->timestamp_1[7], meta->timestamp_1[6]); 4629*c1b3d7c5SThomas E. Spanjaard printf("stripe_sectors %u\n", meta->stripe_sectors); 4630*c1b3d7c5SThomas E. Spanjaard printf("array_width %u\n", meta->array_width); 4631*c1b3d7c5SThomas E. Spanjaard printf("disk_number %u\n", meta->disk_number); 4632*c1b3d7c5SThomas E. Spanjaard printf("disk_sectors %u\n", meta->disk_sectors); 4633*c1b3d7c5SThomas E. Spanjaard printf("=================================================\n"); 4634*c1b3d7c5SThomas E. Spanjaard } 4635*c1b3d7c5SThomas E. Spanjaard 4636*c1b3d7c5SThomas E. Spanjaard static char * 4637*c1b3d7c5SThomas E. Spanjaard ata_raid_jmicron_type(int type) 4638*c1b3d7c5SThomas E. Spanjaard { 4639*c1b3d7c5SThomas E. Spanjaard static char buffer[16]; 4640*c1b3d7c5SThomas E. Spanjaard 4641*c1b3d7c5SThomas E. Spanjaard switch (type) { 4642*c1b3d7c5SThomas E. Spanjaard case JM_T_RAID0: return "RAID0"; 4643*c1b3d7c5SThomas E. Spanjaard case JM_T_RAID1: return "RAID1"; 4644*c1b3d7c5SThomas E. Spanjaard case JM_T_RAID01: return "RAID0+1"; 4645*c1b3d7c5SThomas E. Spanjaard case JM_T_JBOD: return "JBOD"; 4646*c1b3d7c5SThomas E. Spanjaard case JM_T_RAID5: return "RAID5"; 4647*c1b3d7c5SThomas E. Spanjaard default: sprintf(buffer, "UNKNOWN 0x%02x", type); 4648*c1b3d7c5SThomas E. Spanjaard return buffer; 4649*c1b3d7c5SThomas E. Spanjaard } 4650*c1b3d7c5SThomas E. Spanjaard } 4651*c1b3d7c5SThomas E. Spanjaard 4652*c1b3d7c5SThomas E. Spanjaard static void 4653*c1b3d7c5SThomas E. Spanjaard ata_raid_jmicron_print_meta(struct jmicron_raid_conf *meta) 4654*c1b3d7c5SThomas E. Spanjaard { 4655*c1b3d7c5SThomas E. Spanjaard int i; 4656*c1b3d7c5SThomas E. Spanjaard 4657*c1b3d7c5SThomas E. Spanjaard printf("***** ATA JMicron Technology Corp Metadata ******\n"); 4658*c1b3d7c5SThomas E. Spanjaard printf("signature %.2s\n", meta->signature); 4659*c1b3d7c5SThomas E. Spanjaard printf("version 0x%04x\n", meta->version); 4660*c1b3d7c5SThomas E. Spanjaard printf("checksum 0x%04x\n", meta->checksum); 4661*c1b3d7c5SThomas E. Spanjaard printf("disk_id 0x%08x\n", meta->disk_id); 4662*c1b3d7c5SThomas E. Spanjaard printf("offset 0x%08x\n", meta->offset); 4663*c1b3d7c5SThomas E. Spanjaard printf("disk_sectors_low 0x%08x\n", meta->disk_sectors_low); 4664*c1b3d7c5SThomas E. Spanjaard printf("disk_sectors_high 0x%08x\n", meta->disk_sectors_high); 4665*c1b3d7c5SThomas E. Spanjaard printf("name %.16s\n", meta->name); 4666*c1b3d7c5SThomas E. Spanjaard printf("type %s\n", ata_raid_jmicron_type(meta->type)); 4667*c1b3d7c5SThomas E. Spanjaard printf("stripe_shift %d\n", meta->stripe_shift); 4668*c1b3d7c5SThomas E. Spanjaard printf("flags 0x%04x\n", meta->flags); 4669*c1b3d7c5SThomas E. Spanjaard printf("spare:\n"); 4670*c1b3d7c5SThomas E. Spanjaard for (i=0; i < 2 && meta->spare[i]; i++) 4671*c1b3d7c5SThomas E. Spanjaard printf(" %d 0x%08x\n", i, meta->spare[i]); 4672*c1b3d7c5SThomas E. Spanjaard printf("disks:\n"); 4673*c1b3d7c5SThomas E. Spanjaard for (i=0; i < 8 && meta->disks[i]; i++) 4674*c1b3d7c5SThomas E. Spanjaard printf(" %d 0x%08x\n", i, meta->disks[i]); 4675*c1b3d7c5SThomas E. Spanjaard printf("=================================================\n"); 4676*c1b3d7c5SThomas E. Spanjaard } 4677*c1b3d7c5SThomas E. Spanjaard 4678*c1b3d7c5SThomas E. Spanjaard static char * 4679*c1b3d7c5SThomas E. Spanjaard ata_raid_lsiv2_type(int type) 4680*c1b3d7c5SThomas E. Spanjaard { 4681*c1b3d7c5SThomas E. Spanjaard static char buffer[16]; 4682*c1b3d7c5SThomas E. Spanjaard 4683*c1b3d7c5SThomas E. Spanjaard switch (type) { 4684*c1b3d7c5SThomas E. Spanjaard case LSIV2_T_RAID0: return "RAID0"; 4685*c1b3d7c5SThomas E. Spanjaard case LSIV2_T_RAID1: return "RAID1"; 4686*c1b3d7c5SThomas E. Spanjaard case LSIV2_T_SPARE: return "SPARE"; 4687*c1b3d7c5SThomas E. Spanjaard default: sprintf(buffer, "UNKNOWN 0x%02x", type); 4688*c1b3d7c5SThomas E. Spanjaard return buffer; 4689*c1b3d7c5SThomas E. Spanjaard } 4690*c1b3d7c5SThomas E. Spanjaard } 4691*c1b3d7c5SThomas E. Spanjaard 4692*c1b3d7c5SThomas E. Spanjaard static void 4693*c1b3d7c5SThomas E. Spanjaard ata_raid_lsiv2_print_meta(struct lsiv2_raid_conf *meta) 4694*c1b3d7c5SThomas E. Spanjaard { 4695*c1b3d7c5SThomas E. Spanjaard int i; 4696*c1b3d7c5SThomas E. Spanjaard 4697*c1b3d7c5SThomas E. Spanjaard printf("******* ATA LSILogic V2 MegaRAID Metadata *******\n"); 4698*c1b3d7c5SThomas E. Spanjaard printf("lsi_id <%s>\n", meta->lsi_id); 4699*c1b3d7c5SThomas E. Spanjaard printf("dummy_0 0x%02x\n", meta->dummy_0); 4700*c1b3d7c5SThomas E. Spanjaard printf("flags 0x%02x\n", meta->flags); 4701*c1b3d7c5SThomas E. Spanjaard printf("version 0x%04x\n", meta->version); 4702*c1b3d7c5SThomas E. Spanjaard printf("config_entries 0x%02x\n", meta->config_entries); 4703*c1b3d7c5SThomas E. Spanjaard printf("raid_count 0x%02x\n", meta->raid_count); 4704*c1b3d7c5SThomas E. Spanjaard printf("total_disks 0x%02x\n", meta->total_disks); 4705*c1b3d7c5SThomas E. Spanjaard printf("dummy_1 0x%02x\n", meta->dummy_1); 4706*c1b3d7c5SThomas E. Spanjaard printf("dummy_2 0x%04x\n", meta->dummy_2); 4707*c1b3d7c5SThomas E. Spanjaard for (i = 0; i < meta->config_entries; i++) { 4708*c1b3d7c5SThomas E. Spanjaard printf(" type %s\n", 4709*c1b3d7c5SThomas E. Spanjaard ata_raid_lsiv2_type(meta->configs[i].raid.type)); 4710*c1b3d7c5SThomas E. Spanjaard printf(" dummy_0 %02x\n", meta->configs[i].raid.dummy_0); 4711*c1b3d7c5SThomas E. Spanjaard printf(" stripe_sectors %u\n", 4712*c1b3d7c5SThomas E. Spanjaard meta->configs[i].raid.stripe_sectors); 4713*c1b3d7c5SThomas E. Spanjaard printf(" array_width %u\n", 4714*c1b3d7c5SThomas E. Spanjaard meta->configs[i].raid.array_width); 4715*c1b3d7c5SThomas E. Spanjaard printf(" disk_count %u\n", meta->configs[i].raid.disk_count); 4716*c1b3d7c5SThomas E. Spanjaard printf(" config_offset %u\n", 4717*c1b3d7c5SThomas E. Spanjaard meta->configs[i].raid.config_offset); 4718*c1b3d7c5SThomas E. Spanjaard printf(" dummy_1 %u\n", meta->configs[i].raid.dummy_1); 4719*c1b3d7c5SThomas E. Spanjaard printf(" flags %02x\n", meta->configs[i].raid.flags); 4720*c1b3d7c5SThomas E. Spanjaard printf(" total_sectors %u\n", 4721*c1b3d7c5SThomas E. Spanjaard meta->configs[i].raid.total_sectors); 4722*c1b3d7c5SThomas E. Spanjaard } 4723*c1b3d7c5SThomas E. Spanjaard printf("disk_number 0x%02x\n", meta->disk_number); 4724*c1b3d7c5SThomas E. Spanjaard printf("raid_number 0x%02x\n", meta->raid_number); 4725*c1b3d7c5SThomas E. Spanjaard printf("timestamp 0x%08x\n", meta->timestamp); 4726*c1b3d7c5SThomas E. Spanjaard printf("=================================================\n"); 4727*c1b3d7c5SThomas E. Spanjaard } 4728*c1b3d7c5SThomas E. Spanjaard 4729*c1b3d7c5SThomas E. Spanjaard static char * 4730*c1b3d7c5SThomas E. Spanjaard ata_raid_lsiv3_type(int type) 4731*c1b3d7c5SThomas E. Spanjaard { 4732*c1b3d7c5SThomas E. Spanjaard static char buffer[16]; 4733*c1b3d7c5SThomas E. Spanjaard 4734*c1b3d7c5SThomas E. Spanjaard switch (type) { 4735*c1b3d7c5SThomas E. Spanjaard case LSIV3_T_RAID0: return "RAID0"; 4736*c1b3d7c5SThomas E. Spanjaard case LSIV3_T_RAID1: return "RAID1"; 4737*c1b3d7c5SThomas E. Spanjaard default: sprintf(buffer, "UNKNOWN 0x%02x", type); 4738*c1b3d7c5SThomas E. Spanjaard return buffer; 4739*c1b3d7c5SThomas E. Spanjaard } 4740*c1b3d7c5SThomas E. Spanjaard } 4741*c1b3d7c5SThomas E. Spanjaard 4742*c1b3d7c5SThomas E. Spanjaard static void 4743*c1b3d7c5SThomas E. Spanjaard ata_raid_lsiv3_print_meta(struct lsiv3_raid_conf *meta) 4744*c1b3d7c5SThomas E. Spanjaard { 4745*c1b3d7c5SThomas E. Spanjaard int i; 4746*c1b3d7c5SThomas E. Spanjaard 4747*c1b3d7c5SThomas E. Spanjaard printf("******* ATA LSILogic V3 MegaRAID Metadata *******\n"); 4748*c1b3d7c5SThomas E. Spanjaard printf("lsi_id <%.6s>\n", meta->lsi_id); 4749*c1b3d7c5SThomas E. Spanjaard printf("dummy_0 0x%04x\n", meta->dummy_0); 4750*c1b3d7c5SThomas E. Spanjaard printf("version 0x%04x\n", meta->version); 4751*c1b3d7c5SThomas E. Spanjaard printf("dummy_0 0x%04x\n", meta->dummy_1); 4752*c1b3d7c5SThomas E. Spanjaard printf("RAID configs:\n"); 4753*c1b3d7c5SThomas E. Spanjaard for (i = 0; i < 8; i++) { 4754*c1b3d7c5SThomas E. Spanjaard if (meta->raid[i].total_disks) { 4755*c1b3d7c5SThomas E. Spanjaard printf("%02d stripe_pages %u\n", i, 4756*c1b3d7c5SThomas E. Spanjaard meta->raid[i].stripe_pages); 4757*c1b3d7c5SThomas E. Spanjaard printf("%02d type %s\n", i, 4758*c1b3d7c5SThomas E. Spanjaard ata_raid_lsiv3_type(meta->raid[i].type)); 4759*c1b3d7c5SThomas E. Spanjaard printf("%02d total_disks %u\n", i, 4760*c1b3d7c5SThomas E. Spanjaard meta->raid[i].total_disks); 4761*c1b3d7c5SThomas E. Spanjaard printf("%02d array_width %u\n", i, 4762*c1b3d7c5SThomas E. Spanjaard meta->raid[i].array_width); 4763*c1b3d7c5SThomas E. Spanjaard printf("%02d sectors %u\n", i, meta->raid[i].sectors); 4764*c1b3d7c5SThomas E. Spanjaard printf("%02d offset %u\n", i, meta->raid[i].offset); 4765*c1b3d7c5SThomas E. Spanjaard printf("%02d device 0x%02x\n", i, 4766*c1b3d7c5SThomas E. Spanjaard meta->raid[i].device); 4767*c1b3d7c5SThomas E. Spanjaard } 4768*c1b3d7c5SThomas E. Spanjaard } 4769*c1b3d7c5SThomas E. Spanjaard printf("DISK configs:\n"); 4770*c1b3d7c5SThomas E. Spanjaard for (i = 0; i < 6; i++) { 4771*c1b3d7c5SThomas E. Spanjaard if (meta->disk[i].disk_sectors) { 4772*c1b3d7c5SThomas E. Spanjaard printf("%02d disk_sectors %u\n", i, 4773*c1b3d7c5SThomas E. Spanjaard meta->disk[i].disk_sectors); 4774*c1b3d7c5SThomas E. Spanjaard printf("%02d flags 0x%02x\n", i, meta->disk[i].flags); 4775*c1b3d7c5SThomas E. Spanjaard } 4776*c1b3d7c5SThomas E. Spanjaard } 4777*c1b3d7c5SThomas E. Spanjaard printf("device 0x%02x\n", meta->device); 4778*c1b3d7c5SThomas E. Spanjaard printf("timestamp 0x%08x\n", meta->timestamp); 4779*c1b3d7c5SThomas E. Spanjaard printf("checksum_1 0x%02x\n", meta->checksum_1); 4780*c1b3d7c5SThomas E. Spanjaard printf("=================================================\n"); 4781*c1b3d7c5SThomas E. Spanjaard } 4782*c1b3d7c5SThomas E. Spanjaard 4783*c1b3d7c5SThomas E. Spanjaard static char * 4784*c1b3d7c5SThomas E. Spanjaard ata_raid_nvidia_type(int type) 4785*c1b3d7c5SThomas E. Spanjaard { 4786*c1b3d7c5SThomas E. Spanjaard static char buffer[16]; 4787*c1b3d7c5SThomas E. Spanjaard 4788*c1b3d7c5SThomas E. Spanjaard switch (type) { 4789*c1b3d7c5SThomas E. Spanjaard case NV_T_SPAN: return "SPAN"; 4790*c1b3d7c5SThomas E. Spanjaard case NV_T_RAID0: return "RAID0"; 4791*c1b3d7c5SThomas E. Spanjaard case NV_T_RAID1: return "RAID1"; 4792*c1b3d7c5SThomas E. Spanjaard case NV_T_RAID3: return "RAID3"; 4793*c1b3d7c5SThomas E. Spanjaard case NV_T_RAID5: return "RAID5"; 4794*c1b3d7c5SThomas E. Spanjaard case NV_T_RAID01: return "RAID0+1"; 4795*c1b3d7c5SThomas E. Spanjaard default: sprintf(buffer, "UNKNOWN 0x%02x", type); 4796*c1b3d7c5SThomas E. Spanjaard return buffer; 4797*c1b3d7c5SThomas E. Spanjaard } 4798*c1b3d7c5SThomas E. Spanjaard } 4799*c1b3d7c5SThomas E. Spanjaard 4800*c1b3d7c5SThomas E. Spanjaard static void 4801*c1b3d7c5SThomas E. Spanjaard ata_raid_nvidia_print_meta(struct nvidia_raid_conf *meta) 4802*c1b3d7c5SThomas E. Spanjaard { 4803*c1b3d7c5SThomas E. Spanjaard printf("******** ATA nVidia MediaShield Metadata ********\n"); 4804*c1b3d7c5SThomas E. Spanjaard printf("nvidia_id <%.8s>\n", meta->nvidia_id); 4805*c1b3d7c5SThomas E. Spanjaard printf("config_size %d\n", meta->config_size); 4806*c1b3d7c5SThomas E. Spanjaard printf("checksum 0x%08x\n", meta->checksum); 4807*c1b3d7c5SThomas E. Spanjaard printf("version 0x%04x\n", meta->version); 4808*c1b3d7c5SThomas E. Spanjaard printf("disk_number %d\n", meta->disk_number); 4809*c1b3d7c5SThomas E. Spanjaard printf("dummy_0 0x%02x\n", meta->dummy_0); 4810*c1b3d7c5SThomas E. Spanjaard printf("total_sectors %d\n", meta->total_sectors); 4811*c1b3d7c5SThomas E. Spanjaard printf("sectors_size %d\n", meta->sector_size); 4812*c1b3d7c5SThomas E. Spanjaard printf("serial %.16s\n", meta->serial); 4813*c1b3d7c5SThomas E. Spanjaard printf("revision %.4s\n", meta->revision); 4814*c1b3d7c5SThomas E. Spanjaard printf("dummy_1 0x%08x\n", meta->dummy_1); 4815*c1b3d7c5SThomas E. Spanjaard printf("magic_0 0x%08x\n", meta->magic_0); 4816*c1b3d7c5SThomas E. Spanjaard printf("magic_1 0x%016jx\n", meta->magic_1); 4817*c1b3d7c5SThomas E. Spanjaard printf("magic_2 0x%016jx\n", meta->magic_2); 4818*c1b3d7c5SThomas E. Spanjaard printf("flags 0x%02x\n", meta->flags); 4819*c1b3d7c5SThomas E. Spanjaard printf("array_width %d\n", meta->array_width); 4820*c1b3d7c5SThomas E. Spanjaard printf("total_disks %d\n", meta->total_disks); 4821*c1b3d7c5SThomas E. Spanjaard printf("dummy_2 0x%02x\n", meta->dummy_2); 4822*c1b3d7c5SThomas E. Spanjaard printf("type %s\n", ata_raid_nvidia_type(meta->type)); 4823*c1b3d7c5SThomas E. Spanjaard printf("dummy_3 0x%04x\n", meta->dummy_3); 4824*c1b3d7c5SThomas E. Spanjaard printf("stripe_sectors %d\n", meta->stripe_sectors); 4825*c1b3d7c5SThomas E. Spanjaard printf("stripe_bytes %d\n", meta->stripe_bytes); 4826*c1b3d7c5SThomas E. Spanjaard printf("stripe_shift %d\n", meta->stripe_shift); 4827*c1b3d7c5SThomas E. Spanjaard printf("stripe_mask 0x%08x\n", meta->stripe_mask); 4828*c1b3d7c5SThomas E. Spanjaard printf("stripe_sizesectors %d\n", meta->stripe_sizesectors); 4829*c1b3d7c5SThomas E. Spanjaard printf("stripe_sizebytes %d\n", meta->stripe_sizebytes); 4830*c1b3d7c5SThomas E. Spanjaard printf("rebuild_lba %d\n", meta->rebuild_lba); 4831*c1b3d7c5SThomas E. Spanjaard printf("dummy_4 0x%08x\n", meta->dummy_4); 4832*c1b3d7c5SThomas E. Spanjaard printf("dummy_5 0x%08x\n", meta->dummy_5); 4833*c1b3d7c5SThomas E. Spanjaard printf("status 0x%08x\n", meta->status); 4834*c1b3d7c5SThomas E. Spanjaard printf("=================================================\n"); 4835*c1b3d7c5SThomas E. Spanjaard } 4836*c1b3d7c5SThomas E. Spanjaard 4837*c1b3d7c5SThomas E. Spanjaard static char * 4838*c1b3d7c5SThomas E. Spanjaard ata_raid_promise_type(int type) 4839*c1b3d7c5SThomas E. Spanjaard { 4840*c1b3d7c5SThomas E. Spanjaard static char buffer[16]; 4841*c1b3d7c5SThomas E. Spanjaard 4842*c1b3d7c5SThomas E. Spanjaard switch (type) { 4843*c1b3d7c5SThomas E. Spanjaard case PR_T_RAID0: return "RAID0"; 4844*c1b3d7c5SThomas E. Spanjaard case PR_T_RAID1: return "RAID1"; 4845*c1b3d7c5SThomas E. Spanjaard case PR_T_RAID3: return "RAID3"; 4846*c1b3d7c5SThomas E. Spanjaard case PR_T_RAID5: return "RAID5"; 4847*c1b3d7c5SThomas E. Spanjaard case PR_T_SPAN: return "SPAN"; 4848*c1b3d7c5SThomas E. Spanjaard default: sprintf(buffer, "UNKNOWN 0x%02x", type); 4849*c1b3d7c5SThomas E. Spanjaard return buffer; 4850*c1b3d7c5SThomas E. Spanjaard } 4851*c1b3d7c5SThomas E. Spanjaard } 4852*c1b3d7c5SThomas E. Spanjaard 4853*c1b3d7c5SThomas E. Spanjaard static void 4854*c1b3d7c5SThomas E. Spanjaard ata_raid_promise_print_meta(struct promise_raid_conf *meta) 4855*c1b3d7c5SThomas E. Spanjaard { 4856*c1b3d7c5SThomas E. Spanjaard int i; 4857*c1b3d7c5SThomas E. Spanjaard 4858*c1b3d7c5SThomas E. Spanjaard printf("********* ATA Promise FastTrak Metadata *********\n"); 4859*c1b3d7c5SThomas E. Spanjaard printf("promise_id <%s>\n", meta->promise_id); 4860*c1b3d7c5SThomas E. Spanjaard printf("dummy_0 0x%08x\n", meta->dummy_0); 4861*c1b3d7c5SThomas E. Spanjaard printf("magic_0 0x%016jx\n", meta->magic_0); 4862*c1b3d7c5SThomas E. Spanjaard printf("magic_1 0x%04x\n", meta->magic_1); 4863*c1b3d7c5SThomas E. Spanjaard printf("magic_2 0x%08x\n", meta->magic_2); 4864*c1b3d7c5SThomas E. Spanjaard printf("integrity 0x%08x %b\n", meta->raid.integrity, 4865*c1b3d7c5SThomas E. Spanjaard meta->raid.integrity, "\20\10VALID\n" ); 4866*c1b3d7c5SThomas E. Spanjaard printf("flags 0x%02x %b\n", 4867*c1b3d7c5SThomas E. Spanjaard meta->raid.flags, meta->raid.flags, 4868*c1b3d7c5SThomas E. Spanjaard "\20\10READY\7DOWN\6REDIR\5DUPLICATE\4SPARE" 4869*c1b3d7c5SThomas E. Spanjaard "\3ASSIGNED\2ONLINE\1VALID\n"); 4870*c1b3d7c5SThomas E. Spanjaard printf("disk_number %d\n", meta->raid.disk_number); 4871*c1b3d7c5SThomas E. Spanjaard printf("channel 0x%02x\n", meta->raid.channel); 4872*c1b3d7c5SThomas E. Spanjaard printf("device 0x%02x\n", meta->raid.device); 4873*c1b3d7c5SThomas E. Spanjaard printf("magic_0 0x%016jx\n", meta->raid.magic_0); 4874*c1b3d7c5SThomas E. Spanjaard printf("disk_offset %u\n", meta->raid.disk_offset); 4875*c1b3d7c5SThomas E. Spanjaard printf("disk_sectors %u\n", meta->raid.disk_sectors); 4876*c1b3d7c5SThomas E. Spanjaard printf("rebuild_lba 0x%08x\n", meta->raid.rebuild_lba); 4877*c1b3d7c5SThomas E. Spanjaard printf("generation 0x%04x\n", meta->raid.generation); 4878*c1b3d7c5SThomas E. Spanjaard printf("status 0x%02x %b\n", 4879*c1b3d7c5SThomas E. Spanjaard meta->raid.status, meta->raid.status, 4880*c1b3d7c5SThomas E. Spanjaard "\20\6MARKED\5DEGRADED\4READY\3INITED\2ONLINE\1VALID\n"); 4881*c1b3d7c5SThomas E. Spanjaard printf("type %s\n", ata_raid_promise_type(meta->raid.type)); 4882*c1b3d7c5SThomas E. Spanjaard printf("total_disks %u\n", meta->raid.total_disks); 4883*c1b3d7c5SThomas E. Spanjaard printf("stripe_shift %u\n", meta->raid.stripe_shift); 4884*c1b3d7c5SThomas E. Spanjaard printf("array_width %u\n", meta->raid.array_width); 4885*c1b3d7c5SThomas E. Spanjaard printf("array_number %u\n", meta->raid.array_number); 4886*c1b3d7c5SThomas E. Spanjaard printf("total_sectors %u\n", meta->raid.total_sectors); 4887*c1b3d7c5SThomas E. Spanjaard printf("cylinders %u\n", meta->raid.cylinders); 4888*c1b3d7c5SThomas E. Spanjaard printf("heads %u\n", meta->raid.heads); 4889*c1b3d7c5SThomas E. Spanjaard printf("sectors %u\n", meta->raid.sectors); 4890*c1b3d7c5SThomas E. Spanjaard printf("magic_1 0x%016jx\n", meta->raid.magic_1); 4891*c1b3d7c5SThomas E. Spanjaard printf("DISK# flags dummy_0 channel device magic_0\n"); 4892*c1b3d7c5SThomas E. Spanjaard for (i = 0; i < 8; i++) { 4893*c1b3d7c5SThomas E. Spanjaard printf(" %d %b 0x%02x 0x%02x 0x%02x ", 4894*c1b3d7c5SThomas E. Spanjaard i, meta->raid.disk[i].flags, 4895*c1b3d7c5SThomas E. Spanjaard "\20\10READY\7DOWN\6REDIR\5DUPLICATE\4SPARE" 4896*c1b3d7c5SThomas E. Spanjaard "\3ASSIGNED\2ONLINE\1VALID\n", meta->raid.disk[i].dummy_0, 4897*c1b3d7c5SThomas E. Spanjaard meta->raid.disk[i].channel, meta->raid.disk[i].device); 4898*c1b3d7c5SThomas E. Spanjaard printf("0x%016jx\n", meta->raid.disk[i].magic_0); 4899*c1b3d7c5SThomas E. Spanjaard } 4900*c1b3d7c5SThomas E. Spanjaard printf("checksum 0x%08x\n", meta->checksum); 4901*c1b3d7c5SThomas E. Spanjaard printf("=================================================\n"); 4902*c1b3d7c5SThomas E. Spanjaard } 4903*c1b3d7c5SThomas E. Spanjaard 4904*c1b3d7c5SThomas E. Spanjaard static char * 4905*c1b3d7c5SThomas E. Spanjaard ata_raid_sii_type(int type) 4906*c1b3d7c5SThomas E. Spanjaard { 4907*c1b3d7c5SThomas E. Spanjaard static char buffer[16]; 4908*c1b3d7c5SThomas E. Spanjaard 4909*c1b3d7c5SThomas E. Spanjaard switch (type) { 4910*c1b3d7c5SThomas E. Spanjaard case SII_T_RAID0: return "RAID0"; 4911*c1b3d7c5SThomas E. Spanjaard case SII_T_RAID1: return "RAID1"; 4912*c1b3d7c5SThomas E. Spanjaard case SII_T_RAID01: return "RAID0+1"; 4913*c1b3d7c5SThomas E. Spanjaard case SII_T_SPARE: return "SPARE"; 4914*c1b3d7c5SThomas E. Spanjaard default: sprintf(buffer, "UNKNOWN 0x%02x", type); 4915*c1b3d7c5SThomas E. Spanjaard return buffer; 4916*c1b3d7c5SThomas E. Spanjaard } 4917*c1b3d7c5SThomas E. Spanjaard } 4918*c1b3d7c5SThomas E. Spanjaard 4919*c1b3d7c5SThomas E. Spanjaard static void 4920*c1b3d7c5SThomas E. Spanjaard ata_raid_sii_print_meta(struct sii_raid_conf *meta) 4921*c1b3d7c5SThomas E. Spanjaard { 4922*c1b3d7c5SThomas E. Spanjaard printf("******* ATA Silicon Image Medley Metadata *******\n"); 4923*c1b3d7c5SThomas E. Spanjaard printf("total_sectors %ju\n", meta->total_sectors); 4924*c1b3d7c5SThomas E. Spanjaard printf("dummy_0 0x%04x\n", meta->dummy_0); 4925*c1b3d7c5SThomas E. Spanjaard printf("dummy_1 0x%04x\n", meta->dummy_1); 4926*c1b3d7c5SThomas E. Spanjaard printf("controller_pci_id 0x%08x\n", meta->controller_pci_id); 4927*c1b3d7c5SThomas E. Spanjaard printf("version_minor 0x%04x\n", meta->version_minor); 4928*c1b3d7c5SThomas E. Spanjaard printf("version_major 0x%04x\n", meta->version_major); 4929*c1b3d7c5SThomas E. Spanjaard printf("timestamp 20%02x/%02x/%02x %02x:%02x:%02x\n", 4930*c1b3d7c5SThomas E. Spanjaard meta->timestamp[5], meta->timestamp[4], meta->timestamp[3], 4931*c1b3d7c5SThomas E. Spanjaard meta->timestamp[2], meta->timestamp[1], meta->timestamp[0]); 4932*c1b3d7c5SThomas E. Spanjaard printf("stripe_sectors %u\n", meta->stripe_sectors); 4933*c1b3d7c5SThomas E. Spanjaard printf("dummy_2 0x%04x\n", meta->dummy_2); 4934*c1b3d7c5SThomas E. Spanjaard printf("disk_number %u\n", meta->disk_number); 4935*c1b3d7c5SThomas E. Spanjaard printf("type %s\n", ata_raid_sii_type(meta->type)); 4936*c1b3d7c5SThomas E. Spanjaard printf("raid0_disks %u\n", meta->raid0_disks); 4937*c1b3d7c5SThomas E. Spanjaard printf("raid0_ident %u\n", meta->raid0_ident); 4938*c1b3d7c5SThomas E. Spanjaard printf("raid1_disks %u\n", meta->raid1_disks); 4939*c1b3d7c5SThomas E. Spanjaard printf("raid1_ident %u\n", meta->raid1_ident); 4940*c1b3d7c5SThomas E. Spanjaard printf("rebuild_lba %ju\n", meta->rebuild_lba); 4941*c1b3d7c5SThomas E. Spanjaard printf("generation 0x%08x\n", meta->generation); 4942*c1b3d7c5SThomas E. Spanjaard printf("status 0x%02x %b\n", 4943*c1b3d7c5SThomas E. Spanjaard meta->status, meta->status, 4944*c1b3d7c5SThomas E. Spanjaard "\20\1READY\n"); 4945*c1b3d7c5SThomas E. Spanjaard printf("base_raid1_position %02x\n", meta->base_raid1_position); 4946*c1b3d7c5SThomas E. Spanjaard printf("base_raid0_position %02x\n", meta->base_raid0_position); 4947*c1b3d7c5SThomas E. Spanjaard printf("position %02x\n", meta->position); 4948*c1b3d7c5SThomas E. Spanjaard printf("dummy_3 %04x\n", meta->dummy_3); 4949*c1b3d7c5SThomas E. Spanjaard printf("name <%.16s>\n", meta->name); 4950*c1b3d7c5SThomas E. Spanjaard printf("checksum_0 0x%04x\n", meta->checksum_0); 4951*c1b3d7c5SThomas E. Spanjaard printf("checksum_1 0x%04x\n", meta->checksum_1); 4952*c1b3d7c5SThomas E. Spanjaard printf("=================================================\n"); 4953*c1b3d7c5SThomas E. Spanjaard } 4954*c1b3d7c5SThomas E. Spanjaard 4955*c1b3d7c5SThomas E. Spanjaard static char * 4956*c1b3d7c5SThomas E. Spanjaard ata_raid_sis_type(int type) 4957*c1b3d7c5SThomas E. Spanjaard { 4958*c1b3d7c5SThomas E. Spanjaard static char buffer[16]; 4959*c1b3d7c5SThomas E. Spanjaard 4960*c1b3d7c5SThomas E. Spanjaard switch (type) { 4961*c1b3d7c5SThomas E. Spanjaard case SIS_T_JBOD: return "JBOD"; 4962*c1b3d7c5SThomas E. Spanjaard case SIS_T_RAID0: return "RAID0"; 4963*c1b3d7c5SThomas E. Spanjaard case SIS_T_RAID1: return "RAID1"; 4964*c1b3d7c5SThomas E. Spanjaard default: sprintf(buffer, "UNKNOWN 0x%02x", type); 4965*c1b3d7c5SThomas E. Spanjaard return buffer; 4966*c1b3d7c5SThomas E. Spanjaard } 4967*c1b3d7c5SThomas E. Spanjaard } 4968*c1b3d7c5SThomas E. Spanjaard 4969*c1b3d7c5SThomas E. Spanjaard static void 4970*c1b3d7c5SThomas E. Spanjaard ata_raid_sis_print_meta(struct sis_raid_conf *meta) 4971*c1b3d7c5SThomas E. Spanjaard { 4972*c1b3d7c5SThomas E. Spanjaard printf("**** ATA Silicon Integrated Systems Metadata ****\n"); 4973*c1b3d7c5SThomas E. Spanjaard printf("magic 0x%04x\n", meta->magic); 4974*c1b3d7c5SThomas E. Spanjaard printf("disks 0x%02x\n", meta->disks); 4975*c1b3d7c5SThomas E. Spanjaard printf("type %s\n", 4976*c1b3d7c5SThomas E. Spanjaard ata_raid_sis_type(meta->type_total_disks & SIS_T_MASK)); 4977*c1b3d7c5SThomas E. Spanjaard printf("total_disks %u\n", meta->type_total_disks & SIS_D_MASK); 4978*c1b3d7c5SThomas E. Spanjaard printf("dummy_0 0x%08x\n", meta->dummy_0); 4979*c1b3d7c5SThomas E. Spanjaard printf("controller_pci_id 0x%08x\n", meta->controller_pci_id); 4980*c1b3d7c5SThomas E. Spanjaard printf("stripe_sectors %u\n", meta->stripe_sectors); 4981*c1b3d7c5SThomas E. Spanjaard printf("dummy_1 0x%04x\n", meta->dummy_1); 4982*c1b3d7c5SThomas E. Spanjaard printf("timestamp 0x%08x\n", meta->timestamp); 4983*c1b3d7c5SThomas E. Spanjaard printf("model %.40s\n", meta->model); 4984*c1b3d7c5SThomas E. Spanjaard printf("disk_number %u\n", meta->disk_number); 4985*c1b3d7c5SThomas E. Spanjaard printf("dummy_2 0x%02x 0x%02x 0x%02x\n", 4986*c1b3d7c5SThomas E. Spanjaard meta->dummy_2[0], meta->dummy_2[1], meta->dummy_2[2]); 4987*c1b3d7c5SThomas E. Spanjaard printf("=================================================\n"); 4988*c1b3d7c5SThomas E. Spanjaard } 4989*c1b3d7c5SThomas E. Spanjaard 4990*c1b3d7c5SThomas E. Spanjaard static char * 4991*c1b3d7c5SThomas E. Spanjaard ata_raid_via_type(int type) 4992*c1b3d7c5SThomas E. Spanjaard { 4993*c1b3d7c5SThomas E. Spanjaard static char buffer[16]; 4994*c1b3d7c5SThomas E. Spanjaard 4995*c1b3d7c5SThomas E. Spanjaard switch (type) { 4996*c1b3d7c5SThomas E. Spanjaard case VIA_T_RAID0: return "RAID0"; 4997*c1b3d7c5SThomas E. Spanjaard case VIA_T_RAID1: return "RAID1"; 4998*c1b3d7c5SThomas E. Spanjaard case VIA_T_RAID5: return "RAID5"; 4999*c1b3d7c5SThomas E. Spanjaard case VIA_T_RAID01: return "RAID0+1"; 5000*c1b3d7c5SThomas E. Spanjaard case VIA_T_SPAN: return "SPAN"; 5001*c1b3d7c5SThomas E. Spanjaard default: sprintf(buffer, "UNKNOWN 0x%02x", type); 5002*c1b3d7c5SThomas E. Spanjaard return buffer; 5003*c1b3d7c5SThomas E. Spanjaard } 5004*c1b3d7c5SThomas E. Spanjaard } 5005*c1b3d7c5SThomas E. Spanjaard 5006*c1b3d7c5SThomas E. Spanjaard static void 5007*c1b3d7c5SThomas E. Spanjaard ata_raid_via_print_meta(struct via_raid_conf *meta) 5008*c1b3d7c5SThomas E. Spanjaard { 5009*c1b3d7c5SThomas E. Spanjaard int i; 5010*c1b3d7c5SThomas E. Spanjaard 5011*c1b3d7c5SThomas E. Spanjaard printf("*************** ATA VIA Metadata ****************\n"); 5012*c1b3d7c5SThomas E. Spanjaard printf("magic 0x%02x\n", meta->magic); 5013*c1b3d7c5SThomas E. Spanjaard printf("dummy_0 0x%02x\n", meta->dummy_0); 5014*c1b3d7c5SThomas E. Spanjaard printf("type %s\n", 5015*c1b3d7c5SThomas E. Spanjaard ata_raid_via_type(meta->type & VIA_T_MASK)); 5016*c1b3d7c5SThomas E. Spanjaard printf("bootable %d\n", meta->type & VIA_T_BOOTABLE); 5017*c1b3d7c5SThomas E. Spanjaard printf("unknown %d\n", meta->type & VIA_T_UNKNOWN); 5018*c1b3d7c5SThomas E. Spanjaard printf("disk_index 0x%02x\n", meta->disk_index); 5019*c1b3d7c5SThomas E. Spanjaard printf("stripe_layout 0x%02x\n", meta->stripe_layout); 5020*c1b3d7c5SThomas E. Spanjaard printf(" stripe_disks %d\n", meta->stripe_layout & VIA_L_DISKS); 5021*c1b3d7c5SThomas E. Spanjaard printf(" stripe_sectors %d\n", 5022*c1b3d7c5SThomas E. Spanjaard 0x08 << ((meta->stripe_layout & VIA_L_MASK) >> VIA_L_SHIFT)); 5023*c1b3d7c5SThomas E. Spanjaard printf("disk_sectors %ju\n", meta->disk_sectors); 5024*c1b3d7c5SThomas E. Spanjaard printf("disk_id 0x%08x\n", meta->disk_id); 5025*c1b3d7c5SThomas E. Spanjaard printf("DISK# disk_id\n"); 5026*c1b3d7c5SThomas E. Spanjaard for (i = 0; i < 8; i++) { 5027*c1b3d7c5SThomas E. Spanjaard if (meta->disks[i]) 5028*c1b3d7c5SThomas E. Spanjaard printf(" %d 0x%08x\n", i, meta->disks[i]); 5029*c1b3d7c5SThomas E. Spanjaard } 5030*c1b3d7c5SThomas E. Spanjaard printf("checksum 0x%02x\n", meta->checksum); 5031*c1b3d7c5SThomas E. Spanjaard printf("=================================================\n"); 5032*c1b3d7c5SThomas E. Spanjaard } 5033