1 /* $NetBSD: disksubr.c,v 1.36 2019/04/03 22:10:50 christos Exp $ */
2
3 /*
4 * Copyright (c) 1995 Dale Rahn.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30 #include <sys/cdefs.h>
31 __KERNEL_RCSID(0, "$NetBSD: disksubr.c,v 1.36 2019/04/03 22:10:50 christos Exp $");
32
33 #include <sys/param.h>
34 #include <sys/systm.h>
35 #include <sys/buf.h>
36 #include <sys/device.h>
37 #define FSTYPENAMES
38 #include <sys/disklabel.h>
39 #include <sys/disk.h>
40
41 #include <dev/scsipi/scsi_all.h>
42 #include <dev/scsipi/scsipi_all.h>
43 #include <dev/scsipi/scsiconf.h>
44
45 #include <machine/autoconf.h>
46
47 #ifdef DEBUG
48 int disksubr_debug = 0;
49 #endif
50
51 static void bsdtocpulabel(struct disklabel *lp, struct cpu_disklabel *clp);
52 static void cputobsdlabel(struct disklabel *lp, struct cpu_disklabel *clp);
53
54 #ifdef DEBUG
55 static void printlp(struct disklabel *lp, const char *str);
56 static void printclp(struct cpu_disklabel *clp, const char *str);
57 #endif
58
59
60 /*
61 * Attempt to read a disk label from a device
62 * using the indicated strategy routine.
63 * The label must be partly set up before this:
64 * secpercyl and anything required in the strategy routine
65 * (e.g., sector size) must be filled in before calling us.
66 * Returns null on success and an error string on failure.
67 */
68 const char *
readdisklabel(dev_t dev,void (* strat)(struct buf *),struct disklabel * lp,struct cpu_disklabel * clp)69 readdisklabel(dev_t dev, void (*strat)(struct buf *), struct disklabel *lp,
70 struct cpu_disklabel *clp)
71 {
72 struct buf *bp;
73 const char *msg = NULL;
74
75 /* obtain buffer to probe drive with */
76 bp = geteblk((int)lp->d_secsize);
77
78 /* request no partition relocation by driver on I/O operations */
79 bp->b_dev = dev;
80 bp->b_blkno = 0; /* contained in block 0 */
81 bp->b_bcount = lp->d_secsize;
82 bp->b_flags |= B_READ;
83 bp->b_cylinder = 0; /* contained in block 0 */
84 (*strat)(bp);
85
86 if (biowait(bp)) {
87 msg = "cpu_disklabel read error\n";
88 } else {
89 memcpy(clp, bp->b_data, sizeof (struct cpu_disklabel));
90 }
91
92 brelse(bp, 0);
93
94 if (msg || clp->magic1 != DISKMAGIC || clp->magic2 != DISKMAGIC) {
95 return msg;
96 }
97
98 cputobsdlabel(lp, clp);
99 #ifdef DEBUG
100 if(disksubr_debug > 0) {
101 printlp(lp, "readdisklabel: bsd label");
102 printclp(clp, "readdisklabel: cpu label");
103 }
104 #endif
105 return msg;
106 }
107
108 /*
109 * Write disk label back to device after modification.
110 */
111 int
writedisklabel(dev_t dev,void (* strat)(struct buf *),struct disklabel * lp,struct cpu_disklabel * clp)112 writedisklabel(dev_t dev, void (*strat)(struct buf *), struct disklabel *lp,
113 struct cpu_disklabel *clp)
114 {
115 struct buf *bp;
116 int error;
117
118 #ifdef DEBUG
119 if(disksubr_debug > 0) {
120 printlp(lp, "writedisklabel: bsd label");
121 }
122 #endif
123
124 /*
125 * obtain buffer to read initial cpu_disklabel, for bootloader size :-)
126 */
127 bp = geteblk((int)lp->d_secsize);
128
129 /* request no partition relocation by driver on I/O operations */
130 bp->b_dev = dev;
131 bp->b_blkno = 0; /* contained in block 0 */
132 bp->b_bcount = lp->d_secsize;
133 bp->b_flags |= B_READ;
134 bp->b_cylinder = 0; /* contained in block 0 */
135 (*strat)(bp);
136
137 if ( (error = biowait(bp)) != 0 ) {
138 /* nothing */
139 } else {
140 memcpy(clp, bp->b_data, sizeof(struct cpu_disklabel));
141 }
142
143 brelse(bp, 0);
144
145 if (error) {
146 return error;
147 }
148
149 bsdtocpulabel(lp, clp);
150
151 #ifdef DEBUG
152 if (disksubr_debug > 0) {
153 printclp(clp, "writedisklabel: cpu label");
154 }
155 #endif
156
157 if (lp->d_magic == DISKMAGIC && lp->d_magic2 == DISKMAGIC &&
158 dkcksum(lp) == 0) {
159 /* obtain buffer to scrozz drive with */
160 bp = geteblk((int)lp->d_secsize);
161
162 memcpy(bp->b_data, clp, sizeof(struct cpu_disklabel));
163
164 /*
165 * request no partition relocation by driver on I/O operations
166 */
167 bp->b_dev = dev;
168 bp->b_blkno = 0; /* contained in block 0 */
169 bp->b_bcount = lp->d_secsize;
170 bp->b_flags |= B_WRITE;
171 bp->b_cylinder = 0; /* contained in block 0 */
172 (*strat)(bp);
173
174 error = biowait(bp);
175
176 brelse(bp, 0);
177 }
178 return error;
179 }
180
181 static void
bsdtocpulabel(struct disklabel * lp,struct cpu_disklabel * clp)182 bsdtocpulabel(struct disklabel *lp, struct cpu_disklabel *clp)
183 {
184 int i;
185
186 clp->magic1 = lp->d_magic;
187 clp->type = lp->d_type;
188 clp->subtype = lp->d_subtype;
189 strncpy(clp->vid_vd, lp->d_typename, 16);
190 strncpy(clp->packname, lp->d_packname, 16);
191 clp->cfg_psm = lp->d_secsize;
192 clp->cfg_spt = lp->d_nsectors;
193 clp->cfg_trk = lp->d_ncylinders; /* trk is really num of cyl! */
194 clp->cfg_hds = lp->d_ntracks;
195
196 clp->secpercyl = lp->d_secpercyl;
197 clp->secperunit = lp->d_secperunit;
198 clp->sparespertrack = lp->d_sparespertrack;
199 clp->sparespercyl = lp->d_sparespercyl;
200 clp->acylinders = lp->d_acylinders;
201 clp->rpm = lp->d_rpm;
202
203 clp->cfg_ilv = lp->d_interleave;
204 clp->cfg_sof = lp->d_trackskew;
205 clp->cylskew = lp->d_cylskew;
206 clp->headswitch = lp->d_headswitch;
207
208 /* this silly table is for winchester drives */
209 if (lp->d_trkseek < 6) {
210 clp->cfg_ssr = 0;
211 } else if (lp->d_trkseek < 10) {
212 clp->cfg_ssr = 1;
213 } else if (lp->d_trkseek < 15) {
214 clp->cfg_ssr = 2;
215 } else if (lp->d_trkseek < 20) {
216 clp->cfg_ssr = 3;
217 } else {
218 clp->cfg_ssr = 4;
219 }
220
221 clp->flags = lp->d_flags;
222 for (i = 0; i < NDDATA; i++)
223 clp->drivedata[i] = lp->d_drivedata[i];
224 for (i = 0; i < NSPARE; i++)
225 clp->spare[i] = lp->d_spare[i];
226
227 clp->magic2 = lp->d_magic2;
228 clp->checksum = lp->d_checksum;
229 clp->partitions = lp->d_npartitions;
230 clp->bbsize = lp->d_bbsize;
231 clp->sbsize = lp->d_sbsize;
232 clp->checksum = lp->d_checksum;
233 /* note: assume at least 4 partitions */
234 memcpy(clp->vid_4, &lp->d_partitions[0], sizeof(struct partition) * 4);
235 memset(clp->cfg_4, 0, sizeof(struct partition) * 12);
236 memcpy(clp->cfg_4, &lp->d_partitions[4], sizeof(struct partition)
237 * ((MAXPARTITIONS < 16) ? (MAXPARTITIONS - 4) : 12));
238
239 /*
240 * here are the parts of the cpu_disklabel the kernel must init.
241 * see disklabel.h for more details
242 * [note: this used to be handled by 'wrtvid']
243 */
244 memcpy(clp->vid_id, VID_ID, sizeof(clp->vid_id));
245 clp->vid_oss = VID_OSS;
246 clp->vid_osl = VID_OSL;
247 clp->vid_osa_u = VID_OSAU;
248 clp->vid_osa_l = VID_OSAL;
249 clp->vid_cas = VID_CAS;
250 clp->vid_cal = VID_CAL;
251 memcpy(clp->vid_mot, VID_MOT, sizeof(clp->vid_mot));
252 clp->cfg_rec = CFG_REC;
253 clp->cfg_psm = CFG_PSM;
254 }
255
256 static void
cputobsdlabel(struct disklabel * lp,struct cpu_disklabel * clp)257 cputobsdlabel(struct disklabel *lp, struct cpu_disklabel *clp)
258 {
259 int i;
260
261 lp->d_magic = clp->magic1;
262 lp->d_type = clp->type;
263 lp->d_subtype = clp->subtype;
264 strncpy(lp->d_typename, clp->vid_vd, 16);
265 strncpy(lp->d_packname, clp->packname, 16);
266 lp->d_secsize = clp->cfg_psm;
267 lp->d_nsectors = clp->cfg_spt;
268 lp->d_ncylinders = clp->cfg_trk; /* trk is really num of cyl! */
269 lp->d_ntracks = clp->cfg_hds;
270
271 lp->d_secpercyl = clp->secpercyl;
272 lp->d_secperunit = clp->secperunit;
273 lp->d_secpercyl = clp->secpercyl;
274 lp->d_secperunit = clp->secperunit;
275 lp->d_sparespertrack = clp->sparespertrack;
276 lp->d_sparespercyl = clp->sparespercyl;
277 lp->d_acylinders = clp->acylinders;
278 lp->d_rpm = clp->rpm;
279 lp->d_interleave = clp->cfg_ilv;
280 lp->d_trackskew = clp->cfg_sof;
281 lp->d_cylskew = clp->cylskew;
282 lp->d_headswitch = clp->headswitch;
283
284 /* this silly table is for winchester drives */
285 switch (clp->cfg_ssr) {
286 case 0:
287 lp->d_trkseek = 0;
288 break;
289 case 1:
290 lp->d_trkseek = 6;
291 break;
292 case 2:
293 lp->d_trkseek = 10;
294 break;
295 case 3:
296 lp->d_trkseek = 15;
297 break;
298 case 4:
299 lp->d_trkseek = 20;
300 break;
301 default:
302 lp->d_trkseek = 0;
303 }
304 lp->d_flags = clp->flags;
305 for (i = 0; i < NDDATA; i++)
306 lp->d_drivedata[i] = clp->drivedata[i];
307 for (i = 0; i < NSPARE; i++)
308 lp->d_spare[i] = clp->spare[i];
309
310 lp->d_magic2 = clp->magic2;
311 lp->d_checksum = clp->checksum;
312 lp->d_npartitions = clp->partitions;
313 lp->d_bbsize = clp->bbsize;
314 lp->d_sbsize = clp->sbsize;
315 /* note: assume at least 4 partitions */
316 memcpy(&lp->d_partitions[0], clp->vid_4, sizeof(struct partition) * 4);
317 memcpy(&lp->d_partitions[4], clp->cfg_4, sizeof(struct partition)
318 * ((MAXPARTITIONS < 16) ? (MAXPARTITIONS - 4) : 12));
319 lp->d_checksum = 0;
320 lp->d_checksum = dkcksum(lp);
321 #if DEBUG
322 if (disksubr_debug > 0) {
323 printlp(lp, "translated label read from disk\n");
324 }
325 #endif
326 }
327
328 #ifdef DEBUG
329 static void
printlp(struct disklabel * lp,const char * str)330 printlp(struct disklabel *lp, const char *str)
331 {
332 int i;
333
334 printf("%s\n", str);
335 printf("magic1 %x\n", lp->d_magic);
336 printf("magic2 %x\n", lp->d_magic2);
337 printf("typename %s\n", lp->d_typename);
338 printf("secsize %x nsect %x ntrack %x ncylinders %x\n",
339 lp->d_secsize, lp->d_nsectors, lp->d_ntracks, lp->d_ncylinders);
340 printf("Num partitions %x\n", lp->d_npartitions);
341 for (i = 0; i < lp->d_npartitions; i++) {
342 struct partition *part = &lp->d_partitions[i];
343 const char *fstyp = fstypenames[part->p_fstype];
344
345 printf("%c: size %10x offset %10x type %7s frag %5x cpg %3x\n",
346 'a' + i, part->p_size, part->p_offset, fstyp,
347 part->p_frag, part->p_cpg);
348 }
349 }
350
351 static void
printclp(struct cpu_disklabel * clp,const char * str)352 printclp(struct cpu_disklabel *clp, const char *str)
353 {
354 int maxp, i;
355
356 printf("%s\n", str);
357 printf("magic1 %lx\n", clp->magic1);
358 printf("magic2 %lx\n", clp->magic2);
359 printf("typename %s\n", clp->vid_vd);
360 printf("secsize %x nsect %x ntrack %x ncylinders %x\n",
361 clp->cfg_psm, clp->cfg_spt, clp->cfg_hds, clp->cfg_trk);
362 printf("Num partitions %x\n", clp->partitions);
363 maxp = clp->partitions < 16 ? clp->partitions : 16;
364 for (i = 0; i < maxp; i++) {
365 struct partition *part;
366 const char *fstyp;
367
368 if (i < 4) {
369 part = (void *)&clp->vid_4[0];
370 part = &part[i];
371 } else {
372 part = (void *)&clp->cfg_4[0];
373 part = &part[i-4];
374 }
375
376 fstyp = fstypenames[part->p_fstype];
377
378 printf("%c: size %10x offset %10x type %7s frag %5x cpg %3x\n",
379 'a' + i, part->p_size, part->p_offset, fstyp,
380 part->p_frag, part->p_cpg);
381 }
382 }
383 #endif
384