xref: /netbsd-src/sys/arch/cobalt/stand/boot/wd.c (revision aaf4ece63a859a04e37cf3a7229b5fab0157cc06)
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