Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 29 Jan 1998 13:35:56 +0300 (MSK)
From:      vak@crox.net.kiae.su (Serge V.Vakulenko)
To:        FreeBSD-gnats-submit@FreeBSD.ORG
Subject:   kern/5598: [patch] od - support for MO devices with 2k sector size (like Fujitsu M2513 with 640M disks)
Message-ID:  <199801291035.NAA01877@crox.net.kiae.su>

next in thread | raw e-mail | index | archive | help

>Number:         5598
>Category:       kern
>Synopsis:       Support for magneto-optic SCSI devices with 2k sector size added (like Fujitsu M2513 with 640M disks)
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    freebsd-bugs
>State:          open
>Quarter:
>Keywords:
>Date-Required:
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Thu Jan 29 02:40:01 PST 1998
>Last-Modified:
>Originator:     Serge V.Vakulenko
>Organization:
Cronyx Engineering Ltd.
>Release:        FreeBSD 3.0-971225-SNAP i386
>Environment:
	Fujitsu M2513 magneto-optic device, and 640M disks.

>Description:
	The current implementation of UFS file system, disk label
	and partition routines require the driver to handle
	any 512-byte-aligned i/o request.  Most SCSI HDD, CD-ROM
	and MO devices have 512 byte sectors, and cause no problem.
	But the 640M MO disks have 2k sector size, and do not work
	as appropriate.

>How-To-Repeat:
	Try to disklabel the 640M disk, for example:

		disklabel -r -w od0 auto

>Fix:
	After applying the following patch, the disklabel, newfs
	and the UFS filesystem starts working fine, with a good
	data throughput (tested copying 32-megabyte file):
	reading - 1.1 Mb/sec, writing - 0.5 Mb/sec.

--- od30.c	Fri Jan 23 21:09:48 1998
+++ od.c	Tue Jan 27 18:43:16 1998
@@ -66,6 +66,7 @@
 #include <sys/systm.h>
 #include <sys/conf.h>
 #include <sys/buf.h>
+#include <sys/malloc.h>
 #include <sys/cdio.h>
 #include <sys/dkstat.h>
 #include <sys/disklabel.h>
@@ -105,6 +106,13 @@
 	struct diskslices *dk_slices;	/* virtual drives */
 	struct buf_queue_head buf_queue;
 	int dkunit;		/* disk stats unit number */
+	u_char	buf [2048];	/* partial i/o intermediate buffer */
+	u_int32_t blkno;	/* start i/o block number (logical 512) */
+	u_int32_t nblk;		/* total i/o length (logical blocks 512) */
+	u_int32_t ionsec;	/* partial i/o length (physical sectors) */
+	u_int32_t ioflags;
+	int	partial_write;	/* partial write flag */
+	u_char *data;		/* i/o buffer pointer */
 #ifdef DEVFS
 	/* Eventually move all these to common disk struct. */
 	void	*b_devfs_token;
@@ -120,6 +128,7 @@
 static u_int32_t	od_size __P((int unit, int flags));
 static int	od_sense_handler __P((struct scsi_xfer *));
 static void	odstart __P((u_int32_t, u_int32_t));
+static int	od_done __P((struct scsi_xfer *));
 static void	odstrategy1 __P((struct buf *));

 static dev_t odsetunit(dev_t dev, int unit) { return ODSETUNIT(dev, unit); }
@@ -156,7 +165,7 @@
 	od_sense_handler,
 	odstart,		/* have a queue, served by this */
 	NULL,			/* have no async handler */
-	NULL,			/* Use default 'done' routine */
+	od_done,		/* have a post-i/o processing routine */
 	"od",
 	0,
 	{0, 0},
@@ -376,7 +385,7 @@
 		/* XXX as long as it's not 0
 		 *  - readdisklabel divides by it (?)
 		 */
-	label.d_secperunit = od->params.disksize;
+	label.d_secperunit = label.d_secpercyl * od->params.cyls;

 	/* Initialize slice tables. */
 	errcode = dsopen("od", dev, fmt, &od->dk_slices, &label, odstrategy1,
@@ -460,18 +469,10 @@
 		goto bad;
 	}

-
 	secsize = od->params.secsiz;

-	/* make sure the blkno is scalable */
-	if( (bp->b_blkno % (secsize/DEV_BSIZE)) != 0 ) {
-		bp->b_error = EINVAL;
-		printf("od_strategy: Block number is not multiple of sector size (2): 0x%x\n", bp->b_blkno);
-		goto bad;
-	}
-
 	/* make sure that the transfer size is a multiple of the sector size */
