I started off trying to add a 'real' DIOCGPDINFO to cd(4). I chose
to experiment on an hppa install image. And it didn't work because
cd(4) trusts the disk label rather than the device characteristics
when it comes to calculating i/o address and size.
It seems clear to me that we should prefer the physical characteristics
of the device rather than the 'historical' data of the disklabel
at least when it comes to building the physical i/o.
Now, the partition sizes and offsets in a disk label are in d_secsize
units so the offsets at least need to be converted to the device
sector size.
Also re-arrange the order and types of the 'params' structure.
Works for me (tm).
.... Ken
Index: cd.c
===================================================================
RCS file: /cvs/src/sys/scsi/cd.c,v
retrieving revision 1.191
diff -u -p -r1.191 cd.c
--- cd.c 12 Sep 2010 01:54:48 -0000 1.191
+++ cd.c 12 Sep 2010 02:21:10 -0000
@@ -108,8 +108,8 @@ struct cd_softc {
#define CDF_WAITING 0x100
struct scsi_link *sc_link; /* contains our targ, lun, etc. */
struct cd_parms {
- u_int32_t secsize;
daddr64_t disksize; /* total number sectors */
+ u_int32_t secsize; /* size of sectors in bytes */
} params;
struct bufq sc_bufq;
struct scsi_xshandler sc_xsh;
@@ -481,6 +481,7 @@ cdstrategy(struct buf *bp)
{
struct cd_softc *sc;
int s;
+ u_int32_t d_secsize, secsize;
sc = cdlookup(DISKUNIT(bp->b_dev));
if (sc == NULL) {
@@ -494,6 +495,10 @@ cdstrategy(struct buf *bp)
SC_DEBUG(sc->sc_link, SDEV_DB2, ("cdstrategy: %ld bytes @ blk %d\n",
bp->b_bcount, bp->b_blkno));
+
+ d_secsize = sc->sc_dk.dk_label->d_secsize;
+ secsize = sc->params.secsize;
+
/*
* If the device has been made invalid, error out
* maybe the media changed, or no media loaded
@@ -503,12 +508,23 @@ cdstrategy(struct buf *bp)
goto bad;
}
/*
- * The transfer must be a whole number of blocks.
+ * The transfer must be a whole number of sectors.
*/
- if ((bp->b_bcount % sc->sc_dk.dk_label->d_secsize) != 0) {
+ if ((bp->b_bcount % secsize) != 0) {
+ bp->b_error = EINVAL;
+ goto bad;
+ }
+
+ /* Validate convertability of label sectors and device sectors. */
+ if (d_secsize < secsize && (secsize % d_secsize == 0))
+ ;
+ else if (d_secsize > secsize && (d_secsize % secsize == 0))
+ ;
+ else if (d_secsize != secsize) {
bp->b_error = EINVAL;
goto bad;
}
+
/*
* If it's a null transfer, return immediately
*/
@@ -573,9 +589,10 @@ cdstart(struct scsi_xfer *xs)
struct buf *bp;
struct scsi_rw_big *cmd_big;
struct scsi_rw *cmd_small;
- int secno, nsecs;
struct partition *p;
+ daddr64_t secno, nsecs;
int read;
+ u_int32_t d_secsize, secsize;
SC_DEBUG(sc_link, SDEV_DB2, ("cdstart\n"));
@@ -584,6 +601,9 @@ cdstart(struct scsi_xfer *xs)
return;
}
+ d_secsize = sc->sc_dk.dk_label->d_secsize;
+ secsize = sc->params.secsize;
+
/*
* If the device has become invalid, abort all the
* reads and writes until all files have been closed and
@@ -607,11 +627,18 @@ cdstart(struct scsi_xfer *xs)
* First, translate the block to absolute and put it in terms
* of the logical blocksize of the device.
*/
- secno =
- bp->b_blkno / (sc->sc_dk.dk_label->d_secsize / DEV_BSIZE);
+ secno = bp->b_blkno / (secsize / DEV_BSIZE);
+ nsecs = howmany(bp->b_bcount, secsize);
p = &sc->sc_dk.dk_label->d_partitions[DISKPART(bp->b_dev)];
- secno += DL_GETPOFFSET(p);
- nsecs = howmany(bp->b_bcount, sc->sc_dk.dk_label->d_secsize);
+
+ /* Calculate partition offset in secsize units. */
+ p = &sc->sc_dk.dk_label->d_partitions[DISKPART(bp->b_dev)];
+ if (d_secsize < secsize)
+ secno += DL_GETPOFFSET(p) / (secsize / d_secsize);
+ else if (d_secsize > secsize)
+ secno += DL_GETPOFFSET(p) * (d_secsize / secsize);
+ else
+ secno += DL_GETPOFFSET(p);
read = (bp->b_flags & B_READ);
@@ -754,7 +781,7 @@ cdminphys(struct buf *bp)
* in a 10-byte read/write actually means 0 blocks.
*/
if (sc->sc_flags & CDF_ANCIENT) {
- max = sc->sc_dk.dk_label->d_secsize * 0xff;
+ max = sc->params.secsize * 0xff;
if (bp->b_bcount > max)
bp->b_bcount = max;
@@ -850,8 +877,12 @@ cdioctl(dev_t dev, u_long cmd, caddr_t a
bcopy(lp, sc->sc_dk.dk_label, sizeof(*lp));
free(lp, M_TEMP);
break;
- case DIOCGDINFO:
+
case DIOCGPDINFO:
+ cdgetdisklabel(dev, sc, (struct disklabel *)addr, 1);
+ break;
+
+ case DIOCGDINFO:
*(struct disklabel *)addr = *(sc->sc_dk.dk_label);
break;
Index: sd.c
===================================================================
RCS file: /cvs/src/sys/scsi/sd.c,v
retrieving revision 1.214
diff -u -p -r1.214 sd.c
--- sd.c 12 Sep 2010 02:05:54 -0000 1.214
+++ sd.c 12 Sep 2010 02:21:11 -0000
@@ -530,6 +530,7 @@ sdstrategy(struct buf *bp)
{
struct sd_softc *sc;
int s;
+ u_int32_t d_secsize, secsize;
sc = sdlookup(DISKUNIT(bp->b_dev));
if (sc == NULL) {
@@ -543,6 +544,10 @@ sdstrategy(struct buf *bp)
SC_DEBUG(sc->sc_link, SDEV_DB2, ("sdstrategy: %ld bytes @ blk %d\n",
bp->b_bcount, bp->b_blkno));
+
+ d_secsize = sc->sc_dk.dk_label->d_secsize;
+ secsize = sc->params.secsize;
+
/*
* If the device has been made invalid, error out
*/
@@ -562,10 +567,21 @@ sdstrategy(struct buf *bp)
/*
* The transfer must be a whole number of sectors.
*/
- if ((bp->b_bcount % sc->sc_dk.dk_label->d_secsize) != 0) {
+ if ((bp->b_bcount % secsize) != 0) {
bp->b_error = EINVAL;
goto bad;
}
+
+ /* Validate convertability of label sectors and device sectors. */
+ if (d_secsize < secsize && (secsize % d_secsize == 0))
+ ;
+ else if (d_secsize > secsize && (d_secsize % secsize == 0))
+ ;
+ else if (d_secsize != secsize) {
+ bp->b_error = EINVAL;
+ goto bad;
+ }
+
/*
* Do bounds checking, adjust transfer. if error, process.
* If end of partition, just return.
@@ -667,10 +683,11 @@ sdstart(struct scsi_xfer *xs)
struct scsi_link *link = xs->sc_link;
struct sd_softc *sc = link->device_softc;
struct buf *bp;
+ struct partition *p;
daddr64_t secno;
int nsecs;
int read;
- struct partition *p;
+ u_int32_t d_secsize, secsize;
if (sc->flags & SDF_DYING) {
scsi_xs_put(xs);
@@ -688,10 +705,21 @@ sdstart(struct scsi_xfer *xs)
return;
}
- secno = bp->b_blkno / (sc->sc_dk.dk_label->d_secsize / DEV_BSIZE);
+ d_secsize = sc->sc_dk.dk_label->d_secsize;
+ secsize = sc->params.secsize;
+
+ secno = bp->b_blkno / (secsize / DEV_BSIZE);
+ nsecs = howmany(bp->b_bcount, secsize);
+
+ /* Calculate partition offset in secsize units. */
p = &sc->sc_dk.dk_label->d_partitions[DISKPART(bp->b_dev)];
- secno += DL_GETPOFFSET(p);
- nsecs = howmany(bp->b_bcount, sc->sc_dk.dk_label->d_secsize);
+ if (d_secsize < secsize)
+ secno += DL_GETPOFFSET(p) / (secsize / d_secsize);
+ else if (d_secsize > secsize)
+ secno += DL_GETPOFFSET(p) * (d_secsize / secsize);
+ else
+ secno += DL_GETPOFFSET(p);
+
read = bp->b_flags & B_READ;
/*
@@ -828,7 +856,7 @@ sdminphys(struct buf *bp)
* in a 10-byte read/write actually means 0 blocks.
*/
if (sc->flags & SDF_ANCIENT) {
- max = sc->sc_dk.dk_label->d_secsize * 0xff;
+ max = sc->params.secsize * 0xff;
if (bp->b_bcount > max)
bp->b_bcount = max;
@@ -905,6 +933,7 @@ sdioctl(dev_t dev, u_long cmd, caddr_t a
bcopy(lp, sc->sc_dk.dk_label, sizeof(*lp));
free(lp, M_TEMP);
goto exit;
+
case DIOCGPDINFO:
sdgetdisklabel(dev, sc, (struct disklabel *)addr, 1);
goto exit;
Index: sdvar.h
===================================================================
RCS file: /cvs/src/sys/scsi/sdvar.h,v
retrieving revision 1.34
diff -u -p -r1.34 sdvar.h
--- sdvar.h 12 Sep 2010 02:05:54 -0000 1.34
+++ sdvar.h 12 Sep 2010 02:21:11 -0000
@@ -64,11 +64,11 @@ struct sd_softc {
#define SDF_WAITING 0x80
struct scsi_link *sc_link; /* contains our targ, lun, etc. */
struct disk_parms {
- u_long heads; /* number of heads */
- u_long cyls; /* number of cylinders */
- u_long sectors; /* number of sectors/track */
- u_long secsize; /* number of bytes/sector */
daddr64_t disksize; /* total number sectors */
+ u_int32_t secsize; /* number of bytes/sector */
+ u_int32_t heads; /* number of heads */
+ u_int32_t cyls; /* number of cylinders */
+ u_int32_t sectors; /* number of sectors/track */
} params;
void *sc_sdhook; /* our shutdown hook */
struct timeout sc_timeout;