1 1.14 hannken /* $NetBSD: ata_raid_promise.c,v 1.14 2022/03/19 13:51:01 hannken Exp $ */ 2 1.1 thorpej 3 1.1 thorpej /*- 4 1.1 thorpej * Copyright (c) 2000,2001,2002 Sren Schmidt <sos (at) FreeBSD.org> 5 1.1 thorpej * All rights reserved. 6 1.1 thorpej * 7 1.1 thorpej * Redistribution and use in source and binary forms, with or without 8 1.1 thorpej * modification, are permitted provided that the following conditions 9 1.1 thorpej * are met: 10 1.1 thorpej * 1. Redistributions of source code must retain the above copyright 11 1.1 thorpej * notice, this list of conditions and the following disclaimer, 12 1.1 thorpej * without modification, immediately at the beginning of the file. 13 1.1 thorpej * 2. Redistributions in binary form must reproduce the above copyright 14 1.1 thorpej * notice, this list of conditions and the following disclaimer in the 15 1.1 thorpej * documentation and/or other materials provided with the distribution. 16 1.1 thorpej * 3. The name of the author may not be used to endorse or promote products 17 1.1 thorpej * derived from this software without specific prior written permission. 18 1.1 thorpej * 19 1.1 thorpej * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 20 1.1 thorpej * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 21 1.1 thorpej * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 22 1.1 thorpej * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 23 1.1 thorpej * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 24 1.1 thorpej * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 1.1 thorpej * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 1.1 thorpej * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 1.1 thorpej * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 28 1.1 thorpej * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 1.1 thorpej */ 30 1.1 thorpej 31 1.1 thorpej /* 32 1.1 thorpej * Support for parsing Promise ATA RAID controller configuration blocks. 33 1.1 thorpej * 34 1.1 thorpej * Adapted to NetBSD by Jason R. Thorpe of Wasabi Systems, Inc. 35 1.1 thorpej */ 36 1.2 lukem 37 1.2 lukem #include <sys/cdefs.h> 38 1.14 hannken __KERNEL_RCSID(0, "$NetBSD: ata_raid_promise.c,v 1.14 2022/03/19 13:51:01 hannken Exp $"); 39 1.1 thorpej 40 1.1 thorpej #include <sys/param.h> 41 1.1 thorpej #include <sys/buf.h> 42 1.4 yamt #include <sys/bufq.h> 43 1.1 thorpej #include <sys/conf.h> 44 1.1 thorpej #include <sys/device.h> 45 1.1 thorpej #include <sys/disk.h> 46 1.1 thorpej #include <sys/disklabel.h> 47 1.1 thorpej #include <sys/fcntl.h> 48 1.1 thorpej #include <sys/vnode.h> 49 1.8 elad #include <sys/kauth.h> 50 1.1 thorpej 51 1.1 thorpej #include <miscfs/specfs/specdev.h> 52 1.1 thorpej 53 1.1 thorpej #include <dev/ata/atareg.h> 54 1.1 thorpej #include <dev/ata/atavar.h> 55 1.1 thorpej #include <dev/ata/wdvar.h> 56 1.1 thorpej 57 1.1 thorpej #include <dev/ata/ata_raidreg.h> 58 1.1 thorpej #include <dev/ata/ata_raidvar.h> 59 1.1 thorpej 60 1.1 thorpej #ifdef ATA_RAID_DEBUG 61 1.1 thorpej #define DPRINTF(x) printf x 62 1.1 thorpej #else 63 1.1 thorpej #define DPRINTF(x) /* nothing */ 64 1.1 thorpej #endif 65 1.1 thorpej 66 1.1 thorpej int 67 1.1 thorpej ata_raid_read_config_promise(struct wd_softc *sc) 68 1.1 thorpej { 69 1.12 mlelstv struct dk_softc *dksc = &sc->sc_dksc; 70 1.1 thorpej struct promise_raid_conf *info; 71 1.1 thorpej struct vnode *vp; 72 1.1 thorpej int bmajor, error, count; 73 1.1 thorpej u_int disk; 74 1.1 thorpej dev_t dev; 75 1.1 thorpej uint32_t cksum, *ckptr; 76 1.1 thorpej struct ataraid_array_info *aai; 77 1.1 thorpej struct ataraid_disk_info *adi; 78 1.1 thorpej 79 1.13 jdolecek info = kmem_zalloc(sizeof(*info), KM_SLEEP); 80 1.5 perry 81 1.12 mlelstv bmajor = devsw_name2blk(dksc->sc_xname, NULL, 0); 82 1.1 thorpej 83 1.1 thorpej /* Get a vnode for the raw partition of this disk. */ 84 1.12 mlelstv dev = MAKEDISKDEV(bmajor, device_unit(dksc->sc_dev), RAW_PART); 85 1.1 thorpej error = bdevvp(dev, &vp); 86 1.1 thorpej if (error) 87 1.1 thorpej goto out; 88 1.1 thorpej 89 1.14 hannken vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 90 1.9 pooka error = VOP_OPEN(vp, FREAD, NOCRED); 91 1.1 thorpej if (error) { 92 1.1 thorpej vput(vp); 93 1.1 thorpej goto out; 94 1.1 thorpej } 95 1.1 thorpej 96 1.1 thorpej error = ata_raid_config_block_rw(vp, PR_LBA(sc), info, 97 1.1 thorpej sizeof(*info), B_READ); 98 1.10 mjf VOP_CLOSE(vp, FREAD, NOCRED); 99 1.1 thorpej vput(vp); 100 1.1 thorpej if (error) { 101 1.12 mlelstv aprint_error_dev(dksc->sc_dev, 102 1.11 cube "error %d reading Promise config block\n", error); 103 1.1 thorpej goto out; 104 1.1 thorpej } 105 1.1 thorpej 106 1.1 thorpej /* Check the signature. */ 107 1.1 thorpej if (strncmp(info->promise_id, PR_MAGIC, sizeof(PR_MAGIC)) != 0) { 108 1.1 thorpej DPRINTF(("%s: Promise signature check failed\n", 109 1.12 mlelstv dksc->sc_xname)); 110 1.1 thorpej error = ESRCH; 111 1.1 thorpej goto out; 112 1.1 thorpej } 113 1.1 thorpej 114 1.1 thorpej /* Verify the checksum. */ 115 1.1 thorpej for (cksum = 0, ckptr = (uint32_t *) info, count = 0; count < 511; 116 1.1 thorpej count++) 117 1.1 thorpej cksum += *ckptr++; 118 1.1 thorpej if (cksum != *ckptr) { 119 1.11 cube DPRINTF(("%s: Promise checksum failed\n", 120 1.12 mlelstv dksc->sc_xname)); 121 1.1 thorpej error = ESRCH; 122 1.1 thorpej goto out; 123 1.1 thorpej } 124 1.1 thorpej 125 1.1 thorpej if (info->raid.integrity != PR_I_VALID) { 126 1.1 thorpej DPRINTF(("%s: Promise config block marked invalid\n", 127 1.12 mlelstv dksc->sc_xname)); 128 1.1 thorpej error = ESRCH; 129 1.1 thorpej goto out; 130 1.1 thorpej } 131 1.1 thorpej 132 1.1 thorpej /* 133 1.1 thorpej * Lookup or allocate a new array info structure for 134 1.1 thorpej * this array. 135 1.1 thorpej */ 136 1.1 thorpej aai = ata_raid_get_array_info(ATA_RAID_TYPE_PROMISE, 137 1.1 thorpej info->raid.array_number); 138 1.1 thorpej 139 1.1 thorpej if (info->raid.generation == 0 || 140 1.1 thorpej info->raid.generation > aai->aai_generation) { 141 1.1 thorpej aai->aai_generation = info->raid.generation; 142 1.1 thorpej /* aai_type and aai_arrayno filled in already */ 143 1.1 thorpej if ((info->raid.status & 144 1.1 thorpej (PR_S_VALID | PR_S_ONLINE | PR_S_INITED | PR_S_READY)) == 145 1.1 thorpej (PR_S_VALID | PR_S_ONLINE | PR_S_INITED | PR_S_READY)) { 146 1.1 thorpej aai->aai_status |= AAI_S_READY; 147 1.1 thorpej if (info->raid.status & PR_S_DEGRADED) 148 1.1 thorpej aai->aai_status |= AAI_S_DEGRADED; 149 1.1 thorpej } else 150 1.1 thorpej aai->aai_status &= ~AAI_S_READY; 151 1.1 thorpej 152 1.1 thorpej switch (info->raid.type) { 153 1.1 thorpej case PR_T_RAID0: 154 1.1 thorpej aai->aai_level = AAI_L_RAID0; 155 1.1 thorpej break; 156 1.1 thorpej 157 1.1 thorpej case PR_T_RAID1: 158 1.1 thorpej aai->aai_level = AAI_L_RAID1; 159 1.1 thorpej if (info->raid.array_width > 1) 160 1.1 thorpej aai->aai_level |= AAI_L_RAID0; 161 1.1 thorpej break; 162 1.1 thorpej 163 1.1 thorpej case PR_T_SPAN: 164 1.1 thorpej aai->aai_level = AAI_L_SPAN; 165 1.1 thorpej break; 166 1.1 thorpej 167 1.1 thorpej default: 168 1.12 mlelstv aprint_error_dev(dksc->sc_dev, 169 1.11 cube "unknown Promise RAID type 0x%02x\n", 170 1.11 cube info->raid.type); 171 1.1 thorpej error = EINVAL; 172 1.1 thorpej goto out; 173 1.1 thorpej } 174 1.1 thorpej 175 1.1 thorpej aai->aai_interleave = 1U << info->raid.stripe_shift; 176 1.1 thorpej aai->aai_width = info->raid.array_width; 177 1.1 thorpej aai->aai_ndisks = info->raid.total_disks; 178 1.1 thorpej aai->aai_heads = info->raid.heads + 1; 179 1.1 thorpej aai->aai_sectors = info->raid.sectors; 180 1.1 thorpej aai->aai_cylinders = info->raid.cylinders + 1; 181 1.1 thorpej aai->aai_capacity = info->raid.total_sectors; 182 1.1 thorpej aai->aai_offset = 0; 183 1.1 thorpej aai->aai_reserved = 63; 184 1.1 thorpej 185 1.1 thorpej for (disk = 0; disk < aai->aai_ndisks; disk++) { 186 1.1 thorpej adi = &aai->aai_disks[disk]; 187 1.1 thorpej adi->adi_status = 0; 188 1.1 thorpej if (info->raid.disk[disk].flags & PR_F_ONLINE) 189 1.1 thorpej adi->adi_status |= ADI_S_ONLINE; 190 1.1 thorpej if (info->raid.disk[disk].flags & PR_F_ASSIGNED) 191 1.1 thorpej adi->adi_status |= ADI_S_ASSIGNED; 192 1.1 thorpej if (info->raid.disk[disk].flags & PR_F_SPARE) { 193 1.1 thorpej adi->adi_status &= ~ADI_S_ONLINE; 194 1.1 thorpej adi->adi_status |= ADI_S_SPARE; 195 1.1 thorpej } 196 1.1 thorpej if (info->raid.disk[disk].flags & 197 1.1 thorpej (PR_F_REDIR | PR_F_DOWN)) 198 1.1 thorpej adi->adi_status &= ~ADI_S_ONLINE; 199 1.1 thorpej } 200 1.1 thorpej } 201 1.1 thorpej adi = &aai->aai_disks[info->raid.disk_number]; 202 1.1 thorpej if (adi->adi_status) { 203 1.12 mlelstv adi->adi_dev = dksc->sc_dev; 204 1.1 thorpej adi->adi_sectors = info->raid.disk_sectors; 205 1.1 thorpej adi->adi_compsize = sc->sc_capacity - aai->aai_reserved; 206 1.1 thorpej } 207 1.1 thorpej 208 1.1 thorpej error = 0; 209 1.1 thorpej 210 1.1 thorpej out: 211 1.13 jdolecek kmem_free(info, sizeof(*info)); 212 1.1 thorpej return (error); 213 1.1 thorpej } 214