1 /* $NetBSD: wd.c,v 1.4 2015/01/02 19:42: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 * 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 41 #include "boot.h" 42 #include "wdvar.h" 43 44 static int wd_get_params(struct wd_softc *wd); 45 static int wdgetdisklabel(struct wd_softc *wd); 46 static void wdgetdefaultlabel(struct wd_softc *wd, struct disklabel *lp); 47 48 /* 49 * Get drive parameters through 'device identify' command. 50 */ 51 int 52 wd_get_params(struct wd_softc *wd) 53 { 54 int error; 55 uint8_t buf[DEV_BSIZE]; 56 57 if ((error = wdc_exec_identify(wd, buf)) != 0) 58 return error; 59 60 memcpy(&wd->sc_params, buf, sizeof wd->sc_params); 61 62 /* 48-bit LBA addressing */ 63 if ((wd->sc_params.atap_cmd2_en & ATA_CMD2_LBA48) != 0) 64 wd->sc_flags |= WDF_LBA48; 65 66 /* Prior to ATA-4, LBA was optional. */ 67 if ((wd->sc_params.atap_capabilities1 & WDC_CAP_LBA) != 0) 68 wd->sc_flags |= WDF_LBA; 69 70 if ((wd->sc_flags & WDF_LBA48) != 0) { 71 DPRINTF(("Drive supports LBA48.\n")); 72 wd->sc_capacity = 73 ((uint64_t)wd->sc_params.atap_max_lba[3] << 48) | 74 ((uint64_t)wd->sc_params.atap_max_lba[2] << 32) | 75 ((uint64_t)wd->sc_params.atap_max_lba[1] << 16) | 76 ((uint64_t)wd->sc_params.atap_max_lba[0] << 0); 77 DPRINTF(("atap_max_lba = (0x%x, 0x%x, 0x%x, 0x%x)\n", 78 wd->sc_params.atap_max_lba[3], 79 wd->sc_params.atap_max_lba[2], 80 wd->sc_params.atap_max_lba[1], 81 wd->sc_params.atap_max_lba[0])); 82 wd->sc_capacity28 = 83 ((uint32_t)wd->sc_params.atap_capacity[1] << 16) | 84 ((uint32_t)wd->sc_params.atap_capacity[0] << 0); 85 DPRINTF(("atap_capacity = (0x%x, 0x%x)\n", 86 wd->sc_params.atap_capacity[1], 87 wd->sc_params.atap_capacity[0])); 88 } else if ((wd->sc_flags & WDF_LBA) != 0) { 89 DPRINTF(("Drive supports LBA.\n")); 90 wd->sc_capacity = wd->sc_capacity28 = 91 ((uint32_t)wd->sc_params.atap_capacity[1] << 16) | 92 ((uint32_t)wd->sc_params.atap_capacity[0] << 0); 93 } else { 94 DPRINTF(("Drive doesn't support LBA; using CHS.\n")); 95 wd->sc_capacity = wd->sc_capacity28 = 96 wd->sc_params.atap_cylinders * 97 wd->sc_params.atap_heads * 98 wd->sc_params.atap_sectors; 99 } 100 DPRINTF(("wd->sc_capacity = %" PRId64 ", wd->sc_capacity28 = %d.\n", 101 wd->sc_capacity, wd->sc_capacity28)); 102 103 return 0; 104 } 105 106 /* 107 * Initialize disk label to the default value. 108 */ 109 void 110 wdgetdefaultlabel(struct wd_softc *wd, struct disklabel *lp) 111 { 112 113 memset(lp, 0, sizeof(struct disklabel)); 114 115 lp->d_secsize = DEV_BSIZE; 116 lp->d_ntracks = wd->sc_params.atap_heads; 117 lp->d_nsectors = wd->sc_params.atap_sectors; 118 lp->d_ncylinders = wd->sc_params.atap_cylinders; 119 lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors; 120 121 if (strcmp(wd->sc_params.atap_model, "ST506") == 0) 122 lp->d_type = DKTYPE_ST506; 123 else 124 lp->d_type = DKTYPE_ESDI; 125 126 strncpy(lp->d_typename, wd->sc_params.atap_model, 16); 127 strncpy(lp->d_packname, "fictitious", 16); 128 if (wd->sc_capacity > UINT32_MAX) 129 lp->d_secperunit = UINT32_MAX; 130 else 131 lp->d_secperunit = wd->sc_capacity; 132 lp->d_rpm = 3600; 133 lp->d_interleave = 1; 134 lp->d_flags = 0; 135 136 lp->d_partitions[RAW_PART].p_offset = 0; 137 lp->d_partitions[RAW_PART].p_size = 138 lp->d_secperunit * (lp->d_secsize / DEV_BSIZE); 139 lp->d_partitions[RAW_PART].p_fstype = FS_UNUSED; 140 lp->d_npartitions = MAXPARTITIONS; /* RAW_PART + 1 ??? */ 141 142 lp->d_magic = DISKMAGIC; 143 lp->d_magic2 = DISKMAGIC; 144 lp->d_checksum = dkcksum(lp); 145 146 /* 147 * Set partition 'a' to be the whole disk. 148 * Cleared if we find an mbr or a netbsd label. 149 */ 150 lp->d_partitions[0].p_size = lp->d_partitions[RAW_PART].p_size; 151 lp->d_partitions[0].p_fstype = FS_BSDFFS; 152 } 153 154 /* 155 * Read disk label from the device. 156 */ 157 int 158 wdgetdisklabel(struct wd_softc *wd) 159 { 160 char *msg; 161 size_t rsize; 162 struct disklabel *lp; 163 uint8_t buf[DEV_BSIZE]; 164 165 wdgetdefaultlabel(wd, &wd->sc_label); 166 167 if (wdstrategy(wd, F_READ, LABELSECTOR, DEV_BSIZE, buf, &rsize)) 168 return EOFFSET; 169 170 if ((msg = getdisklabel(buf + LABELOFFSET, &wd->sc_label))) 171 printf("wd%d: getdisklabel: %s\n", wd->sc_unit, msg); 172 173 lp = &wd->sc_label; 174 175 /* check partition */ 176 if ((wd->sc_part >= lp->d_npartitions) || 177 (lp->d_partitions[wd->sc_part].p_fstype == FS_UNUSED)) { 178 DPRINTF(("illegal partition\n")); 179 return EPART; 180 } 181 182 DPRINTF(("label info: d_secsize %d, d_nsectors %d, d_ncylinders %d," 183 " d_ntracks %d, d_secpercyl %d\n", 184 wd->sc_label.d_secsize, 185 wd->sc_label.d_nsectors, 186 wd->sc_label.d_ncylinders, 187 wd->sc_label.d_ntracks, 188 wd->sc_label.d_secpercyl)); 189 190 return 0; 191 } 192 193 /* 194 * Open device (read drive parameters and disklabel) 195 */ 196 int 197 wdopen(struct open_file *f, ...) 198 { 199 int error; 200 va_list ap; 201 u_int unit, part; 202 struct wd_softc *wd; 203 204 va_start(ap, f); 205 unit = va_arg(ap, u_int); 206 part = va_arg(ap, u_int); 207 va_end(ap); 208 209 DPRINTF(("wdopen: %d:%d\n", unit, part)); 210 211 wd = alloc(sizeof(struct wd_softc)); 212 if (wd == NULL) 213 return ENOMEM; 214 215 memset(wd, 0, sizeof(struct wd_softc)); 216 217 if (wdc_init(wd, &unit) != 0) 218 return (ENXIO); 219 220 wd->sc_part = part; 221 wd->sc_unit = unit; 222 223 if ((error = wd_get_params(wd)) != 0) 224 return error; 225 226 if ((error = wdgetdisklabel(wd)) != 0) 227 return error; 228 229 f->f_devdata = wd; 230 return 0; 231 } 232 233 /* 234 * Close device. 235 */ 236 int 237 wdclose(struct open_file *f) 238 { 239 240 return 0; 241 } 242 243 /* 244 * Read some data. 245 */ 246 int 247 wdstrategy(void *f, int rw, daddr_t dblk, size_t size, void *p, size_t *rsize) 248 { 249 int i, nsect; 250 daddr_t blkno; 251 struct wd_softc *wd; 252 struct partition *pp; 253 uint8_t *buf; 254 255 if (size == 0) 256 return 0; 257 258 if (rw != F_READ) 259 return EOPNOTSUPP; 260 261 buf = p; 262 wd = f; 263 pp = &wd->sc_label.d_partitions[wd->sc_part]; 264 265 nsect = howmany(size, wd->sc_label.d_secsize); 266 blkno = dblk + pp->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