wd.c revision 1.4.16.1 1 /* $NetBSD: wd.c,v 1.4.16.1 2019/01/18 08:50:19 pgoyette 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