1 /* $NetBSD: wd.c,v 1.1 2010/10/14 06:50:43 kiyohara 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 <machine/stdarg.h> 41 #include <dev/raidframe/raidframevar.h> /* For RF_PROTECTED_SECTORS */ 42 43 #include "boot.h" 44 #include "wdvar.h" 45 46 #ifdef DEBUG 47 #define DPRINTF(x) printf x 48 #else 49 #define DPRINTF(x) 50 #endif 51 52 static int wd_get_params(struct wd_softc *wd); 53 static int wdgetdisklabel(struct wd_softc *wd); 54 static void wdgetdefaultlabel(struct wd_softc *wd, struct disklabel *lp); 55 56 int wdopen(struct open_file *, ...); 57 int wdclose(struct open_file *); 58 int wdstrategy(void *, int, daddr_t, size_t, void *, size_t *); 59 60 /* 61 * Get drive parameters through 'device identify' command. 62 */ 63 int 64 wd_get_params(struct wd_softc *wd) 65 { 66 int error; 67 uint8_t buf[DEV_BSIZE]; 68 69 if ((error = wdc_exec_identify(wd, buf)) != 0) 70 return error; 71 72 wd->sc_params = *(struct ataparams *)buf; 73 74 /* 48-bit LBA addressing */ 75 if ((wd->sc_params.atap_cmd2_en & ATA_CMD2_LBA48) != 0) 76 wd->sc_flags |= WDF_LBA48; 77 78 /* Prior to ATA-4, LBA was optional. */ 79 if ((wd->sc_params.atap_capabilities1 & WDC_CAP_LBA) != 0) 80 wd->sc_flags |= WDF_LBA; 81 82 if ((wd->sc_flags & WDF_LBA48) != 0) { 83 DPRINTF(("Drive supports LBA48.\n")); 84 wd->sc_capacity = 85 ((uint64_t)wd->sc_params.atap_max_lba[3] << 48) | 86 ((uint64_t)wd->sc_params.atap_max_lba[2] << 32) | 87 ((uint64_t)wd->sc_params.atap_max_lba[1] << 16) | 88 ((uint64_t)wd->sc_params.atap_max_lba[0] << 0); 89 DPRINTF(("atap_max_lba = (0x%x, 0x%x, 0x%x, 0x%x)\n", 90 wd->sc_params.atap_max_lba[3], 91 wd->sc_params.atap_max_lba[2], 92 wd->sc_params.atap_max_lba[1], 93 wd->sc_params.atap_max_lba[0])); 94 wd->sc_capacity28 = 95 ((uint32_t)wd->sc_params.atap_capacity[1] << 16) | 96 ((uint32_t)wd->sc_params.atap_capacity[0] << 0); 97 DPRINTF(("atap_capacity = (0x%x, 0x%x)\n", 98 wd->sc_params.atap_capacity[1], 99 wd->sc_params.atap_capacity[0])); 100 } else if ((wd->sc_flags & WDF_LBA) != 0) { 101 DPRINTF(("Drive supports LBA.\n")); 102 wd->sc_capacity = 103 ((uint32_t)wd->sc_params.atap_capacity[1] << 16) | 104 ((uint32_t)wd->sc_params.atap_capacity[0] << 0); 105 wd->sc_capacity28 = 106 ((uint32_t)wd->sc_params.atap_capacity[1] << 16) | 107 ((uint32_t)wd->sc_params.atap_capacity[0] << 0); 108 } else { 109 DPRINTF(("Drive doesn't support LBA; using CHS.\n")); 110 wd->sc_capacity = wd->sc_capacity28 = 111 wd->sc_params.atap_cylinders * 112 wd->sc_params.atap_heads * 113 wd->sc_params.atap_sectors; 114 } 115 DPRINTF(("wd->sc_capacity = %" PRId64 ", wd->sc_capacity28 = %d.\n", 116 wd->sc_capacity, wd->sc_capacity28)); 117 118 return 0; 119 } 120 121 /* 122 * Initialize disk label to the default value. 123 */ 124 void 125 wdgetdefaultlabel(struct wd_softc *wd, struct disklabel *lp) 126 { 127 128 memset(lp, 0, sizeof(struct disklabel)); 129 130 lp->d_secsize = DEV_BSIZE; 131 lp->d_ntracks = wd->sc_params.atap_heads; 132 lp->d_nsectors = wd->sc_params.atap_sectors; 133 lp->d_ncylinders = wd->sc_params.atap_cylinders; 134 lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors; 135 136 if (strcmp((const char *)wd->sc_params.atap_model, "ST506") == 0) 137 lp->d_type = DTYPE_ST506; 138 else 139 lp->d_type = DTYPE_ESDI; 140 141 strncpy(lp->d_typename, (const char *)wd->sc_params.atap_model, 16); 142 strncpy(lp->d_packname, "fictitious", 16); 143 if (wd->sc_capacity > UINT32_MAX) 144 lp->d_secperunit = UINT32_MAX; 145 else 146 lp->d_secperunit = wd->sc_capacity; 147 lp->d_rpm = 3600; 148 lp->d_interleave = 1; 149 lp->d_flags = 0; 150 151 lp->d_partitions[RAW_PART].p_offset = 0; 152 lp->d_partitions[RAW_PART].p_size = 153 lp->d_secperunit * (lp->d_secsize / DEV_BSIZE); 154 lp->d_partitions[RAW_PART].p_fstype = FS_UNUSED; 155 lp->d_npartitions = MAXPARTITIONS; /* RAW_PART + 1 ??? */ 156 157 lp->d_magic = DISKMAGIC; 158 lp->d_magic2 = DISKMAGIC; 159 lp->d_checksum = dkcksum(lp); 160 } 161 162 /* 163 * Read disk label from the device. 164 */ 165 int 166 wdgetdisklabel(struct wd_softc *wd) 167 { 168 struct mbr_sector *mbr; 169 struct mbr_partition *mp; 170 struct disklabel *lp; 171 size_t rsize; 172 int sector, i; 173 char *msg; 174 uint8_t buf[DEV_BSIZE]; 175 176 wdgetdefaultlabel(wd, &wd->sc_label); 177 178 /* 179 * Find NetBSD Partition in DOS partition table. 180 */ 181 sector = 0; 182 if (wdstrategy(wd, F_READ, MBR_BBSECTOR, DEV_BSIZE, buf, &rsize)) 183 return EOFFSET; 184 185 mbr = (struct mbr_sector *)buf; 186 if (mbr->mbr_magic == htole16(MBR_MAGIC)) { 187 /* 188 * Lookup NetBSD slice. If there is none, go ahead 189 * and try to read the disklabel off sector #0. 190 */ 191 mp = mbr->mbr_parts; 192 for (i = 0; i < MBR_PART_COUNT; i++) { 193 if (mp[i].mbrp_type == MBR_PTYPE_NETBSD) { 194 sector = le32toh(mp[i].mbrp_start); 195 break; 196 } 197 } 198 } 199 200 if (wdstrategy(wd, F_READ, sector + LABELSECTOR, DEV_BSIZE, 201 buf, &rsize)) 202 return EOFFSET; 203 204 msg = getdisklabel((const char *)buf + LABELOFFSET, &wd->sc_label); 205 if (msg) 206 printf("ide/0/%s/0: getdisklabel: %s\n", 207 (wd->sc_unit == 0) ? "master" : "slave", msg); 208 209 lp = &wd->sc_label; 210 211 /* check partition */ 212 if ((wd->sc_part >= lp->d_npartitions) || 213 (lp->d_partitions[wd->sc_part].p_fstype == FS_UNUSED)) { 214 DPRINTF(("illegal partition\n")); 215 return EPART; 216 } 217 218 DPRINTF(("label info: d_secsize %d, d_nsectors %d, d_ncylinders %d," 219 " d_ntracks %d, d_secpercyl %d\n", 220 wd->sc_label.d_secsize, 221 wd->sc_label.d_nsectors, 222 wd->sc_label.d_ncylinders, 223 wd->sc_label.d_ntracks, 224 wd->sc_label.d_secpercyl)); 225 226 return 0; 227 } 228 229 /* 230 * Open device (read drive parameters and disklabel) 231 */ 232 int 233 wdopen(struct open_file *f, ...) 234 { 235 int error; 236 va_list ap; 237 u_int ctlr, unit, lunit, part; 238 struct wd_softc *wd; 239 240 va_start(ap, f); 241 ctlr = va_arg(ap, u_int); 242 unit = va_arg(ap, u_int); 243 lunit = va_arg(ap, u_int); 244 part = va_arg(ap, u_int); 245 va_end(ap); 246 247 DPRINTF(("wdopen: ide/%d/%s/%d_%d\n", 248 ctlr, (unit == 0) ? "master" : "slave", lunit, part)); 249 if (lunit != 0) 250 return ENOENT; 251 252 wd = alloc(sizeof(struct wd_softc)); 253 if (wd == NULL) 254 return ENOMEM; 255 256 memset(wd, 0, sizeof(struct wd_softc)); 257 258 wd->sc_part = part; 259 wd->sc_unit = unit; 260 wd->sc_ctlr = ctlr; 261 262 if ((error = wd_get_params(wd)) != 0) 263 return error; 264 265 if ((error = wdgetdisklabel(wd)) != 0) 266 return error; 267 268 f->f_devdata = wd; 269 return 0; 270 } 271 272 /* 273 * Close device. 274 */ 275 int 276 wdclose(struct open_file *f) 277 { 278 279 return 0; 280 } 281 282 /* 283 * Read some data. 284 */ 285 int 286 wdstrategy(void *f, int rw, daddr_t dblk, size_t size, void *p, size_t *rsize) 287 { 288 int i, nsect; 289 daddr_t blkno; 290 struct wd_softc *wd; 291 struct partition *pp; 292 uint8_t *buf; 293 294 if (size == 0) 295 return 0; 296 297 if (rw != F_READ) 298 return EOPNOTSUPP; 299 300 buf = p; 301 wd = f; 302 pp = &wd->sc_label.d_partitions[wd->sc_part]; 303 304 nsect = howmany(size, wd->sc_label.d_secsize); 305 blkno = dblk + pp->p_offset; 306 if (pp->p_fstype == FS_RAID) 307 blkno += RF_PROTECTED_SECTORS; 308 309 for (i = 0; i < nsect; i++, blkno++) { 310 int error; 311 312 if ((error = wdc_exec_read(wd, WDCC_READ, blkno, buf)) != 0) 313 return error; 314 315 buf += wd->sc_label.d_secsize; 316 } 317 318 *rsize = size; 319 return 0; 320 } 321