1 /* $NetBSD: wd.c,v 1.5 2005/12/11 12:17:06 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 * 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 47 #include "boot.h" 48 #include "wdvar.h" 49 50 static int wd_get_params(struct wd_softc *wd); 51 static int wdgetdisklabel(struct wd_softc *wd); 52 static void wdgetdefaultlabel(struct wd_softc *wd, struct disklabel *lp); 53 54 /* 55 * Get drive parameters through 'device identify' command. 56 */ 57 int 58 wd_get_params(wd) 59 struct wd_softc *wd; 60 { 61 int error; 62 unsigned char 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(wd, lp) 91 struct wd_softc *wd; 92 struct disklabel *lp; 93 { 94 memset(lp, 0, sizeof(struct disklabel)); 95 96 lp->d_secsize = DEV_BSIZE; 97 lp->d_ntracks = wd->sc_params.atap_heads; 98 lp->d_nsectors = wd->sc_params.atap_sectors; 99 lp->d_ncylinders = wd->sc_params.atap_cylinders; 100 lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors; 101 102 if (strcmp(wd->sc_params.atap_model, "ST506") == 0) 103 lp->d_type = DTYPE_ST506; 104 else 105 lp->d_type = DTYPE_ESDI; 106 107 strncpy(lp->d_typename, wd->sc_params.atap_model, 16); 108 strncpy(lp->d_packname, "fictitious", 16); 109 if (wd->sc_capacity > UINT32_MAX) 110 lp->d_secperunit = UINT32_MAX; 111 else 112 lp->d_secperunit = wd->sc_capacity; 113 lp->d_rpm = 3600; 114 lp->d_interleave = 1; 115 lp->d_flags = 0; 116 117 lp->d_partitions[RAW_PART].p_offset = 0; 118 lp->d_partitions[RAW_PART].p_size = 119 lp->d_secperunit * (lp->d_secsize / DEV_BSIZE); 120 lp->d_partitions[RAW_PART].p_fstype = FS_UNUSED; 121 lp->d_npartitions = MAXPARTITIONS; /* RAW_PART + 1 ??? */ 122 123 lp->d_magic = DISKMAGIC; 124 lp->d_magic2 = DISKMAGIC; 125 lp->d_checksum = dkcksum(lp); 126 } 127 128 /* 129 * Read disk label from the device. 130 */ 131 int 132 wdgetdisklabel(wd) 133 struct wd_softc *wd; 134 { 135 char *msg; 136 int sector; 137 size_t rsize; 138 struct disklabel *lp; 139 unsigned char buf[DEV_BSIZE]; 140 141 wdgetdefaultlabel(wd, &wd->sc_label); 142 143 /* 144 * Find NetBSD Partition in DOS partition table. 145 */ 146 sector = 0; 147 if (wdstrategy(wd, F_READ, MBR_BBSECTOR, DEV_BSIZE, buf, &rsize)) 148 return EOFFSET; 149 150 if (*(u_int16_t *)&buf[MBR_MAGIC_OFFSET] == MBR_MAGIC) { 151 int i; 152 struct mbr_partition *mp; 153 154 /* 155 * Lookup NetBSD slice. If there is none, go ahead 156 * and try to read the disklabel off sector #0. 157 */ 158 mp = (struct mbr_partition *)&buf[MBR_PART_OFFSET]; 159 for (i = 0; i < MBR_PART_COUNT; i++) { 160 if (mp[i].mbrp_type == MBR_PTYPE_NETBSD) { 161 sector = mp[i].mbrp_start; 162 break; 163 } 164 } 165 } 166 167 if (wdstrategy(wd, F_READ, sector + LABELSECTOR, DEV_BSIZE, 168 buf, &rsize)) 169 return EOFFSET; 170 171 if ( (msg = getdisklabel(buf + LABELOFFSET, &wd->sc_label))) 172 printf("wd%d: getdisklabel: %s\n", wd->sc_unit, msg); 173 174 lp = &wd->sc_label; 175 176 /* check partition */ 177 if ((wd->sc_part >= lp->d_npartitions) || 178 (lp->d_partitions[wd->sc_part].p_fstype == FS_UNUSED)) { 179 DPRINTF(("illegal partition\n")); 180 return (EPART); 181 } 182 183 DPRINTF(("label info: d_secsize %d, d_nsectors %d, d_ncylinders %d," 184 "d_ntracks %d, d_secpercyl %d\n", 185 wd->sc_label.d_secsize, 186 wd->sc_label.d_nsectors, 187 wd->sc_label.d_ncylinders, 188 wd->sc_label.d_ntracks, 189 wd->sc_label.d_secpercyl)); 190 191 return (0); 192 } 193 194 /* 195 * Open device (read drive parameters and disklabel) 196 */ 197 int 198 wdopen(struct open_file *f, ...) 199 { 200 int error; 201 va_list ap; 202 u_int unit, part; 203 struct wd_softc *wd; 204 205 va_start(ap, f); 206 unit = va_arg(ap, u_int); 207 part = va_arg(ap, u_int); 208 va_end(ap); 209 210 DPRINTF(("wdopen: %d:%d\n", unit, part)); 211 212 wd = alloc(sizeof(struct wd_softc)); 213 if (wd == NULL) 214 return ENOMEM; 215 216 memset(wd, 0, sizeof(struct wd_softc)); 217 218 if (wdc_init(wd, &unit) != 0) 219 return (ENXIO); 220 221 wd->sc_part = part; 222 wd->sc_unit = unit; 223 224 if ( (error = wd_get_params(wd)) != 0) 225 return (error); 226 227 if ( (error = wdgetdisklabel(wd)) != 0) 228 return error; 229 230 f->f_devdata = wd; 231 return (0); 232 } 233 234 /* 235 * Close device. 236 */ 237 int 238 wdclose(struct open_file *f) 239 { 240 return 0; 241 } 242 243 /* 244 * Read some data. 245 */ 246 int 247 wdstrategy(f, rw, dblk, size, buf, rsize) 248 void *f; 249 int rw; 250 daddr_t dblk; 251 size_t size; 252 void *buf; 253 size_t *rsize; 254 { 255 int i, nsect; 256 daddr_t blkno; 257 struct wd_softc *wd = f; 258 259 if (size == 0) 260 return (0); 261 262 if (rw != F_READ) 263 return EOPNOTSUPP; 264 265 nsect = howmany(size, wd->sc_label.d_secsize); 266 blkno = dblk + wd->sc_label.d_partitions[wd->sc_part].p_offset; 267 268 for (i = 0; i < nsect; i++, blkno++) { 269 int error; 270 271 if ( (error = wdc_exec_read(wd, WDCC_READ, blkno, buf)) != 0) 272 return (error); 273 274 buf += wd->sc_label.d_secsize; 275 } 276 277 *rsize = size; 278 return (0); 279 } 280