diff options
author | Per Fogelstrom <pefo@cvs.openbsd.org> | 2004-08-23 14:24:58 +0000 |
---|---|---|
committer | Per Fogelstrom <pefo@cvs.openbsd.org> | 2004-08-23 14:24:58 +0000 |
commit | a311b7957d8de9da5b69807d5b6cac213a6744ef (patch) | |
tree | 8c4fae19cbf6b64e994f16b30566b35bf4374e20 /sys/arch/mips64 | |
parent | 734774568039991fce29dd03476f90c2bfaaefcc (diff) |
new disklabel for sgi
Diffstat (limited to 'sys/arch/mips64')
-rw-r--r-- | sys/arch/mips64/include/disklabel.h | 383 | ||||
-rw-r--r-- | sys/arch/mips64/mips64/disksubr.c | 932 |
2 files changed, 1115 insertions, 200 deletions
diff --git a/sys/arch/mips64/include/disklabel.h b/sys/arch/mips64/include/disklabel.h index 8a02db20cfc..d54c41c341d 100644 --- a/sys/arch/mips64/include/disklabel.h +++ b/sys/arch/mips64/include/disklabel.h @@ -1,5 +1,5 @@ -/* $OpenBSD: disklabel.h,v 1.1 2004/08/06 20:56:01 pefo Exp $ */ -/* $NetBSD: disklabel.h,v 1.3 1996/03/09 20:52:54 ghudson Exp $ */ +/* $OpenBSD: disklabel.h,v 1.2 2004/08/23 14:24:56 pefo Exp $ */ +/* $NetBSD: disklabel.h,v 1.1 1995/02/13 23:07:34 cgd Exp $ */ /* * Copyright (c) 1994 Christopher G. Demetriou @@ -31,18 +31,42 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef _MIPS_DISKLABEL_H_ -#define _MIPS_DISKLABEL_H_ +#ifndef _MACHINE_DISKLABEL_H_ +#define _MACHINE_DISKLABEL_H_ -#define LABELSECTOR 1 /* sector containing label */ -#define LABELOFFSET 0 /* offset of label in sector */ -#define MAXPARTITIONS 16 /* number of partitions */ -#define RAW_PART 2 /* raw partition: ie. rsd0c */ +enum disklabel_tag { DLT_ALPHA, DLT_I386, DLT_AMIGA, DLT_HPPA, DLT_SGI }; + +/* + * What disklabels are we probing for, and in which order? + */ +#ifndef LABELPROBES +#define LABELPROBES DLT_ALPHA, DLT_I386, DLT_AMIGA, DLT_HPPA, DLT_SGI +#endif + +#define ALPHA_LABELSECTOR 0 /* sector containing label */ +#define ALPHA_LABELOFFSET 64 /* offset of label in sector */ +#define I386_LABELSECTOR 1 /* sector containing label */ +#define I386_LABELOFFSET 0 /* offset of label in sector */ +#define AMIGA_LABELSECTOR 0 /* sector containing label */ +#define AMIGA_LABELOFFSET 64 /* offset of label in sector */ +#define HPPA_LABELSECTOR 1 /* sector containing label */ +#define HPPA_LABELOFFSET 0 /* offset of label in sector */ +#define SGI_LABELSECTOR 1 /* sector containing label */ +#define SGI_LABELOFFSET 0 /* offset of label in sector */ + +#define LABELSECTOR SGI_LABELSECTOR +#define LABELOFFSET SGI_LABELOFFSET + +#define MAXPARTITIONS 16 /* number of partitions */ +#define RAW_PART 2 /* raw partition: xx?c */ /* DOS partition table -- located in boot block */ #define DOSBBSECTOR 0 /* DOS boot block relative sector # */ #define DOSPARTOFF 446 +#define DOSACTIVE 0x80 #define NDOSPART 4 +#define DOSMBR_SIGNATURE 0xaa55 +#define DOSMBR_SIGNATURE_OFF 0x1fe struct dos_partition { u_int8_t dp_flag; /* bootstrap flags */ @@ -72,16 +96,343 @@ struct dos_partition { #define DOSPTYP_OPENBSD 0xa6 /* OpenBSD partition type */ #define DOSPTYP_NETBSD 0xa9 /* NetBSD partition type */ +/* Isolate the relevant bits to get sector and cylinder. */ +#define DPSECT(s) ((s) & 0x3f) +#define DPCYL(c, s) ((c) + (((s) & 0xc0) << 2)) + +/* + * describes ados Rigid Disk Blocks + * which are used to partition a drive + */ +#define RDBNULL ((u_int32_t)0xffffffff) + +/* + * you will find rdblock somewhere in [0, RDBMAXBLOCKS) + */ +#define RDB_MAXBLOCKS 16 + +struct rdblock { + u_int32_t id; /* 'RDSK' */ + u_int32_t nsumlong; /* number of longs in check sum */ + u_int32_t chksum; /* simple additive with wrap checksum */ + u_int32_t hostid; /* scsi target of host */ + u_int32_t nbytes; /* size of disk blocks */ + u_int32_t flags; + u_int32_t badbhead; /* linked list of badblocks */ + u_int32_t partbhead; /* linked list of partblocks */ + u_int32_t fsbhead; /* " " of fsblocks */ + u_int32_t driveinit; + u_int32_t resv1[6]; /* RDBNULL */ + u_int32_t ncylinders; /* number of cylinders on drive */ + u_int32_t nsectors; /* number of sectors per track */ + u_int32_t nheads; /* number of tracks per cylinder */ + u_int32_t interleave; + u_int32_t park; /* only used with st506 i.e. not */ + u_int32_t resv2[3]; + u_int32_t wprecomp; /* start cyl for write precomp */ + u_int32_t reducedwrite; /* start cyl for reduced write current */ + u_int32_t steprate; /* driver step rate in ?s */ + u_int32_t resv3[5]; + u_int32_t rdblowb; /* lowblock of range for rdb's */ + u_int32_t rdbhighb; /* high block of range for rdb's */ + u_int32_t lowcyl; /* low cylinder of partition area */ + u_int32_t highcyl; /* upper cylinder of partition area */ + u_int32_t secpercyl; /* number of sectors per cylinder */ + u_int32_t parkseconds; /* zero if no park needed */ + u_int32_t resv4[2]; + char diskvendor[8]; /* inquiry stuff */ + char diskproduct[16]; /* inquiry stuff */ + char diskrevision[4]; /* inquiry stuff */ + char contvendor[8]; /* inquiry stuff */ + char contproduct[16]; /* inquiry stuff */ + char contrevision[4]; /* inquiry stuff */ +#if never_use_secsize + u_int32_t resv5[0]; +#endif +}; + + +#define RDBF_LAST 0x1 /* last drive available */ +#define RDBF_LASTLUN 0x2 /* last LUN available */ +#define RDBF_LASTUNIT 0x4 /* last target available */ +#define RDBF_NORESELECT 0x8 /* do not use reselect */ +#define RDBF_DISKID 0x10 /* disk id is valid ?? */ +#define RDBF_CTRLID 0x20 /* ctrl id is valid ?? */ +#define RDBF_SYNC 0x40 /* drive supports SCSI synchronous mode */ + +struct ados_environ { + u_int32_t tabsize; /* 0: environ table size */ + u_int32_t sizeblock; /* 1: n long words in a block */ + u_int32_t secorg; /* 2: not used must be zero */ + u_int32_t numheads; /* 3: number of surfaces */ + u_int32_t secperblk; /* 4: must be 1 */ + u_int32_t secpertrk; /* 5: blocks per track */ + u_int32_t resvblocks; /* 6: reserved blocks at start */ + u_int32_t prefac; /* 7: must be 0 */ + u_int32_t interleave; /* 8: normally 1 */ + u_int32_t lowcyl; /* 9: low cylinder of partition */ + u_int32_t highcyl; /* 10: upper cylinder of partition */ + u_int32_t numbufs; /* 11: ados: number of buffers */ + u_int32_t membuftype; /* 12: ados: type of bufmem */ + u_int32_t maxtrans; /* 13: maxtrans the ctrlr supports */ + u_int32_t mask; /* 14: mask for valid address */ + u_int32_t bootpri; /* 15: boot priority for autoboot */ + u_int32_t dostype; /* 16: filesystem type */ + u_int32_t baud; /* 17: serial handler baud rate */ + u_int32_t control; /* 18: control word for fs */ + u_int32_t bootblocks; /* 19: blocks containing boot code */ + u_int32_t fsize; /* 20: file system block size */ + u_int32_t frag; /* 21: allowable frags per block */ + u_int32_t cpg; /* 22: cylinders per group */ +}; + +struct partblock { + u_int32_t id; /* 'PART' */ + u_int32_t nsumlong; /* number of longs in check sum */ + u_int32_t chksum; /* simple additive with wrap checksum */ + u_int32_t hostid; /* scsi target of host */ + u_int32_t next; /* next in chain */ + u_int32_t flags; /* see below */ + u_int32_t resv1[3]; + u_char partname[32]; /* (BCPL) part name (may not be unique) */ + u_int32_t resv2[15]; + struct ados_environ e; +#if never_use_secsize + u_int32_t extra[9]; /* 8 for extra added to environ */ +#endif +}; + +#define PBF_BOOTABLE 0x1 /* partition is bootable */ +#define PBF_NOMOUNT 0x2 /* partition should be mounted */ + +struct badblock { + u_int32_t id; /* 'BADB' */ + u_int32_t nsumlong; /* number of longs in check sum */ + u_int32_t chksum; /* simple additive with wrap checksum */ + u_int32_t hostid; /* scsi target of host */ + u_int32_t next; /* next in chain */ + u_int32_t resv; + struct badblockent { + u_int32_t badblock; + u_int32_t goodblock; + } badtab[0]; /* 61 for secsize == 512 */ +}; + +struct fsblock { + u_int32_t id; /* 'FSHD' */ + u_int32_t nsumlong; /* number of longs in check sum */ + u_int32_t chksum; /* simple additive with wrap checksum */ + u_int32_t hostid; /* scsi target of host */ + u_int32_t next; /* next in chain */ + u_int32_t flags; + u_int32_t resv1[2]; + u_int32_t dostype; /* this is a file system for this type */ + u_int32_t version; /* version of this fs */ + u_int32_t patchflags; /* describes which functions to replace */ + u_int32_t type; /* zero */ + u_int32_t task; /* zero */ + u_int32_t lock; /* zero */ + u_int32_t handler; /* zero */ + u_int32_t stacksize; /* to use when loading handler */ + u_int32_t priority; /* to run the fs at. */ + u_int32_t startup; /* zero */ + u_int32_t lsegblocks; /* linked list of lsegblocks of fs code */ + u_int32_t globalvec; /* bcpl vector not used mostly */ +#if never_use_secsize + u_int32_t resv2[44]; +#endif +}; + +struct lsegblock { + u_int32_t id; /* 'LSEG' */ + u_int32_t nsumlong; /* number of longs in check sum */ + u_int32_t chksum; /* simple additive with wrap checksum */ + u_int32_t hostid; /* scsi target of host */ + u_int32_t next; /* next in chain */ + u_int32_t loaddata[0]; /* load segment data, 123 for secsize == 512 */ +}; + +#define RDBLOCK_ID 0x5244534b /* 'RDSK' */ +#define PARTBLOCK_ID 0x50415254 /* 'PART' */ +#define BADBLOCK_ID 0x42414442 /* 'BADB' */ +#define FSBLOCK_ID 0x46534844 /* 'FSHD' */ +#define LSEGBLOCK_ID 0x4c534547 /* 'LSEG' */ + +/* + * volume header for "LIF" format volumes + */ +struct lifvol { + short vol_id; + char vol_label[6]; + u_int vol_addr; + short vol_oct; + short vol_dummy; + u_int vol_dirsize; + short vol_version; + short vol_zero; + u_int vol_number; + u_int vol_lastvol; + u_int vol_length; + char vol_toc[6]; + char vol_dummy1[198]; + + u_int ipl_addr; + u_int ipl_size; + u_int ipl_entry; + + u_int vol_dummy2; +}; + +struct lifdir { + char dir_name[10]; + u_short dir_type; + u_int dir_addr; + u_int dir_length; + char dir_toc[6]; + short dir_flag; + u_int dir_implement; +}; + +struct lif_load { + int address; + int count; +}; + +#define HPUX_MAGIC 0x8b7f6a3c +#define HPUX_MAXPART 16 +struct hpux_label { + int32_t hl_magic1; + u_int32_t hl_magic; + int32_t hl_version; + struct { + int32_t hlp_blah[2]; + int32_t hlp_start; + int32_t hlp_length; + } hl_parts[HPUX_MAXPART]; + u_int8_t hl_flags[HPUX_MAXPART]; +#define HPUX_PART_ROOT 0x10 +#define HPUX_PART_SWAP 0x14 +#define HPUX_PART_BOOT 0x32 + int32_t hl_blah[3*16]; + u_int16_t hl_boot; + u_int16_t hl_reserved; + int32_t hl_magic2; +}; + +#define LIF_VOL_ID -32768 +#define LIF_VOL_OCT 4096 +#define LIF_DIR_SWAP 0x5243 +#define LIF_DIR_HPLBL 0xa271 +#define LIF_DIR_FS 0xcd38 +#define LIF_DIR_IOMAP 0xcd60 +#define LIF_DIR_HPUX 0xcd80 +#define LIF_DIR_ISL 0xce00 +#define LIF_DIR_PAD 0xcffe +#define LIF_DIR_AUTO 0xcfff +#define LIF_DIR_EST 0xd001 +#define LIF_DIR_TYPE 0xe942 + +#define LIF_DIR_FLAG 0x8001 /* dont ask me! */ +#define LIF_SECTSIZE 256 + +#define LIF_NUMDIR 16 + +#define LIF_VOLSTART 0 +#define LIF_VOLSIZE sizeof(struct lifvol) +#define LIF_DIRSTART 2048 +#define LIF_DIRSIZE (LIF_NUMDIR * sizeof(struct lifdir)) +#define LIF_FILESTART 8192 + +#define btolifs(b) (((b) + (LIF_SECTSIZE - 1)) / LIF_SECTSIZE) +#define lifstob(s) ((s) * LIF_SECTSIZE) +#define lifstodb(s) ((s) * LIF_SECTSIZE / DEV_BSIZE) + +/* SGI */ +struct devparms { + u_int8_t dp_skew; + u_int8_t dp_gap1; + u_int8_t dp_gap2; + u_int8_t dp_spares_cyl; + u_int16_t dp_cyls; + u_int16_t dp_shd0; + u_int16_t dp_trks0; + u_int8_t dp_ctq_depth; + u_int8_t dp_cylshi; + u_int16_t dp_unused; + u_int16_t dp_secs; + u_int16_t dp_secbytes; + u_int16_t dp_interleave; + u_int32_t dp_flags; + u_int32_t dp_datarate; + u_int32_t dp_nretries; + u_int32_t dp_mspw; + u_int16_t dp_xgap1; + u_int16_t dp_xsync; + u_int16_t dp_xrdly; + u_int16_t dp_xgap2; + u_int16_t dp_xrgate; + u_int16_t dp_xwcont; +} __attribute__((__packed__)); + +struct sgilabel { +#define SGILABEL_MAGIC 0xbe5a941 + u_int32_t magic; + int16_t root; + int16_t swap; + char bootfile[16]; + struct devparms dp; + struct { + char name[8]; + int32_t block; + int32_t bytes; + } voldir[15]; + struct { + int32_t blocks; + int32_t first; + int32_t type; + } partitions[MAXPARTITIONS]; + int32_t checksum; + int32_t _pad; +} __attribute__((__packed__)); + +#define SGI_PTYPE_VOLHDR 0 +#define SGI_PTYPE_RAW 3 +#define SGI_PTYPE_BSD 4 +#define SGI_PTYPE_VOLUME 6 +#define SGI_PTYPE_EFS 7 +#define SGI_PTYPE_LVOL 8 +#define SGI_PTYPE_RLVOL 9 +#define SGI_PTYPE_XFS 10 +#define SGI_PTYPE_XFSLOG 11 +#define SGI_PTYPE_XLV 12 +#define SGI_PTYPE_XVM 13 + + #include <sys/dkbad.h> struct cpu_disklabel { - struct dos_partition dosparts[NDOSPART]; - struct dkbad bad; + enum disklabel_tag labeltag; + int labelsector; + union { + struct { + } _alpha; + struct { + struct dos_partition dosparts[NDOSPART]; + struct dkbad bad; + } _i386; + struct { + u_int32_t rdblock; /* RDBNULL -> inval. */ + u_int32_t pblist[MAXPARTITIONS];/* pblock number */ + int pbindex[MAXPARTITIONS]; /* index of pblock */ + int valid; /* valid? */ + } _amiga; + struct { + struct lifvol lifvol; + struct lifdir lifdir[LIF_NUMDIR]; + struct hpux_label hplabel; + } _hppa; + } u; }; -#define DKBAD(x) ((x)->bad) - -/* Isolate the relevant bits to get sector and cylinder. */ -#define DPSECT(s) ((s) & 0x3f) -#define DPCYL(c, s) ((c) + (((s) & 0xc0) << 2)) +#define DKBAD(x) ((x)->u._i386.bad) -#endif /* !_MIPS_DISKLABEL_H_ */ +#endif /* _MACHINE_DISKLABEL_H_ */ diff --git a/sys/arch/mips64/mips64/disksubr.c b/sys/arch/mips64/mips64/disksubr.c index 278ac87c471..8ff5c4b0449 100644 --- a/sys/arch/mips64/mips64/disksubr.c +++ b/sys/arch/mips64/mips64/disksubr.c @@ -1,7 +1,8 @@ -/* $OpenBSD: disksubr.c,v 1.4 2004/08/11 10:21:08 deraadt Exp $ */ -/* $NetBSD: disksubr.c,v 1.21 1996/05/03 19:42:03 christos Exp $ */ +/* $OpenBSD: disksubr.c,v 1.5 2004/08/23 14:24:56 pefo Exp $ */ /* + * Copyright (c) 1999 Michael Shalayeff + * Copyright (c) 1997 Niklas Hallqvist * Copyright (c) 1996 Theo de Raadt * Copyright (c) 1982, 1986, 1988 Regents of the University of California. * All rights reserved. @@ -14,11 +15,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * @@ -37,6 +34,19 @@ * @(#)ufs_disksubr.c 7.16 (Berkeley) 5/4/91 */ +/* + * This disksubr.c module started to take it's present form on OpenBSD/alpha + * but it was always thought it should be made completely MI and not need to + * be in that alpha-specific tree at all. + * + * XXX The DOS partitioning code is not endian-independent, only native + * endian DOS partition tables can be parsed yet. + * + * XXX Amiga RDB partitioning is not understood yet. + * + * XXX HPUX disklabel is not understood yet. + */ + #include <sys/param.h> #include <sys/systm.h> #include <sys/buf.h> @@ -45,12 +55,45 @@ #include <sys/syslog.h> #include <sys/disk.h> -#include <mips64/archtype.h> +/* The native defaults... */ +#if defined(alpha) && !defined(DISKLABEL_ALPHA) +#define DISKLABEL_ALPHA +#elif (defined(i386) || defined(arc)) && !defined(DISKLABEL_I386) +#define DISKLABEL_I386 +#elif defined(amiga) && !defined(DISKLABEL_AMIGA) +#define DISKLABEL_AMIGA +#elif defined(hppa) && !defined(DISKLABEL_HPPA) +#define DISKLABEL_HPPA +#elif defined(__sgi__) && !defined(DISKLABEL_SGI) +#define DISKLABEL_SGI +#endif #define b_cylin b_resid -#define BOOT_MAGIC 0xAA55 -#define BOOT_MAGIC_OFF (DOSPARTOFF+NDOSPART*sizeof(struct dos_partition)) +#if defined(DISKLABEL_I386) || defined(DISKLABEL_ALPHA) || defined(DISKLABEL_AMIGA) || defined(DISKLABEL_HPPA) || defined(DISKLABEL_SGI) || defined(DISKLABEL_ALL) +void swapdisklabel(struct disklabel *d); +char *readbsdlabel(struct buf *, void (*)(struct buf *), int, int, + int, int, struct disklabel *, int); +#endif +#if defined(DISKLABEL_I386) || defined(DISKLABEL_ALL) +char *readdoslabel(struct buf *, void (*)(struct buf *), + struct disklabel *, struct cpu_disklabel *, int *, int *, int); +#endif +#if defined(DISKLABEL_AMIGA) || defined(DISKLABEL_ALL) +char *readamigalabel(struct buf *, void (*)(struct buf *), + struct disklabel *, struct cpu_disklabel *, int); +#endif +#if defined(DISKLABEL_HPPA) || defined(DISKLABEL_ALL) +char *readliflabel(struct buf *, void (*)(struct buf *), + struct disklabel *, struct cpu_disklabel *, int *, int *, int); +#endif +#if defined(DISKLABEL_SGI) || defined(DISKLABEL_ALL) +char *readsgilabel(struct buf *, void (*)(struct buf *), + struct disklabel *, struct cpu_disklabel *, int *, int *, int); +void map_sgi_label(struct disklabel *, struct sgilabel *); +#endif + +static enum disklabel_tag probe_order[] = { LABELPROBES, -1 }; void dk_establish(dk, dev) @@ -59,42 +102,158 @@ dk_establish(dk, dev) { } +#if defined(DISKLABEL_I386) || defined(DISKLABEL_ALPHA) || defined(DISKLABEL_AMIGA) || defined(DISKLABEL_HPPA) || defined(DISKLABEL_SGI) || defined(DISKLABEL_ALL) + +/* + * Byteswap all the fields that might be swapped. + */ +void +swapdisklabel(dlp) + struct disklabel *dlp; +{ + int i; + struct partition *pp; + + swap32(dlp->d_magic); + swap16(dlp->d_type); + swap16(dlp->d_subtype); + swap32(dlp->d_secsize); + swap32(dlp->d_nsectors); + swap32(dlp->d_ntracks); + swap32(dlp->d_ncylinders); + swap32(dlp->d_secpercyl); + swap32(dlp->d_secperunit); + swap16(dlp->d_sparespertrack); + swap16(dlp->d_sparespercyl); + swap32(dlp->d_acylinders); + swap16(dlp->d_rpm); + swap16(dlp->d_interleave); + swap16(dlp->d_trackskew); + swap16(dlp->d_cylskew); + swap32(dlp->d_headswitch); + swap32(dlp->d_trkseek); + swap32(dlp->d_flags); + for (i = 0; i < NDDATA; i++) + swap32(dlp->d_drivedata[i]); + for (i = 0; i < NSPARE; i++) + swap32(dlp->d_spare[i]); + swap32(dlp->d_magic2); + swap16(dlp->d_checksum); + swap16(dlp->d_npartitions); + swap32(dlp->d_bbsize); + swap32(dlp->d_sbsize); + for (i = 0; i < MAXPARTITIONS; i++) { + pp = &dlp->d_partitions[i]; + swap32(pp->p_size); + swap32(pp->p_offset); + swap32(pp->p_fsize); + swap16(pp->p_cpg); + } +} + +/* + * Try to read a standard BSD disklabel at a certain sector. + */ +char * +readbsdlabel(bp, strat, cyl, sec, off, endian, lp, spoofonly) + struct buf *bp; + void (*strat)(struct buf *); + int cyl, sec, off, endian; + struct disklabel *lp; + int spoofonly; +{ + struct disklabel *dlp; + char *msg = NULL; + u_int16_t cksum; + u_int32_t magic; + + if (endian != LITTLE_ENDIAN && endian != BIG_ENDIAN) + panic("readbsdlabel: unsupported byteorder %d", endian); + + /* don't read the on-disk label if we are in spoofed-only mode */ + if (spoofonly) + return (NULL); + + bp->b_blkno = sec; + bp->b_cylin = cyl; + bp->b_bcount = lp->d_secsize; + bp->b_flags = B_BUSY | B_READ; + (*strat)(bp); + + /* if successful, locate disk label within block and validate */ + if (biowait(bp)) { + /* XXX we return the faked label built so far */ + msg = "disk label I/O error"; + return (msg); + } + + magic = endian == BIG_ENDIAN ? htobe32(DISKMAGIC) : htole32(DISKMAGIC); + + /* + * If off is negative, search until the end of the sector for + * the label, otherwise, just look at the specific location + * we're given. + */ + dlp = (struct disklabel *)(bp->b_data + (off >= 0 ? off : 0)); + do { + if (dlp->d_magic != magic || dlp->d_magic2 != magic) { + if (msg == NULL) + msg = "no disk label"; + } else { + cksum = dkcksum(dlp); + if (endian != BYTE_ORDER) + swapdisklabel(dlp); + if (dlp->d_npartitions > MAXPARTITIONS || cksum != 0) { + msg = "disk label corrupted"; + /* swap back if necessary. */ + if (off < 0 && endian != BYTE_ORDER) + swapdisklabel(dlp); + } else { + *lp = *dlp; + /* Recalc magic on foreign labels */ + if (endian != BYTE_ORDER) { + lp->d_checksum = 0; + lp->d_checksum = dkcksum(lp); + } + msg = NULL; + break; + } + } + if (off >= 0) + break; + dlp = (struct disklabel *)((char *)dlp + sizeof(int32_t)); + } while (dlp <= (struct disklabel *)(bp->b_data + lp->d_secsize - + sizeof(*dlp))); + return (msg); +} +#endif + /* * Attempt to read a disk label from a device - * using the indicated stategy routine. + * using the indicated strategy routine. * The label must be partly set up before this: * secpercyl, secsize and anything required for a block i/o read * operation in the driver's strategy/start routines * must be filled in before calling us. * - * If dos partition table requested, attempt to load it and - * find disklabel inside a DOS partition. Also, if bad block - * table needed, attempt to extract it as well. Return buffer - * for use in signalling errors if requested. - * - * We would like to check if each MBR has a valid BOOT_MAGIC, but - * we cannot because it doesn't always exist. So.. we assume the - * MBR is valid. - * * Returns null on success and an error string on failure. */ char * readdisklabel(dev, strat, lp, osdep, spoofonly) dev_t dev; - void (*strat) __P((struct buf *)); + void (*strat)(struct buf *); struct disklabel *lp; struct cpu_disklabel *osdep; int spoofonly; { - struct dos_partition *dp = osdep->dosparts, *dp2; - struct dkbad *bdp = &DKBAD(osdep); - struct buf *bp; - struct disklabel *dlp; - char *msg = NULL, *cp; - int dospartoff, cyl, i, ourpart = -1; + struct buf *bp = NULL; + char *msg = "no disk label"; + enum disklabel_tag *tp; + int i; + struct disklabel minilabel, fallbacklabel; /* minimal requirements for archtypal disk label */ - if (lp->d_secsize == 0) + if (lp->d_secsize < DEV_BSIZE) lp->d_secsize = DEV_BSIZE; if (lp->d_secperunit == 0) lp->d_secperunit = 0x1fffffff; @@ -110,14 +269,120 @@ readdisklabel(dev, strat, lp, osdep, spoofonly) if (lp->d_partitions[i].p_size == 0) lp->d_partitions[i].p_size = 0x1fffffff; lp->d_partitions[i].p_offset = 0; + minilabel = fallbacklabel = *lp; /* get a buffer and initialize it */ bp = geteblk((int)lp->d_secsize); bp->b_dev = dev; + for (tp = probe_order; msg && *tp != -1; tp++) { + switch (*tp) { + case DLT_ALPHA: +#if defined(DISKLABEL_ALPHA) || defined(DISKLABEL_ALL) + msg = readbsdlabel(bp, strat, 0, ALPHA_LABELSECTOR, + ALPHA_LABELOFFSET, LITTLE_ENDIAN, lp, spoofonly); +#endif + break; + + case DLT_I386: +#if defined(DISKLABEL_I386) || defined(DISKLABEL_ALL) + msg = readdoslabel(bp, strat, lp, osdep, 0, 0, spoofonly); + if (msg) + /* Fallback alternative */ + fallbacklabel = *lp; +#endif + break; + + case DLT_AMIGA: +#if defined(DISKLABEL_AMIGA) || defined(DISKLABEL_ALL) + msg = readamigalabel(bp, strat, lp, osdep, spoofonly); +#endif + break; + + case DLT_HPPA: +#if defined(DISKLABEL_HPPA) || defined(DISKLABEL_ALL) + msg = readliflabel(bp, strat, lp, osdep, 0, 0, spoofonly); +#endif + break; + + case DLT_SGI: +#if defined(DISKLABEL_SGI) || defined(DISKLABEL_ALL) + msg = readsgilabel(bp, strat, lp, osdep, 0, 0, spoofonly); + if (msg) + /* Fallback alternative */ + fallbacklabel = *lp; +#endif + break; + + default: + panic("unrecognized disklabel tag %d", *tp); + } + if (msg) + *lp = minilabel; + } + + /* Record metainformation about the disklabel. */ + if (msg == NULL) { + osdep->labelsector = bp->b_blkno; + osdep->labeltag = *tp; + } + +#if defined(CD9660) + if (msg && iso_disklabelspoof(dev, strat, lp) == 0) + msg = NULL; +#endif + + /* If there was an error, still provide a decent fake one. */ + if (msg) + *lp = fallbacklabel; + +done: + if (bp) { + bp->b_flags |= B_INVAL; + brelse(bp); + } + return (msg); +} + +#if defined(DISKLABEL_I386) || defined(DISKLABEL_ALL) +/* + * If dos partition table requested, attempt to load it and + * find disklabel inside a DOS partition. Also, if bad block + * table needed, attempt to extract it as well. Return buffer + * for use in signalling errors if requested. + * + * We would like to check if each MBR has a valid BOOT_MAGIC, but + * we cannot because it doesn't always exist. So.. we assume the + * MBR is valid. + */ +char * +readdoslabel(bp, strat, lp, osdep, partoffp, cylp, spoofonly) + struct buf *bp; + void (*strat)(struct buf *); + struct disklabel *lp; + struct cpu_disklabel *osdep; + int *partoffp; + int *cylp; + int spoofonly; +{ + struct dos_partition *dp = osdep->u._i386.dosparts, *dp2; + struct dkbad *db, *bdp = &DKBAD(osdep); + char *msg = NULL, *cp; + int dospartoff, cyl, i, ourpart = -1; + dev_t dev; + + if (lp->d_secpercyl == 0) { + msg = "invalid label, d_secpercyl == 0"; + return (msg); + } + if (lp->d_secsize == 0) { + msg = "invalid label, d_secsize == 0"; + return (msg); + } + /* do dos partitions in the process of getting disklabel? */ dospartoff = 0; - cyl = LABELSECTOR / lp->d_secpercyl; + cyl = I386_LABELSECTOR / lp->d_secpercyl; if (dp) { daddr_t part_blkno = DOSBBSECTOR; unsigned long extoff = 0; @@ -130,6 +395,8 @@ readdisklabel(dev, strat, lp, osdep, spoofonly) while (wander && n < 8 && loop < 8) { loop++; wander = 0; + if (part_blkno < extoff) + part_blkno = extoff; /* read boot record */ bp->b_blkno = part_blkno; @@ -141,45 +408,45 @@ readdisklabel(dev, strat, lp, osdep, spoofonly) /* if successful, wander through dos partition table */ if (biowait(bp)) { msg = "dos partition I/O error"; - goto done; + if (partoffp) + *partoffp = -1; + return (msg); } - if (((int *)bp->b_data)[0] == 0x01084025 && - ((int *)bp->b_data)[1] == 0x01294825) { - goto nodoslabel; - } - bcopy(bp->b_data + DOSPARTOFF, dp, NDOSPART * sizeof(*dp)); + bcopy(bp->b_data + DOSPARTOFF, dp, + NDOSPART * sizeof(*dp)); if (ourpart == -1) { /* Search for our MBR partition */ - for (dp2=dp, i=0; i < NDOSPART && ourpart == -1; - i++, dp2++) - if (get_le(&dp2->dp_size) && + for (dp2=dp, i=0; + i < NDOSPART && ourpart == -1; i++, dp2++) + if (dp2->dp_size && dp2->dp_typ == DOSPTYP_OPENBSD) ourpart = i; - for (dp2=dp, i=0; i < NDOSPART && ourpart == -1; - i++, dp2++) - if (get_le(&dp2->dp_size) && + for (dp2=dp, i=0; + i < NDOSPART && ourpart == -1; i++, dp2++) + if (dp2->dp_size && dp2->dp_typ == DOSPTYP_FREEBSD) ourpart = i; - for (dp2=dp, i=0; i < NDOSPART && ourpart == -1; - i++, dp2++) - if (get_le(&dp2->dp_size) && + for (dp2=dp, i=0; + i < NDOSPART && ourpart == -1; i++, dp2++) + if (dp2->dp_size && dp2->dp_typ == DOSPTYP_NETBSD) ourpart = i; if (ourpart == -1) goto donot; /* - * This is our MBR partition. need sector address - * for SCSI/IDE, cylinder for ESDI/ST506/RLL + * This is our MBR partition. need sector + * address for SCSI/IDE, cylinder for + * ESDI/ST506/RLL */ dp2 = &dp[ourpart]; - dospartoff = get_le(&dp2->dp_start) + part_blkno; + dospartoff = dp2->dp_start + part_blkno; cyl = DPCYL(dp2->dp_scyl, dp2->dp_ssect); /* XXX build a temporary disklabel */ - lp->d_partitions[0].p_size = get_le(&dp2->dp_size); - lp->d_partitions[0].p_offset = - get_le(&dp2->dp_start) + part_blkno; + lp->d_partitions[0].p_size = dp2->dp_size; + lp->d_partitions[0].p_offset = dp2->dp_start + + part_blkno; if (lp->d_ntracks == 0) lp->d_ntracks = dp2->dp_ehd + 1; if (lp->d_nsectors == 0) @@ -198,13 +465,11 @@ donot: if (dp2->dp_typ == DOSPTYP_OPENBSD) continue; - if (get_le(&dp2->dp_size) > lp->d_secperunit) - continue; - if (get_le(&dp2->dp_size)) - pp->p_size = get_le(&dp2->dp_size); - if (get_le(&dp2->dp_start)) + if (dp2->dp_size) + pp->p_size = dp2->dp_size; + if (dp2->dp_start) pp->p_offset = - get_le(&dp2->dp_start) + part_blkno; + dp2->dp_start + part_blkno; switch (dp2->dp_typ) { case DOSPTYP_UNUSED: @@ -238,9 +503,11 @@ donot: n++; break; case DOSPTYP_EXTEND: - part_blkno = get_le(&dp2->dp_start) + extoff; - if (!extoff) - extoff = get_le(&dp2->dp_start); + part_blkno = dp2->dp_start + extoff; + if (!extoff) { + extoff = dp2->dp_start; + part_blkno = 0; + } wander = 1; break; default: @@ -252,54 +519,30 @@ donot: } lp->d_bbsize = 8192; lp->d_sbsize = 64*1024; /* XXX ? */ - lp->d_npartitions = MAXPARTITIONS; + lp->d_npartitions = n > 0 ? n + 8 : 3; } -nodoslabel: - /* don't read the on-disk label if we are in spoofed-only mode */ - if (spoofonly) - goto done; + /* record the OpenBSD partition's placement for the caller */ + if (partoffp) + *partoffp = dospartoff; + if (cylp) + *cylp = cyl; /* next, dig out disk label */ - bp->b_blkno = dospartoff + LABELSECTOR; - bp->b_cylin = cyl; - bp->b_bcount = lp->d_secsize; - bp->b_flags = B_BUSY | B_READ; - (*strat)(bp); - - /* if successful, locate disk label within block and validate */ - if (biowait(bp)) { - /* XXX we return the faked label built so far */ - msg = "disk label I/O error"; - goto done; - } - for (dlp = (struct disklabel *)bp->b_data; - dlp <= (struct disklabel *)(bp->b_data + lp->d_secsize - sizeof(*dlp)); - dlp = (struct disklabel *)((char *)dlp + sizeof(long))) { - if (dlp->d_magic != DISKMAGIC || dlp->d_magic2 != DISKMAGIC) { - if (msg == NULL) - msg = "no disk label"; - } else if (dlp->d_npartitions > MAXPARTITIONS || - dkcksum(dlp) != 0) - msg = "disk label corrupted"; - else { - *lp = *dlp; - msg = NULL; - break; - } - } - - if (msg) { -#if defined(CD9660) - if (iso_disklabelspoof(dev, strat, lp) == 0) - msg = NULL; -#endif - goto done; - } + msg = readbsdlabel(bp, strat, cyl, dospartoff + I386_LABELSECTOR, -1, + LITTLE_ENDIAN, lp, spoofonly); + if (msg) + return (msg); /* obtain bad sector table if requested and present */ if (bdp && (lp->d_flags & D_BADSECT)) { - struct dkbad *db; + /* + * get a new buffer and initialize it as callers trust the + * buffer given to us, to point at the disklabel sector. + */ + dev = bp->b_dev; + bp = geteblk((int)lp->d_secsize); + bp->b_dev = dev; i = 0; do { @@ -315,13 +558,13 @@ nodoslabel: (*strat)(bp); /* if successful, validate, otherwise try another */ - if (biowait(bp)) { + if (biowait(bp)) msg = "bad sector table I/O error"; - } else { + else { db = (struct dkbad *)(bp->b_data); #define DKBAD_MAGIC 0x4321 - if (db->bt_mbz == 0 - && db->bt_flag == DKBAD_MAGIC) { + if (db->bt_mbz == 0 && + db->bt_flag == DKBAD_MAGIC) { msg = NULL; *bdp = *db; break; @@ -329,14 +572,305 @@ nodoslabel: msg = "bad sector table corrupted"; } } while ((bp->b_flags & B_ERROR) && (i += 2) < 10 && - i < lp->d_nsectors); + i < lp->d_nsectors); + + /* Give back the bad block buffer. */ + bp->b_flags |= B_INVAL; + brelse(bp); } + return (msg); +} +#endif -done: - bp->b_flags |= B_INVAL; - brelse(bp); +#if defined(DISKLABEL_AMIGA) || defined(DISKLABEL_ALL) +/* + * XXX RDB parsing is missing still. + */ +char * +readamigalabel(bp, strat, lp, osdep, spoofonly) + struct buf *bp; + void (*strat)(struct buf *); + struct disklabel *lp; + struct cpu_disklabel *osdep; + int spoofonly; +{ + char *msg; + + msg = readbsdlabel(bp, strat, 0, AMIGA_LABELSECTOR, AMIGA_LABELOFFSET, + BIG_ENDIAN, lp, spoofonly); return (msg); } +#endif + +#if defined(DISKLABEL_HPPA) || defined(DISKLABEL_ALL) +char * +readliflabel (bp, strat, lp, osdep, partoffp, cylp, spoofonly) + struct buf *bp; + void (*strat)(struct buf *); + struct disklabel *lp; + struct cpu_disklabel *osdep; + int *partoffp; + int *cylp; + int spoofonly; +{ + int fsoff; + + /* read LIF volume header */ + bp->b_blkno = btodb(LIF_VOLSTART); + bp->b_bcount = lp->d_secsize; + bp->b_flags = B_BUSY | B_READ; + bp->b_cylin = btodb(LIF_VOLSTART) / lp->d_secpercyl; + (*strat)(bp); + + if (biowait(bp)) { + if (partoffp) + *partoffp = -1; + return "LIF volume header I/O error"; + } + + bcopy (bp->b_data, &osdep->u._hppa.lifvol, sizeof(struct lifvol)); + if (osdep->u._hppa.lifvol.vol_id != LIF_VOL_ID) { + fsoff = 0; + } else { + struct lifdir *p; + struct buf *dbp; + dev_t dev; + + dev = bp->b_dev; + dbp = geteblk(LIF_DIRSIZE); + dbp->b_dev = dev; + + /* read LIF directory */ + dbp->b_blkno = lifstodb(osdep->u._hppa.lifvol.vol_addr); + dbp->b_bcount = lp->d_secsize; + dbp->b_flags = B_BUSY | B_READ; + dbp->b_cylin = dbp->b_blkno / lp->d_secpercyl; + (*strat)(dbp); + + if (biowait(dbp)) { + if (partoffp) + *partoffp = -1; + + dbp->b_flags |= B_INVAL; + brelse(dbp); + return ("LIF directory I/O error"); + } + + bcopy(dbp->b_data, osdep->u._hppa.lifdir, LIF_DIRSIZE); + dbp->b_flags |= B_INVAL; + brelse(dbp); + + /* scan for LIF_DIR_FS dir entry */ + for (fsoff = -1, p = &osdep->u._hppa.lifdir[0]; + fsoff < 0 && p < &osdep->u._hppa.lifdir[LIF_NUMDIR]; p++) { + if (p->dir_type == LIF_DIR_FS || + p->dir_type == LIF_DIR_HPLBL) + break; + } + + if (p->dir_type == LIF_DIR_FS) + fsoff = lifstodb(p->dir_addr); + else if (p->dir_type == LIF_DIR_HPLBL) { + struct hpux_label *hl; + struct partition *pp; + u_int8_t fstype; + int i; + + dev = bp->b_dev; + dbp = geteblk(LIF_DIRSIZE); + dbp->b_dev = dev; + + /* read LIF directory */ + dbp->b_blkno = lifstodb(p->dir_addr); + dbp->b_bcount = lp->d_secsize; + dbp->b_flags = B_BUSY | B_READ; + dbp->b_cylin = dbp->b_blkno / lp->d_secpercyl; + (*strat)(dbp); + + if (biowait(dbp)) { + if (partoffp) + *partoffp = -1; + + dbp->b_flags |= B_INVAL; + brelse(dbp); + return ("HOUX label I/O error"); + } + + bcopy(dbp->b_data, &osdep->u._hppa.hplabel, + sizeof(osdep->u._hppa.hplabel)); + dbp->b_flags |= B_INVAL; + brelse(dbp); + + hl = &osdep->u._hppa.hplabel; + if (hl->hl_magic1 != hl->hl_magic2 || + hl->hl_magic != HPUX_MAGIC || + hl->hl_version != 1) { + if (partoffp) + *partoffp = -1; + + return "HPUX label magic mismatch"; + } + + lp->d_bbsize = 8192; + lp->d_sbsize = 8192; + for (i = 0; i < MAXPARTITIONS; i++) { + lp->d_partitions[i].p_size = 0; + lp->d_partitions[i].p_offset = 0; + lp->d_partitions[i].p_fstype = 0; + } + + for (i = 0; i < HPUX_MAXPART; i++) { + if (!hl->hl_flags[i]) + continue; + + if (hl->hl_flags[i] == HPUX_PART_ROOT) { + pp = &lp->d_partitions[0]; + fstype = FS_BSDFFS; + } else if (hl->hl_flags[i] == HPUX_PART_SWAP) { + pp = &lp->d_partitions[1]; + fstype = FS_SWAP; + } else if (hl->hl_flags[i] == HPUX_PART_BOOT) { + pp = &lp->d_partitions[RAW_PART + 1]; + fstype = FS_BSDFFS; + } else + continue; + + pp->p_size = hl->hl_parts[i].hlp_length * 2; + pp->p_offset = hl->hl_parts[i].hlp_start * 2; + pp->p_fstype = fstype; + } + + lp->d_partitions[RAW_PART].p_size = lp->d_secperunit; + lp->d_partitions[RAW_PART].p_offset = 0; + lp->d_partitions[RAW_PART].p_fstype = FS_UNUSED; + lp->d_npartitions = MAXPARTITIONS; + lp->d_magic = DISKMAGIC; + lp->d_magic2 = DISKMAGIC; + lp->d_checksum = 0; + lp->d_checksum = dkcksum(lp); + + return (NULL); + } + + /* if no suitable lifdir entry found assume zero */ + if (fsoff < 0) { + fsoff = 0; + } + } + + if (partoffp) + *partoffp = fsoff; + + return readbsdlabel(bp, strat, 0, fsoff + HPPA_LABELSECTOR, + HPPA_LABELOFFSET, BIG_ENDIAN, lp, spoofonly); +} +#endif + +#if defined(DISKLABEL_SGI) || defined(DISKLABEL_ALL) +/* + * + */ +char * +readsgilabel(bp, strat, lp, osdep, partoffp, cylp, spoofonly) + struct buf *bp; + void (*strat)(struct buf *); + struct disklabel *lp; + struct cpu_disklabel *osdep; + int *partoffp; + int *cylp; + int spoofonly; +{ + struct sgilabel *dlp; + char *msg = NULL; + int fsoffs = 0; + + /* don't read the on-disk label if we are in spoofed-only mode */ + if (spoofonly) + return (NULL); + + if (partoffp) + *partoffp = -1; + + bp->b_blkno = 0; + bp->b_cylin = 0; + bp->b_bcount = lp->d_secsize; + bp->b_flags = B_BUSY | B_READ; + (*strat)(bp); + + /* if successful, locate disk label within block and validate */ + if (biowait(bp)) { + if (partoffp) + *partoffp = -1; + return "disk label I/O error"; + } + + dlp = (struct sgilabel *)(bp->b_data); + if (dlp->magic != htobe32(SGILABEL_MAGIC)) { + fsoffs = 0; + } else { + int i, *p, cs; + + cs = 0; + p = (int *)dlp; + i = sizeof(struct sgilabel) / sizeof(int); + while(i--) + cs += *p++; + if (cs != 0) + return "sgilabel checksum error"; + + /* Set up partitions i-l if there is no BSD label. */ + lp->d_secsize = dlp->dp.dp_secbytes; + lp->d_nsectors = dlp->dp.dp_secs; + lp->d_ntracks = dlp->dp.dp_trks0; + lp->d_ncylinders = dlp->dp.dp_cyls; + lp->d_interleave = dlp->dp.dp_interleave; + lp->d_npartitions = MAXPARTITIONS; + + map_sgi_label(lp, dlp); + + fsoffs = dlp->partitions[0].first; + if (dlp->partitions[0].blocks == 0) + msg = "no BSD partition"; + } + + if (msg) + return msg; + + if (partoffp) + *partoffp = fsoffs; + + msg = readbsdlabel(bp, strat, 0, fsoffs + SGI_LABELSECTOR, + SGI_LABELOFFSET, BIG_ENDIAN, lp, spoofonly); + return msg; +} + +void +map_sgi_label(struct disklabel *lp, struct sgilabel *dlp) +{ +static struct {int m; int b;} maptab[] = { + { 0, FS_BSDFFS}, { 1, FS_SWAP}, { 10, FS_BSDFFS}, + { 3, FS_BSDFFS}, { 4, FS_BSDFFS}, { 5, FS_BSDFFS}, + { 6, FS_BSDFFS}, { 7, FS_BSDFFS}, { 8, FS_OTHER}, + { 9, FS_BSDFFS}, { 2, FS_UNUSED}, { 11, FS_BSDFFS}, + { 12, FS_BSDFFS}, { 13, FS_BSDFFS}, { 14, FS_BSDFFS}, + { 15, FS_BSDFFS} +}; + int i; + + for (i = 0; i < 16; i++) { + int bsd = maptab[i].m; + + lp->d_partitions[bsd].p_offset = dlp->partitions[i].first; + lp->d_partitions[bsd].p_size = dlp->partitions[i].blocks; + lp->d_partitions[bsd].p_fstype = maptab[i].b; + if (lp->d_partitions[bsd].p_fstype == FS_BSDFFS) { + lp->d_partitions[bsd].p_fsize = 1024; + lp->d_partitions[bsd].p_frag = 8; + lp->d_partitions[bsd].p_cpg = 16; + } + } +} +#endif /* * Check new disk label for sensibility @@ -356,7 +890,14 @@ setdisklabel(olp, nlp, openmask, osdep) (nlp->d_secsize % DEV_BSIZE) != 0) return(EINVAL); - /* special case to allow disklabel to be invalidated */ + /* + * XXX Nice thought, but it doesn't work, if the intention was to + * force a reread at the next *readdisklabel call. That does not + * happen. There's still some use for it though as you can pseudo- + * partitition the disk. + * + * Special case to allow disklabel to be invalidated. + */ if (nlp->d_magic == 0xffffffff) { *olp = *nlp; return (0); @@ -369,13 +910,14 @@ setdisklabel(olp, nlp, openmask, osdep) /* XXX missing check if other dos partitions will be overwritten */ while (openmask != 0) { - i = ffs(openmask) - 1; + i = ffs((long)openmask) - 1; openmask &= ~(1 << i); if (nlp->d_npartitions <= i) return (EBUSY); opp = &olp->d_partitions[i]; npp = &nlp->d_partitions[i]; - if (npp->p_offset != opp->p_offset || npp->p_size < opp->p_size) + if (npp->p_offset != opp->p_offset || + npp->p_size < opp->p_size) return (EBUSY); /* * Copy internally-set partition information @@ -397,101 +939,118 @@ setdisklabel(olp, nlp, openmask, osdep) /* * Write disk label back to device after modification. - * XXX cannot handle OpenBSD partitions in extended partitions! */ int writedisklabel(dev, strat, lp, osdep) dev_t dev; - void (*strat) __P((struct buf *)); + void (*strat)(struct buf *); struct disklabel *lp; struct cpu_disklabel *osdep; { - struct dos_partition *dp = osdep->dosparts, *dp2; + enum disklabel_tag *tp; + char *msg = "no disk label"; struct buf *bp; - struct disklabel *dlp; - int error, dospartoff, cyl, i; - int ourpart = -1; + struct disklabel dl; +#if defined(DISKLABEL_I386) || defined(DISKLABEL_HPPA) || defined(DISKLABEL_SGI) || defined(DISKLABEL_ALL) + struct cpu_disklabel cdl; +#endif + int labeloffset, error, i, endian, partoff = 0, cyl = 0; + u_int64_t csum, *p; /* get a buffer and initialize it */ bp = geteblk((int)lp->d_secsize); bp->b_dev = dev; - /* do dos partitions in the process of getting disklabel? */ - dospartoff = 0; - cyl = LABELSECTOR / lp->d_secpercyl; - if (dp) { - /* read master boot record */ - bp->b_blkno = DOSBBSECTOR; - bp->b_bcount = lp->d_secsize; - bp->b_flags = B_BUSY | B_READ; - bp->b_cylin = DOSBBSECTOR / lp->d_secpercyl; - (*strat)(bp); + /* + * I once played with the thought of using osdep->label{tag,sector} + * as a cache for knowing where (and what) to write. However, now I + * think it might be useful to reprobe if someone has written + * a newer disklabel of another type with disklabel(8) and -r. + */ + for (tp = probe_order; msg && *tp != -1; tp++) { + dl = *lp; + switch (*tp) { + case DLT_ALPHA: +#if defined(DISKLABEL_ALPHA) || defined(DISKLABEL_ALL) + msg = readbsdlabel(bp, strat, 0, ALPHA_LABELSECTOR, + ALPHA_LABELOFFSET, LITTLE_ENDIAN, &dl, 0); + labeloffset = ALPHA_LABELOFFSET; + endian = LITTLE_ENDIAN; +#endif + break; - if ((error = biowait(bp)) != 0) - goto done; + case DLT_I386: +#if defined(DISKLABEL_I386) || defined(DISKLABEL_ALL) + msg = readdoslabel(bp, strat, &dl, &cdl, &partoff, + &cyl, 0); + labeloffset = I386_LABELOFFSET; + endian = LITTLE_ENDIAN; +#endif + break; - if (((int *)bp->b_data)[0] == 0x01084025 && - ((int *)bp->b_data)[1] == 0x01294825) { - goto nodoslabel; - } - /* XXX how do we check veracity/bounds of this? */ - bcopy(bp->b_data + DOSPARTOFF, dp, - NDOSPART * sizeof(*dp)); - - for (dp2=dp, i=0; i < NDOSPART && ourpart == -1; i++, dp2++) - if (get_le(&dp2->dp_size) && dp2->dp_typ == DOSPTYP_OPENBSD) - ourpart = i; - for (dp2=dp, i=0; i < NDOSPART && ourpart == -1; i++, dp2++) - if (get_le(&dp2->dp_size) && dp2->dp_typ == DOSPTYP_FREEBSD) - ourpart = i; - for (dp2=dp, i=0; i < NDOSPART && ourpart == -1; i++, dp2++) - if (get_le(&dp2->dp_size) && dp2->dp_typ == DOSPTYP_NETBSD) - ourpart = i; - - if (ourpart != -1) { - dp2 = &dp[ourpart]; + case DLT_AMIGA: +#if defined(DISKLABEL_AMIGA) || defined(DISKLABEL_ALL) + msg = readamigalabel(bp, strat, &dl, &cdl, 0); + labeloffset = AMIGA_LABELOFFSET; + endian = BIG_ENDIAN; +#endif + break; - /* - * need sector address for SCSI/IDE, - * cylinder for ESDI/ST506/RLL - */ - dospartoff = get_le(&dp2->dp_start); - cyl = DPCYL(dp2->dp_scyl, dp2->dp_ssect); + case DLT_HPPA: +#if defined(DISKLABEL_HPPA) || defined(DISKLABEL_ALL) + msg = readliflabel(bp, strat, &dl, &cdl, &partoff, + &cyl, 0); + labeloffset = HPPA_LABELOFFSET; + endian = BIG_ENDIAN; +#endif + break; + + case DLT_SGI: +#if defined(DISKLABEL_SGI) || defined(DISKLABEL_ALL) + msg = readsgilabel(bp, strat, &dl, &cdl, &partoff, + &cyl, 0); + labeloffset = SGI_LABELOFFSET; + endian = BIG_ENDIAN; +#endif + break; + + default: + panic("unrecognized disklabel tag %d", *tp); } } -nodoslabel: - /* next, dig out disk label */ - bp->b_blkno = dospartoff + LABELSECTOR; - bp->b_cylin = cyl; - bp->b_bcount = lp->d_secsize; - bp->b_flags = B_BUSY | B_READ; - (*strat)(bp); + if (msg) { + if (partoff == -1) + return EIO; - /* if successful, locate disk label within block and validate */ - if ((error = biowait(bp)) != 0) - goto done; - for (dlp = (struct disklabel *)bp->b_data; - dlp <= (struct disklabel *)(bp->b_data + lp->d_secsize - sizeof(*dlp)); - dlp = (struct disklabel *)((char *)dlp + sizeof(long))) { - if (dlp->d_magic == DISKMAGIC && dlp->d_magic2 == DISKMAGIC && - dkcksum(dlp) == 0) { - *dlp = *lp; - bp->b_flags = B_BUSY | B_WRITE; - (*strat)(bp); - error = biowait(bp); - goto done; - } + /* Write it in the regular place with native byte order. */ + labeloffset = LABELOFFSET; + endian = BYTE_ORDER; + bp->b_blkno = partoff + LABELSECTOR; + bp->b_cylin = cyl; + bp->b_bcount = lp->d_secsize; + } + + if (endian != BYTE_ORDER) { + swapdisklabel(lp); + /* recalc checksum */ + lp->d_checksum = 0; + lp->d_checksum = dkcksum(lp); + } + + *(struct disklabel *)(bp->b_data + labeloffset) = *lp; + + /* Alpha bootblocks are checksummed. */ + if (*tp == DLT_ALPHA) { + for (csum = i = 0, p = (u_int64_t *)bp->b_data; i < 63; i++) + csum += *p++; + *p = csum; } - /* Write it in the regular place. */ - *(struct disklabel *)bp->b_data = *lp; bp->b_flags = B_BUSY | B_WRITE; (*strat)(bp); error = biowait(bp); - goto done; -done: bp->b_flags |= B_INVAL; brelse(bp); return (error); @@ -511,10 +1070,17 @@ bounds_check_with_label(bp, lp, osdep, wlabel) { #define blockpersec(count, lp) ((count) * (((lp)->d_secsize) / DEV_BSIZE)) struct partition *p = lp->d_partitions + DISKPART(bp->b_dev); - int labelsector = blockpersec(lp->d_partitions[RAW_PART].p_offset, lp) + - LABELSECTOR; + int labelsector = blockpersec(lp->d_partitions[RAW_PART].p_offset, + lp) + osdep->labelsector; int sz = howmany(bp->b_bcount, DEV_BSIZE); + /* avoid division by zero */ + if (lp->d_secpercyl == 0) { + bp->b_error = EINVAL; + goto bad; + } + + /* beyond partition? */ if (bp->b_blkno + sz > blockpersec(p->p_size, lp)) { sz = blockpersec(p->p_size, lp) - bp->b_blkno; if (sz == 0) { @@ -533,9 +1099,7 @@ bounds_check_with_label(bp, lp, osdep, wlabel) /* Overwriting disk label? */ if (bp->b_blkno + blockpersec(p->p_offset, lp) <= labelsector && -#if LABELSECTOR != 0 bp->b_blkno + blockpersec(p->p_offset, lp) + sz > labelsector && -#endif (bp->b_flags & B_READ) == 0 && !wlabel) { bp->b_error = EROFS; goto bad; |