1 /* $NetBSD: wd.c,v 1.8 2007/10/17 19:54:09 garbled 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 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the NetBSD 21 * Foundation, Inc. and its contributors. 22 * 4. Neither the name of The NetBSD Foundation nor the names of its 23 * contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 * POSSIBILITY OF SUCH DAMAGE. 37 */ 38 39 #include <sys/types.h> 40 #include <sys/stdint.h> 41 42 #include <lib/libsa/stand.h> 43 44 #include <machine/param.h> 45 #include <machine/stdarg.h> 46 #include <dev/raidframe/raidframevar.h> /* For RF_PROTECTED_SECTORS */ 47 48 #include "boot.h" 49 #include "wdvar.h" 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 /* 56 * Get drive parameters through 'device identify' command. 57 */ 58 int 59 wd_get_params(struct wd_softc *wd) 60 { 61 int error; 62 uint8_t buf[DEV_BSIZE]; 63 64 if ((error = wdc_exec_identify(wd, buf)) != 0) 65 return error; 66 67 wd->sc_params = *(struct ataparams *)buf; 68 69 /* 48-bit LBA addressing */ 70 if ((wd->sc_params.atap_cmd2_en & ATA_CMD2_LBA48) != 0) { 71 DPRINTF(("Drive supports LBA48.\n")); 72 #if defined(_ENABLE_LBA48) 73 wd->sc_flags |= WDF_LBA48; 74 #endif 75 } 76 77 /* Prior to ATA-4, LBA was optional. */ 78 if ((wd->sc_params.atap_capabilities1 & WDC_CAP_LBA) != 0) { 79 DPRINTF(("Drive supports LBA.\n")); 80 wd->sc_flags |= WDF_LBA; 81 } 82 83 return 0; 84 } 85 86 /* 87 * Initialize disk label to the default value. 88 */ 89 void 90 wdgetdefaultlabel(struct wd_softc *wd, struct disklabel *lp) 91 { 92 93 memset(lp, 0, sizeof(struct disklabel)); 94 95 lp->d_secsize = DEV_BSIZE; 96 lp->d_ntracks = wd->sc_params.atap_heads; 97 lp->d_nsectors = wd->sc_params.atap_sectors; 98 lp->d_ncylinders = wd->sc_params.atap_cylinders; 99 lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors; 100 101 if (strcmp(wd->sc_params.atap_model, "ST506") == 0) 102 lp->d_type = DTYPE_ST506; 103 else 104 lp->d_type = DTYPE_ESDI; 105 106 strncpy(lp->d_typename, wd->sc_params.atap_model, 16); 107 strncpy(lp->d_packname, "fictitious", 16); 108 if (wd->sc_capacity > UINT32_MAX) 109 lp->d_secperunit = UINT32_MAX; 110 else 111 lp->d_secperunit = wd->sc_capacity; 112 lp->d_rpm = 3600; 113 lp->d_interleave = 1; 114 lp->d_flags = 0; 115 116 lp->d_partitions[RAW_PART].p_offset = 0; 117 lp->d_partitions[RAW_PART].p_size = 118 lp->d_secperunit * (lp->d_secsize / DEV_BSIZE); 119 lp->d_partitions[RAW_PART].p_fstype = FS_UNUSED; 120 lp->d_npartitions = MAXPARTITIONS; /* RAW_PART + 1 ??? */ 121 122 lp->d_magic = DISKMAGIC; 123 lp->d_magic2 = DISKMAGIC; 124 lp->d_checksum = dkcksum(lp); 125 } 126 127 /* 128 * Read disk label from the device. 129 */ 130 int 131 wdgetdisklabel(struct wd_softc *wd) 132 { 133 char *msg; 134 int sector; 135 size_t rsize; 136 struct disklabel *lp; 137 uint8_t buf[DEV_BSIZE]; 138 139 wdgetdefaultlabel(wd, &wd->sc_label); 140 141 /* 142 * Find NetBSD Partition in DOS partition table. 143 */ 144 sector = 0; 145 if (wdstrategy(wd, F_READ, MBR_BBSECTOR, DEV_BSIZE, buf, &rsize)) 146 return EOFFSET; 147 148 if (*(uint16_t *)&buf[MBR_MAGIC_OFFSET] == MBR_MAGIC) { 149 int i; 150 struct mbr_partition *mp; 151 152 /* 153 * Lookup NetBSD slice. If there is none, go ahead 154 * and try to read the disklabel off sector #0. 155 */ 156 mp = (struct mbr_partition *)&buf[MBR_PART_OFFSET]; 157 for (i = 0; i < MBR_PART_COUNT; i++) { 158 if (mp[i].mbrp_type == MBR_PTYPE_NETBSD) { 159 sector = mp[i].mbrp_start; 160 break; 161 } 162 } 163 } 164 165 if (wdstrategy(wd, F_READ, sector + LABELSECTOR, DEV_BSIZE, 166 buf, &rsize)) 167 return EOFFSET; 168 169 if ((msg = getdisklabel(buf + LABELOFFSET, &wd->sc_label))) 170 printf("wd%d: getdisklabel: %s\n", wd->sc_unit, msg); 171 172 lp = &wd->sc_label; 173 174 /* check partition */ 175 if ((wd->sc_part >= lp->d_npartitions) || 176 (lp->d_partitions[wd->sc_part].p_fstype == FS_UNUSED)) { 177 DPRINTF(("illegal partition\n")); 178 return EPART; 179 } 180 181 DPRINTF(("label info: d_secsize %d, d_nsectors %d, d_ncylinders %d," 182 "d_ntracks %d, d_secpercyl %d\n", 183 wd->sc_label.d_secsize, 184 wd->sc_label.d_nsectors, 185 wd->sc_label.d_ncylinders, 186 wd->sc_label.d_ntracks, 187 wd->sc_label.d_secpercyl)); 188 189 return 0; 190 } 191 192 /* 193 * Open device (read drive parameters and disklabel) 194 */ 195 int 196 wdopen(struct open_file *f, ...) 197 { 198 int error; 199 va_list ap; 200 u_int unit, part; 201 struct wd_softc *wd; 202 203 va_start(ap, f); 204 unit = va_arg(ap, u_int); 205 part = va_arg(ap, u_int); 206 va_end(ap); 207 208 DPRINTF(("wdopen: %d:%d\n", unit, part)); 209 210 wd = alloc(sizeof(struct wd_softc)); 211 if (wd == NULL) 212 return ENOMEM; 213 214 memset(wd, 0, sizeof(struct wd_softc)); 215 216 if (wdc_init(wd, &unit) != 0) 217 return (ENXIO); 218 219 wd->sc_part = part; 220 wd->sc_unit = unit; 221 222 if ((error = wd_get_params(wd)) != 0) 223 return error; 224 225 if ((error = wdgetdisklabel(wd)) != 0) 226 return error; 227 228 f->f_devdata = wd; 229 return 0; 230 } 231 232 /* 233 * Close device. 234 */ 235 int 236 wdclose(struct open_file *f) 237 { 238 239 return 0; 240 } 241 242 /* 243 * Read some data. 244 */ 245 int 246 wdstrategy(void *f, int rw, daddr_t dblk, size_t size, void *buf, size_t *rsize) 247 { 248 int i, nsect; 249 daddr_t blkno; 250 struct wd_softc *wd; 251 struct partition *pp; 252 253 if (size == 0) 254 return 0; 255 256 if (rw != F_READ) 257 return EOPNOTSUPP; 258 259 wd = f; 260 pp = &wd->sc_label.d_partitions[wd->sc_part]; 261 262 nsect = howmany(size, wd->sc_label.d_secsize); 263 blkno = dblk + pp->p_offset; 264 if (pp->p_fstype == FS_RAID) 265 blkno += RF_PROTECTED_SECTORS; 266 267 for (i = 0; i < nsect; i++, blkno++) { 268 int error; 269 270 if ((error = wdc_exec_read(wd, WDCC_READ, blkno, buf)) != 0) 271 return error; 272 273 buf += wd->sc_label.d_secsize; 274 } 275 276 *rsize = size; 277 return 0; 278 } 279