summaryrefslogtreecommitdiff
path: root/sys/scsi
diff options
context:
space:
mode:
authorConstantine Sapuntzakis <csapuntz@cvs.openbsd.org>1999-07-25 07:09:21 +0000
committerConstantine Sapuntzakis <csapuntz@cvs.openbsd.org>1999-07-25 07:09:21 +0000
commitc5091939f49bf18ce06780a7e49c968611317f11 (patch)
tree14ea0ba2b7d637c18fe007d908ef0886d939202f /sys/scsi
parent7c82046e621c85d85b87aaa0519535530e5c9d83 (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.h101
-rw-r--r--sys/scsi/scsi_all.h19
-rw-r--r--sys/scsi/scsi_base.c43
-rw-r--r--sys/scsi/scsi_disk.h122
-rw-r--r--sys/scsi/scsiconf.h16
-rw-r--r--sys/scsi/sd.c430
-rw-r--r--sys/scsi/sd_atapi.c145
-rw-r--r--sys/scsi/sd_scsi.c303
-rw-r--r--sys/scsi/sdvar.h106
-rw-r--r--sys/scsi/st.c14
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;
}
/*