-	if( (bp->b_bcount % secsize) != 0 ) {
+	if( (bp->b_bcount % DEV_BSIZE) != 0 ) {
 		bp->b_error = EINVAL;
 		printf("od_strategy: Invalid b_bcount %d at block number: 0x%x\n", bp->b_bcount, bp->b_blkno);
 		goto bad;
@@ -552,6 +553,157 @@
 	odstrategy(bp);
 }

+static int
+od_io (struct scsi_link *sc_link, struct buf *bp)
+{
+	struct scsi_data *od = sc_link->sd;
+	int blocks_per_sector = od->params.secsiz / DEV_BSIZE;
+	int op = (bp->b_flags & B_READ) ? READ_BIG : WRITE_BIG;
+	u_char *data = od->data;
+	struct scsi_rw_big cmd;
+
+	od->partial_write = 0;
+	od->ionsec = od->nblk / blocks_per_sector;
+	if (od->blkno % blocks_per_sector || od->nblk < blocks_per_sector) {
+		/* partial i/o, read the whole sector */
+		op = READ_BIG;
+		od->ionsec = 1;
+		data = od->buf;
+	}
+
+	/*
+	 *  Fill out the scsi command
+	 */
+	cmd.op_code = op;
+	scsi_uto4b (od->blkno / blocks_per_sector, &cmd.addr_3);
+	scsi_uto2b (od->ionsec, &cmd.length2);
+	cmd.byte2 = cmd.reserved = cmd.control = 0;
+
+	/*
+	 * Call the routine that chats with the adapter.
+	 * Note: we cannot sleep as we may be an interrupt
+	 */
+	if (scsi_scsi_cmd (sc_link, (struct scsi_generic*) &cmd, sizeof(cmd),
+	    data, od->ionsec * od->params.secsiz, OD_RETRIES, 100000, bp,
+	    od->ioflags | (op==READ_BIG ? SCSI_DATA_IN : SCSI_DATA_OUT))
+	    == SUCCESSFULLY_QUEUED)
+		return 0;
+	return -1;
+}
+
+/*
+ * This routine is called by the scsi interrupt when the transfer is complete.
+ */
+static int
+od_done (struct scsi_xfer *xs)
+{
+	struct scsi_link *sc_link = xs->sc_link;
+	struct scsi_data *od = sc_link->sd;
+	struct buf *bp = xs->bp;
+	int blocks_per_sector = od->params.secsiz / DEV_BSIZE;
+	struct scsi_rw_big cmd;
+
+	if (! bp || xs->error == XS_TIMEOUT)
+		return 0;
+
+	if (od->blkno % blocks_per_sector) {
+		int offset = od->blkno % blocks_per_sector * DEV_BSIZE;
+		int len = blocks_per_sector * DEV_BSIZE - offset;
+
+		if (len > bp->b_bcount)
+			len = bp->b_bcount;
+		od->nblk -= len / DEV_BSIZE;
+		od->data += len;
+
+		if (bp->b_flags & B_READ) {
+			/* partial read */
+			od->blkno += len / DEV_BSIZE;
+			bcopy (od->buf + offset, bp->b_data, len);
+			if (od->nblk == 0)
+				return 0;
+			goto doio;
+		}
+
+		/* partial write */
+		bcopy (bp->b_data, od->buf + offset, len);
+		od->partial_write = 1;
+
+		free (xs, M_TEMP);
+		sc_link->active--;
+		sc_link->opennings++;
+
+		/* write sector back */
+		cmd.op_code = WRITE_BIG;
+		scsi_uto4b (od->blkno / blocks_per_sector, &cmd.addr_3);
+		scsi_uto2b (1, &cmd.length2);
+		cmd.byte2 = cmd.reserved = cmd.control = 0;
+		if (scsi_scsi_cmd (sc_link, (struct scsi_generic*) &cmd,
+		    sizeof(cmd), od->buf, od->params.secsiz, OD_RETRIES,
+		    100000, bp, od->ioflags | SCSI_DATA_OUT)
+		    != SUCCESSFULLY_QUEUED) {
+			bp->b_error = EIO;
+			bp->b_flags |= B_ERROR;
+		}
+		od->blkno += len / DEV_BSIZE;
+		return -2;
+	}
+
+	if (od->partial_write)
+		goto doio;
+
+	if (od->nblk % blocks_per_sector) {
+		if (od->nblk >= blocks_per_sector) {
+			int len = od->nblk / blocks_per_sector *
+				blocks_per_sector * DEV_BSIZE;
+			od->blkno += len / DEV_BSIZE;
+			od->nblk -= len / DEV_BSIZE;
+			od->data += len;
+			goto doio;
+		}
+		if (bp->b_flags & B_READ) {
+			/* partial read */
+			bcopy (od->buf, od->data, od->nblk * DEV_BSIZE);
+			return 0;
+		}
+
+		/* partial write */
+		bcopy (od->data, od->buf, od->nblk * DEV_BSIZE);
+		od->nblk = 0;
+
+		free (xs, M_TEMP);
+		sc_link->active--;
+		sc_link->opennings++;
+
+		/* write sector back */
+		cmd.op_code = WRITE_BIG;
+		scsi_uto4b (od->blkno / blocks_per_sector, &cmd.addr_3);
+		scsi_uto2b (1, &cmd.length2);
+		cmd.byte2 = cmd.reserved = cmd.control = 0;
+		if (scsi_scsi_cmd (sc_link, (struct scsi_generic*) &cmd,
+		    sizeof(cmd), od->buf, od->params.secsiz, OD_RETRIES,
+		    100000, bp, od->ioflags | SCSI_DATA_OUT)
+		    != SUCCESSFULLY_QUEUED) {
+			bp->b_error = EIO;
+			bp->b_flags |= B_ERROR;
+		}
+		return -2;
+	}
+	return 0;
+doio:
+	if (od->nblk == 0)
+		return 0;
+
+	free (xs, M_TEMP);
+	sc_link->active--;
+	sc_link->opennings++;
+
+	if (od_io (sc_link, bp) < 0) {
+		bp->b_error = EIO;
+		bp->b_flags |= B_ERROR;
+	}
+	return -2;
+}
+
 /*
  * odstart looks to see if there is a buf waiting for the device
  * and that the device is not already busy. If both are true,
@@ -574,8 +726,6 @@
 	register struct	scsi_link *sc_link = SCSI_LINK(&od_switch, unit);
 	register struct scsi_data *od = sc_link->sd;
 	struct buf *bp = 0;
-	struct scsi_rw_big cmd;
-	u_int32_t blkno, nblk;
 	u_int32_t secsize;

 	SC_DEBUG(sc_link, SDEV_DB2, ("odstart "));
@@ -607,55 +757,33 @@
 		 * re-openned
 		 */
 		if (!(sc_link->flags & SDEV_MEDIA_LOADED)) {
-			goto bad;
+			printf("od%ld: media not loaded\n", unit);
+bad:			bp->b_error = EIO;
+			bp->b_flags |= B_ERROR;
+			biodone(bp);
+			continue;
 		}
+
 		/*
 		 * We have a buf, now we know we are going to go through
 		 * With this thing..
 		 */
 		secsize = od->params.secsiz;
-		blkno = bp->b_pblkno;
-		if (bp->b_bcount & (secsize - 1))
-		{
-		    goto bad;
-		}
-		nblk = bp->b_bcount / secsize;
-
-		/*
-		 *  Fill out the scsi command
-		 */
-		cmd.op_code = (bp->b_flags & B_READ)
-		    ? READ_BIG : WRITE_BIG;
-		scsi_uto4b(blkno, &cmd.addr_3);
-		scsi_uto2b(nblk, &cmd.length2);
-		cmd.byte2 = cmd.reserved = cmd.control = 0;
-		/*
-		 * Call the routine that chats with the adapter.
-		 * Note: we cannot sleep as we may be an interrupt
-		 */
-		if (scsi_scsi_cmd(sc_link,
-			(struct scsi_generic *) &cmd,
-			sizeof(cmd),
-			(u_char *) bp->b_data,
-			bp->b_bcount,
-			OD_RETRIES,
-			100000,
-			bp,
-			flags | ((bp->b_flags & B_READ) ?
-			    SCSI_DATA_IN : SCSI_DATA_OUT))
-		    == SUCCESSFULLY_QUEUED) {
-			odqueues++;
-			if(od->dkunit >= 0) {
-				dk_xfer[od->dkunit]++;
-				dk_seek[od->dkunit]++; /* don't know */
-				dk_wds[od->dkunit] += bp->b_bcount >> 6;
-			}
-		} else {
-bad:
+		od->blkno = bp->b_pblkno * (secsize/DEV_BSIZE) +
+			bp->b_blkno % (secsize/DEV_BSIZE);
+		od->nblk = bp->b_bcount / DEV_BSIZE;
+		od->data = bp->b_data;
+		od->ioflags = flags;
+		if (od_io (sc_link, bp) < 0) {
 			printf("od%ld: oops not queued\n", unit);
-			bp->b_error = EIO;
-			bp->b_flags |= B_ERROR;
-			biodone(bp);
+			goto bad;
+		}
+
+		odqueues++;
+		if(od->dkunit >= 0) {
+			dk_xfer[od->dkunit]++;
+			dk_seek[od->dkunit]++; /* don't know */
+			dk_wds[od->dkunit] += bp->b_bcount >> 6;
 		}
 	}
 }
>Audit-Trail:
>Unformatted:



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199801291035.NAA01877>