Subject: initial work to get netbsd/sparc be able to read/write disklabels.
To: None <port-sparc@NetBSD.ORG>
From: matthew green <mrg@mame.mu.OZ.AU>
List: port-sparc
Date: 03/19/1995 12:04:05
i'm about to get a new harddisk, and i really would like to be able
to partition the disk with netbsd/sparc, and not having to use the
sunos format program.  so i've done some initial hacking on the
disklabel program, and the disk routines for the sparc, to give us
the ability to read and write both netbsd and sunos disklabels.

please note that i have *NOT* tested the writing bit yet.  i don't
have my new disk, and i don't trust that i won't break my current
boot disks partition table.  the reading does work reasonably well,
however:

splode src/sbin/disklabel> ./disklabel -r /dev/rsd0a
# /dev/rsd0a:
type: SCSI
disk:
label: SUN0424 cyl 1151
flags:
bytes/sector: 512
sectors/track: 80
tracks/cylinder: 9
sectors/cylinder: 720
cylinders: 1151
rpm: 4400
interleave: 1
trackskew: 0
cylinderskew: 0
headswitch: 0           # milliseconds
track-to-track seek: 0  # milliseconds
drivedata: 0

8 partitions:
#        size   offset    fstype   [fsize bsize   cpg]
  a:    41040        0    4.2BSD        0     0     0   # (Cyl.    0 - 56)
  b:    57600    41040      swap                        # (Cyl.   57 - 136)
  c:   828720        0   unknown                        # (Cyl.    0 - 1150)
  f:   122400    98640    4.2BSD        0     0     0   # (Cyl.  137 - 306)
  g:   607680   221040    4.2BSD        0     0     0   # (Cyl.  307 - 1150)
disklabel: boot block size 0
disklabel: super block size 0
splode src/sbin/disklabel>

a few of the things aren't right, but that's because i haven't see
a simple way to calculate them from the info the sun disklabel has in
it (considerably less than a netbsd one).  but the partition table
infomation is correct.  it didn't really guess SCSI, that's hard
coded at the moment, but everything else is right.

if anyone has a machine they can easily test this on, please do and
let me know how it goes.

i must stress again that a lot of these changes have *NOT* been
tested and may result in broken partition infomation for some of the
disk drives.

enjoy.

.mrg. 

Index: src/sys/arch/sparc/sparc/disksubr.c
===================================================================
RCS file: /local/cvs/src/sys/arch/sparc/sparc/disksubr.c,v
retrieving revision 1.1.1.1
diff -c -r1.1.1.1 disksubr.c
*** disksubr.c	1994/12/14 12:46:28	1.1.1.1
--- disksubr.c	1995/03/18 00:57:17
***************
*** 49,54 ****
--- 49,55 ----
  
  int sun_disklabel_to_bsd	__P((caddr_t, struct disklabel *));
  int sun_disklabel_from_bsd	__P((caddr_t, struct disklabel *));
+ u_short sun_cksum		__P((struct sun_disklabel *));
  
  extern struct device *bootdv;
  
***************
*** 125,131 ****
  		goto done;
  	}
  
