Subject: Re: Block Mail
To: None <mark@good.com>
From: Michael L. Hitch <osymh@gemini.oscs.montana.edu>
List: current-users
Date: 08/27/1994 13:59:35
On Aug 26,  2:45pm, Mark Gooderum wrote:
> I would love to help make this work (I've got a couple of older but very
> big 1024 block SCSI drives I scrounged that otherwise work).
>  
> I've played a bit with having physio() stuff the block value into both
> b_lblkno and b_blkno.  

  Here's a solution I'm trying right now.  I've been running in on my
512-byte sector disks with no problems.  It also seems to be working
on an M-O disk using 1024-sectors.  Newfs and fsck work fine, and the
filesystem can be mounted.

  The physio() routine sets the B_RAW flag, and my change uses that flag
to decide how to handle the b_blkno field.  [I.e. if B_RAW is set, then
the b_blkno value is in DEV_BSIZE blocks, otherwise the b_blkno value is
in real blocks.]  There are two changes - one to the SCSI disk driver
(sd.c) and the other to the bounds_check_with_label() routine, since the
meaning of b_blkno is different.  Note that the partition size must be
in real blocks, not in DEV_BSIZE blocks;  newfs uses the real block size
when calculating the file system size.

  The change to sd.c is fairly simple:

*** /mnt/src/sys/scsi/sd.c	Wed Jul 27 08:24:59 1994
--- /sys/scsi/sd.c	Fri Aug 26 21:02:46 1994
***************
*** 491,499 ****
  		 * We have a buf, now we know we are going to go through
  		 * With this thing..
  		 *
! 		 *  First, translate the block to absolute
  		 */
! 		blkno = bp->b_blkno / (sd->params.blksize / DEV_BSIZE);
  		if (SDPART(bp->b_dev) != RAW_PART) {
  			p = &sd->sc_dk.dk_label.d_partitions[SDPART(bp->b_dev)];
  			blkno += p->p_offset;
--- 491,501 ----
  		 * We have a buf, now we know we are going to go through
  		 * With this thing..
  		 *
! 		 *  First, translate the block to absolute if B_RAW
  		 */
! 		blkno = bp->b_blkno;
! 		if (bp->b_flags & B_RAW)
! 			blkno /= sd->params.blksize / DEV_BSIZE;
  		if (SDPART(bp->b_dev) != RAW_PART) {
  			p = &sd->sc_dk.dk_label.d_partitions[SDPART(bp->b_dev)];
  			blkno += p->p_offset;
***************
*** 645,655 ****
  	 */
  	sd->sc_dk.dk_label.d_partitions[0].p_offset = 0;
  	sd->sc_dk.dk_label.d_partitions[0].p_size =
! 	    sd->params.disksize * (sd->params.blksize / DEV_BSIZE);
  	sd->sc_dk.dk_label.d_partitions[0].p_fstype = 9;	/* XXXX */
  	sd->sc_dk.dk_label.d_partitions[RAW_PART].p_offset = 0;
  	sd->sc_dk.dk_label.d_partitions[RAW_PART].p_size =
! 	    sd->params.disksize * (sd->params.blksize / DEV_BSIZE);
  	sd->sc_dk.dk_label.d_npartitions = MAXPARTITIONS;
  
  	sd->sc_dk.dk_label.d_secsize = sd->params.blksize;
--- 647,657 ----
  	 */
  	sd->sc_dk.dk_label.d_partitions[0].p_offset = 0;
  	sd->sc_dk.dk_label.d_partitions[0].p_size =
! 	    sd->params.disksize;
  	sd->sc_dk.dk_label.d_partitions[0].p_fstype = 9;	/* XXXX */
  	sd->sc_dk.dk_label.d_partitions[RAW_PART].p_offset = 0;
  	sd->sc_dk.dk_label.d_partitions[RAW_PART].p_size =
! 	    sd->params.disksize;
  	sd->sc_dk.dk_label.d_npartitions = MAXPARTITIONS;
  
  	sd->sc_dk.dk_label.d_secsize = sd->params.blksize;


  This also requires some changes to the bounds_check_with_label()
routine in disksubr.c.  Not being very familiar with real disk labels
and the i386 stuff, I'm not certain what would need to be changed for
the i386 port.  This is what I currently have for the Amiga routine:

	pp = &lp->d_partitions[DISKPART(bp->b_dev)];
	if (bp->b_flags & B_RAW) {
		maxsz = pp->p_size * (lp->d_secsize / DEV_BSIZE);
		sz = (bp->b_bcount + DEV_BSIZE) / DEV_BSIZE;
	} else {
		maxsz = pp->p_size;
		sz = (bp->b_bcount + lp->d_secsize - 1) / lp->d_secsize;
	}

	if (bp->b_blkno < 0 || bp->b_blkno + sz > maxsz) {
		if (bp->b_blkno == maxsz) {
			/* 
			 * trying to get one block beyond return EOF.
			 */
			bp->b_resid = bp->b_bcount;
			return(0);
		}
		sz = maxsz - bp->b_blkno;
		if (sz <= 0 || bp->b_blkno < 0) {
			bp->b_error = EINVAL;
			bp->b_flags |= B_ERROR;
			return(-1);
		}
		/* 
		 * adjust count down
		 */
		if (bp->b_flags & B_RAW)
			bp->b_bcount = sz << DEV_BSHIFT;
		else
			bp->b_bcount = sz * lp->d_secsize;
	}



> I also haven't made the physio() like changes to the CD code, 
> I have no CD drive to test with.

  The CD code shouldn't require any changes.  The SCSI CD driver is
separate from the SCSI disk driver.  At least for the current time, the
cd9660 file system is using DEV_BSIZE logical blocks, which is the same
as physio(), so nothing different is required in cd.c.  However,
thinking about it reminded me that access to /dev/cd0 won't work
correctly because it uses the real sector size to calculate the block
number. That's probably nothing to worry too much about at this time.
Because the cd driver is also calling bounds_check_with_label(), the
check isn't going to be entirely correct for block accesses, but I don't
think it will break CDROM access.

Michael

-- 
Michael L. Hitch			INTERNET:  osymh@montana.edu
Computer Consultant
Office of Systems and Computing Services
Montana State University	Bozeman, MT	USA

------------------------------------------------------------------------------