diff options
author | Constantine Sapuntzakis <csapuntz@cvs.openbsd.org> | 1999-07-25 07:09:21 +0000 |
---|---|---|
committer | Constantine Sapuntzakis <csapuntz@cvs.openbsd.org> | 1999-07-25 07:09:21 +0000 |
commit | c5091939f49bf18ce06780a7e49c968611317f11 (patch) | |
tree | 14ea0ba2b7d637c18fe007d908ef0886d939202f /sys/scsi/sd_scsi.c | |
parent | 7c82046e621c85d85b87aaa0519535530e5c9d83 (diff) |
Merge sd stuff from NetBSD-current. Helps with LS-120, ZIP
More SCSI logic from NetBSD-current
Some tape fixes. ATAPI tapes do not work yet for most operations.
Diffstat (limited to 'sys/scsi/sd_scsi.c')
-rw-r--r-- | sys/scsi/sd_scsi.c | 303 |
1 files changed, 303 insertions, 0 deletions
diff --git a/sys/scsi/sd_scsi.c b/sys/scsi/sd_scsi.c new file mode 100644 index 00000000000..fb230f79d23 --- /dev/null +++ b/sys/scsi/sd_scsi.c @@ -0,0 +1,303 @@ +/* $OpenBSD: sd_scsi.c,v 1.1 1999/07/25 07:09:19 csapuntz Exp $ */ +/* $NetBSD: sd_scsi.c,v 1.8 1998/10/08 20:21:13 thorpej Exp $ */ + +/*- + * Copyright (c) 1998 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Charles M. Hannum. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Originally written by Julian Elischer (julian@dialix.oz.au) + * for TRW Financial Systems for use under the MACH(2.5) operating system. + * + * TRW Financial Systems, in accordance with their agreement with Carnegie + * Mellon University, makes this software available to CMU to distribute + * or use in any manner that they see fit as long as this message is kept with + * the software. For this reason TFS also grants any other persons or + * organisations permission to use or modify this software. + * + * TFS supplies this software to be publicly redistributed + * on the understanding that TFS is not responsible for the correct + * functioning of this software in any circumstances. + * + * Ported to run under 386BSD by Julian Elischer (julian@dialix.oz.au) Sept 1992 + */ + +#include <sys/types.h> +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/buf.h> +#include <sys/malloc.h> +#include <sys/errno.h> +#include <sys/device.h> +#include <sys/disk.h> +#include <sys/conf.h> + +#include <scsi/scsi_all.h> +#include <scsi/scsi_disk.h> +#include <scsi/scsiconf.h> +#include <scsi/sdvar.h> + +struct sd_scsibus_mode_sense_data { + struct scsi_mode_header header; + struct scsi_blk_desc blk_desc; + union scsi_disk_pages pages; +}; + +static int sd_scsibus_mode_sense __P((struct sd_softc *, + struct sd_scsibus_mode_sense_data *, int, int)); +static int sd_scsibus_get_parms __P((struct sd_softc *, + struct disk_parms *, int)); +static int sd_scsibus_get_optparms __P((struct sd_softc *, + struct disk_parms *, int)); +static void sd_scsibus_flush __P((struct sd_softc *, int)); + +const struct sd_ops sd_scsibus_ops = { + sd_scsibus_get_parms, + sd_scsibus_flush, +}; + +static int +sd_scsibus_mode_sense(sd, scsi_sense, page, flags) + struct sd_softc *sd; + struct sd_scsibus_mode_sense_data *scsi_sense; + int page, flags; +{ + struct scsi_mode_sense scsi_cmd; + + /* + * Make sure the sense buffer is clean before we do + * the mode sense, so that checks for bogus values of + * 0 will work in case the mode sense fails. + */ + bzero(scsi_sense, sizeof(*scsi_sense)); + + bzero(&scsi_cmd, sizeof(scsi_cmd)); + scsi_cmd.opcode = MODE_SENSE; + scsi_cmd.page = page; + scsi_cmd.length = 0x20; + /* + * If the command worked, use the results to fill out + * the parameter structure + */ + return (scsi_scsi_cmd(sd->sc_link, + (struct scsi_generic *)&scsi_cmd, sizeof(scsi_cmd), + (u_char *)scsi_sense, sizeof(*scsi_sense), + SDRETRIES, 6000, NULL, flags | SCSI_DATA_IN | SCSI_SILENT)); +} + +static int +sd_scsibus_get_optparms(sd, dp, flags) + struct sd_softc *sd; + struct disk_parms *dp; + int flags; +{ + struct scsi_mode_sense scsi_cmd; + struct sd_scsibus_mode_sense_data scsi_sense; + u_long sectors; + int error; + + dp->blksize = 512; + if ((sectors = scsi_size(sd->sc_link, flags)) == 0) + return (SDGP_RESULT_OFFLINE); /* XXX? */ + + /* XXX + * It is better to get the following params from the + * mode sense page 6 only (optical device parameter page). + * However, there are stupid optical devices which does NOT + * support the page 6. Ghaa.... + */ + bzero(&scsi_cmd, sizeof(scsi_cmd)); + scsi_cmd.opcode = MODE_SENSE; + scsi_cmd.page = 0x3f; /* all pages */ + scsi_cmd.length = sizeof(struct scsi_mode_header) + + sizeof(struct scsi_blk_desc); + + if ((error = scsi_scsi_cmd(sd->sc_link, + (struct scsi_generic *)&scsi_cmd, sizeof(scsi_cmd), + (u_char *)&scsi_sense, sizeof(scsi_sense), SDRETRIES, + 6000, NULL, flags | SCSI_DATA_IN)) != 0) + return (SDGP_RESULT_OFFLINE); /* XXX? */ + + dp->blksize = _3btol(scsi_sense.blk_desc.blklen); + if (dp->blksize == 0) + dp->blksize = 512; + + /* + * Create a pseudo-geometry. + */ + dp->heads = 64; + dp->sectors = 32; + dp->cyls = sectors / (dp->heads * dp->sectors); + dp->disksize = sectors; + + return (SDGP_RESULT_OK); +} + +/* + * Get the scsi driver to send a full inquiry to the * device and use the + * results to fill out the disk parameter structure. + */ +static int +sd_scsibus_get_parms(sd, dp, flags) + struct sd_softc *sd; + struct disk_parms *dp; + int flags; +{ + struct sd_scsibus_mode_sense_data scsi_sense; + u_long sectors; + int page; + int error; + + dp->rot_rate = 3600; /* XXX any way of getting this? */ + + /* + * If offline, the SDEV_MEDIA_LOADED flag will be + * cleared by the caller if necessary. + */ + if (sd->type == T_OPTICAL) + return (sd_scsibus_get_optparms(sd, dp, flags)); + + if ((error = sd_scsibus_mode_sense(sd, &scsi_sense, page = 4, + flags)) == 0) { + SC_DEBUG(sd->sc_link, SDEV_DB3, + ("%d cyls, %d heads, %d precomp, %d red_write, %d land_zone\n", + _3btol(scsi_sense.pages.rigid_geometry.ncyl), + scsi_sense.pages.rigid_geometry.nheads, + _2btol(scsi_sense.pages.rigid_geometry.st_cyl_wp), + _2btol(scsi_sense.pages.rigid_geometry.st_cyl_rwc), + _2btol(scsi_sense.pages.rigid_geometry.land_zone))); + + /* + * KLUDGE!! (for zone recorded disks) + * give a number of sectors so that sec * trks * cyls + * is <= disk_size + * can lead to wasted space! THINK ABOUT THIS ! + */ + dp->heads = scsi_sense.pages.rigid_geometry.nheads; + dp->cyls = _3btol(scsi_sense.pages.rigid_geometry.ncyl); + dp->blksize = _3btol(scsi_sense.blk_desc.blklen); + + if (dp->heads == 0 || dp->cyls == 0) + goto fake_it; + + if (dp->blksize == 0) + dp->blksize = 512; + + sectors = scsi_size(sd->sc_link, flags); + dp->disksize = sectors; + sectors /= (dp->heads * dp->cyls); + dp->sectors = sectors; /* XXX dubious on SCSI */ + + return (SDGP_RESULT_OK); + } + + if ((error = sd_scsibus_mode_sense(sd, &scsi_sense, page = 5, + flags)) == 0) { + dp->heads = scsi_sense.pages.flex_geometry.nheads; + dp->cyls = _2btol(scsi_sense.pages.flex_geometry.ncyl); + dp->blksize = _3btol(scsi_sense.blk_desc.blklen); + dp->sectors = scsi_sense.pages.flex_geometry.ph_sec_tr; + dp->disksize = dp->heads * dp->cyls * dp->sectors; + if (dp->disksize == 0) + goto fake_it; + + if (dp->blksize == 0) + dp->blksize = 512; + + return (SDGP_RESULT_OK); + } + +fake_it: + if ((sd->sc_link->quirks & SDEV_NOMODESENSE) == 0) { + if (error == 0) + printf("%s: mode sense (%d) returned nonsense", + sd->sc_dev.dv_xname, page); + else + printf("%s: could not mode sense (4/5)", + sd->sc_dev.dv_xname); + printf("; using fictitious geometry\n"); + } + /* + * use adaptec standard fictitious geometry + * this depends on which controller (e.g. 1542C is + * different. but we have to put SOMETHING here..) + */ + sectors = scsi_size(sd->sc_link, flags); + dp->heads = 64; + dp->sectors = 32; + dp->cyls = sectors / (64 * 32); + dp->blksize = 512; + dp->disksize = sectors; + return (SDGP_RESULT_OK); +} + +static void +sd_scsibus_flush(sd, flags) + struct sd_softc *sd; + int flags; +{ + struct scsi_link *sc_link = sd->sc_link; + struct scsi_synchronize_cache sync_cmd; + + /* + * If the device is SCSI-2, issue a SYNCHRONIZE CACHE. + * We issue with address 0 length 0, which should be + * interpreted by the device as "all remaining blocks + * starting at address 0". We ignore ILLEGAL REQUEST + * in the event that the command is not supported by + * the device, and poll for completion so that we know + * that the cache has actually been flushed. + * + * Unless, that is, the device can't handle the SYNCHRONIZE CACHE + * command, as indicated by our quirks flags. + * + * XXX What about older devices? + */ + if ((sc_link->scsi_version & SID_ANSII) >= 2 && + (sc_link->quirks & SDEV_NOSYNCCACHE) == 0) { + bzero(&sync_cmd, sizeof(sync_cmd)); + sync_cmd.opcode = SYNCHRONIZE_CACHE; + + if (scsi_scsi_cmd(sc_link, + (struct scsi_generic *)&sync_cmd, sizeof(sync_cmd), + NULL, 0, SDRETRIES, 100000, NULL, + flags|SCSI_IGNORE_ILLEGAL_REQUEST)) + printf("%s: WARNING: cache synchronization failed\n", + sd->sc_dev.dv_xname); + else + sd->flags |= SDF_FLUSHING; + } +} |