- #ifdef notyet
  	dlp = (struct disklabel *)(bp->b_un.b_addr + SUN_LABELOFFSET);
  	if (dlp->d_magic == DISKMAGIC) {
  		if (dkcksum(dlp)) {
--- 126,131 ----
***************
*** 135,141 ****
  		*lp = *dlp;
  		goto done;
  	}
- #endif
  	msg = "no disk label";
  done:
  	bp->b_flags = B_INVAL | B_AGE | B_READ;
--- 135,140 ----
***************
*** 208,214 ****
  	register struct disklabel *lp;
  	struct cpu_disklabel *clp;
  {
- #if 0 
  	struct buf *bp; 
  	struct disklabel *dlp;
  	struct sun_disklabel *slp;
--- 207,212 ----
***************
*** 217,223 ****
  	bp = geteblk((int)lp->d_secsize);
  	bp->b_dev = dev;
  	bp->b_blkno = LABELSECTOR;
! 	bp->b_cylin = 0;
  	bp->b_bcount = lp->d_secsize;
  	bp->b_flags = B_READ;           /* get current label */
  	(*strat)(bp);
--- 215,221 ----
  	bp = geteblk((int)lp->d_secsize);
  	bp->b_dev = dev;
  	bp->b_blkno = LABELSECTOR;
! 	bp->b_resid = 0;
  	bp->b_bcount = lp->d_secsize;
  	bp->b_flags = B_READ;           /* get current label */
  	(*strat)(bp);
***************
*** 238,248 ****
  done:
  	brelse(bp);
  	return (error); 
- #else   
- 	/* Not sure if the above is right yet... -gwr/pmg */
- 
- 	return ENODEV;
- #endif
  }
  
  
--- 236,241 ----
***************
*** 337,351 ****
  	if (v)
  		return v;
  	sl = (struct sun_disklabel *)cp;
! 	lp->d_magic = 0;			/* denote as pseudo */
  	lp->d_ncylinders = sl->sl_ncylinders;
  	lp->d_acylinders = sl->sl_acylinders;
  	v = (lp->d_ntracks = sl->sl_ntracks) *
  	    (lp->d_nsectors = sl->sl_nsectors);
  	lp->d_secpercyl = v;
! 	lp->d_npartitions = MAXPARTITIONS;
  
! 	for (i = 0; i < MAXPARTITIONS; i++) {
  		spp = &sl->sl_part[i];
  		npp = &lp->d_partitions[i];
  		npp->p_offset = spp->sdkp_cyloffset * v;
--- 330,355 ----
  	if (v)
  		return v;
  	sl = (struct sun_disklabel *)cp;
! 	lp->d_magic = SUN_DKMAGIC;			/* denote as pseudo */
! 	lp->d_magic2 = SUN_DKMAGIC;
! 	lp->d_type = DTYPE_SCSI;             /* XXX assume scsi disk */
  	lp->d_ncylinders = sl->sl_ncylinders;
  	lp->d_acylinders = sl->sl_acylinders;
+ 	lp->d_secsize = DEV_BSIZE;
+ 	lp->d_secperunit = 0;
+ 	lp->d_sparespertrack = 0;     /* # of spare sectors per track */
+ 	lp->d_sparespercyl = sl->sl_sparespercyl;
+ 	lp->d_rpm = sl->sl_rpm;
+ 	lp->d_interleave = sl->sl_interleave;
+ 	lp->d_trackskew = lp->d_cylskew = 0;
+ 	lp->d_headswitch = lp->d_trkseek = lp->d_flags = 0;
+ 	bcopy(sl->sl_text, lp->d_packname, sizeof(lp->d_packname));
  	v = (lp->d_ntracks = sl->sl_ntracks) *
  	    (lp->d_nsectors = sl->sl_nsectors);
  	lp->d_secpercyl = v;
! 	lp->d_npartitions = 8;
  
! 	for (i = 0; i < 8; i++) {
  		spp = &sl->sl_part[i];
  		npp = &lp->d_partitions[i];
  		npp->p_offset = spp->sdkp_cyloffset * v;
***************
*** 353,361 ****
--- 357,424 ----
  		if (npp->p_size)
  			npp->p_fstype = sun_fstypes[i];
  	}
+ 	lp->d_checksum = 0;
+ 	lp->d_checksum = dkcksum(lp);
  	return 0;
  }
  
+ int
+ sun_disklabel_from_bsd(cp, lp)
+ 	register caddr_t cp;
+ 	register struct disklabel *lp;
+ {
+ 	u_short *sp;
+ 	struct sun_disklabel *sl;
+ 	struct partition *npp;
+ 	struct sun_dkpart *spp;
+ 	int v, i;
+ 
+ 	sp = (u_short *)(cp + sizeof(struct sun_disklabel));
+ 	--sp;
+ 	v = 0;
+ 	while (sp >= (u_short *)cp)
+ 		v ^= *sp--;
+ 	if (v)
+ 		return v;
+ 
+ 	sl = (struct sun_disklabel *)cp;
+ 	if (sizeof(sl->sl_text) > sizeof(lp->d_packname))
+ 		bzero(sl->sl_text + sizeof(lp->d_packname), sizeof(sl->sl_text) - sizeof(lp->d_packname));
+ 	bcopy(lp->d_packname, sl->sl_text, sizeof(lp->d_packname));
+ 	sl->sl_rpm = lp->d_rpm;
+ 	sl->sl_sparespercyl = lp->d_sparespercyl;
+ 	sl->sl_interleave = lp->d_interleave;
+ 	sl->sl_ncylinders = lp->d_ncylinders;
+ 	sl->sl_acylinders = lp->d_acylinders;
+ 	sl->sl_ntracks = lp->d_ntracks;
+ 	sl->sl_nsectors = lp->d_nsectors;
+ 	sl->sl_magic = lp->d_magic;
+ 
+ 	v = lp->d_secpercyl;
+ 	for (i = 0; i < 8; i++) {
+ 		npp = &lp->d_partitions[i];
+ 		spp = &sl->sl_part[i];
+ 		spp->sdkp_cyloffset = npp->p_offset / v;
+ 		spp->sdkp_nsectors = npp->p_size;
+ 	}
+ 	sl->sl_cksum = 0;
+ 	sl->sl_cksum = sun_cksum(sl);
+ 	return 0;
+ }
+ 
+ u_short
+ sun_cksum(sl)
+ 	register struct sun_disklabel *sl;
+ {
+ 	register u_short *start, *end;
+ 	register u_short sum = 0;
+ 
+ 	start = (u_short *)sl;
+ 	end = (u_short *)&sl->sl_cksum;
+ 	while (start < end)
+ 		sum ^= *start++;
+ 	return (sum);
+ }
  
  /* move this to compat/sunos */
  int
Index: src/sbin/disklabel/disklabel.c
===================================================================
RCS file: /local/cvs/src/sbin/disklabel/disklabel.c,v
retrieving revision 1.1.1.1
diff -c -r1.1.1.1 disklabel.c
*** disklabel.c	1995/03/17 16:41:52	1.1.1.1
--- disklabel.c	1995/03/19 00:51:21
***************
*** 55,60 ****
--- 55,63 ----
  #include <sys/wait.h>
  #define DKTYPENAMES
  #include <sys/disklabel.h>
+ #ifdef sparc
+ #include <machine/sun_disklabel.h>
+ #endif
  
  #include <ufs/ffs/fs.h>
  
***************
*** 142,147 ****
--- 145,155 ----
  void setbootflag __P((struct disklabel *));
  void usage __P((void));
  u_short dkcksum __P((struct disklabel *));
+ #ifdef sparc
+ int sun_disklabel_to_bsd __P((struct sun_disklabel *, struct disklabel **));
+ int sun_disklabel_from_bsd __P((struct disklabel *, struct sun_disklabel **));
+ u_short sun_cksum __P((struct sun_disklabel *));
+ #endif
  
  
  int
***************
*** 376,389 ****
  	char *boot;
  	struct disklabel *lp;
  {
  	int writeable;
  	off_t sectoffset = 0;
  
  #if NUMBOOT > 0
  	setbootflag(lp);
  #endif
! 	lp->d_magic = DISKMAGIC;
! 	lp->d_magic2 = DISKMAGIC;
  	lp->d_checksum = 0;
  	lp->d_checksum = dkcksum(lp);
  	if (rflag) {
--- 384,407 ----
  	char *boot;
  	struct disklabel *lp;
  {
+ #ifdef sparc
+ 	struct sun_disklabel *sl;
+ #endif
  	int writeable;
  	off_t sectoffset = 0;
  
  #if NUMBOOT > 0
  	setbootflag(lp);
  #endif
! #ifdef sparc
! 	if (lp->d_magic != SUN_DKMAGIC)
! 	{
! #endif
! 		lp->d_magic = DISKMAGIC;
! 		lp->d_magic2 = DISKMAGIC;
! #ifdef sparc
! 	}
! #endif
  	lp->d_checksum = 0;
  	lp->d_checksum = dkcksum(lp);
  	if (rflag) {
***************
*** 441,446 ****
--- 459,478 ----
  		writeable = 1;
  		if (ioctl(f, DIOCWLABEL, &writeable) < 0)
  			perror("ioctl DIOCWLABEL");
+ #ifdef sparc
+ 		if (lp->d_magic == SUN_DKMAGIC) {
+ 			if (sun_disklabel_from_bsd(lp, &sl)) {
+ 				warn("can't convert lable to SunOS format");
+ 				return (1);
+ 			}
+ 			if (write(f, sl, sizeof(struct sun_disklabel)) !=
+ 			    sizeof(struct sun_disklabel)) {
+ 				perror("write");
+ 				return(1);
+ 			}
+ 			goto written;
+ 		}
+ #endif
  		if (write(f, boot, lp->d_bbsize) != lp->d_bbsize) {
  			perror("write");
  			return (1);
***************
*** 454,459 ****
--- 486,492 ----
  			return(1);
  		}
  #endif
+ written:
  		writeable = 0;
  		if (ioctl(f, DIOCWLABEL, &writeable) < 0)
  			perror("ioctl DIOCWLABEL");
***************
*** 562,567 ****
--- 595,603 ----
  	int f;
  {
  	struct disklabel *lp;
+ #ifdef sparc
+ 	struct sun_disklabel *sl;
+ #endif
  
  	if (rflag) {
  		char *msg;
***************
*** 586,591 ****
--- 622,637 ----
  				msg = "disk label corrupted";
  			}
  		}
+ #ifdef sparc
+ 		sl = (struct sun_disklabel *)bootarea;
+ 		if (sl->sl_magic == SUN_DKMAGIC) {
+ 			sun_disklabel_to_bsd(sl, &lp);
+ 			if (lp)
+ 				return (lp);
+ 			msg = "SunOS disk label corrupted";
+ 		}
+ #endif
+ 		
  		/* lp = (struct disklabel *)(bootarea + LABELOFFSET); */
  		errx(1, msg);
  	} else {
***************
*** 595,600 ****
--- 641,748 ----
  	}
  	return (lp);
  }
+ 
+ #ifdef sparc
+ /* What partition types to assume for Sun disklabels: */
+ static u_char
+ sun_fstypes[8] = {
+ 	FS_BSDFFS,	/* a */
+ 	FS_SWAP,	/* b */
+ 	FS_OTHER,	/* c */
+ 	FS_BSDFFS,	/* d */
+ 	FS_BSDFFS,	/* e */
+ 	FS_BSDFFS,	/* f */
+ 	FS_BSDFFS,	/* g */
+ 	FS_BSDFFS,	/* h */
+ };
+ 
+ int
+ sun_disklabel_to_bsd(sl, lp)
+ 	register struct sun_disklabel *sl;
+ 	register struct disklabel **lp;
+ {
+ 	u_short *sp;
+ 	struct partition *npp;
+ 	struct sun_dkpart *spp;
+ 	int i, v;
+ 	u_short sum;
+ 
+ 	sum = sl->sl_cksum;
+ 	sl->sl_cksum = 0;
+ 	if (sum != sun_cksum(sl))
+ 		return 1;
+ 	(*lp) = (struct disklabel *) malloc(sizeof(struct disklabel));
+ 	if (!*lp)
+ 		err(4, "malloc failed");
+ 	(*lp)->d_magic = sl->sl_magic;			/* denote as pseudo */
+ 	(*lp)->d_magic2 = sl->sl_magic;
+ 	(*lp)->d_type = DTYPE_SCSI;		/* XXX assume scsi disk */
+ 	(*lp)->d_ncylinders = sl->sl_ncylinders;
+ 	(*lp)->d_acylinders = sl->sl_acylinders;
+ 	(*lp)->d_secsize = DEV_BSIZE;
+ 	(*lp)->d_secperunit = 0;
+ 	(*lp)->d_sparespertrack = 0;     /* # of spare sectors per track */
+ 	(*lp)->d_sparespercyl = sl->sl_sparespercyl;
+ 	(*lp)->d_rpm = sl->sl_rpm;
+ 	(*lp)->d_interleave = sl->sl_interleave;
+ 	(*lp)->d_trackskew = (*lp)->d_cylskew = 0;
+ 	(*lp)->d_headswitch = (*lp)->d_trkseek = (*lp)->d_flags = 0;
+ 	bcopy(sl->sl_text, (*lp)->d_packname, sizeof((*lp)->d_packname));
+ 	v = ((*lp)->d_ntracks = sl->sl_ntracks) *
+ 	    ((*lp)->d_nsectors = sl->sl_nsectors);
+ 	(*lp)->d_secpercyl = v;
+ 	(*lp)->d_npartitions = 8;
+ 
+ 	for (i = 0; i < MAXPARTITIONS; i++) {
+ 		spp = &sl->sl_part[i];
+ 		npp = &(*lp)->d_partitions[i];
+ 		npp->p_offset = spp->sdkp_cyloffset * v;
+ 		npp->p_size = spp->sdkp_nsectors;
+ 		if (npp->p_size)
+ 			npp->p_fstype = sun_fstypes[i];
+ 	}
+ 	(*lp)->d_checksum = 0;
+ 	(*lp)->d_checksum = dkcksum(*lp);
+ 	return 0;
+ }
+ 
+ int
+ sun_disklabel_from_bsd(lp, sl)
+ 	register struct disklabel *lp;
+ 	register struct sun_disklabel **sl;
+ {
+ 	u_short *sp;
+ 	struct partition *npp;
+ 	struct sun_dkpart *spp;
+ 	int v, i;
+ 
+ 	(*sl) = (struct sun_disklabel *) malloc(sizeof(struct sun_disklabel));
+ 	if (!*sl)
+ 		err(4, "malloc failed");
+ 	if (sizeof((*sl)->sl_text) > sizeof(lp->d_packname))
+ 		bzero((*sl)->sl_text + sizeof(lp->d_packname), sizeof((*sl)->sl_text) - sizeof(lp->d_packname));
+ 	bcopy(lp->d_packname, (*sl)->sl_text, sizeof(lp->d_packname));
+ 	(*sl)->sl_rpm = lp->d_rpm;
+ 	(*sl)->sl_sparespercyl = lp->d_sparespercyl;
+ 	(*sl)->sl_interleave = lp->d_interleave;
+ 	(*sl)->sl_ncylinders = lp->d_ncylinders;
+ 	(*sl)->sl_acylinders = lp->d_acylinders;
+ 	(*sl)->sl_ntracks = lp->d_ntracks;
+ 	(*sl)->sl_nsectors = lp->d_nsectors;
+ 	(*sl)->sl_magic = lp->d_magic;
+ 
+ 	v = lp->d_secpercyl;
+ 	for (i = 0; i < MAXPARTITIONS; i++) {
+ 		npp = &lp->d_partitions[i];
+ 		spp = &(*sl)->sl_part[i];
+ 		spp->sdkp_cyloffset = npp->p_offset / v;
+ 		spp->sdkp_nsectors = npp->p_size;
+ 	}
+ 	(*sl)->sl_cksum = 0;
+ 	(*sl)->sl_cksum = sun_cksum(*sl);
+ 	return 0;
+ }
+ #endif
  
  /*
   * Construct a bootarea (d_bbsize bytes) in the specified buffer ``boot''
Index: src/sbin/disklabel/dkcksum.c
===================================================================
RCS file: /local/cvs/src/sbin/disklabel/dkcksum.c,v
retrieving revision 1.1.1.1
diff -c -r1.1.1.1 dkcksum.c
*** dkcksum.c	1995/03/17 16:41:52	1.1.1.1
--- dkcksum.c	1995/03/19 00:51:21
***************
*** 38,43 ****
--- 38,47 ----
  
  #include <sys/types.h>
  #include <sys/disklabel.h>
+ #ifdef sparc
+ #include <machine/sun_disklabel.h>
+ #endif
+ 
  
  u_short
  dkcksum(lp)
***************
*** 52,54 ****
--- 56,74 ----
  		sum ^= *start++;
  	return (sum);
  }
+ 
+ #ifdef sparc
+ u_short
+ sun_cksum(sl)
+ 	register struct sun_disklabel *sl;
+ {
+ 	register u_short *start, *end;
+ 	register u_short sum = 0;
+ 
+ 	start = (u_short *)sl;
+ 	end = (u_short *)&sl->sl_cksum;
+ 	while (start < end)
+ 		sum ^= *start++;
+ 	return (sum);
+ }
+ #endif