diff options
author | joerg <joerg@FreeBSD.org> | 1996-06-16 19:58:24 +0000 |
---|---|---|
committer | joerg <joerg@FreeBSD.org> | 1996-06-16 19:58:24 +0000 |
commit | 430ed8358f665cb8c94daed8af79b03feb618253 (patch) | |
tree | 61d438a0d22be7509fbff474187544485a46763b /sys | |
parent | 2ed1eb601cc4e9be6c14bf238d58b578b06a4b15 (diff) | |
download | FreeBSD-src-430ed8358f665cb8c94daed8af79b03feb618253.zip FreeBSD-src-430ed8358f665cb8c94daed8af79b03feb618253.tar.gz |
Miscellaneous cleanup and minor fixes by Shunsuke and by me.
. use new-style options
. introduce an option OD_AUTO_TURNOFF
. try to use the native geometry as reported by the drive instead of
a faked on -- MOs do have a ``classical'' geometry
. make the scsi_start_unit() actually working
. some cosmetic fixes
Submitted by: akiyama@kme.mei.co.jp (Shunsuke Akiyama)
Diffstat (limited to 'sys')
-rw-r--r-- | sys/conf/options | 6 | ||||
-rw-r--r-- | sys/scsi/od.c | 237 |
2 files changed, 147 insertions, 96 deletions
diff --git a/sys/conf/options b/sys/conf/options index df0c9a1..678321e 100644 --- a/sys/conf/options +++ b/sys/conf/options @@ -1,4 +1,4 @@ -# $Id: options,v 1.13 1996/05/31 00:20:28 peter Exp $ +# $Id: options,v 1.14 1996/06/12 19:33:49 gpalmer Exp $ # Option name filename @@ -59,6 +59,10 @@ NBUF opt_param.h SCSI_REPORT_GEOMETRY opt_scsi.h SCSI_DELAY opt_scsi.h +# Options used only in scsi/od.c. +OD_BOGUS_NOT_READY opt_od.h +OD_AUTO_TURNOFF opt_od.h + # Resource limits. CHILD_MAX opt_rlimit.h OPEN_MAX opt_rlimit.h diff --git a/sys/scsi/od.c b/sys/scsi/od.c index ec39429..610fe9a 100644 --- a/sys/scsi/od.c +++ b/sys/scsi/od.c @@ -28,7 +28,7 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * - * $Id: od.c,v 1.16 1996/05/19 19:26:21 joerg Exp $ + * $Id: od.c,v 1.15.1.3 1996/05/06 15:14:57 shun Exp $ */ /* @@ -39,13 +39,25 @@ * If drive returns sense key as 0x02 with vendor specific additional * sense code (ASC) and additional sense code qualifier (ASCQ), or * illegal ASC and ASCQ. This cause an error (NOT READY) and retrying. - * To suppress this, uncomment this. + * To suppress this, uncomment following. + * Or put "options OD_BOGUS_NOT_READY" entry into your kernel + * configuration file. * #define OD_BOGUS_NOT_READY */ +/* + * For an automatic spindown, try this. Again, preferrably as an + * option in your config file. + * WARNING! Use at your own risk. Joerg's ancient SONY SMO drive + * groks it fine, while Shunsuke's Fujitsu chokes on it and times + * out. +#define OD_AUTO_TURNOFF + */ + #include "opt_bounce.h" #include "opt_scsi.h" +#include "opt_od.h" #define SPLOD splbio #include <sys/types.h> @@ -94,10 +106,11 @@ struct scsi_data { #define ODINIT 0x04 /* device has been init'd */ struct disk_parms { u_char heads; /* Number of heads */ - u_int16_t cyls; /* Number of cylinders */ - u_char sectors; /* dubious *//* Number of sectors/track */ + u_int16_t cyls; /* Number of cylinders (ficticous) */ + u_int16_t sectors; /* Number of sectors/track */ u_int16_t secsiz; /* Number of bytes/sector */ u_int32_t disksize; /* total number sectors */ + u_int16_t rpm; /* medium rotation rate */ } params; struct diskslices *dk_slices; /* virtual drives */ struct buf_queue_head buf_queue; @@ -110,8 +123,6 @@ struct scsi_data { #endif }; -static void od_get_geometry __P((u_int32_t, u_int16_t *, - u_char *, u_char *)); static errval od_get_parms __P((int unit, int flags)); #ifdef notyet static errval od_reassign_blocks __P((int unit, int block)); @@ -242,6 +253,8 @@ odattach(struct scsi_link *sc_link) * the drive. We cannot use interrupts yet, so the * request must specify this. */ + scsi_start_unit(sc_link, SCSI_NOSLEEP | SCSI_NOMASK + | SCSI_ERR_OK | SCSI_SILENT); od_get_parms(unit, SCSI_NOSLEEP | SCSI_NOMASK | SCSI_SILENT); /* * if we don't have actual parameters, assume 512 bytes/sec @@ -263,9 +276,12 @@ odattach(struct scsi_link *sc_link) #endif { sc_print_addr(sc_link); - printf("with %d cyls, %d heads, and an average %d sectors/track", + printf("with approximate %d cyls, %d heads, and %d sectors/track", dp->cyls, dp->heads, dp->sectors); } +#ifdef OD_AUTO_TURNOFF + scsi_stop_unit(sc_link, 0, SCSI_ERR_OK | SCSI_SILENT); +#endif /* OD_AUTO_TURNOFF */ od->flags |= ODINIT; od_registerdev(unit); @@ -322,18 +338,25 @@ od_open(dev, mode, fmt, p, sc_link) dev, unit, PARTITION(dev))); /* - * Check that it is still responding and ok. if the media has - * been changed this will result in a "unit attention" error - * which the error code will disregard because the SDEV_OPEN - * or SDEV_MEDIA_LOADED flag is not yet set. Makes sure that - * we know it if the media has been changed.. + * Try to clear "Unit Attention" condition, when media had + * been changed before. + * This operation also clears the SDEV_MEDIA_LOADED flag in its + * error handling routine. */ scsi_test_unit_ready(sc_link, SCSI_SILENT); /* - * If it's been invalidated, then forget the label + * Try to start the drive (ignore failure). */ + scsi_start_unit(sc_link, SCSI_ERR_OK | SCSI_SILENT); + scsi_prevent(sc_link, PR_PREVENT, SCSI_ERR_OK | SCSI_SILENT); + + SC_DEBUG(sc_link, SDEV_DB3, ("'start' attempted ")); + sc_link->flags |= SDEV_OPEN; /* unit attn becomes an err now */ + /* + * If it's been invalidated, then forget the label. + */ if (!(sc_link->flags & SDEV_MEDIA_LOADED)) { /* * If somebody still has it open, then forbid re-entry. @@ -358,14 +381,6 @@ od_open(dev, mode, fmt, p, sc_link) SC_DEBUG(sc_link, SDEV_DB3, ("device present\n")); /* - * In case it is a funny one, tell it to start - * not needed for most hard drives (ignore failure) - */ - scsi_start_unit(sc_link, SCSI_ERR_OK | SCSI_SILENT); - scsi_prevent(sc_link, PR_PREVENT, SCSI_ERR_OK | SCSI_SILENT); - SC_DEBUG(sc_link, SDEV_DB3, ("'start' attempted ")); - - /* * Load the physical device parameters */ errcode = od_get_parms(unit, 0); /* sets SDEV_MEDIA_LOADED */ @@ -395,6 +410,7 @@ od_open(dev, mode, fmt, p, sc_link) label.d_ntracks = od->params.heads; label.d_ncylinders = od->params.cyls; label.d_secpercyl = od->params.heads * od->params.sectors; + label.d_rpm = od->params.rpm; /* maybe wrong */ if (label.d_secpercyl == 0) label.d_secpercyl = 64*32; /* XXX as long as it's not 0 @@ -416,6 +432,9 @@ od_open(dev, mode, fmt, p, sc_link) bad: if (!dsisopen(od->dk_slices)) { scsi_prevent(sc_link, PR_ALLOW, SCSI_ERR_OK | SCSI_SILENT); +#ifdef OD_AUTO_TURNOFF + scsi_stop_unit(sc_link, 0, SCSI_ERR_OK | SCSI_SILENT); +#endif /* OD_AUTO_TURNOFF */ sc_link->flags &= ~SDEV_OPEN; } return errcode; @@ -439,6 +458,9 @@ od_close(dev, fflag, fmt, p, sc_link) dsclose(dev, fmt, od->dk_slices); if (!dsisopen(od->dk_slices)) { scsi_prevent(sc_link, PR_ALLOW, SCSI_SILENT | SCSI_ERR_OK); +#ifdef OD_AUTO_TURNOFF + scsi_stop_unit(sc_link, 0, SCSI_ERR_OK | SCSI_SILENT); +#endif /* OD_AUTO_TURNOFF */ sc_link->flags &= ~SDEV_OPEN; } return 0; @@ -600,12 +622,8 @@ odstart(u_int32_t unit, u_int32_t flags) */ cmd.op_code = (bp->b_flags & B_READ) ? READ_BIG : WRITE_BIG; - cmd.addr_3 = (blkno & 0xff000000UL) >> 24; - cmd.addr_2 = (blkno & 0xff0000) >> 16; - cmd.addr_1 = (blkno & 0xff00) >> 8; - cmd.addr_0 = blkno & 0xff; - cmd.length2 = (nblk & 0xff00) >> 8; - cmd.length1 = (nblk & 0xff); + 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. @@ -668,6 +686,7 @@ od_ioctl(dev_t dev, int cmd, caddr_t addr, int flag, struct proc *p, break; case CDIOCEJECT: error = scsi_stop_unit(sc_link, 1, 0); + sc_link->flags &= ~SDEV_MEDIA_LOADED; break; case CDIOCALLOW: error = scsi_prevent(sc_link, PR_ALLOW, 0); @@ -699,47 +718,114 @@ od_size(unit, flags) int unit, flags; { struct scsi_read_cap_data rdcap; - struct scsi_read_capacity scsi_cmd; - u_int32_t size; - u_int32_t secsize; + struct scsi_read_capacity rdcap_cmd; struct scsi_link *sc_link = SCSI_LINK(&od_switch, unit); struct scsi_data *od = sc_link->sd; + struct scsi_mode_sense mdsense_cmd; + struct scsi_mode_sense_data { + struct scsi_mode_header header; + struct blk_desc blk_desc; + union disk_pages pages; + } scsi_sense; /* * make up a scsi command and ask the scsi driver to do * it for you. */ - bzero(&scsi_cmd, sizeof(scsi_cmd)); - scsi_cmd.op_code = READ_CAPACITY; + bzero(&rdcap_cmd, sizeof(rdcap_cmd)); + rdcap_cmd.op_code = READ_CAPACITY; /* * If the command works, interpret the result as a 4 byte * number of blocks */ if (scsi_scsi_cmd(sc_link, - (struct scsi_generic *) &scsi_cmd, - sizeof(scsi_cmd), + (struct scsi_generic *) &rdcap_cmd, + sizeof(rdcap_cmd), (u_char *) & rdcap, sizeof(rdcap), OD_RETRIES, - 20000, + 10000, NULL, flags | SCSI_DATA_IN) != 0) { return 0; } else { - size = rdcap.addr_0; - size += rdcap.addr_1 << 8; - size += rdcap.addr_2 << 16; - size += rdcap.addr_3 << 24; - size += 1; - secsize = rdcap.length_0; - secsize += rdcap.length_1 << 8; - secsize += rdcap.length_2 << 16; - secsize += rdcap.length_3 << 24; + od->params.disksize = scsi_4btou(&rdcap.addr_3) + 1; + od->params.secsiz = scsi_4btou(&rdcap.length_3); } - od->params.disksize = size; - od->params.secsiz = secsize; - return size; + + /* + * do a "mode sense page 4" (rigid disk drive geometry) + */ + bzero(&mdsense_cmd, sizeof(mdsense_cmd)); + mdsense_cmd.op_code = MODE_SENSE; + mdsense_cmd.page = 4; + mdsense_cmd.length = 0x20; + /* + * If the command worked, use the results to fill out + * the parameter structure + */ + if (scsi_scsi_cmd(sc_link, + (struct scsi_generic *) &mdsense_cmd, + sizeof(mdsense_cmd), + (u_char *) & scsi_sense, + sizeof(scsi_sense), + OD_RETRIES, + 10000, + NULL, + flags | SCSI_SILENT | SCSI_DATA_IN) != 0) { + + /* default to a ficticous geometry */ + od->params.heads = 64; + } else { + SC_DEBUG(sc_link, SDEV_DB3, + ("%ld cyls, %d heads, %d rpm\n", + scsi_3btou(&scsi_sense.pages.rigid_geometry.ncyl_2), + scsi_sense.pages.rigid_geometry.nheads, + scsi_2btou(&scsi_sense.pages.rigid_geometry.medium_rot_rate_1))); + + od->params.heads = scsi_sense.pages.rigid_geometry.nheads; + if (od->params.heads == 0) + od->params.heads = 64; /* ficticous */ + od->params.rpm = + scsi_2btou(&scsi_sense.pages.rigid_geometry.medium_rot_rate_1); + } + + /* + * do a "mode sense page 3" (format device) + */ + bzero(&mdsense_cmd, sizeof(mdsense_cmd)); + mdsense_cmd.op_code = MODE_SENSE; + mdsense_cmd.page = 3; + mdsense_cmd.length = 0x20; + /* + * If the command worked, use the results to fill out + * the parameter structure + */ + if (scsi_scsi_cmd(sc_link, + (struct scsi_generic *) &mdsense_cmd, + sizeof(mdsense_cmd), + (u_char *) & scsi_sense, + sizeof(scsi_sense), + OD_RETRIES, + 10000, + NULL, + flags | SCSI_SILENT | SCSI_DATA_IN) != 0) { + + /* default to a ficticous geometry */ + od->params.sectors = 32; + } else { + SC_DEBUG(sc_link, SDEV_DB3, + ("%d secs\n", + scsi_2btou(&scsi_sense.pages.disk_format.ph_sec_t_1))); + + od->params.sectors = + scsi_2btou(&scsi_sense.pages.disk_format.ph_sec_t_1); + if (od->params.sectors == 0) + od->params.sectors = 32; /* ficticous */ + } + + return od->params.disksize; } #ifdef notyet @@ -760,10 +846,7 @@ od_reassign_blocks(unit, block) rbdata.length_msb = 0; rbdata.length_lsb = sizeof(rbdata.defect_descriptor[0]); - rbdata.defect_descriptor[0].dlbaddr_3 = ((block >> 24) & 0xff); - rbdata.defect_descriptor[0].dlbaddr_2 = ((block >> 16) & 0xff); - rbdata.defect_descriptor[0].dlbaddr_1 = ((block >> 8) & 0xff); - rbdata.defect_descriptor[0].dlbaddr_0 = ((block) & 0xff); + scsi_uto4b(block, &rbdata.defect_descriptor[0].dlbaddr_3); return scsi_scsi_cmd(sc_link, (struct scsi_generic *) &scsi_cmd, @@ -776,47 +859,6 @@ od_reassign_blocks(unit, block) SCSI_DATA_OUT); } #endif -#define b2tol(a) (((unsigned)(a##_1) << 8) + (unsigned)a##_0 ) - -/* - * Get ficticious geometry from total sectors. - */ -static void -od_get_geometry(total, cp, hp, sp) - u_int32_t total; - u_int16_t *cp; - u_char *hp; - u_char *sp; -{ - u_int16_t cyls; - u_char heads; - u_char sectors; - - heads = 64; - sectors = 32; - - if (total != 0) { - cyls = total / (64 * 32); - while (cyls >= 1024) { - if (heads < 128) { - heads *= 2; - } else { - heads = 255; - sectors = 63; - cyls = total / (heads * sectors); - break; - } - cyls = total / (heads * sectors); - } - if (total > (cyls * heads * sectors)) - cyls++; - } else - cyls = 0; - - *cp = cyls; - *hp = heads; - *sp = sectors; -} /* * Get the scsi driver to send a full inquiry to the @@ -843,10 +885,15 @@ od_get_parms(unit, flags) * Use ficticious geometry, this depends on the size of medium. */ sectors = od_size(unit, flags); - /* od_size() sets secsiz and disksize */ + /* od_size() sets secsiz, disksize, sectors, and heads */ - od_get_geometry(sectors, &disk_parms->cyls, &disk_parms->heads, - &disk_parms->sectors); + /* ficticous number of cylinders, so that C*H*S <= total */ + if (disk_parms->sectors != 0 && disk_parms->heads != 0) { + disk_parms->cyls = + sectors / (disk_parms->sectors * disk_parms->heads); + } else { + disk_parms->cyls = 0; + } if (sectors != 0) { sc_link->flags |= SDEV_MEDIA_LOADED; |