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