xref: /netbsd-src/sys/arch/mmeye/stand/boot/wd.c (revision b45fa494daa2ba02187711d31a4144faf0993066)
1 /*	$NetBSD: wd.c,v 1.2 2011/07/04 12:03:56 mrg 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 #include <machine/stdarg.h>
41 
42 #include "boot.h"
43 #include "wdvar.h"
44 
45 static int  wd_get_params(struct wd_softc *wd);
46 static int  wdgetdisklabel(struct wd_softc *wd);
47 static void wdgetdefaultlabel(struct wd_softc *wd, struct disklabel *lp);
48 
49 /*
50  * Get drive parameters through 'device identify' command.
51  */
52 int
53 wd_get_params(struct wd_softc *wd)
54 {
55 	int error;
56 	uint8_t buf[DEV_BSIZE];
57 
58 	if ((error = wdc_exec_identify(wd, buf)) != 0)
59 		return error;
60 
61 	memcpy(&wd->sc_params, buf, sizeof wd->sc_params);
62 
63 	/* 48-bit LBA addressing */
64 	if ((wd->sc_params.atap_cmd2_en & ATA_CMD2_LBA48) != 0)
65 		wd->sc_flags |= WDF_LBA48;
66 
67 	/* Prior to ATA-4, LBA was optional. */
68 	if ((wd->sc_params.atap_capabilities1 & WDC_CAP_LBA) != 0)
69 		wd->sc_flags |= WDF_LBA;
70 
71 	if ((wd->sc_flags & WDF_LBA48) != 0) {
72 		DPRINTF(("Drive supports LBA48.\n"));
73 		wd->sc_capacity =
74 		    ((uint64_t)wd->sc_params.atap_max_lba[3] << 48) |
75 		    ((uint64_t)wd->sc_params.atap_max_lba[2] << 32) |
76 		    ((uint64_t)wd->sc_params.atap_max_lba[1] << 16) |
77 		    ((uint64_t)wd->sc_params.atap_max_lba[0] <<  0);
78 		DPRINTF(("atap_max_lba = (0x%x, 0x%x, 0x%x, 0x%x)\n",
79 		    wd->sc_params.atap_max_lba[3],
80 		    wd->sc_params.atap_max_lba[2],
81 		    wd->sc_params.atap_max_lba[1],
82 		    wd->sc_params.atap_max_lba[0]));
83 		wd->sc_capacity28 =
84 		    ((uint32_t)wd->sc_params.atap_capacity[1] << 16) |
85 		    ((uint32_t)wd->sc_params.atap_capacity[0] <<  0);
86 		DPRINTF(("atap_capacity = (0x%x, 0x%x)\n",
87 		    wd->sc_params.atap_capacity[1],
88 		    wd->sc_params.atap_capacity[0]));
89 	} else if ((wd->sc_flags & WDF_LBA) != 0) {
90 		DPRINTF(("Drive supports LBA.\n"));
91 		wd->sc_capacity = wd->sc_capacity28 =
92 		    ((uint32_t)wd->sc_params.atap_capacity[1] << 16) |
93 		    ((uint32_t)wd->sc_params.atap_capacity[0] <<  0);
94 	} else {
95 		DPRINTF(("Drive doesn't support LBA; using CHS.\n"));
96 		wd->sc_capacity = wd->sc_capacity28 =
97 		    wd->sc_params.atap_cylinders *
98 		    wd->sc_params.atap_heads *
99 		    wd->sc_params.atap_sectors;
100 	}
101 	DPRINTF(("wd->sc_capacity = %" PRId64 ", wd->sc_capacity28 = %d.\n",
102 	    wd->sc_capacity, wd->sc_capacity28));
103 
104 	return 0;
105 }
106 
107 /*
108  * Initialize disk label to the default value.
109  */
110 void
111 wdgetdefaultlabel(struct wd_softc *wd, struct disklabel *lp)
112 {
113 
114 	memset(lp, 0, sizeof(struct disklabel));
115 
116 	lp->d_secsize = DEV_BSIZE;
117 	lp->d_ntracks = wd->sc_params.atap_heads;
118 	lp->d_nsectors = wd->sc_params.atap_sectors;
119 	lp->d_ncylinders = wd->sc_params.atap_cylinders;
120 	lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors;
121 
122 	if (strcmp(wd->sc_params.atap_model, "ST506") == 0)
123 		lp->d_type = DTYPE_ST506;
124 	else
125 		lp->d_type = DTYPE_ESDI;
126 
127 	strncpy(lp->d_typename, wd->sc_params.atap_model, 16);
128 	strncpy(lp->d_packname, "fictitious", 16);
129 	if (wd->sc_capacity > UINT32_MAX)
130 		lp->d_secperunit = UINT32_MAX;
131 	else
132 		lp->d_secperunit = wd->sc_capacity;
133 	lp->d_rpm = 3600;
134 	lp->d_interleave = 1;
135 	lp->d_flags = 0;
136 
137 	lp->d_partitions[RAW_PART].p_offset = 0;
138 	lp->d_partitions[RAW_PART].p_size =
139 	lp->d_secperunit * (lp->d_secsize / DEV_BSIZE);
140 	lp->d_partitions[RAW_PART].p_fstype = FS_UNUSED;
141 	lp->d_npartitions = MAXPARTITIONS;	/* RAW_PART + 1 ??? */
142 
143 	lp->d_magic = DISKMAGIC;
144 	lp->d_magic2 = DISKMAGIC;
145 	lp->d_checksum = dkcksum(lp);
146 
147 	/*
148 	 * Set partition 'a' to be the whole disk.
149 	 * Cleared if we find an mbr or a netbsd label.
150 	 */
151 	lp->d_partitions[0].p_size = lp->d_partitions[RAW_PART].p_size;
152 	lp->d_partitions[0].p_fstype = FS_BSDFFS;
153 }
154 
155 /*
156  * Read disk label from the device.
157  */
158 int
159 wdgetdisklabel(struct wd_softc *wd)
160 {
161 	char *msg;
162 	size_t rsize;
163 	struct disklabel *lp;
164 	uint8_t buf[DEV_BSIZE];
165 
166 	wdgetdefaultlabel(wd, &wd->sc_label);
167 
168 	if (wdstrategy(wd, F_READ, LABELSECTOR, DEV_BSIZE, 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 
241 	return 0;
242 }
243 
244 /*
245  * Read some data.
246  */
247 int
248 wdstrategy(void *f, int rw, daddr_t dblk, size_t size, void *p, size_t *rsize)
249 {
250 	int i, nsect;
251 	daddr_t blkno;
252 	struct wd_softc *wd;
253 	struct partition *pp;
254 	uint8_t *buf;
255 
256 	if (size == 0)
257 		return 0;
258 
259 	if (rw != F_READ)
260 		return EOPNOTSUPP;
261 
262 	buf = p;
263 	wd = f;
264 	pp = &wd->sc_label.d_partitions[wd->sc_part];
265 
266 	nsect = howmany(size, wd->sc_label.d_secsize);
267 	blkno = dblk + pp->p_offset;
268 
269 	for (i = 0; i < nsect; i++, blkno++) {
270 		int error;
271 
272 		if ((error = wdc_exec_read(wd, WDCC_READ, blkno, buf)) != 0)
273 			return error;
274 
275 		buf += wd->sc_label.d_secsize;
276 	}
277 
278 	*rsize = size;
279 	return 0;
280 }
281