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 | |
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')
-rw-r--r-- | sys/scsi/atapi_disk.h | 101 | ||||
-rw-r--r-- | sys/scsi/scsi_all.h | 19 | ||||
-rw-r--r-- | sys/scsi/scsi_base.c | 43 | ||||
-rw-r--r-- | sys/scsi/scsi_disk.h | 122 | ||||
-rw-r--r-- | sys/scsi/scsiconf.h | 16 | ||||
-rw-r--r-- | sys/scsi/sd.c | 430 | ||||
-rw-r--r-- | sys/scsi/sd_atapi.c | 145 | ||||
-rw-r--r-- | sys/scsi/sd_scsi.c | 303 | ||||
-rw-r--r-- | sys/scsi/sdvar.h | 106 | ||||
-rw-r--r-- | sys/scsi/st.c | 14 |
10 files changed, 1035 insertions, 264 deletions
diff --git a/sys/scsi/atapi_disk.h b/sys/scsi/atapi_disk.h new file mode 100644 index 00000000000..36b545a1c21 --- /dev/null +++ b/sys/scsi/atapi_disk.h @@ -0,0 +1,101 @@ +/* $OpenBSD: atapi_disk.h,v 1.1 1999/07/25 07:09:19 csapuntz Exp $ */ +/* $NetBSD: atapi_disk.h,v 1.3 1998/02/13 08:28:21 enami Exp $ */ + +/* + * Copyright 1998 + * Digital Equipment Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and conditions. + * Subject to these conditions, you may download, copy, install, + * use, modify and distribute this software in source and/or binary + * form. No title or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions as + * they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or logo of + * Digital Equipment Corporation. Neither the "Digital Equipment + * Corporation" name nor any trademark or logo of Digital Equipment + * Corporation may be used to endorse or promote products derived + * from this software without the prior written permission of + * Digital Equipment Corporation. + * + * 3) This software is provided "AS-IS" and any express or implied + * warranties, including but not limited to, any implied warranties + * of merchantability, fitness for a particular purpose, or + * non-infringement are disclaimed. In no event shall DIGITAL be + * liable for any damages whatsoever, and in particular, DIGITAL + * shall not be liable for special, indirect, consequential, or + * incidental damages or damages for lost profits, loss of + * revenue or loss of use, whether such damages arise in contract, + * negligence, tort, under statute, in equity, at law or otherwise, + * even if advised of the possibility of such damage. + */ + +/* + * Definitions of commands and structures specific to ATAPI disks. + * + * Chris Demetriou, January 10, 1998. + */ + +#define ATAPI_READ_FORMAT_CAPACITIES 0x23 +struct atapi_read_format_capacities { + u_int8_t opcode; + u_int8_t byte2; + u_int8_t reserved1[5]; + u_int8_t length[2]; + u_int8_t reserved2[3]; +}; + +struct atapi_capacity_list_header { + u_int8_t reserved[3]; + u_int8_t length; +}; + +struct atapi_capacity_descriptor { + u_int8_t nblks[4]; + u_int8_t byte5; + u_int8_t blklen[3]; +}; + +/* codes only valid in the current/maximum capacity descriptor */ +#define ATAPI_CAP_DESC_CODE_MASK 0x3 +/* reserved 0x0 */ +#define ATAPI_CAP_DESC_CODE_UNFORMATTED 0x1 +#define ATAPI_CAP_DESC_CODE_FORMATTED 0x2 +#define ATAPI_CAP_DESC_CODE_NONE 0x3 + +#define ATAPI_CAP_DESC_SIZE(n) \ + (sizeof(struct atapi_capacity_list_header) + \ + (n) * sizeof(struct atapi_capacity_descriptor)) +#define ATAPI_CAP_DESC_OFFSET_HEADER 0 +#define ATAPI_CAP_DESC_OFFSET_DESC(n) ATAPI_CAP_DESC_SIZE(n) + +struct atapi_flex_geometry_page { + u_int8_t pg_code; /* page code */ + u_int8_t pg_length; /* page length */ + u_int8_t xfr_rate[2]; /* transfer rate, Kb/sec */ + u_int8_t nheads; /* number of heads */ + u_int8_t ph_sec_tr; /* physical sectors per track */ + u_int8_t blklen[2]; /* block length (bytes per sector) */ + u_int8_t ncyl[2]; /* number of cylinders */ + u_int8_t reserved1[18]; + u_int8_t rot_rate[2]; /* medium rotation rate (RPM) */ +}; + +#define ATAPI_FLEX_GEOMETRY_PAGE 0x05 + +union atapi_sd_pages { + u_int8_t page_code; + struct atapi_flex_geometry_page flex_geometry; +}; + +struct atapi_sd_mode_data { + struct atapi_mode_header header; + union atapi_sd_pages pages; +}; + +#define FLEXGEOMETRYPAGESIZE \ + (sizeof(struct atapi_mode_header) + sizeof(struct atapi_flex_geometry_page)) diff --git a/sys/scsi/scsi_all.h b/sys/scsi/scsi_all.h index 746d6dbf086..09823d53085 100644 --- a/sys/scsi/scsi_all.h +++ b/sys/scsi/scsi_all.h @@ -1,4 +1,4 @@ -/* $OpenBSD: scsi_all.h,v 1.5 1997/04/14 04:09:06 downsj Exp $ */ +/* $OpenBSD: scsi_all.h,v 1.6 1999/07/25 07:09:19 csapuntz Exp $ */ /* $NetBSD: scsi_all.h,v 1.10 1996/09/12 01:57:17 thorpej Exp $ */ /* @@ -267,6 +267,23 @@ struct scsi_sense_data { /*32*/ u_int8_t extra_bytes[14]; }; +#define SKEY_NO_SENSE 0x00 +#define SKEY_RECOVERED_ERROR 0x01 +#define SKEY_NOT_READY 0x02 +#define SKEY_MEDIUM_ERROR 0x03 +#define SKEY_HARDWARE_ERROR 0x04 +#define SKEY_ILLEGAL_REQUEST 0x05 +#define SKEY_UNIT_ATTENTION 0x06 +#define SKEY_WRITE_PROTECT 0x07 +#define SKEY_BLANK_CHECK 0x08 +#define SKEY_VENDOR_UNIQUE 0x09 +#define SKEY_COPY_ABORTED 0x0A +#define SKEY_ABORTED_COMMAND 0x0B +#define SKEY_EQUAL 0x0C +#define SKEY_VOLUME_OVERFLOW 0x0D +#define SKEY_MISCOMPARE 0x0E +#define SKEY_RESERVED 0x0F + struct scsi_blk_desc { u_int8_t density; u_int8_t nblocks[3]; diff --git a/sys/scsi/scsi_base.c b/sys/scsi/scsi_base.c index 3387b1148f3..7c87c282b5e 100644 --- a/sys/scsi/scsi_base.c +++ b/sys/scsi/scsi_base.c @@ -1,4 +1,4 @@ -/* $OpenBSD: scsi_base.c,v 1.24 1999/04/20 19:04:34 weingart Exp $ */ +/* $OpenBSD: scsi_base.c,v 1.25 1999/07/25 07:09:19 csapuntz Exp $ */ /* $NetBSD: scsi_base.c,v 1.43 1997/04/02 02:29:36 mycroft Exp $ */ /* @@ -531,6 +531,7 @@ sc_err1(xs, async) break; case XS_SENSE: + case XS_SHORTSENSE: if ((error = scsi_interpret_sense(xs)) == ERESTART) { if (xs->error == XS_BUSY) { xs->error = XS_SENSE; @@ -573,6 +574,15 @@ sc_err1(xs, async) error = EIO; break; + case XS_RESET: + if (xs->retries) { + SC_DEBUG(xs->sc_link, SDEV_DB3, + ("restarting command destroyed by reset\n")); + goto retry; + } + error = EIO; + break; + default: sc_print_addr(xs->sc_link); printf("unknown error category from scsi driver\n"); @@ -632,7 +642,7 @@ scsi_interpret_sense(xs) if (sc_link->device->err_handler) { SC_DEBUG(sc_link, SDEV_DB2, ("calling private err_handler()\n")); error = (*sc_link->device->err_handler) (xs); - if (error != -1) + if (error != SCSIRET_CONTINUE) return error; /* error >= 0 better ? */ } /* otherwise use the default */ @@ -653,14 +663,14 @@ scsi_interpret_sense(xs) key = sense->flags & SSD_KEY; switch (key) { - case 0x0: /* NO SENSE */ - case 0x1: /* RECOVERED ERROR */ + case SKEY_NO_SENSE: + case SKEY_RECOVERED_ERROR: if (xs->resid == xs->datalen) xs->resid = 0; /* not short read */ - case 0xc: /* EQUAL */ + case SKEY_EQUAL: error = 0; break; - case 0x2: /* NOT READY */ + case SKEY_NOT_READY: if ((sc_link->flags & SDEV_REMOVABLE) != 0) sc_link->flags &= ~SDEV_MEDIA_LOADED; if ((xs->flags & SCSI_IGNORE_NOT_READY) != 0) @@ -678,14 +688,17 @@ scsi_interpret_sense(xs) return EIO; error = EIO; break; - case 0x5: /* ILLEGAL REQUEST */ + case SKEY_ILLEGAL_REQUEST: if ((xs->flags & SCSI_IGNORE_ILLEGAL_REQUEST) != 0) return 0; if ((xs->flags & SCSI_SILENT) != 0) return EIO; error = EINVAL; break; - case 0x6: /* UNIT ATTENTION */ + case SKEY_UNIT_ATTENTION: + if (sense->add_sense_code == 0x29 && + sense->add_sense_code_qual == 0x00) + return (ERESTART); /* device or bus reset */ if ((sc_link->flags & SDEV_REMOVABLE) != 0) sc_link->flags &= ~SDEV_MEDIA_LOADED; if ((xs->flags & SCSI_IGNORE_MEDIA_CHANGE) != 0 || @@ -696,23 +709,25 @@ scsi_interpret_sense(xs) return EIO; error = EIO; break; - case 0x7: /* DATA PROTECT */ + case SKEY_WRITE_PROTECT: error = EROFS; break; - case 0x8: /* BLANK CHECK */ + case SKEY_BLANK_CHECK: error = 0; break; - case 0xb: /* COMMAND ABORTED */ + case SKEY_ABORTED_COMMAND: error = ERESTART; break; - case 0xd: /* VOLUME OVERFLOW */ + case SKEY_VOLUME_OVERFLOW: error = ENOSPC; break; default: error = EIO; break; } - scsi_print_sense(xs, 0); + + if ((xs->flags & SCSI_SILENT) == 0) + scsi_print_sense(xs, 0); return error; @@ -721,7 +736,7 @@ scsi_interpret_sense(xs) */ default: sc_print_addr(sc_link); - printf("error code %d", + printf("Sense Error Code %d", sense->error_code & SSD_ERRCODE); if ((sense->error_code & SSD_ERRCODE_VALID) != 0) { struct scsi_sense_data_unextended *usense = diff --git a/sys/scsi/scsi_disk.h b/sys/scsi/scsi_disk.h index 002812619c7..33c207d6bb7 100644 --- a/sys/scsi/scsi_disk.h +++ b/sys/scsi/scsi_disk.h @@ -1,4 +1,4 @@ -/* $OpenBSD: scsi_disk.h,v 1.6 1997/04/14 04:09:09 downsj Exp $ */ +/* $OpenBSD: scsi_disk.h,v 1.7 1999/07/25 07:09:19 csapuntz Exp $ */ /* $NetBSD: scsi_disk.h,v 1.10 1996/07/05 16:19:05 christos Exp $ */ /* @@ -57,6 +57,87 @@ #ifndef _SCSI_SCSI_DISK_H #define _SCSI_SCSI_DISK_H 1 +/* + * XXX Is this also used by ATAPI? + */ +#define FORMAT_UNIT 0x04 +struct scsi_format_unit { + u_int8_t opcode; + u_int8_t flags; +#define SFU_DLF_MASK 0x07 +#define SFU_CMPLST 0x08 +#define SFU_FMTDATA 0x10 + u_int8_t vendor_specific; + u_int8_t interleave[2]; + u_int8_t control; +}; + +/* + * If the FmtData bit is set, a FORMAT UNIT parameter list is transfered + * to the target during the DATA OUT phase. The parameter list includes + * + * Defect list header + * Initialization pattern descriptor (if any) + * Defect descriptor(s) (if any) + */ + +struct scsi_format_unit_defect_list_header { + u_int8_t reserved; + u_int8_t flags; +#define DLH_VS 0x01 /* vendor specific */ +#define DLH_IMMED 0x02 /* immediate return */ +#define DLH_DSP 0x04 /* disable saving parameters */ +#define DLH_IP 0x08 /* initialization pattern */ +#define DLH_STPF 0x10 /* stop format */ +#define DLH_DCRT 0x20 /* disable certification */ +#define DLH_DPRY 0x40 /* disable primary */ +#define DLH_FOV 0x80 /* format options valid */ + u_int8_t defect_lst_len[2]; +}; + +/* + * See Table 117 of the SCSI-2 specification for a description of + * the IP modifier. + */ +struct scsi_initialization_pattern_descriptor { + u_int8_t ip_modifier; + u_int8_t pattern_type; +#define IP_TYPE_DEFAULT 0x01 +#define IP_TYPE_REPEAT 0x01 + /* 0x02 -> 0x7f: reserved */ + /* 0x80 -> 0xff: vendor-specific */ + u_int8_t pattern_length[2]; +#if 0 + u_int8_t pattern[...]; +#endif +}; + +/* + * Defect desciptors. These are used as the defect lists in the FORMAT UNIT + * and READ DEFECT DATA commands, and as the translate page of the + * SEND DIAGNOSTIC and RECEIVE DIAGNOSTIC RESULTS commands. + */ + +/* Block format */ +struct scsi_defect_descriptor_bf { + u_int8_t block_address[4]; +}; + +/* Bytes from index format */ +struct scsi_defect_descriptor_bfif { + u_int8_t cylinder[2]; + u_int8_t head; + u_int8_t bytes_from_index[2]; +}; + +/* Physical sector format */ +struct scsi_defect_descriptor_psf { + u_int8_t cylinder[2]; + u_int8_t head; + u_int8_t sector[2]; +}; + + struct scsi_reassign_blocks { u_int8_t opcode; u_int8_t byte2; @@ -64,6 +145,17 @@ struct scsi_reassign_blocks { u_int8_t control; }; +/* + * XXX Is this also used by ATAPI? + */ +#define REZERO_UNIT 0x01 +struct scsi_rezero_unit { + u_int8_t opcode; + u_int8_t byte2; + u_int8_t reserved[3]; + u_int8_t control; +}; + struct scsi_rw { u_int8_t opcode; u_int8_t addr[3]; @@ -102,21 +194,37 @@ struct scsi_start_stop { }; +/* + * XXX Does ATAPI have an equivalent? + */ +#define SYNCHRONIZE_CACHE 0x35 +struct scsi_synchronize_cache { + u_int8_t opcode; + u_int8_t flags; +#define SSC_RELADR 0x01 +#define SSC_IMMED 0x02 + u_int8_t addr[4]; + u_int8_t reserved; + u_int8_t length[2]; + u_int8_t control; +}; + + /* * Opcodes */ - #define REASSIGN_BLOCKS 0x07 #define READ_COMMAND 0x08 -#define WRITE_COMMAND 0x0a -#define MODE_SELECT 0x15 +#define WRITE_COMMAND 0x0a +#define MODE_SELECT 0x15 #define MODE_SENSE 0x1a #define START_STOP 0x1b -#define PREVENT_ALLOW 0x1e -#define READ_CAPACITY 0x25 +#define PREVENT_ALLOW 0x1e +#define READ_CAPACITY 0x25 #define READ_BIG 0x28 #define WRITE_BIG 0x2a +#define SYNCHRONIZE_CACHE 0x35 struct scsi_read_cap_data { @@ -132,7 +240,7 @@ struct scsi_reassign_blocks_data { } defect_descriptor[1]; }; -union disk_pages { +union scsi_disk_pages { #define DISK_PGCODE 0x3F /* only 6 bits valid */ struct page_disk_format { u_int8_t pg_code; /* page code (should be 3) */ diff --git a/sys/scsi/scsiconf.h b/sys/scsi/scsiconf.h index 6a0520f6c35..7c7333e50a1 100644 --- a/sys/scsi/scsiconf.h +++ b/sys/scsi/scsiconf.h @@ -1,4 +1,4 @@ -/* $OpenBSD: scsiconf.h,v 1.18 1999/07/20 06:21:59 csapuntz Exp $ */ +/* $OpenBSD: scsiconf.h,v 1.19 1999/07/25 07:09:19 csapuntz Exp $ */ /* $NetBSD: scsiconf.h,v 1.35 1997/04/02 02:29:38 mycroft Exp $ */ /* @@ -109,6 +109,15 @@ struct scsi_adapter { #define ESCAPE_NOT_SUPPORTED 3 /* + * Device Specific Sense Handlers return either an errno + * or one of these three items. + */ + +#define SCSIRET_NOERROR 0 /* No Error */ +#define SCSIRET_RETRY -1 /* Retry the command that got this sense */ +#define SCSIRET_CONTINUE -2 /* Continue with standard sense processing */ + +/* * These entry points are called by the low-end drivers to get services from * whatever high-end drivers they are attached to. Each device type has one * of these statically allocated. @@ -164,7 +173,7 @@ struct scsi_link { #define ADEV_NOCAPACITY 0x0200 #define ADEV_NOTUR 0x0400 #define ADEV_NODOORLOCK 0x0800 - +#define SDEV_NOSYNCCACHE 0x1000 /* no SYNCHRONIZE_CACHE */ u_int8_t inquiry_flags; /* copy of flags from probe INQUIRY */ struct scsi_device *device; /* device entry points etc. */ void *device_softc; /* needed for call to foo_start */ @@ -259,6 +268,7 @@ struct scsi_xfer { #define SCSI_DATA_OUT 0x1000 /* expect data to flow OUT of memory */ #define SCSI_TARGET 0x2000 /* This defines a TARGET mode op. */ #define SCSI_ESCAPE 0x4000 /* Escape operation */ +#define SCSI_URGENT 0x8000 /* Urgent operation (e.g., HTAG) */ /* * Escape op codes. This provides an extensible setup for operations @@ -278,6 +288,8 @@ struct scsi_xfer { #define XS_SELTIMEOUT 3 /* The device timed out.. turned off? */ #define XS_TIMEOUT 4 /* The Timeout reported was caught by SW */ #define XS_BUSY 5 /* The device busy, try again later? */ +#define XS_SHORTSENSE 6 /* Check the ATAPI sense for the error */ +#define XS_RESET 8 /* bus was reset; possible retry command */ caddr_t scsi_inqmatch __P((struct scsi_inquiry_data *, caddr_t, int, int, int *)); diff --git a/sys/scsi/sd.c b/sys/scsi/sd.c index 973165a045a..c69a593273e 100644 --- a/sys/scsi/sd.c +++ b/sys/scsi/sd.c @@ -1,8 +1,12 @@ -/* $OpenBSD: sd.c,v 1.35 1999/07/23 06:17:09 deraadt Exp $ */ +/* $OpenBSD: sd.c,v 1.36 1999/07/25 07:09:19 csapuntz Exp $ */ /* $NetBSD: sd.c,v 1.111 1997/04/02 02:29:41 mycroft Exp $ */ -/* - * Copyright (c) 1994, 1995, 1997 Charles M. Hannum. All rights reserved. +/*- + * 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 @@ -14,20 +18,23 @@ * 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 Charles M. Hannum. - * 4. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. + * 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 AUTHOR ``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 AUTHOR 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. + * 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. */ /* @@ -69,11 +76,11 @@ #include <scsi/scsi_all.h> #include <scsi/scsi_disk.h> #include <scsi/scsiconf.h> +#include <scsi/sdvar.h> #include <ufs/ffs/fs.h> /* for BBSIZE and SBSIZE */ #define SDOUTSTANDING 4 -#define SDRETRIES 4 #define SDUNIT(dev) DISKUNIT(dev) #define SDPART(dev) DISKPART(dev) @@ -81,39 +88,6 @@ #define SDLABELDEV(dev) (MAKESDDEV(major(dev), SDUNIT(dev), RAW_PART)) -struct sd_softc { - struct device sc_dev; - struct disk sc_dk; - - int flags; -#define SDF_LOCKED 0x01 -#define SDF_WANTED 0x02 -#define SDF_WLABEL 0x04 /* label is writable */ -#define SDF_LABELLING 0x08 /* writing label */ -#define SDF_ANCIENT 0x10 /* disk is ancient; for minphys */ - struct scsi_link *sc_link; /* contains our targ, lun, etc. */ - struct disk_parms { - u_char heads; /* number of heads */ - u_short cyls; /* number of cylinders */ - u_char sectors; /* number of sectors/track */ - int blksize; /* number of bytes/sector */ - u_long disksize; /* total number sectors */ - } params; - struct disk_name { - char vendor[9]; /* disk vendor/manufacturer */ - char product[17]; /* disk product model */ - char revision[5]; /* drive/firmware revision */ - } name; - struct buf buf_queue; - u_int8_t type; -}; - -struct scsi_mode_sense_data { - struct scsi_mode_header header; - struct scsi_blk_desc blk_desc; - union disk_pages pages; -}; - int sdmatch __P((struct device *, void *, void *)); void sdattach __P((struct device *, struct device *, void *)); int sdlock __P((struct sd_softc *)); @@ -123,11 +97,10 @@ void sdgetdisklabel __P((dev_t, struct sd_softc *, struct disklabel *, struct cpu_disklabel *, int)); void sdstart __P((void *)); void sddone __P((struct scsi_xfer *)); +void sd_shutdown __P((void *)); int sd_reassign_blocks __P((struct sd_softc *, u_long)); -int sd_get_optparms __P((struct sd_softc *, int, struct disk_parms *)); -int sd_get_parms __P((struct sd_softc *, int)); -static int sd_mode_sense __P((struct sd_softc *, struct scsi_mode_sense_data *, - int, int)); +int sd_interpret_sense __P((struct scsi_xfer *)); + void viscpy __P((u_char *, u_char *, int)); struct cfattach sd_ca = { @@ -141,7 +114,7 @@ struct cfdriver sd_cd = { struct dkdriver sddkdriver = { sdstrategy }; struct scsi_device sd_switch = { - NULL, /* Use default error handler */ + sd_interpret_sense, /* check out error handler first */ sdstart, /* have a queue, served by this */ NULL, /* have no async handler */ sddone, /* deal with stats at interrupt time */ @@ -158,6 +131,9 @@ struct scsi_inquiry_pattern sd_patterns[] = { "", "", ""}, }; +extern struct sd_ops sd_scsibus_ops; +extern struct sd_ops sd_atapibus_ops; + int sdmatch(parent, match, aux) struct device *parent; @@ -181,7 +157,7 @@ sdattach(parent, self, aux) struct device *parent, *self; void *aux; { - int error; + int error, result; struct sd_softc *sd = (void *)self; struct disk_parms *dp = &sd->params; struct scsibus_attach_args *sa = aux; @@ -208,10 +184,17 @@ sdattach(parent, self, aux) dk_establish(&sd->sc_dk, &sd->sc_dev); + if (sc_link->flags & SDEV_ATAPI) { + sd->sc_ops = &sd_atapibus_ops; + } else { + sd->sc_ops = &sd_scsibus_ops; + } + /* * Note if this device is ancient. This is used in sdminphys(). */ - if ((sa->sa_inqbuf->version & SID_ANSII) == 0) + if (!(sc_link->flags & SDEV_ATAPI) && + (sa->sa_inqbuf->version & SID_ANSII) == 0) sd->flags |= SDF_ANCIENT; /* @@ -234,18 +217,51 @@ sdattach(parent, self, aux) viscpy(sd->name.product, sa->sa_inqbuf->product, 16); viscpy(sd->name.revision, sa->sa_inqbuf->revision, 4); - if (error || sd_get_parms(sd, SCSI_AUTOCONF) != 0) - printf("drive offline\n"); - else { - printf("%ld", dp->disksize / (1048576 / dp->blksize)); - if (dp->disksize < 11520) - printf(".%2ld", - dp->disksize / (1024*10 / dp->blksize) - - dp->disksize / (1048576 / dp->blksize) * 100); - printf("MB, %d cyl, %d head, %d sec, %d bytes/sec, %ld sec total\n", - dp->cyls, - dp->heads, dp->sectors, dp->blksize, dp->disksize); + if (error) + result = SDGP_RESULT_OFFLINE; + else + result = (*sd->sc_ops->sdo_get_parms)(sd, &sd->params, + SCSI_AUTOCONF); + + switch (result) { + case SDGP_RESULT_OK: + printf("%ldMB, %d cyl, %d head, %d sec, %d bytes/sec, %ld sec to +tal\n", + dp->disksize / (1048576 / dp->blksize), dp->cyls, + dp->heads, dp->sectors, dp->blksize, dp->disksize); + + break; + + case SDGP_RESULT_OFFLINE: + printf("drive offline"); + break; + + case SDGP_RESULT_UNFORMATTED: + printf("unformatted media"); + break; + +#ifdef DIAGNOSTIC + default: + panic("sdattach: unknown result from get_parms"); + break; +#endif } + printf("\n"); + +#ifdef notyet + /* + * Establish a shutdown hook so that we can ensure that + * our data has actually made it onto the platter at + * shutdown time. Note that this relies on the fact + * that the shutdown hook code puts us at the head of + * the list (thus guaranteeing that our hook runs before + * our ancestors'). + */ + if ((sd->sc_sdhook = + shutdownhook_establish(sd_shutdown, sd)) == NULL) + printf("%s: WARNING: unable to establish shutdown hook\n", + sd->sc_dev.dv_xname); +#endif } /* @@ -309,7 +325,7 @@ sdopen(dev, flag, fmt, p) SC_DEBUG(sc_link, SDEV_DB1, ("sdopen: dev=0x%x (unit %d (of %d), partition %d)\n", dev, unit, - sd_cd.cd_ndevs, SDPART(dev))); + sd_cd.cd_ndevs, part)); if ((error = sdlock(sd)) != 0) return error; @@ -355,7 +371,8 @@ sdopen(dev, flag, fmt, p) sc_link->flags |= SDEV_MEDIA_LOADED; /* Load the physical device parameters. */ - if (sd_get_parms(sd, 0) != 0) { + if ((*sd->sc_ops->sdo_get_parms)(sd, &sd->params, + 0) == SDGP_RESULT_OFFLINE) { error = ENXIO; goto bad2; } @@ -436,7 +453,9 @@ sdclose(dev, flag, fmt, p) sd->sc_dk.dk_openmask = sd->sc_dk.dk_copenmask | sd->sc_dk.dk_bopenmask; if (sd->sc_dk.dk_openmask == 0) { - /* XXX Must wait for I/O to complete! */ + if ((sd->flags & SDF_DIRTY) != 0 && + sd->sc_ops->sdo_flush != NULL) + (*sd->sc_ops->sdo_flush)(sd, 0); scsi_prevent(sd->sc_link, PR_ALLOW, SCSI_IGNORE_ILLEGAL_REQUEST | SCSI_IGNORE_NOT_READY); @@ -479,7 +498,10 @@ sdstrategy(bp) * If the device has been made invalid, error out */ if ((sd->sc_link->flags & SDEV_MEDIA_LOADED) == 0) { - bp->b_error = EIO; + if (sd->sc_link->flags & SDEV_OPEN) + bp->b_error = EIO; + else + bp->b_error = ENODEV; goto bad; } /* @@ -639,6 +661,14 @@ sdstart(v) disk_busy(&sd->sc_dk); /* + * Mark the disk dirty so that the cache will be + * flushed on close. + */ + if ((bp->b_flags & B_READ) == 0) + sd->flags |= SDF_DIRTY; + + + /* * Call the routine that chats with the adapter. * Note: we cannot sleep as we may be an interrupt */ @@ -660,6 +690,11 @@ sddone(xs) { struct sd_softc *sd = xs->sc_link->device_softc; + if (sd->flags & SDF_FLUSHING) { + /* Flush completed, no longer dirty. */ + sd->flags &= ~(SDF_FLUSHING|SDF_DIRTY); + } + if (xs->bp != NULL) disk_unbusy(&sd->sc_dk, (xs->bp->b_bcount - xs->bp->b_resid)); } @@ -726,14 +761,31 @@ sdioctl(dev, cmd, addr, flag, p) { struct sd_softc *sd = sd_cd.cd_devs[SDUNIT(dev)]; int error; + int part = SDPART(dev); SC_DEBUG(sd->sc_link, SDEV_DB2, ("sdioctl 0x%lx ", cmd)); /* * If the device is not valid.. abandon ship */ - if ((sd->sc_link->flags & SDEV_MEDIA_LOADED) == 0) - return EIO; + if ((sd->sc_link->flags & SDEV_MEDIA_LOADED) == 0) { + switch (cmd) { + case DIOCWLABEL: + case DIOCLOCK: + case DIOCEJECT: + case SCIOCIDENTIFY: + case SCIOCCOMMAND: + case SCIOCDEBUG: + if (part == RAW_PART) + break; + /* FALLTHROUGH */ + default: + if ((sd->sc_link->flags & SDEV_OPEN) == 0) + return (ENODEV); + else + return (EIO); + } + } switch (cmd) { case DIOCGPDINFO: { @@ -807,7 +859,7 @@ sdioctl(dev, cmd, addr, flag, p) return error; default: - if (SDPART(dev) != RAW_PART) + if (part != RAW_PART) return ENOTTY; return scsi_do_ioctl(sd->sc_link, dev, cmd, addr, flag, p); } @@ -889,6 +941,22 @@ sdgetdisklabel(dev, sd, lp, clp, spoofonly) } } + +void +sd_shutdown(arg) + void *arg; +{ + struct sd_softc *sd = arg; + + /* + * If the disk cache needs to be flushed, and the disk supports + * it, flush it. We're cold at this point, so we poll for + * completion. + */ + if ((sd->flags & SDF_DIRTY) != 0 && sd->sc_ops->sdo_flush != NULL) + (*sd->sc_ops->sdo_flush)(sd, SCSI_AUTOCONF); +} + /* * Tell the device to map out a defective block */ @@ -912,178 +980,68 @@ sd_reassign_blocks(sd, blkno) 5000, NULL, SCSI_DATA_OUT); } - -static int -sd_mode_sense(sd, scsi_sense, page, flags) - struct sd_softc *sd; - struct scsi_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); -} - -int -sd_get_optparms(sd, flags, dp) - struct sd_softc *sd; - int flags; - struct disk_parms *dp; -{ - struct scsi_mode_sense scsi_cmd; - struct scsi_mode_sense_data { - struct scsi_mode_header header; - struct scsi_blk_desc blk_desc; - union disk_pages pages; - } scsi_sense; - u_long sectors; - int error; - - dp->blksize = DEV_BSIZE; - if ((sectors = scsi_size(sd->sc_link, flags)) == 0) - return 1; - - /* 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 error; - - dp->blksize = _3btol(scsi_sense.blk_desc.blklen); - if (dp->blksize == 0) - dp->blksize = DEV_BSIZE; - - /* - * Create a pseudo-geometry. - */ - dp->heads = 64; - dp->sectors = 32; - dp->cyls = sectors / (dp->heads * dp->sectors); - dp->disksize = sectors; - - return 0; -} - /* - * Get the scsi driver to send a full inquiry to the * device and use the - * results to fill out the disk parameter structure. + * Check Errors */ int -sd_get_parms(sd, flags) - struct sd_softc *sd; - int flags; +sd_interpret_sense(xs) + struct scsi_xfer *xs; { - struct disk_parms *dp = &sd->params; - struct scsi_mode_sense_data scsi_sense; - u_long sectors; - int page; - int error; - - if (sd->type == T_OPTICAL) { - if ((error = sd_get_optparms(sd, flags, dp)) != 0) - sd->sc_link->flags &= ~SDEV_MEDIA_LOADED; - return error; - } - - if ((error = sd_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 = DEV_BSIZE; + struct scsi_link *sc_link = xs->sc_link; + struct scsi_sense_data *sense = &xs->sense; + struct sd_softc *sd = sc_link->device_softc; + int retval = SCSIRET_CONTINUE; - sectors = scsi_size(sd->sc_link, flags); - dp->disksize = sectors; - sectors /= (dp->heads * dp->cyls); - dp->sectors = sectors; /* XXX dubious on SCSI */ - - return 0; + /* + * If the device is not open yet, let the generic code handle it. + */ + if ((sc_link->flags & SDEV_MEDIA_LOADED) == 0) { + return (retval); } - if ((error = sd_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 = DEV_BSIZE; - - return 0; + /* + * If it isn't a extended or extended/deferred error, let + * the generic code handle it. + */ + if ((sense->error_code & SSD_ERRCODE) != 0x70 && + (sense->error_code & SSD_ERRCODE) != 0x71) { /* DEFFERRED */ + return (retval); } -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)", + if ((sense->flags & SSD_KEY) == SKEY_NOT_READY && + sense->add_sense_code == 0x4) { + if (sense->add_sense_code_qual == 0x01) { + printf("%s: ..is spinning up...waiting\n", sd->sc_dev.dv_xname); - printf("; using fictitious geometry\n"); + /* + * I really need a sdrestart function I can call here. + */ + delay(1000000 * 5); /* 5 seconds */ + retval = SCSIRET_RETRY; + } else if ((sense->add_sense_code_qual == 0x2) && + (sd->sc_link->quirks & SDEV_NOSTARTUNIT) == 0) { + if (sd->sc_link->flags & SDEV_REMOVABLE) { + printf( + "%s: removable disk stopped - not restarting\n", + sd->sc_dev.dv_xname); + retval = EIO; + } else { + printf("%s: respinning up disk\n", + sd->sc_dev.dv_xname); + retval = scsi_start(sd->sc_link, SSS_START, + SCSI_URGENT | SCSI_NOSLEEP); + if (retval != 0) { + printf( + "%s: respin of disk failed - %d\n", + sd->sc_dev.dv_xname, retval); + retval = EIO; + } else { + retval = SCSIRET_RETRY; + } + } + } } - /* - * 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 = DEV_BSIZE; - dp->disksize = sectors; - return 0; + return (retval); } int diff --git a/sys/scsi/sd_atapi.c b/sys/scsi/sd_atapi.c new file mode 100644 index 00000000000..7397421a809 --- /dev/null +++ b/sys/scsi/sd_atapi.c @@ -0,0 +1,145 @@ +/* $OpenBSD: sd_atapi.c,v 1.1 1999/07/25 07:09:19 csapuntz Exp $ */ +/* $NetBSD: sd_atapi.c,v 1.3 1998/08/31 22:28:07 cgd Exp $ */ + +/* + * Copyright 1998 + * Digital Equipment Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and conditions. + * Subject to these conditions, you may download, copy, install, + * use, modify and distribute this software in source and/or binary + * form. No title or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions as + * they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or logo of + * Digital Equipment Corporation. Neither the "Digital Equipment + * Corporation" name nor any trademark or logo of Digital Equipment + * Corporation may be used to endorse or promote products derived + * from this software without the prior written permission of + * Digital Equipment Corporation. + * + * 3) This software is provided "AS-IS" and any express or implied + * warranties, including but not limited to, any implied warranties + * of merchantability, fitness for a particular purpose, or + * non-infringement are disclaimed. In no event shall DIGITAL be + * liable for any damages whatsoever, and in particular, DIGITAL + * shall not be liable for special, indirect, consequential, or + * incidental damages or damages for lost profits, loss of + * revenue or loss of use, whether such damages arise in contract, + * negligence, tort, under statute, in equity, at law or otherwise, + * even if advised of the possibility of such damage. + */ + +/* + * ATAPI disk attachment for the 'sd' driver. + * + * Chris Demetriou, January 10, 1998. + */ + +#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/atapi_all.h> +#include <scsi/atapi_disk.h> +#include <scsi/sdvar.h> + +static int sd_atapibus_get_parms __P((struct sd_softc *, + struct disk_parms *, int)); + +const struct sd_ops sd_atapibus_ops = { + sd_atapibus_get_parms, +}; + +static int +sd_atapibus_get_parms(sd, dp, flags) + struct sd_softc *sd; + struct disk_parms *dp; + int flags; +{ + struct atapi_read_format_capacities scsi_cmd; + struct atapi_capacity_descriptor *descp; + struct atapi_sd_mode_data sense_data; + char capacity_data[ATAPI_CAP_DESC_SIZE(1)]; + int error; + + bzero(&scsi_cmd, sizeof scsi_cmd); + scsi_cmd.opcode = ATAPI_READ_FORMAT_CAPACITIES; + _lto2b(ATAPI_CAP_DESC_SIZE(1), scsi_cmd.length); + + error = scsi_scsi_cmd(sd->sc_link, + (struct scsi_generic *)&scsi_cmd, sizeof(scsi_cmd), + (void *)capacity_data, ATAPI_CAP_DESC_SIZE(1), SDRETRIES, 20000, + NULL, flags | SCSI_DATA_IN); + SC_DEBUG(sd->sc_link, SDEV_DB2, + ("sd_atapibus_get_parms: read format capacities error=%d\n", + error)); + if (error != 0) + return (SDGP_RESULT_OFFLINE); + + descp = (struct atapi_capacity_descriptor *) + &capacity_data[ATAPI_CAP_DESC_OFFSET_DESC(0)]; + + switch (descp->byte5 & ATAPI_CAP_DESC_CODE_MASK) { + case ATAPI_CAP_DESC_CODE_UNFORMATTED: + return SDGP_RESULT_UNFORMATTED; + + case ATAPI_CAP_DESC_CODE_FORMATTED: + break; + + default: +#ifdef DIAGNOSTIC + printf("%s: strange capacity descriptor byte5 0x%x\n", + sd->sc_dev.dv_xname, (u_int)descp->byte5); +#endif + /* FALLTHROUGH */ + case ATAPI_CAP_DESC_CODE_NONE: + return SDGP_RESULT_OFFLINE; + } + + dp->disksize = _4btol(descp->nblks); + dp->blksize = _3btol(descp->blklen); + + /* + * First, set up standard fictitious geometry, a la sd_scsi.c. + */ + dp->heads = 64; + dp->sectors = 32; + dp->cyls = dp->disksize / (64 * 32); + dp->rot_rate = 3600; + + /* + * Then try to get something better. If we can't, that's + * still OK. + * + * XXX Rigid geometry page? + */ + error = atapi_mode_sense(sd->sc_link, ATAPI_FLEX_GEOMETRY_PAGE, + (struct atapi_mode_header *)&sense_data, FLEXGEOMETRYPAGESIZE, + flags, SDRETRIES, 20000); + SC_DEBUG(sd->sc_link, SDEV_DB2, + ("sd_atapibus_get_parms: mode sense (flex) error=%d\n", error)); + if (error != 0) + return (SDGP_RESULT_OK); + + dp->heads = sense_data.pages.flex_geometry.nheads; + dp->sectors = sense_data.pages.flex_geometry.ph_sec_tr; + dp->cyls = _2btol(sense_data.pages.flex_geometry.ncyl); + dp->rot_rate = _2btol(sense_data.pages.flex_geometry.rot_rate); + + return (SDGP_RESULT_OK); +} 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; + } +} diff --git a/sys/scsi/sdvar.h b/sys/scsi/sdvar.h new file mode 100644 index 00000000000..5cecac31811 --- /dev/null +++ b/sys/scsi/sdvar.h @@ -0,0 +1,106 @@ +/* $OpenBSD: sdvar.h,v 1.1 1999/07/25 07:09:20 csapuntz Exp $ */ +/* $NetBSD: sdvar.h,v 1.7 1998/08/17 00:49:03 mycroft 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 + */ + +#define SDRETRIES 4 + +struct sd_ops; + +struct sd_softc { + struct device sc_dev; + struct disk sc_dk; + + int flags; +#define SDF_LOCKED 0x01 +#define SDF_WANTED 0x02 +#define SDF_WLABEL 0x04 /* label is writable */ +#define SDF_LABELLING 0x08 /* writing label */ +#define SDF_ANCIENT 0x10 /* disk is ancient; for minphys */ +#define SDF_DIRTY 0x20 /* disk is dirty; needs cache flush */ +#define SDF_FLUSHING 0x40 /* flushing, for sddone() */ + 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 blksize; /* number of bytes/sector */ + u_long disksize; /* total number sectors */ + u_long rot_rate; /* rotational rate, in RPM */ + } params; + struct buf buf_queue; + u_int8_t type; + struct disk_name { + char vendor[9]; /* disk vendor/manufacturer */ + char product[17]; /* disk product model */ + char revision[5]; /* drive/firmware revision */ + } name; + const struct sd_ops *sc_ops; /* our bus-dependent ops vector */ + + void *sc_sdhook; /* our shutdown hook */ + +#if NRND > 0 + rndsource_element_t rnd_source; +#endif +}; + +struct sd_ops { + int (*sdo_get_parms) __P((struct sd_softc *, struct disk_parms *, + int)); + void (*sdo_flush) __P((struct sd_softc *, int)); +}; +#define SDGP_RESULT_OK 0 /* paramters obtained */ +#define SDGP_RESULT_OFFLINE 1 /* no media, or otherwise losing */ +#define SDGP_RESULT_UNFORMATTED 2 /* unformatted media (max params) */ + diff --git a/sys/scsi/st.c b/sys/scsi/st.c index eccd4b177e8..c41124be019 100644 --- a/sys/scsi/st.c +++ b/sys/scsi/st.c @@ -1,4 +1,4 @@ -/* $OpenBSD: st.c,v 1.25 1998/07/23 09:11:09 deraadt Exp $ */ +/* $OpenBSD: st.c,v 1.26 1999/07/25 07:09:20 csapuntz Exp $ */ /* $NetBSD: st.c,v 1.71 1997/02/21 23:03:49 thorpej Exp $ */ /* @@ -671,8 +671,11 @@ st_mount_tape(dev, flags) * Load the physical device parameters * loads: blkmin, blkmax */ - if ((error = st_read_block_limits(st, 0)) != 0) + if (!(sc_link->flags & SDEV_ATAPI) && + (error = st_read_block_limits(st, 0)) != 0) { return error; + } + /* * Load the media dependent parameters * includes: media_blksize,media_density,numblks @@ -1488,6 +1491,9 @@ st_mode_select(st, flags) return 0; } + if (sc_link->flags & SDEV_ATAPI) + return 0; + /* * Set up for a mode select */ @@ -1794,7 +1800,7 @@ st_interpret_sense(xs) else info = xs->datalen; /* bad choice if fixed blocks */ if ((sense->error_code & SSD_ERRCODE) != 0x70) - return -1; /* let the generic code handle it */ + return SCSIRET_CONTINUE; /* let the generic code handle it */ if (st->flags & ST_FIXEDBLOCKS) { xs->resid = info * st->blksize; if (sense->flags & SSD_EOM) { @@ -1899,7 +1905,7 @@ st_interpret_sense(xs) return 0; } } - return -1; /* let the default/generic handler handle it */ + return SCSIRET_CONTINUE; } /* |