1 /* @(#)labelsubs.c 1.25 09/07/11 Copyright 1988-2009 J. Schilling */
2 #include <schily/mconfig.h>
3 #ifndef lint
4 static UConst char sccsid[] =
5 "@(#)labelsubs.c 1.25 09/07/11 Copyright 1988-2009 J. Schilling";
6 #endif
7 /*
8 * Subroutines that deal with the primary disk label
9 *
10 * Copyright (c) 1988-2009 J. Schilling
11 */
12 /*
13 * The contents of this file are subject to the terms of the
14 * Common Development and Distribution License, Version 1.0 only
15 * (the "License"). You may not use this file except in compliance
16 * with the License.
17 *
18 * See the file CDDL.Schily.txt in this distribution for details.
19 * A copy of the CDDL is also available via the Internet at
20 * http://www.opensource.org/licenses/cddl1.txt
21 *
22 * When distributing Covered Code, include this CDDL HEADER in each
23 * file and include the License file CDDL.Schily.txt from this distribution.
24 */
25
26 #include <schily/param.h> /* XXX nonportable to use u_char */
27 #include <schily/stdio.h>
28 #include <schily/standard.h>
29 #include <schily/signal.h>
30 #include <schily/stdlib.h>
31 #include <schily/errno.h>
32 #include <schily/schily.h>
33
34 #include "dsklabel.h"
35
36 #include <scg/scsireg.h>
37 #include <scg/scsidefs.h>
38 #include <scg/scsitransp.h>
39
40 #include "scsicmds.h"
41
42 #include "fmt.h"
43
44 extern int debug;
45 extern int nowait;
46
47 extern int autoformat;
48 extern int reformat_only;
49 extern int label;
50
51 union x_label {
52 struct dk_label label;
53 char space[MAX_SECSIZE];
54 } x_label;
55 struct dk_label *d_label = (struct dk_label *)&x_label;
56
57 extern char *Lname;
58
59 EXPORT void read_primary_label __PR((SCSI *scgp, struct disk *dp));
60 EXPORT void create_label __PR((SCSI *scgp, struct disk *dp));
61 LOCAL void set_driver_geom __PR((SCSI *scgp));
62 EXPORT void label_disk __PR((SCSI *scgp, struct disk *dp));
63 LOCAL BOOL read_backup_label __PR((SCSI *scgp, struct disk *dp, struct dk_label *lp));
64 LOCAL void labelintr __PR((int sig));
65 LOCAL BOOL scan_backup_label __PR((SCSI *scgp, struct dk_label *lp, long *start, BOOL lgeom_ok));
66 EXPORT int read_disk_label __PR((SCSI *scgp, struct dk_label *lp, long secno));
67 LOCAL void print_label_err __PR((struct dk_label *lp));
68 LOCAL BOOL has_space_for_acyl __PR((SCSI *scgp, struct disk *dp, long *lblk));
69 LOCAL BOOL has_unused_space __PR((SCSI *scgp, struct disk *dp, long *lblk));
70 EXPORT long get_default_lncyl __PR((SCSI *scgp, struct disk *dp));
71 EXPORT void select_label_geom __PR((SCSI *scgp, struct disk *dp));
72 EXPORT BOOL select_backup_label __PR((SCSI *scgp, struct disk *dp, BOOL lgeom_ok));
73 LOCAL BOOL get_defpart __PR((SCSI *scgp, struct disk *dp, struct dk_label *lp));
74 EXPORT void select_partition __PR((SCSI *scgp, struct disk *dp));
75 EXPORT void get_default_partition __PR((SCSI *scgp, struct disk *dp));
76
77 EXPORT void
read_primary_label(scgp,dp)78 read_primary_label(scgp, dp)
79 SCSI *scgp;
80 struct disk *dp;
81 {
82 if (dp->formatted > 0 && !yes("Ignore old disk Label? ")) {
83 /*
84 * Disk is formatted,
85 * Label magic and Label checksum OK, use it!
86 */
87 if (read_disk_label(scgp, d_label, 0L) < 0) {
88 error("Could not read label from disk\n");
89
90 if (select_backup_label(scgp, dp, FALSE) == TRUE)
91 dp->labelread = 1;
92
93 } else if (setval_from_label(dp, d_label)) {
94 dp->labelread = 1;
95 printf("<%s>\n", d_label->dkl_asciilabel);
96
97 } else {
98 print_label_err(d_label);
99 }
100 } else if (dp->formatted == 0) {
101 /*
102 * Disk is formatted,
103 * Corrupt Label.
104 */
105 if (select_backup_label(scgp, dp, FALSE) == TRUE)
106 dp->labelread = 1;
107 }
108 }
109
110 EXPORT void
create_label(scgp,dp)111 create_label(scgp, dp)
112 SCSI *scgp;
113 struct disk *dp;
114 {
115 extern int format_done;
116 BOOL geom_changed = FALSE;
117 BOOL write_label = format_done && !nowait;
118
119 if (autoformat) {
120 label_disk(scgp, dp);
121 return;
122 }
123 scgp->silent++;
124 read_capacity(scgp);
125 scgp->silent--;
126 if ((scgp->cap->c_baddr + 1) != dp->cur_capacity) {
127 printf("WARNING:\n");
128 printf("Format changed Disk Geometry.\n");
129 printf("Capacity before: %ld Capacity after: %ld\n",
130 dp->cur_capacity,
131 (long)(scgp->cap->c_baddr + 1));
132
133 dp->cur_capacity = scgp->cap->c_baddr + 1;
134 select_label_geom(scgp, dp);
135 geom_changed = TRUE;
136 write_label = TRUE;
137 }
138 if (debug)
139 printf("nowait: %d write_label: %d geom_changed: %d\n",
140 nowait, write_label, geom_changed);
141 /*
142 * ALT: !nowait
143 * NEU:
144 * Wenn nowait, Label nicht schreiben es sei denn geometrie ge�ndert.
145 * Wenn nicht formatiert, fragen ob Label schreiben
146 * Wenn formatiert, fragen ob Label �ndern
147 * (impliziert ge�ndertes Label schreiben)
148 * Wenn formatiert & geometrie ge�ndert, dann immber Label �ndern.
149 */
150 if ((write_label || !format_done) &&
151 yes("Print disk label? ")) {
152 printlabel(d_label);
153 checklabel(dp, d_label, 0);
154 }
155 if ((write_label || !format_done) &&
156 (geom_changed || yes("Modify disk label? "))) do {
157 write_label = TRUE;
158
159 makelabel(scgp, dp, d_label);
160 printlabel(d_label);
161 checklabel(dp, d_label, 1);
162 } while (!yes("Use this label? "));
163
164 if (debug)
165 printf("nowait: %d write_label: %d geom_changed: %d\n",
166 nowait, write_label, geom_changed);
167 /*
168 * fill in default vtmap if not done yet
169 */
170 check_vtmap(d_label, label || write_label);
171 if (label) {
172 writelabel(Lname, d_label);
173 /* NOTREACHED */
174 } else if (write_label) {
175 if (!format_done && !yes("Write label on disk? "))
176 exit(1);
177 label_disk(scgp, dp);
178 }
179 }
180
181 LOCAL void
set_driver_geom(scgp)182 set_driver_geom(scgp)
183 SCSI *scgp;
184 {
185 int diskno = maptodisk(scg_scsibus(scgp), scg_target(scgp), scg_lun(scgp));
186 char *dname;
187 struct dk_label xl;
188
189 if (diskno < 0) {
190 errmsgno(EX_BAD,
191 "Cannot set geometry to driver (cannot map disk name).\n");
192 return;
193 }
194 dname = diskdevname(diskno);
195
196 if (!readlabel(dname, &xl)) {
197 if (geterrno() == ENXIO) {
198 errmsgno(EX_BAD, "Cannot verify mapping.\n");
199 if (yes("Set geometry to driver? "))
200 (void) setlabel(dname, d_label);
201 }
202 return;
203 }
204
205 if (cmpbytes(d_label, &xl, sizeof (xl)) < sizeof (xl)) {
206 errmsgno(EX_BAD,
207 "Will not set geometry to driver (mapping error).\n");
208 return;
209 }
210 (void) setlabel(dname, d_label);
211 }
212
213 /*---------------------------------------------------------------------------
214 |
215 | Die Backuplabels stehen auf dem letzten Reservezylinder
216 | auf dem letzten Kopf.
217 |
218 +---------------------------------------------------------------------------*/
219 EXPORT void
label_disk(scgp,dp)220 label_disk(scgp, dp)
221 SCSI *scgp;
222 struct disk *dp;
223 {
224 long backup_label_blk;
225 int i;
226
227 backup_label_blk = d_label->dkl_ncyl + d_label->dkl_acyl - 1;
228 backup_label_blk *= d_label->dkl_nhead * d_label->dkl_nsect;
229 backup_label_blk += (d_label->dkl_nhead-1) * d_label->dkl_nsect;
230
231 if (old_acb(scgp->dev)) {
232 backup_label_blk = d_label->dkl_pcyl;
233 backup_label_blk *= d_label->dkl_nhead * d_label->dkl_nsect;
234 backup_label_blk -= (d_label->dkl_nhead-1) * d_label->dkl_nsect;
235 }
236
237 if (write_scsi(scgp, (caddr_t)d_label, 0L, 1) < 0)
238 error("Could not write label to disk\n");
239 if (dp->lacyl > 0) {
240 for (i = 1; i < 10; i += 2) {
241 if (write_scsi(scgp, (caddr_t)d_label, backup_label_blk+i, 1) < 0)
242 error("Could not write backup label to disk\n");
243 }
244 }
245 set_driver_geom(scgp);
246 }
247
248 /*---------------------------------------------------------------------------
249 |
250 | Die Backuplabels stehen auf dem letzten Alternativen Zylinder
251 | auf dem letzten Kopf auf den ersten 5 ungeraden Sektoren.
252 | Bei Adaptec 4000 geht das nicht, weil i.a. die Kapazitaet nicht
253 | ausreicht. Daher:
254 | Alt: Letzter Alternativen Zylinder Kopf 1
255 | Neu: Letzter Alternativen Zylinder Kopf 2
256 |
257 +---------------------------------------------------------------------------*/
258 LOCAL BOOL
read_backup_label(scgp,dp,lp)259 read_backup_label(scgp, dp, lp)
260 SCSI *scgp;
261 struct disk *dp;
262 struct dk_label *lp;
263 {
264 long backup_label_blk;
265 int i;
266 int ret;
267
268 backup_label_blk = d_label->dkl_ncyl + d_label->dkl_acyl - 1;
269 backup_label_blk *= d_label->dkl_nhead * d_label->dkl_nsect;
270 backup_label_blk += (d_label->dkl_nhead-1) * d_label->dkl_nsect;
271 printf("lab: %ld\n", backup_label_blk+1);
272 backup_label_blk = dp->lncyl + dp->lacyl - 1;
273 backup_label_blk *= dp->lhead * dp->lspt;
274 backup_label_blk += (dp->lhead-1) * dp->lspt;
275 printf("lab: %ld\n", backup_label_blk+1);
276
277 if (old_acb(scgp->dev)) {
278 if (dp->lpcyl > 0)
279 backup_label_blk = dp->lpcyl;
280 else
281 backup_label_blk = dp->pcyl;
282 backup_label_blk *= dp->lhead * dp->lspt;
283 backup_label_blk -= (dp->lhead-1) * dp->lspt;
284 }
285
286 if (dp->lacyl > 0) {
287 for (i = 1; i < 10; i += 2) {
288 if ((ret = read_disk_label(scgp, lp, backup_label_blk+i)) < 0)
289 error("Could not read backup label from disk\n");
290 if (ret == TRUE)
291 return (TRUE);
292 error("Backup label: ");
293 print_label_err(lp);
294 }
295 return (FALSE);
296 }
297 error("No alt Cylinders!\n");
298 return (FALSE);
299 }
300
301 LOCAL int scan_intr;
302
303 LOCAL void
labelintr(sig)304 labelintr(sig)
305 int sig;
306 {
307 scan_intr++;
308 }
309
310 LOCAL BOOL
scan_backup_label(scgp,lp,start,lgeom_ok)311 scan_backup_label(scgp, lp, start, lgeom_ok)
312 SCSI *scgp;
313 struct dk_label *lp;
314 long *start;
315 BOOL lgeom_ok;
316 {
317 int i;
318 int limit;
319 long l;
320 void (*osig) __PR((int));
321
322 scgp->silent++;
323 if (read_capacity(scgp) < 0) {
324 scgp->silent--;
325 return (FALSE);
326 }
327 scgp->silent--;
328 if (start && *start)
329 l = *start;
330 else
331 l = scgp->cap->c_baddr;
332
333 osig = signal(SIGINT, labelintr);
334
335 printf("Scanning for backup label..."); flush();
336
337 limit = scgp->cap->c_baddr/200;
338 if (!lgeom_ok)
339 limit *= 10;
340 scan_intr = 0;
341 for (i = 0; scan_intr == 0 && i < limit; i++, l--) {
342 if (read_disk_label(scgp, lp, l) == TRUE) {
343 printf("\nScan for backup label: found at: %ld n: %d\n",
344 l, i);
345 signal(SIGINT, osig);
346 if (start)
347 *start = --l;
348 return (TRUE);
349 }
350 }
351 signal(SIGINT, osig);
352
353 printf("\nScan for backup label: NOT found : %ld n: %d\n", l, i);
354 return (FALSE);
355 }
356
357 EXPORT int
read_disk_label(scgp,lp,secno)358 read_disk_label(scgp, lp, secno)
359 SCSI *scgp;
360 struct dk_label *lp;
361 long secno;
362 {
363 fillbytes((caddr_t)lp, sizeof (*lp), '\0');
364 if (read_scsi(scgp, (caddr_t)lp, secno, 1) < 0)
365 return (-1);
366 return (lp->dkl_magic == DKL_MAGIC && lp->dkl_cksum == do_cksum(lp));
367 }
368
369 LOCAL void
print_label_err(lp)370 print_label_err(lp)
371 struct dk_label *lp;
372 {
373 /* if (lp->dkl_magic == 0 || do_cksum(lp) == 0)*/
374 /* error("Could not read label.\n");*/
375 if (lp->dkl_magic != DKL_MAGIC)
376 error("No label found.\n");
377 if (lp->dkl_cksum != do_cksum(lp))
378 error("Corrupt label.\n");
379 }
380
381 LOCAL BOOL
has_space_for_acyl(scgp,dp,lblk)382 has_space_for_acyl(scgp, dp, lblk)
383 SCSI *scgp;
384 struct disk *dp;
385 long *lblk;
386 {
387 *lblk = dp->lncyl + dp->lacyl - 1;
388 *lblk *= dp->lhead * dp->lspt;
389 *lblk += (dp->lhead - 1) * dp->lspt;
390 *lblk += 9; /* XXX letztes backuplabel */
391 if (*lblk > scgp->cap->c_baddr) {
392 *lblk -= scgp->cap->c_baddr;
393 *lblk += dp->lhead * dp->lspt;
394 *lblk /= dp->lhead * dp->lspt;
395 printf("WARNING: Alternate cylinders exceed end of disk. (%ld cyls)\n", *lblk);
396 return (FALSE);
397 }
398 return (TRUE);
399 }
400
401 LOCAL BOOL
has_unused_space(scgp,dp,lblk)402 has_unused_space(scgp, dp, lblk)
403 SCSI *scgp;
404 struct disk *dp;
405 long *lblk;
406 {
407 /*
408 * Wenn aus Sicht der Labelgeometrie mindestens ein ganzer
409 * Zylinder oder mehr verschenkt wird, wird gewarnt.
410 */
411 *lblk = scgp->cap->c_baddr + 1;
412 *lblk -= (dp->lncyl+dp->lacyl) * dp->lhead*dp->lspt;
413
414 if (*lblk >= dp->lhead * dp->lspt) {
415 *lblk /= dp->lhead * dp->lspt;
416 printf("WARNING: Unused space on disk. (%ld cyls)\n", *lblk);
417 printf("\tThis may be correct on a generic label that fits for a group of disks.\n");
418 printf("\tIn this case the disk space must match the smallest disk of that group.\n");
419 return (TRUE);
420 }
421 return (FALSE);
422 }
423
424 EXPORT long
get_default_lncyl(scgp,dp)425 get_default_lncyl(scgp, dp)
426 SCSI *scgp;
427 struct disk *dp;
428 {
429 long lncyl;
430
431 if (dp->lpcyl < 0 || dp->lpcyl != dp->pcyl) {
432 printf("NOTICE: setting lpcyl:\n");
433 printf("get_default_lncyl lpcyl: %ld lhead: %ld lspt: %ld\n", dp->lpcyl, dp->lhead, dp->lspt);
434 get_lgeom_defaults(scgp, dp);
435 printf("get_default_lncyl lpcyl: %ld lhead: %ld lspt: %ld\n", dp->lpcyl, dp->lhead, dp->lspt);
436 }
437 if (scgp->cap->c_baddr <= 0) {
438 lncyl = dp->lpcyl-dp->lacyl;
439 } else if (dp->lhead > 0 && dp->lspt > 0 && dp->lacyl > 0) {
440 lncyl = scgp->cap->c_baddr+1;
441 lncyl /= dp->lhead*dp->lspt;
442 lncyl -= dp->lacyl;
443 } else {
444 lncyl = -1;
445 }
446 return (lncyl);
447 }
448
449 EXPORT void
select_label_geom(scgp,dp)450 select_label_geom(scgp, dp)
451 SCSI *scgp;
452 struct disk *dp;
453 {
454 long minlacyl = old_acb(scgp->dev) ? 2L : 1L;
455 long maxlncyl;
456 long lncyl;
457 long lblk;
458
459 lncyl = get_default_lncyl(scgp, dp);
460 top:
461 getlong("Enter number of data heads (Label)",
462 &dp->lhead, 1L, 0xFFFEL);
463 getlong("Enter number of data sectors/track (Label)",
464 &dp->lspt, 1L, 0xFFFEL);
465 getlong("Enter number of alternate cylinders (Label)",
466 &dp->lacyl, minlacyl, 10L);
467
468 maxlncyl = dp->pcyl;
469 maxlncyl *= dp->nhead*dp->spt;
470
471 if (!reformat_only)
472 printf("Sch�tze cap: %ld ist cap: %ld\n", maxlncyl, (long)scgp->cap->c_baddr+1);
473
474 maxlncyl /= dp->lhead*dp->lspt;
475 maxlncyl -= dp->lacyl;
476
477 lncyl = get_default_lncyl(scgp, dp);
478
479 if (!reformat_only) {
480 printf("Current lncyl: %ld\n", dp->lncyl);
481 printf("Sch�tze lncyl: %ld\n", lncyl);
482 printf("old: %ld new: %ld\n",
483 dp->pcyl-dp->lacyl, maxlncyl);
484 }
485 if (lncyl > maxlncyl && lncyl > dp->lpcyl)
486 maxlncyl = lncyl;
487 if (dp->lpcyl-dp->lacyl > maxlncyl)
488 maxlncyl = dp->lpcyl-dp->lacyl;
489 if (dp->lncyl < 0)
490 dp->lncyl = lncyl;
491 getlong("Enter number of data cylinders (Label)",
492 &dp->lncyl, 1L, maxlncyl);
493
494 dp->int_cyl = dp->pcyl - dp->lncyl
495 - dp->lacyl - dp->atrk/dp->nhead;
496 /*printf("int_cyl: %d\n", dp->int_cyl);*/
497
498 if (!has_space_for_acyl(scgp, dp, &lblk)) {
499 if (!yes("Use this label geometry? ")) {
500 if (yes("Adjust number of data cylinders to maximum possible value? "))
501 dp->lncyl -= lblk;
502 goto top;
503 }
504 }
505
506 /*
507 * Hilfe fuer die Wartung der Datei 'sformat.dat'
508 * Der Service soll nicht sehen, dasz Platz verschenkt ist.
509 */
510 if (!reformat_only && has_unused_space(scgp, dp, &lblk)) {
511 if (!yes("Use this label geometry? ")) {
512 if (yes("Adjust number of data cylinders to maximum possible value? "))
513 dp->lncyl += lblk;
514 goto top;
515 }
516 }
517 }
518
519 EXPORT BOOL
select_backup_label(scgp,dp,lgeom_ok)520 select_backup_label(scgp, dp, lgeom_ok)
521 SCSI *scgp;
522 struct disk *dp;
523 BOOL lgeom_ok;
524 {
525 union x_label d_blabel;
526 long start = 0L;
527
528 if (!lgeom_ok) {
529 printf("WARNING:\n\n");
530 printf("The label geometry is not known at this time.\n\n");
531 printf("Scanning for backup labels may take a long time!\n");
532 printf("If you want to confirm the correct geometry,\n");
533 printf("hit RETURN on the next question.\n");
534 }
535 if (!yes("%s for backup labels? ", lgeom_ok ? "Search":"Scan"))
536 return (FALSE);
537
538 if (lgeom_ok && read_backup_label(scgp, dp, &d_blabel.label)) {
539 printf("<%s>\n", d_blabel.label.dkl_asciilabel);
540 } else {
541 do {
542 if (!scan_backup_label(scgp, &d_blabel.label,
543 &start, lgeom_ok))
544 return (FALSE);
545
546 printf("<%s>\n", d_blabel.label.dkl_asciilabel);
547 if (yes("Print partition table? ")) {
548 printparts(&d_blabel.label);
549 }
550 } while (yes("Scan for other backup label? "));
551 }
552
553 if (yes("Use backuplabel? ")) {
554 movebytes((caddr_t)&d_blabel.label,
555 (caddr_t)d_label, sizeof (*d_label));
556
557 if (!setval_from_label(dp, d_label)) {
558 print_label_err(d_label);
559 fillbytes((caddr_t)d_label, sizeof (*d_label), '\0');
560 return (FALSE);
561 }
562 return (TRUE);
563 }
564 return (FALSE);
565 }
566
567 LOCAL BOOL
get_defpart(scgp,dp,lp)568 get_defpart(scgp, dp, lp)
569 SCSI *scgp;
570 struct disk *dp;
571 struct dk_label *lp;
572 {
573 get_lgeom_defaults(scgp, dp);
574 label_null(lp);
575 return (get_part_defaults(scgp, dp, lp));
576 }
577
578 EXPORT void
select_partition(scgp,dp)579 select_partition(scgp, dp)
580 SCSI *scgp;
581 struct disk *dp;
582 {
583 struct dk_label d_xlabel;
584 char *pname = dp->default_part;
585
586 label_null(&d_xlabel);
587 if (dp->labelread > 0)
588 movebytes((char *)d_label, (char *)&d_xlabel, sizeof (*d_label));
589 if (!yes("Use default partition? "))
590 pname = NULL;
591 if (ext_part(scgp, dp->disk_type, pname, dp->default_part,
592 &d_xlabel, get_defpart, dp)) {
593 if (dp->labelread < 0 || yes("Use selected label? ")) {
594 printf("setval: %d\n", setval_from_label(dp, &d_xlabel));
595 /* merge_label(&d_xlabel, d_label);*/
596 movebytes((char *)&d_xlabel, (char *)d_label,
597 sizeof (*d_label));
598 if (dp->labelread < 0)
599 dp->labelread = 0;
600 else
601 dp->labelread = 1;
602 }
603 #ifdef ALT_deflabel
604 /*
605 * Wenn die Autpart hier und nicht in ext_part() vorgenommen wird, dann
606 * wird dp->labelread nicht auf 0 gesetzt und damit
607 * immer Labelgeometrie abgefragt. Ist das besser?
608 */
609 } else if (pname == NULL) {
610 if (get_defpart(&d_xlabel)) {
611 printparts(&d_xlabel);
612 movebytes((char *)&d_xlabel, (char *)d_label,
613 sizeof (*d_label));
614 }
615 #endif
616 }
617 }
618
619 EXPORT void
get_default_partition(scgp,dp)620 get_default_partition(scgp, dp)
621 SCSI *scgp;
622 struct disk *dp;
623 {
624 struct dk_label d_xlabel;
625 char *pname = dp->default_part;
626
627 label_null(&d_xlabel);
628 /*
629 * Wenn nur default Label aus der Datenbank zul�ssig sein sollen, dann
630 * mu� statt get_defpart() ein NULL Pointer genommen werden.
631 */
632 if (ext_part(scgp, dp->disk_type, pname, pname,
633 &d_xlabel, get_defpart, dp)) {
634 if (!setval_from_label(dp, &d_xlabel)) {
635 comerrno(EX_BAD, "BAD default partition.\n");
636 /* NOTREACHED */
637 }
638 /* merge_label(&d_xlabel, d_label);*/
639 movebytes((char *)&d_xlabel, (char *)d_label,
640 sizeof (*d_label));
641 dp->labelread = 1;
642 } else {
643 comerrno(EX_BAD, "Default partition not found.\n");
644 /* NOTREACHED */
645 }
646 }
647