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