1 1.4 jdolecek /* $NetBSD: wd.c,v 1.4 2019/01/08 19:41:09 jdolecek Exp $ */ 2 1.1 kiyohara 3 1.1 kiyohara /*- 4 1.1 kiyohara * Copyright (c) 2003 The NetBSD Foundation, Inc. 5 1.1 kiyohara * All rights reserved. 6 1.1 kiyohara * 7 1.1 kiyohara * This code is derived from software contributed to The NetBSD Foundation 8 1.1 kiyohara * by Manuel Bouyer. 9 1.1 kiyohara * 10 1.1 kiyohara * Redistribution and use in source and binary forms, with or without 11 1.1 kiyohara * modification, are permitted provided that the following conditions 12 1.1 kiyohara * are met: 13 1.1 kiyohara * 1. Redistributions of source code must retain the above copyright 14 1.1 kiyohara * notice, this list of conditions and the following disclaimer. 15 1.1 kiyohara * 2. Redistributions in binary form must reproduce the above copyright 16 1.1 kiyohara * notice, this list of conditions and the following disclaimer in the 17 1.1 kiyohara * documentation and/or other materials provided with the distribution. 18 1.1 kiyohara * 19 1.1 kiyohara * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 1.1 kiyohara * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 1.1 kiyohara * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 1.1 kiyohara * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 1.1 kiyohara * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 1.1 kiyohara * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 1.1 kiyohara * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 1.1 kiyohara * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 1.1 kiyohara * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 1.1 kiyohara * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 1.1 kiyohara * POSSIBILITY OF SUCH DAMAGE. 30 1.1 kiyohara */ 31 1.1 kiyohara 32 1.1 kiyohara #include <sys/param.h> 33 1.1 kiyohara #include <sys/types.h> 34 1.1 kiyohara #include <sys/stdint.h> 35 1.1 kiyohara 36 1.1 kiyohara #include <lib/libsa/stand.h> 37 1.1 kiyohara #include <lib/libkern/libkern.h> 38 1.1 kiyohara 39 1.1 kiyohara #include <dev/raidframe/raidframevar.h> /* For RF_PROTECTED_SECTORS */ 40 1.1 kiyohara 41 1.1 kiyohara #include "boot.h" 42 1.1 kiyohara #include "wdvar.h" 43 1.1 kiyohara 44 1.1 kiyohara #ifdef DEBUG 45 1.1 kiyohara #define DPRINTF(x) printf x 46 1.1 kiyohara #else 47 1.1 kiyohara #define DPRINTF(x) 48 1.1 kiyohara #endif 49 1.1 kiyohara 50 1.1 kiyohara static int wd_get_params(struct wd_softc *wd); 51 1.1 kiyohara static int wdgetdisklabel(struct wd_softc *wd); 52 1.1 kiyohara static void wdgetdefaultlabel(struct wd_softc *wd, struct disklabel *lp); 53 1.1 kiyohara 54 1.1 kiyohara int wdopen(struct open_file *, ...); 55 1.1 kiyohara int wdclose(struct open_file *); 56 1.1 kiyohara int wdstrategy(void *, int, daddr_t, size_t, void *, size_t *); 57 1.1 kiyohara 58 1.1 kiyohara /* 59 1.1 kiyohara * Get drive parameters through 'device identify' command. 60 1.1 kiyohara */ 61 1.1 kiyohara int 62 1.1 kiyohara wd_get_params(struct wd_softc *wd) 63 1.1 kiyohara { 64 1.1 kiyohara int error; 65 1.1 kiyohara uint8_t buf[DEV_BSIZE]; 66 1.1 kiyohara 67 1.1 kiyohara if ((error = wdc_exec_identify(wd, buf)) != 0) 68 1.1 kiyohara return error; 69 1.1 kiyohara 70 1.1 kiyohara wd->sc_params = *(struct ataparams *)buf; 71 1.1 kiyohara 72 1.1 kiyohara /* 48-bit LBA addressing */ 73 1.1 kiyohara if ((wd->sc_params.atap_cmd2_en & ATA_CMD2_LBA48) != 0) 74 1.1 kiyohara wd->sc_flags |= WDF_LBA48; 75 1.1 kiyohara 76 1.1 kiyohara /* Prior to ATA-4, LBA was optional. */ 77 1.1 kiyohara if ((wd->sc_params.atap_capabilities1 & WDC_CAP_LBA) != 0) 78 1.1 kiyohara wd->sc_flags |= WDF_LBA; 79 1.1 kiyohara 80 1.1 kiyohara if ((wd->sc_flags & WDF_LBA48) != 0) { 81 1.1 kiyohara DPRINTF(("Drive supports LBA48.\n")); 82 1.1 kiyohara wd->sc_capacity = 83 1.1 kiyohara ((uint64_t)wd->sc_params.atap_max_lba[3] << 48) | 84 1.1 kiyohara ((uint64_t)wd->sc_params.atap_max_lba[2] << 32) | 85 1.1 kiyohara ((uint64_t)wd->sc_params.atap_max_lba[1] << 16) | 86 1.1 kiyohara ((uint64_t)wd->sc_params.atap_max_lba[0] << 0); 87 1.1 kiyohara DPRINTF(("atap_max_lba = (0x%x, 0x%x, 0x%x, 0x%x)\n", 88 1.1 kiyohara wd->sc_params.atap_max_lba[3], 89 1.1 kiyohara wd->sc_params.atap_max_lba[2], 90 1.1 kiyohara wd->sc_params.atap_max_lba[1], 91 1.1 kiyohara wd->sc_params.atap_max_lba[0])); 92 1.1 kiyohara wd->sc_capacity28 = 93 1.1 kiyohara ((uint32_t)wd->sc_params.atap_capacity[1] << 16) | 94 1.1 kiyohara ((uint32_t)wd->sc_params.atap_capacity[0] << 0); 95 1.1 kiyohara DPRINTF(("atap_capacity = (0x%x, 0x%x)\n", 96 1.1 kiyohara wd->sc_params.atap_capacity[1], 97 1.1 kiyohara wd->sc_params.atap_capacity[0])); 98 1.1 kiyohara } else if ((wd->sc_flags & WDF_LBA) != 0) { 99 1.1 kiyohara DPRINTF(("Drive supports LBA.\n")); 100 1.1 kiyohara wd->sc_capacity = 101 1.1 kiyohara ((uint32_t)wd->sc_params.atap_capacity[1] << 16) | 102 1.1 kiyohara ((uint32_t)wd->sc_params.atap_capacity[0] << 0); 103 1.1 kiyohara wd->sc_capacity28 = 104 1.1 kiyohara ((uint32_t)wd->sc_params.atap_capacity[1] << 16) | 105 1.1 kiyohara ((uint32_t)wd->sc_params.atap_capacity[0] << 0); 106 1.1 kiyohara } else { 107 1.1 kiyohara DPRINTF(("Drive doesn't support LBA; using CHS.\n")); 108 1.1 kiyohara wd->sc_capacity = wd->sc_capacity28 = 109 1.1 kiyohara wd->sc_params.atap_cylinders * 110 1.1 kiyohara wd->sc_params.atap_heads * 111 1.1 kiyohara wd->sc_params.atap_sectors; 112 1.1 kiyohara } 113 1.1 kiyohara DPRINTF(("wd->sc_capacity = %" PRId64 ", wd->sc_capacity28 = %d.\n", 114 1.1 kiyohara wd->sc_capacity, wd->sc_capacity28)); 115 1.1 kiyohara 116 1.1 kiyohara return 0; 117 1.1 kiyohara } 118 1.1 kiyohara 119 1.1 kiyohara /* 120 1.1 kiyohara * Initialize disk label to the default value. 121 1.1 kiyohara */ 122 1.1 kiyohara void 123 1.1 kiyohara wdgetdefaultlabel(struct wd_softc *wd, struct disklabel *lp) 124 1.1 kiyohara { 125 1.1 kiyohara 126 1.1 kiyohara memset(lp, 0, sizeof(struct disklabel)); 127 1.1 kiyohara 128 1.1 kiyohara lp->d_secsize = DEV_BSIZE; 129 1.1 kiyohara lp->d_ntracks = wd->sc_params.atap_heads; 130 1.1 kiyohara lp->d_nsectors = wd->sc_params.atap_sectors; 131 1.1 kiyohara lp->d_ncylinders = wd->sc_params.atap_cylinders; 132 1.1 kiyohara lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors; 133 1.1 kiyohara 134 1.1 kiyohara if (strcmp((const char *)wd->sc_params.atap_model, "ST506") == 0) 135 1.3 christos lp->d_type = DKTYPE_ST506; 136 1.1 kiyohara else 137 1.3 christos lp->d_type = DKTYPE_ESDI; 138 1.1 kiyohara 139 1.1 kiyohara strncpy(lp->d_typename, (const char *)wd->sc_params.atap_model, 16); 140 1.1 kiyohara strncpy(lp->d_packname, "fictitious", 16); 141 1.1 kiyohara if (wd->sc_capacity > UINT32_MAX) 142 1.1 kiyohara lp->d_secperunit = UINT32_MAX; 143 1.1 kiyohara else 144 1.1 kiyohara lp->d_secperunit = wd->sc_capacity; 145 1.1 kiyohara lp->d_rpm = 3600; 146 1.1 kiyohara lp->d_interleave = 1; 147 1.1 kiyohara lp->d_flags = 0; 148 1.1 kiyohara 149 1.1 kiyohara lp->d_partitions[RAW_PART].p_offset = 0; 150 1.1 kiyohara lp->d_partitions[RAW_PART].p_size = 151 1.1 kiyohara lp->d_secperunit * (lp->d_secsize / DEV_BSIZE); 152 1.1 kiyohara lp->d_partitions[RAW_PART].p_fstype = FS_UNUSED; 153 1.1 kiyohara lp->d_npartitions = MAXPARTITIONS; /* RAW_PART + 1 ??? */ 154 1.1 kiyohara 155 1.1 kiyohara lp->d_magic = DISKMAGIC; 156 1.1 kiyohara lp->d_magic2 = DISKMAGIC; 157 1.1 kiyohara lp->d_checksum = dkcksum(lp); 158 1.1 kiyohara } 159 1.1 kiyohara 160 1.1 kiyohara /* 161 1.1 kiyohara * Read disk label from the device. 162 1.1 kiyohara */ 163 1.1 kiyohara int 164 1.1 kiyohara wdgetdisklabel(struct wd_softc *wd) 165 1.1 kiyohara { 166 1.1 kiyohara struct mbr_sector *mbr; 167 1.1 kiyohara struct mbr_partition *mp; 168 1.1 kiyohara struct disklabel *lp; 169 1.1 kiyohara size_t rsize; 170 1.1 kiyohara int sector, i; 171 1.1 kiyohara char *msg; 172 1.1 kiyohara uint8_t buf[DEV_BSIZE]; 173 1.1 kiyohara 174 1.1 kiyohara wdgetdefaultlabel(wd, &wd->sc_label); 175 1.1 kiyohara 176 1.1 kiyohara /* 177 1.1 kiyohara * Find NetBSD Partition in DOS partition table. 178 1.1 kiyohara */ 179 1.1 kiyohara sector = 0; 180 1.1 kiyohara if (wdstrategy(wd, F_READ, MBR_BBSECTOR, DEV_BSIZE, buf, &rsize)) 181 1.1 kiyohara return EOFFSET; 182 1.1 kiyohara 183 1.1 kiyohara mbr = (struct mbr_sector *)buf; 184 1.1 kiyohara if (mbr->mbr_magic == htole16(MBR_MAGIC)) { 185 1.1 kiyohara /* 186 1.1 kiyohara * Lookup NetBSD slice. If there is none, go ahead 187 1.1 kiyohara * and try to read the disklabel off sector #0. 188 1.1 kiyohara */ 189 1.1 kiyohara mp = mbr->mbr_parts; 190 1.1 kiyohara for (i = 0; i < MBR_PART_COUNT; i++) { 191 1.1 kiyohara if (mp[i].mbrp_type == MBR_PTYPE_NETBSD) { 192 1.1 kiyohara sector = le32toh(mp[i].mbrp_start); 193 1.1 kiyohara break; 194 1.1 kiyohara } 195 1.1 kiyohara } 196 1.1 kiyohara } 197 1.1 kiyohara 198 1.1 kiyohara if (wdstrategy(wd, F_READ, sector + LABELSECTOR, DEV_BSIZE, 199 1.1 kiyohara buf, &rsize)) 200 1.1 kiyohara return EOFFSET; 201 1.1 kiyohara 202 1.1 kiyohara msg = getdisklabel((const char *)buf + LABELOFFSET, &wd->sc_label); 203 1.1 kiyohara if (msg) 204 1.1 kiyohara printf("ide/0/%s/0: getdisklabel: %s\n", 205 1.1 kiyohara (wd->sc_unit == 0) ? "master" : "slave", msg); 206 1.1 kiyohara 207 1.1 kiyohara lp = &wd->sc_label; 208 1.1 kiyohara 209 1.1 kiyohara /* check partition */ 210 1.1 kiyohara if ((wd->sc_part >= lp->d_npartitions) || 211 1.1 kiyohara (lp->d_partitions[wd->sc_part].p_fstype == FS_UNUSED)) { 212 1.1 kiyohara DPRINTF(("illegal partition\n")); 213 1.1 kiyohara return EPART; 214 1.1 kiyohara } 215 1.1 kiyohara 216 1.1 kiyohara DPRINTF(("label info: d_secsize %d, d_nsectors %d, d_ncylinders %d," 217 1.1 kiyohara " d_ntracks %d, d_secpercyl %d\n", 218 1.1 kiyohara wd->sc_label.d_secsize, 219 1.1 kiyohara wd->sc_label.d_nsectors, 220 1.1 kiyohara wd->sc_label.d_ncylinders, 221 1.1 kiyohara wd->sc_label.d_ntracks, 222 1.1 kiyohara wd->sc_label.d_secpercyl)); 223 1.1 kiyohara 224 1.1 kiyohara return 0; 225 1.1 kiyohara } 226 1.1 kiyohara 227 1.1 kiyohara /* 228 1.1 kiyohara * Open device (read drive parameters and disklabel) 229 1.1 kiyohara */ 230 1.1 kiyohara int 231 1.1 kiyohara wdopen(struct open_file *f, ...) 232 1.1 kiyohara { 233 1.1 kiyohara int error; 234 1.1 kiyohara va_list ap; 235 1.1 kiyohara u_int ctlr, unit, lunit, part; 236 1.1 kiyohara struct wd_softc *wd; 237 1.1 kiyohara 238 1.1 kiyohara va_start(ap, f); 239 1.1 kiyohara ctlr = va_arg(ap, u_int); 240 1.1 kiyohara unit = va_arg(ap, u_int); 241 1.1 kiyohara lunit = va_arg(ap, u_int); 242 1.1 kiyohara part = va_arg(ap, u_int); 243 1.1 kiyohara va_end(ap); 244 1.1 kiyohara 245 1.1 kiyohara DPRINTF(("wdopen: ide/%d/%s/%d_%d\n", 246 1.1 kiyohara ctlr, (unit == 0) ? "master" : "slave", lunit, part)); 247 1.1 kiyohara if (lunit != 0) 248 1.1 kiyohara return ENOENT; 249 1.1 kiyohara 250 1.1 kiyohara wd = alloc(sizeof(struct wd_softc)); 251 1.1 kiyohara if (wd == NULL) 252 1.1 kiyohara return ENOMEM; 253 1.1 kiyohara 254 1.1 kiyohara memset(wd, 0, sizeof(struct wd_softc)); 255 1.1 kiyohara 256 1.1 kiyohara wd->sc_part = part; 257 1.1 kiyohara wd->sc_unit = unit; 258 1.1 kiyohara wd->sc_ctlr = ctlr; 259 1.1 kiyohara 260 1.1 kiyohara if ((error = wd_get_params(wd)) != 0) 261 1.1 kiyohara return error; 262 1.1 kiyohara 263 1.1 kiyohara if ((error = wdgetdisklabel(wd)) != 0) 264 1.1 kiyohara return error; 265 1.1 kiyohara 266 1.1 kiyohara f->f_devdata = wd; 267 1.1 kiyohara return 0; 268 1.1 kiyohara } 269 1.1 kiyohara 270 1.1 kiyohara /* 271 1.1 kiyohara * Close device. 272 1.1 kiyohara */ 273 1.1 kiyohara int 274 1.1 kiyohara wdclose(struct open_file *f) 275 1.1 kiyohara { 276 1.1 kiyohara 277 1.1 kiyohara return 0; 278 1.1 kiyohara } 279 1.1 kiyohara 280 1.1 kiyohara /* 281 1.1 kiyohara * Read some data. 282 1.1 kiyohara */ 283 1.1 kiyohara int 284 1.1 kiyohara wdstrategy(void *f, int rw, daddr_t dblk, size_t size, void *p, size_t *rsize) 285 1.1 kiyohara { 286 1.1 kiyohara int i, nsect; 287 1.1 kiyohara daddr_t blkno; 288 1.1 kiyohara struct wd_softc *wd; 289 1.1 kiyohara struct partition *pp; 290 1.1 kiyohara uint8_t *buf; 291 1.1 kiyohara 292 1.1 kiyohara if (size == 0) 293 1.1 kiyohara return 0; 294 1.1 kiyohara 295 1.1 kiyohara if (rw != F_READ) 296 1.1 kiyohara return EOPNOTSUPP; 297 1.1 kiyohara 298 1.1 kiyohara buf = p; 299 1.1 kiyohara wd = f; 300 1.1 kiyohara pp = &wd->sc_label.d_partitions[wd->sc_part]; 301 1.1 kiyohara 302 1.1 kiyohara nsect = howmany(size, wd->sc_label.d_secsize); 303 1.1 kiyohara blkno = dblk + pp->p_offset; 304 1.1 kiyohara if (pp->p_fstype == FS_RAID) 305 1.1 kiyohara blkno += RF_PROTECTED_SECTORS; 306 1.1 kiyohara 307 1.1 kiyohara for (i = 0; i < nsect; i++, blkno++) { 308 1.1 kiyohara int error; 309 1.1 kiyohara 310 1.1 kiyohara if ((error = wdc_exec_read(wd, WDCC_READ, blkno, buf)) != 0) 311 1.1 kiyohara return error; 312 1.1 kiyohara 313 1.1 kiyohara buf += wd->sc_label.d_secsize; 314 1.1 kiyohara } 315 1.1 kiyohara 316 1.1 kiyohara *rsize = size; 317 1.1 kiyohara return 0; 318 1.1 kiyohara } 319