summaryrefslogtreecommitdiff
path: root/scsi/disk_label.c
diff options
context:
space:
mode:
Diffstat (limited to 'scsi/disk_label.c')
-rw-r--r--scsi/disk_label.c692
1 files changed, 692 insertions, 0 deletions
diff --git a/scsi/disk_label.c b/scsi/disk_label.c
new file mode 100644
index 0000000..ab20378
--- /dev/null
+++ b/scsi/disk_label.c
@@ -0,0 +1,692 @@
+/*
+ * Copyright (c) 1996 The University of Utah and
+ * the Computer Systems Laboratory at the University of Utah (CSL).
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify and distribute this software is hereby
+ * granted provided that (1) source code retains these copyright, permission,
+ * and disclaimer notices, and (2) redistributions including binaries
+ * reproduce the notices in supporting documentation, and (3) all advertising
+ * materials mentioning features or use of this software display the following
+ * acknowledgement: ``This product includes software developed by the
+ * Computer Systems Laboratory at the University of Utah.''
+ *
+ * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS
+ * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF
+ * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * CSL requests users of this software to return to csl-dist@cs.utah.edu any
+ * improvements that they make and grant CSL redistribution rights.
+ *
+ * Author: Kevin T. Van Maren, University of Utah CSL
+ */
+
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+
+/*
+ * Copyright (c) 1994 Shantanu Goel
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * THE AUTHOR ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. THE AUTHOR DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ */
+
+/* This file contains the partition code that is used by the Mach
+ * device drivers (ide & scsi). */
+
+#include <scsi/compat_30.h>
+#include <sys/types.h>
+
+#include <scsi/rz_labels.h>
+#include <i386at/disk.h> /* combine & rename these... */
+
+#define SECTOR_SIZE 512 /* BAD!!! */
+
+#define DSLICE(dev) ((dev >> 4) & 0x3f)
+#define DPART(dev) (dev & 0xf)
+
+/* note: 0 will supress ALL output;
+ 1 is 'normal' output; 2 is verbose; 3 is Very verbose */
+#define PARTITION_DEBUG 1
+
+#define min(x,y) (x<y?x:y)
+
+/*
+ * Label that is filled in with extra info
+ */
+struct disklabel default_label =
+{
+ DISKMAGIC, DTYPE_SCSI, 0,
+ "SCSI", "",
+ DEV_BSIZE, 1, 1, 1, 1, 1, 0, 0, 0,
+ 3600, 1, 1, 1, 0, 0, 0,
+ {0,}, {0,},
+ DISKMAGIC, 0,
+ 8, 8192, 8192,
+ {{ -1, 0, 1024, FS_BSDFFS, 8, 3 },
+ { -1, 0, 1024, FS_BSDFFS, 8, 3 },
+ { -1, 0, 1024, FS_BSDFFS, 8, 3 },
+ { -1, 0, 1024, FS_BSDFFS, 8, 3 },
+ { -1, 0, 1024, FS_BSDFFS, 8, 3 },
+ { -1, 0, 1024, FS_BSDFFS, 8, 3 },
+ { -1, 0, 1024, FS_BSDFFS, 8, 3 },
+ { -1, 0, 1024, FS_BSDFFS, 8, 3 }}
+};
+
+
+
+/* the device driver calls this just to save some info it got from the HW */
+/* This is a bad holdover from the disklabel days, and needs to go */
+fudge_bsd_label(struct disklabel *label, int type, int total_secs, int heads, int sectors, int sectorsize, int n)
+{
+ *label=default_label;
+
+ label->d_ncylinders = total_secs/(heads*sectors);
+ label->d_ntracks = heads;
+ label->d_nsectors = sectors;
+
+ label->d_secpercyl = heads*sectors;
+ label->d_secperunit = total_secs;
+
+ /* this is never used, but ... */
+ label->d_partitions[MAXPARTITIONS].p_offset = 0;
+ label->d_partitions[MAXPARTITIONS].p_size = total_secs;
+
+ /* ??
+ */
+ label->d_secsize = sectorsize;
+ label->d_type = type;
+ label->d_subtype = 0xa; /* ??? */
+
+ label->d_npartitions = n; /* up to 'c' */
+ label->d_checksum = 0;
+
+ /* should do a checksum on it now */
+}
+
+
+
+/* This is placed here to
+ a. provide comparability with existing servers
+ b. allow the use of FreeBSD-style slices to access ANY disk partition
+ c. provide an easy migration path to lites-based partition code
+ by only passing the drive name to get the entire disk (sd0).
+
+ This will be called by every routine that needs to access partition info
+ based on a device number. It is slower than the old method of indexing
+ into a disklabel, but is more flexible, and reasonably fast in the (future)
+ case where Lites will access the whole disk. An array of disklabels
+ could have been used, but this is more compact and general. The underlying
+ structure does not limit it to 2-levels, but keeping the kernel interface
+ simple does. */
+
+
+/* this code and data structure based on conversation with Bryan Ford */
+/* Note: this is called ON EVERY read or write. It makes sense to
+ optimize this for the common case. Hopefully the common case
+ will become the '0,0' case, as partitioning is moved out of the
+ kernel. (Downside is kernel can't protect filesystems from each other).
+ It is slower than indexing into a 1-D array, but not much. */
+
+struct diskpart *lookup_part(struct diskpart *array, int dev_number)
+{
+/* Note: 10 bit encoding to get partitions 0-15 (0,a-h typically), and slices
+ * 0-63
+ */
+
+ int slice = DSLICE(dev_number);
+ int part = DPART(dev_number);
+ struct diskpart *s;
+
+ if (slice == 0) /* compatability slice */
+ {
+ if (part == 0) /* whole disk */
+ return &array[0];
+
+ if (array[0].type == DISKPART_DOS)
+ {
+ int i;
+ for (i = 0; i < array[0].nsubs; i++)
+ {
+ s = &array[0].subs[i];
+ if ( s->type == DISKPART_BSD
+ || s->type == DISKPART_VTOC)
+ {
+ if (part > s->nsubs)
+ return 0;
+ return (&s->subs[part-1]);
+ }
+ }
+ }
+
+ if (part > array[0].nsubs)
+ return 0;
+ return(&array[0].subs[part-1]);
+ }
+ else
+ {
+ if ( array[0].type != DISKPART_DOS
+ || slice > array[0].nsubs)
+ return 0;
+
+ s = &array[0].subs[slice-1];
+
+ if (part == 0) /* whole slice */
+ return (s);
+ if (part > s->nsubs)
+ return 0;
+
+ return (&s->subs[part-1]);
+ }
+}
+
+
+
+
+static inline void fill_array(struct diskpart *array, int start, int size,
+ struct diskpart *subs, int nsubs, short type, short fsys)
+{
+ array->start=start;
+ array->size=size;
+ array->subs=subs;
+ array->nsubs=nsubs;
+ array->type=type;
+ array->fsys=fsys;
+#if (PARTITION_DEBUG > 2)
+ printf("fill: type %d:%d, start %d, size %d, %d parts\n",type,fsys,
+ start,size,nsubs);
+#endif
+}
+
+
+
+
+void print_array(struct diskpart *array, int level)
+{
+ int i,j;
+ struct diskpart *subs;
+
+#if (PARTITION_DEBUG)
+ subs=array[0].subs;
+
+ for (i=0;i<array[0].nsubs;i++) {
+ for (j=0;j<level;j++)
+ printf(" ");
+ printf("%c: %d, %d, %d, %d (%d subparts)\n",'a'+i,
+ subs[i].start, subs[i].size, subs[i].fsys,
+ subs[i].type, subs[i].nsubs);
+ if (subs[i].nsubs>0)
+ print_array(&subs[i], level+1);
+ }
+#endif
+}
+
+
+
+/* individual routines to find the drive labels.
+ There needs to be a function for every different method for partitioning
+ much of the following code is derived from the SCSI/IDE drivers */
+
+int get_dos(struct diskpart *array, char *buff, int start,
+ void *driver_info, int (*bottom_read_fun)(),
+ char *name, int max_part)
+{
+
+ bios_label_t *mp;
+ struct bios_partition_info *pp;
+
+ int count, i, j;
+ int pstart, psize;
+ int ext=-1, mystart=start, mybase;
+ int first=1;
+
+ /* note: start is added, although a start != 0 is meaningless
+ to DOS and anything else... */
+
+ /* check the boot sector for a partition table. */
+ (*bottom_read_fun)(driver_info, start, buff); /* always in sector 0 */
+
+ /*
+ * Check for valid partition table.
+ */
+ mp = (bios_label_t *)&buff[BIOS_LABEL_BYTE_OFFSET];
+ if (mp->magic != BIOS_LABEL_MAGIC) {
+#if (PARTITION_DEBUG>1)
+ printf("%s invalid partition table\n", name);
+#endif
+ return(0); /* didn't add any partitions */
+ }
+#if (PARTITION_DEBUG>1)
+ printf("DOS partition table found\n");
+#endif
+
+ count=min(4,max_part); /* always 4 (primary) partitions */
+#if (PARTITION_DEBUG)
+ if (count<4) printf("More partitions than space!\n");
+#endif
+
+
+ /* fill the next 4 entries in the array */
+ for (i=0, pp=(struct bios_partition_info *)mp->partitions;
+ i<count; i++,pp++) {
+
+ fill_array(&array[i], pp->offset, pp->n_sectors, NULL, 0,
+ DISKPART_NONE, pp->systid);
+ if ((pp->systid == DOS_EXTENDED) &&(ext<0)) {
+ mystart+=pp->offset;
+ ext=i;
+ }
+ }
+
+ /* if there is an extended partition, find all the logical partitions */
+ /* note: logical start at '5' (extended is one of the numbered 1-4) */
+
+ /* logical partitions 'should' be nested inside the primary, but
+ then it would be impossible to NAME a disklabel inside a logical
+ partition, which would be nice to do */
+#if (PARTITION_DEBUG>1)
+ if (ext>=0)
+ printf("extended partition found: %d\n",ext);
+#endif 0
+
+ while (ext>=0) {
+ pp = &(((struct bios_partition_info *)mp->partitions)[ext]);
+
+ /* read the EXTENDED partition table */
+ if (first) {
+ mybase=mystart;
+ first=0;
+ } else {
+ mybase=mystart+pp->offset;
+ }
+
+ (*bottom_read_fun)(driver_info, mybase, buff);
+
+ if (mp->magic != BIOS_LABEL_MAGIC) {
+#if (PARTITION_DEBUG>1)
+ printf("%s invalid expanded magic\n", name);
+#endif
+ return(count);/*don't add any more partitions*/
+ }
+
+ /* just in case more than one partition is there...*/
+ /* search the EXTENDED partition table */
+ ext=-1;
+ for (j=0,pp=(struct bios_partition_info *)mp->partitions;
+ j<4; j++,pp++) {
+
+ if (pp->systid && (pp->systid!=DOS_EXTENDED)) {
+ if (count<max_part) {
+ fill_array(&array[count],
+ mybase +pp->offset,
+ pp->n_sectors, NULL, 0, DISKPART_NONE,
+ pp->systid);
+ count++; }
+ else {
+#if (PARTITION_DEBUG)
+ printf("More partitions than space!\n");
+#endif
+ return(count);
+ }
+ } else if ((ext<0) &&(pp->systid==DOS_EXTENDED)) {
+ ext=j;
+ /* recursivly search the chain here */
+ }
+ }
+ }
+#if (PARTITION_DEBUG>1)
+ printf("%d dos partitions\n",count);
+#endif 0
+ return(count); /* number dos partitions found */
+
+}
+
+
+
+/* this should work on the bare drive, or in a dos partition */
+int get_disklabel(struct diskpart *array, char *buff, int start,
+ void *driver_info, int (*bottom_read_fun)(),
+ char *name, int max_part)
+{
+ struct disklabel *dlp;
+ int mybase = start + (512 * LBLLOC)/SECTOR_SIZE, i;
+ int count;
+
+ (*bottom_read_fun)(driver_info, mybase, buff);
+
+ dlp = (struct disklabel *)buff;
+ if (dlp->d_magic != DISKMAGIC || dlp->d_magic2 != DISKMAGIC) {
+#if (PARTITION_DEBUG>1)
+ printf("%s no BSD label found\n",name);
+#endif
+ return(0); /* no partitions added */
+ }
+#if (PARTITION_DEBUG>1)
+ printf(" BSD LABEL\n");
+#endif 0
+ /* note: BSD disklabel offsets are from start of DRIVE -- uuggh */
+
+ count=min(8,max_part); /* always 8 in a disklabel */
+#if (PARTITION_DEBUG)
+ if (count<8) printf("More partitions than space!\n");
+#endif
+ /* COPY into the array */
+ for (i=0;i<count;i++)
+ fill_array(&array[i], /* mybase + */
+ dlp->d_partitions[i].p_offset,
+ dlp->d_partitions[i].p_size,
+ NULL, 0, DISKPART_NONE, dlp->d_partitions[i].p_fstype);
+
+ /* note: p_fstype is not the same set as the DOS types */
+
+ return(count); /* 'always' 8 partitions in disklabel -- if space */
+
+/* UNREACHED CODE FOLLOWS: (alternative method in scsi) */
+#if 0
+ (*bottom_read_fun)(driver_info, (start)+LABELSECTOR, buff);
+
+ register int j;
+ boolean_t found;
+
+ for (j = LABELOFFSET, found = FALSE;
+ j < (SECTOR_SIZE-sizeof(struct disklabel));
+ j += sizeof(int)) {
+ search = (struct disklabel *)&buff[j];
+ if (search->d_magic == DISKMAGIC &&
+ search->d_magic2 == DISKMAGIC) {
+ found = TRUE;
+ break;
+ }
+ }
+ if (found) {
+#if (PARTITION_DEBUG>1)
+ printf("Label found in LABELSECTOR\n");
+#endif
+ } else {
+ search = 0;
+ }
+
+
+#endif 0
+
+}
+
+
+/* NOT TESTED! */
+/* VTOC in sector 29 */
+int get_vtoc(struct diskpart *array, char *buff, int start,
+ void *driver_info, int (*bottom_read_fun)(),
+ char *name, int max_part)
+{
+ struct evtoc *evp;
+ int n,i;
+ struct disklabel lpl;
+ struct disklabel *lp = &lpl;
+
+#if (PARTITION_DEBUG)
+ printf("Read VTOC.\n");
+#endif
+ (*bottom_read_fun)(driver_info, start +PDLOCATION, buff);
+ evp = (struct evtoc *)buff;
+ if (evp->sanity != VTOC_SANE) {
+#if (PARTITION_DEBUG)
+ printf("%s evtoc corrupt or not found\n", name);
+#endif
+ return(0);
+ }
+ n = min(evp->nparts,max_part); /* no longer DISKLABEL limitations... */
+#if 0
+ n = (evp->nparts > MAXPARTITIONS) ? MAXPARTITIONS : evp->nparts;
+#endif 0
+
+ for (i = 0; i < n; i++)
+ fill_array(&array[i], /* mybase + */
+ evp->part[i].p_start,
+ evp->part[i].p_size,
+ NULL, 0, DISKPART_NONE, FS_BSDFFS);
+
+ return(n); /* (evp->nparts) */
+}
+
+
+/* NOT TESTED! */
+int get_omron(struct diskpart *array, char *buff, int start,
+ void *driver_info, int (*bottom_read_fun)(),
+ char *name, int max_part)
+{
+
+ struct disklabel *label;
+
+ /* here look for an Omron label */
+ register omron_label_t *part;
+ int i;
+
+#if (PARTITION_DEBUG)
+ printf("Looking for Omron label...\n");
+#endif
+
+ (*bottom_read_fun)(driver_info, start+
+ OMRON_LABEL_BYTE_OFFSET/SECTOR_SIZE, buff);
+
+ part = (omron_label_t*)&buff[OMRON_LABEL_BYTE_OFFSET%SECTOR_SIZE];
+ if (part->magic == OMRON_LABEL_MAGIC) {
+#if (PARTITION_DEBUG)
+ printf("{Using OMRON label}");
+#endif
+ for (i = 0; i < 8; i++) {
+ label->d_partitions[i].p_size = part->partitions[i].n_sectors;
+ label->d_partitions[i].p_offset = part->partitions[i].offset;
+ }
+ bcopy(part->packname, label->d_packname, 16);
+ label->d_ncylinders = part->ncyl;
+ label->d_acylinders = part->acyl;
+ label->d_ntracks = part->nhead;
+ label->d_nsectors = part->nsect;
+ /* Many disks have this wrong, therefore.. */
+#if 0
+ label->d_secperunit = part->maxblk;
+#else
+ label->d_secperunit = label->d_ncylinders * label->d_ntracks *
+ label->d_nsectors;
+#endif 0
+
+ return(8);
+ }
+#if (PARTITION_DEBUG)
+ printf("No Omron label found.\n");
+#endif
+ return(0);
+}
+
+
+/* NOT TESTED! */
+int get_dec(struct diskpart *array, char *buff, int start,
+ void *driver_info, int (*bottom_read_fun)(),
+ char *name, int max_part)
+{
+ struct disklabel *label;
+
+ /* here look for a DEC label */
+ register dec_label_t *part;
+ int i;
+
+#if (PARTITION_DEBUG)
+ printf("Checking for dec_label...\n");
+#endif
+
+ (*bottom_read_fun)(driver_info, start +
+ DEC_LABEL_BYTE_OFFSET/SECTOR_SIZE, buff);
+
+ if (part->magic == DEC_LABEL_MAGIC) {
+#if (PARTITION_DEBUG)
+ printf("{Using DEC label}");
+#endif
+ for (i = 0; i < 8; i++) {
+ label->d_partitions[i].p_size = part->partitions[i].n_sectors;
+ label->d_partitions[i].p_offset = part->partitions[i].offset;
+ }
+ return(8);
+ }
+#if (PARTITION_DEBUG)
+ printf("No dec label found.\n");
+#endif
+
+ return(0);
+}
+
+
+
+
+/* array is a pointer to an array of partition_info structures */
+/* array_size is the number of pre-allocated entries there are */
+int get_only_partition(void *driver_info, int (*bottom_read_fun)(),
+ struct diskpart *array, int array_size,
+ int disk_size, char *drive_name)
+{
+ char buff[SECTOR_SIZE];
+ int i,n,cnt;
+ int arrsize;
+ struct diskpart *res;
+
+ /* first fill in the entire disk stuff */
+ /* or should the calling routine do that already? */
+
+ fill_array(array, 0, disk_size, NULL, 0, -1, -1);
+
+ /* while the structure does not preclude additional nestings,
+ additional ones make no sense currently, so they are not
+ checked (Mach can't handle them anyway). It might be nice
+ if for all partitions found, all types of sub-partitions
+ were looked for (unnecessary). This will be done when this
+ is moved out of ther kernel, and there is some way to name them */
+
+ arrsize = array_size -1; /* 1 for whole disk */
+
+ /* search for dos partition table */
+ /* find all the partitions (including logical) */
+ n=get_dos(&array[1], buff, 0,
+ driver_info, (bottom_read_fun), drive_name,
+ arrsize);
+
+ if (n>0) {
+ fill_array(array, 0, disk_size, &array[1], n,
+ DISKPART_DOS, 256+DISKPART_DOS);
+ arrsize-=n;
+
+
+ /* search each one for a BSD disklabel (iff BSDOS) */
+ /* note: searchine extended and logical partitions */
+ for (i=0;i<n;i++)
+ if (array[i+1].fsys==BSDOS) {
+#if (PARTITION_DEBUG)
+ printf("BSD OS slice: %d\n",i+1);
+#endif
+ cnt=get_disklabel(&array[n+1], buff,
+ array[i+1].start,
+ driver_info, (bottom_read_fun),
+ drive_name,arrsize);
+
+ if (cnt>0) {
+ arrsize-=cnt;
+ fill_array(&array[i+1],array[i+1].start,
+ array[i+1].size, &array[n+1],
+ cnt, DISKPART_BSD,
+ array[i+1].fsys);
+ }
+ n+=cnt;
+ }
+
+ /* search for VTOC -- in a DOS partition as well */
+ for (i=0;i<n;i++)
+ if (array[i+1].fsys==UNIXOS) {
+#if (PARTITION_DEBUG)
+ printf("UNIXOS (vtoc) partition\n");
+#endif
+ cnt=get_vtoc(&array[n+1], buff,
+ array[i+1].start,
+ driver_info, (bottom_read_fun),
+ drive_name,arrsize);
+
+ if (cnt>0) {
+ arrsize-=cnt;
+ fill_array(&array[i+1],array[i+1].start,
+ array[i+1].size, &array[n+1],
+ cnt, DISKPART_VTOC,
+ array[i+1].fsys);
+ }
+ n+=cnt;
+ }
+ }
+
+ /* search for only disklabel */
+ if (n==0) {
+ fill_array(array, 0, disk_size, &array[1], n, DISKPART_BSD,
+ 256+DISKPART_BSD);
+ n=get_disklabel(&array[1], buff, 0, driver_info,
+ (bottom_read_fun), drive_name,arrsize);
+ }
+
+ /* search for only VTOC -- NOT TESTED! */
+ if (n==0) {
+ fill_array(array, 0, disk_size, &array[1], n, DISKPART_VTOC,
+ 256+DISKPART_VTOC);
+ n=get_vtoc(&array[1], buff, 0, driver_info, (bottom_read_fun),
+ drive_name,arrsize);
+ }
+#if 0
+ /* search for only omron -- NOT TESTED! */
+ if (n==0) {
+ fill_array(array, 0, disk_size, &array[1], n, DISKPART_OMRON,
+ 256+DISKPART_OMRON);
+ n=get_omron(&array[1], buff, 0,driver_info, (bottom_read_fun),
+ drive_name,arrsize);
+ }
+
+ /* search for only dec -- NOT TESTED! */
+ if (n==0) {
+ fill_array(array, 0, disk_size, &array[1], n, DISKPART_DEC,
+ 256+DISKPART_DEC);
+ n=get_dec(&array[1], buff, 0, driver_info, (bottom_read_fun),
+ drive_name,arrsize);
+ }
+#endif 0
+
+#if (PARTITION_DEBUG) /* print out what we found */
+ print_array(array,0);
+#endif
+
+}
+
+