From 519fb2b727df5a6bd1f2d4ae60c2b9bd8f12a493 Mon Sep 17 00:00:00 2001 From: Rod Grimes Date: Thu, 18 Nov 1993 05:03:27 +0000 Subject: [PATCH 1/1] New version of scsi code from Julian --- sys/conf/files | 7 +- sys/i386/conf/LINT | 3 +- sys/i386/i386/conf.c | 47 +- sys/i386/include/param.h | 6 +- sys/i386/isa/aha1542.c | 1929 ++++++++++----------- sys/i386/isa/aha1742.c | 1768 ++++++++++---------- sys/i386/isa/bt742a.c | 2026 +++++++++++----------- sys/i386/isa/ultra14f.c | 1626 +++++++++--------- sys/i386/isa/wd.c | 4 +- sys/i386/isa/wx.c | 4 +- sys/kern/kern__physio.c | 25 +- sys/kern/kern_subr.c | 4 +- sys/scsi/README | 189 +-- sys/scsi/cd.c | 2246 +++++++++---------------- sys/scsi/ch.c | 1204 ++++--------- sys/scsi/scsi_all.h | 93 +- sys/scsi/scsi_base.c | 852 ++++++++++ sys/scsi/scsi_cd.h | 10 +- sys/scsi/scsi_changer.h | 9 +- sys/scsi/scsi_debug.h | 53 + sys/scsi/scsi_disk.h | 11 +- sys/scsi/scsi_ioctl.c | 329 ++++ sys/scsi/scsi_tape.h | 12 +- sys/scsi/scsiconf.c | 1110 ++++++------ sys/scsi/scsiconf.h | 259 ++- sys/scsi/sd.c | 2072 ++++++++--------------- sys/scsi/st.c | 3439 +++++++++++++++++--------------------- sys/scsi/su.c | 4 + sys/scsi/uk.c | 156 ++ sys/sys/buf.h | 9 +- sys/sys/chio.h | 9 +- sys/sys/mtio.h | 22 +- sys/sys/scsiio.h | 63 + 33 files changed, 9300 insertions(+), 10300 deletions(-) create mode 100644 sys/scsi/scsi_base.c create mode 100644 sys/scsi/scsi_debug.h create mode 100644 sys/scsi/scsi_ioctl.c create mode 100644 sys/scsi/su.c create mode 100644 sys/scsi/uk.c create mode 100644 sys/sys/scsiio.h diff --git a/sys/conf/files b/sys/conf/files index 57092967eb..948431a20f 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -1,4 +1,4 @@ -# $Id: files,v 1.9 1993/11/07 22:54:36 wollman Exp $ +# $Id: files,v 1.10 1993/11/18 00:06:16 wollman Exp $ # ddb/db_access.c optional ddb ddb/db_aout.c optional ddb @@ -199,9 +199,12 @@ pcfs/pcfs_vnops.c optional pcfs scsi/cd.c optional cd scsi/ch.c optional ch scsi/scsiconf.c optional scbus +scsi/scsi_base.c optional scbus +scsi/scsi_ioctl.c optional scbus scsi/sd.c optional sd -scsi/sg.c optional sg scsi/st.c optional st +scsi/su.c optional su +scsi/uk.c optional uk ufs/mfs_vfsops.c optional mfs ufs/mfs_vnops.c optional mfs ufs/ufs_alloc.c standard diff --git a/sys/i386/conf/LINT b/sys/i386/conf/LINT index a48a73ba8d..ef33ef57b5 100644 --- a/sys/i386/conf/LINT +++ b/sys/i386/conf/LINT @@ -4,7 +4,7 @@ # # This kernel is NOT MEANT to be runnable! # -# $Id: LINT,v 1.28 1993/11/07 22:54:51 wollman Exp $ +# $Id: LINT,v 1.29 1993/11/17 23:24:12 wollman Exp $ # machine "i386" @@ -87,6 +87,7 @@ options "SHMMAXPGS=64" # 256Kb of sharable memory #pseudo-device tb #tablet line discipline. pseudo-device tpip #pseudo-device tun +device uk0 #unknown scsi devices pseudo-device vnodepager # diff --git a/sys/i386/i386/conf.c b/sys/i386/i386/conf.c index 755a0dd139..ae333fd586 100644 --- a/sys/i386/i386/conf.c +++ b/sys/i386/i386/conf.c @@ -1,4 +1,4 @@ -/*- +/* * Copyright (c) 1990 The Regents of the University of California. * All rights reserved. * @@ -34,7 +34,7 @@ * SUCH DAMAGE. * * from: @(#)conf.c 5.8 (Berkeley) 5/12/91 - * $Id: conf.c,v 1.13 1993/10/26 22:25:20 nate Exp $ + * $Id: conf.c,v 1.14 1993/11/03 18:07:32 nate Exp $ */ #include "param.h" @@ -126,20 +126,6 @@ int chopen(),chclose(),chioctl(); #define chioctl enxio #endif -#include "sg.h" -#if NSG > 0 -int sgopen(),sgclose(),sgioctl(),sgstrategy(); -#define sgdump enxio -#define sgsize NULL -#else -#define sgopen enxio -#define sgclose enxio -#define sgstrategy enxio -#define sgioctl enxio -#define sgdump enxio -#define sgsize NULL -#endif - #include "wt.h" #if NWT > 0 int wtopen(),wtclose(),wtstrategy(),wtioctl(); @@ -377,6 +363,26 @@ extern struct tty sio_tty[]; #define sio_tty NULL #endif +#include "su.h" +#if NSU > 0 +int suopen(),suclose(),suioctl(); +#define susize NULL +#else +#define suopen enxio +#define suclose enxio +#define suioctl enxio +#define susize NULL +#endif + +#include "uk.h" +#if NUK > 0 +int ukopen(),ukclose(),ukioctl(); +#else +#define ukopen enxio +#define ukclose enxio +#define ukioctl enxio +#endif + struct cdevsw cdevsw[] = { { cnopen, cnclose, cnread, cnwrite, /*0*/ @@ -433,9 +439,9 @@ struct cdevsw cdevsw[] = { chopen, chclose, enxio, enxio, /*17*/ chioctl, enxio, enxio, NULL, /* ch */ enxio, enxio, enxio }, - { sgopen, sgclose, enodev, enodev, /*18*/ - sgioctl, enodev, nullop, NULL, /* scsi 'generic' */ - seltrue, enodev, sgstrategy }, + { suopen, suclose, enodev, enodev, /*18*/ + suioctl, enodev, nullop, NULL, /* scsi 'generic' */ + seltrue, enodev, enodev }, { twopen, twclose, twread, twwrite, /*19*/ enodev, nullop, nullop, NULL, /* tw */ twselect, enodev, enodev }, @@ -472,6 +478,9 @@ struct cdevsw cdevsw[] = { sndopen, sndclose, sndread, sndwrite, /*30*/ sndioctl, enodev, enodev, NULL, /* sound driver */ sndselect, enodev, NULL }, + { ukopen, ukclose, enxio, enxio, /*31*/ + ukioctl, enxio, enxio, NULL, /* unknown */ + enxio, enxio, enxio }, /* scsi */ /* * If you need a cdev major number, please contact the FreeBSD team * by sending mail to `freebsd-hackers@freefall.cdrom.com'. diff --git a/sys/i386/include/param.h b/sys/i386/include/param.h index c9e77b2e06..8f46b47206 100644 --- a/sys/i386/include/param.h +++ b/sys/i386/include/param.h @@ -34,7 +34,7 @@ * SUCH DAMAGE. * * from: @(#)param.h 5.8 (Berkeley) 6/28/91 - * $Id: param.h,v 1.8 1993/11/07 17:42:58 wollman Exp $ + * $Id: param.h,v 1.9 1993/11/13 02:25:14 davidg Exp $ */ #ifndef _MACHINE_PARAM_H_ @@ -157,8 +157,4 @@ #define i386_btop(x) ((unsigned)(x) >> PGSHIFT) #define i386_ptob(x) ((unsigned)(x) << PGSHIFT) -/* - * phystokv stolen from SCSI device drivers and fixed to use KERNBASE - */ -#define PHYSTOKV(x) (x | KERNBASE) #endif /* _MACHINE_PARAM_H_ */ diff --git a/sys/i386/isa/aha1542.c b/sys/i386/isa/aha1542.c index c2426245b2..b731ed631d 100644 --- a/sys/i386/isa/aha1542.c +++ b/sys/i386/isa/aha1542.c @@ -12,97 +12,49 @@ * on the understanding that TFS is not responsible for the correct * functioning of this software in any circumstances. * - * $Id: aha1542.c,v 1.13 1993/10/28 02:38:36 rgrimes Exp $ + * $Id: aha1542.c,v 2.8 93/10/24 12:55:08 julian Exp Locker: julian $ */ /* * Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992 */ -/* - * a FEW lines in this driver come from a MACH adaptec-disk driver - * so the copyright below is included: - * - * Copyright 1990 by Open Software Foundation, - * Grenoble, FRANCE - * - * All Rights Reserved - * - * Permission to use, copy, modify, and distribute this software and - * its documentation for any purpose and without fee is hereby granted, - * provided that the above copyright notice appears in all copies and - * that both the copyright notice and this permission notice appear in - * supporting documentation, and that the name of OSF or Open Software - * Foundation not be used in advertising or publicity pertaining to - * distribution of the software without specific, written prior - * permission. - * - * OSF DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, - * IN NO EVENT SHALL OSF BE LIABLE FOR ANY SPECIAL, INDIRECT, OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM - * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, - * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION - * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - - #include +#ifdef KERNEL /* don't laugh.. look for main() */ #include #include #include #include #include +#include #include #include #include - -#ifdef MACH /* EITHER CMU OR OSF */ -#include -#include -#include - -#ifdef OSF /* OSF ONLY */ -#include -#include -#include -#include - -#else OSF /* CMU ONLY */ -#include -#include -#endif OSF -#endif MACH /* end of MACH specific */ - -#ifdef __386BSD__ /* 386BSD specific */ -#define isa_dev isa_device -#define dev_unit id_unit -#define dev_addr id_iobase - #include +#endif /* KERNEL */ #include #include -#endif __386BSD__ - -#ifdef __386BSD__ +#ifdef KERNEL #include "ddb.h" #if NDDB > 0 -int Debugger(); -#else NDDB +int Debugger(); +#else /* NDDB */ #define Debugger() panic("should call debugger here (adaptec.c)") -#endif NDDB -#endif __386BSD__ -extern int hz; -extern int delaycount; /* from clock setup code */ +#endif /* NDDB */ +extern int hz; +#else /*KERNEL */ +#define NAHA 1 +#endif /*KERNEL */ /************************** board definitions *******************************/ + /* * I/O Port Interface */ -#define AHA_BASE aha_base[unit] +#define AHA_BASE aha->aha_base #define AHA_CTRL_STAT_PORT (AHA_BASE + 0x0) /* control & status */ #define AHA_CMD_DATA_PORT (AHA_BASE + 0x1) /* cmds and datas */ #define AHA_INTR_PORT (AHA_BASE + 0x2) /* Intr. stat */ @@ -155,7 +107,7 @@ extern int delaycount; /* from clock setup code */ #define AHA_MBX_ENABLE 0x29 /* enable mail box interface */ struct aha_cmd_buf { - u_char byte[16]; + u_char byte[16]; }; /* @@ -178,8 +130,8 @@ struct aha_mbx { struct aha_mbx_out { unsigned char cmd; unsigned char ccb_addr[3]; - } mbo [AHA_MBX_SIZE]; - struct aha_mbx_in{ + } mbo[AHA_MBX_SIZE]; + struct aha_mbx_in { unsigned char stat; unsigned char ccb_addr[3]; } mbi[AHA_MBX_SIZE]; @@ -193,60 +145,59 @@ struct aha_mbx { #define AHA_MBO_START 0x1 /* MBO activate entry */ #define AHA_MBO_ABORT 0x2 /* MBO abort entry */ +/* + * mbi.stat values + */ + #define AHA_MBI_FREE 0x0 /* MBI entry is free */ #define AHA_MBI_OK 0x1 /* completed without error */ #define AHA_MBI_ABORT 0x2 /* aborted ccb */ #define AHA_MBI_UNKNOWN 0x3 /* Tried to abort invalid CCB */ #define AHA_MBI_ERROR 0x4 /* Completed with error */ -extern struct aha_mbx aha_mbx[]; - /* FOR OLD VERSIONS OF THE !%$@ this may have to be 16 (yuk) */ #define AHA_NSEG 17 /* Number of scatter gather segments <= 16 */ /* allow 64 K i/o (min) */ struct aha_ccb { - unsigned char opcode; - unsigned char lun:3; - unsigned char data_in:1; /* must be 0 */ - unsigned char data_out:1; /* must be 0 */ - unsigned char target:3; - unsigned char scsi_cmd_length; - unsigned char req_sense_length; - unsigned char data_length[3]; - unsigned char data_addr[3]; - unsigned char link_addr[3]; - unsigned char link_id; - unsigned char host_stat; - unsigned char target_stat; - unsigned char reserved[2]; - struct scsi_generic scsi_cmd; - struct scsi_sense_data scsi_sense; - struct aha_scat_gath { + unsigned char opcode; + unsigned char lun:3; + unsigned char data_in:1; /* must be 0 */ + unsigned char data_out:1; /* must be 0 */ + unsigned char target:3; + unsigned char scsi_cmd_length; + unsigned char req_sense_length; + unsigned char data_length[3]; + unsigned char data_addr[3]; + unsigned char link_addr[3]; + unsigned char link_id; + unsigned char host_stat; + unsigned char target_stat; + unsigned char reserved[2]; + struct scsi_generic scsi_cmd; + struct scsi_sense_data scsi_sense; + struct aha_scat_gath { unsigned char seg_len[3]; unsigned char seg_addr[3]; } scat_gath[AHA_NSEG]; - struct aha_ccb *next; - struct scsi_xfer *xfer; /* the scsi_xfer for this cmd */ - struct aha_mbx_out *mbx; /* pointer to mail box */ - int flags; + struct aha_ccb *next; + struct scsi_xfer *xfer; /* the scsi_xfer for this cmd */ + struct aha_mbx_out *mbx; /* pointer to mail box */ + int flags; #define CCB_FREE 0 #define CCB_ACTIVE 1 #define CCB_ABORTED 2 - }; - /* * opcode fields */ #define AHA_INITIATOR_CCB 0x00 /* SCSI Initiator CCB */ #define AHA_TARGET_CCB 0x01 /* SCSI Target CCB */ -#define AHA_INIT_SCAT_GATH_CCB 0x02 /* SCSI Initiator with scattter gather*/ +#define AHA_INIT_SCAT_GATH_CCB 0x02 /* SCSI Initiator with scatter gather */ #define AHA_RESET_CCB 0x81 /* SCSI Bus reset */ - /* * aha_ccb.host_stat values */ @@ -266,34 +217,28 @@ struct aha_ccb { #define AHA_INV_CCB 0x1a /* Invalid CCB or segment list */ #define AHA_ABORTED 42 - - - -struct aha_setup -{ - u_char sync_neg:1; - u_char parity:1; - u_char :6; - u_char speed; - u_char bus_on; - u_char bus_off; - u_char num_mbx; - u_char mbx[3]; - struct - { - u_char offset:4; - u_char period:3; - u_char valid:1; - }sync[8]; - u_char disc_sts; +struct aha_setup { + u_char sync_neg:1; + u_char parity:1; + u_char:6; + u_char speed; + u_char bus_on; + u_char bus_off; + u_char num_mbx; + u_char mbx[3]; + struct { + u_char offset:4; + u_char period:3; + u_char valid:1; + } sync[8]; + u_char disc_sts; }; -struct aha_config -{ - u_char chan; - u_char intr; - u_char scsi_dev:3; - u_char :5; +struct aha_config { + u_char chan; + u_char intr; + u_char scsi_dev:3; + u_char:5; }; struct aha_inquire @@ -331,58 +276,82 @@ struct aha_extbios #define CHAN6 0x40 #define CHAN7 0x80 - /*********************************** end of board definitions***************/ - -#ifdef MACH -#define PHYSTOKV(x) phystokv(x) -#define KVTOPHYS(x) kvtophys(x) -#else MACH -#ifdef __386BSD__ +#define PHYSTOKV(x) (((long int)(x)) ^ aha->kv_phys_xor) #define KVTOPHYS(x) vtophys(x) -#else __386BSD__ -#endif __386BSD__ -#endif MACH #define AHA_DMA_PAGES AHA_NSEG #define PAGESIZ 4096 #define INVALIDATE_CACHE {asm volatile( ".byte 0x0F ;.byte 0x08" ); } - -u_char aha_scratch_buf[256]; -#ifdef MACH -caddr_t aha_base[NAHA]; /* base port for each board */ -#else -short aha_base[NAHA]; /* base port for each board */ -#endif -struct aha_mbx aha_mbx[NAHA]; -struct aha_ccb *aha_ccb_free[NAHA]; -struct aha_ccb aha_ccb[NAHA][AHA_MBX_SIZE]; -struct scsi_xfer aha_scsi_xfer[NAHA]; -struct isa_dev *ahainfo[NAHA]; -struct aha_ccb *aha_get_ccb(); -int aha_int[NAHA]; -int aha_dma[NAHA]; -int aha_scsi_dev[NAHA]; -int aha_initialized[NAHA]; -#ifdef OSF -int aha_attached[NAHA]; -#endif OSF +u_char aha_scratch_buf[256]; #ifdef AHADEBUG -int aha_debug = 1; -#endif /*AHADEBUG*/ +int aha_debug = 1; +#endif /*AHADEBUG */ -int ahaprobe(), ahaattach(), ahaintr(); -#ifdef MACH -struct isa_driver ahadriver = { ahaprobe, 0, ahaattach, "aha", 0, 0, 0}; -int (*ahaintrs[])() = {ahaintr, 0}; -#endif -#ifdef __386BSD__ -struct isa_driver ahadriver = { ahaprobe, ahaattach, "aha",}; -#endif __386BSD__ -static int ahaunit = 0; +struct aha_data { + short aha_base; /* base port for each board */ + /* + * xor this with a physaddr to get a kv addr and visa versa + * for items in THIS STRUCT only. + * Used to get the CCD's physical and kv addresses from each + * other. + */ + long int kv_phys_xor; + struct aha_mbx aha_mbx; /* all the mailboxes */ + struct aha_ccb *aha_ccb_free; /* the next free ccb */ + struct aha_ccb aha_ccb[AHA_MBX_SIZE]; /* all the CCBs */ + int aha_int; /* our irq level */ + int aha_dma; /* out DMA req channel */ + int aha_scsi_dev; /* ourscsi bus address */ + struct scsi_link sc_link; /* prototype for subdevs */ +} *ahadata[NAHA]; + +struct aha_ccb *aha_get_ccb(); +int ahaprobe(); +void aha_done(); +int ahaattach(); +int ahaintr(); +int32 aha_scsi_cmd(); +void aha_timeout(); +void ahaminphys(); +u_int32 aha_adapter_info(); + +#ifdef KERNEL +struct scsi_adapter aha_switch = +{ + aha_scsi_cmd, + ahaminphys, + 0, + 0, + aha_adapter_info, + "aha", + 0, 0 +}; + +/* the below structure is so we have a default dev struct for out link struct */ +struct scsi_device aha_dev = +{ + NULL, /* Use default error handler */ + NULL, /* have a queue, served by this */ + NULL, /* have no async handler */ + NULL, /* Use default 'done' routine */ + "aha", + 0, + 0, 0 +}; +struct isa_driver ahadriver = +{ + ahaprobe, + ahaattach, + "aha" +}; + +#endif /* KERNEL */ + +static int ahaunit = 0; #define aha_abortmbx(mbx) \ (mbx)->cmd = AHA_MBO_ABORT; \ @@ -391,330 +360,307 @@ static int ahaunit = 0; (mbx)->cmd = AHA_MBO_START; \ outb(AHA_CMD_DATA_PORT, AHA_START_SCSI); +#define AHA_RESET_TIMEOUT 1000 /* time to wait for reset (mSec) */ +#ifndef KERNEL +main() +{ + printf("size of aha_data is %d\n", sizeof(struct aha_data)); + printf("size of aha_ccb is %d\n", sizeof(struct aha_ccb)); + printf("size of aha_mbx is %d\n", sizeof(struct aha_mbx)); +} +#else /*KERNEL */ -int aha_scsi_cmd(); -int aha_timeout(); -void ahaminphys(); -long int aha_adapter_info(); - -struct scsi_switch aha_switch = -{ - aha_scsi_cmd, - ahaminphys, - 0, - 0, - aha_adapter_info, - "aha", - 0,0 -}; -#define AHA_CMD_TIMEOUT_FUDGE 200 /* multiplied to get Secs */ -#define AHA_RESET_TIMEOUT 1000000 /* time to wait for reset */ -#define AHA_SCSI_TIMEOUT_FUDGE 20 /* divided by for mSecs */ - - -/***********************************************************************\ -* aha_cmd(unit,icnt, ocnt,wait, retval, opcode, args) * -* Activate Adapter command * -* icnt: number of args (outbound bytes written after opcode) * -* ocnt: number of expected returned bytes * -* wait: number of seconds to wait for response * -* retval: buffer where to place returned bytes * -* opcode: opcode AHA_NOP, AHA_MBX_INIT, AHA_START_SCSI ... * -* args: parameters * -* * -* Performs an adapter command through the ports. Not to be confused * -* with a scsi command, which is read in via the dma * -* One of the adapter commands tells it to read in a scsi command * -\***********************************************************************/ - - -aha_cmd(unit,icnt, ocnt, wait,retval, opcode, args) - -u_char *retval; -unsigned opcode; -u_char args; +/* + * aha_cmd(unit,icnt, ocnt,wait, retval, opcode, args) + * Activate Adapter command + * icnt: number of args (outbound bytes written after opcode) + * ocnt: number of expected returned bytes + * wait: number of seconds to wait for response + * retval: buffer where to place returned bytes + * opcode: opcode AHA_NOP, AHA_MBX_INIT, AHA_START_SCSI ... + * args: parameters + * + * Performs an adapter command through the ports. Not to be confused + * with a scsi command, which is read in via the dma. One of the adapter + * commands tells it to read in a scsi command but that one is done + * separately. This is only called during set-up. + */ +int +aha_cmd(unit, icnt, ocnt, wait, retval, opcode, args) + u_char *retval; + unsigned opcode; + u_char args; { + struct aha_data *aha = ahadata[unit]; unsigned *ic = &opcode; - u_char oc; + u_char oc; register i; - int sts; - - /*******************************************************\ - * multiply the wait argument by a big constant * - * zero defaults to 1 * - \*******************************************************/ - if(!wait) - wait = AHA_CMD_TIMEOUT_FUDGE * delaycount; + int sts; + + /* + * multiply the wait argument by a big constant + * zero defaults to 1 sec.. + * all wait loops are in 50uSec cycles + */ + if (wait) + wait *= 20000; else - wait *= AHA_CMD_TIMEOUT_FUDGE * delaycount; - /*******************************************************\ - * Wait for the adapter to go idle, unless it's one of * - * the commands which don't need this * - \*******************************************************/ - if (opcode != AHA_MBX_INIT && opcode != AHA_START_SCSI) - { - i = AHA_CMD_TIMEOUT_FUDGE * delaycount; /* 1 sec?*/ - while (--i) - { + wait = 20000; + /* + * Wait for the adapter to go idle, unless it's one of + * the commands which don't need this + */ + if (opcode != AHA_MBX_INIT && opcode != AHA_START_SCSI) { + i = 20000; /*do this for upto about a second */ + while (--i) { sts = inb(AHA_CTRL_STAT_PORT); - if (sts & AHA_IDLE) - { + if (sts & AHA_IDLE) { break; } + DELAY(50); } - if (!i) - { + if (!i) { printf("aha%d: aha_cmd, host not idle(0x%x)\n", - unit,sts); - return(ENXIO); + unit, sts); + return (ENXIO); } } - /*******************************************************\ - * Now that it is idle, if we expect output, preflush the* - * queue feeding to us. * - \*******************************************************/ - if (ocnt) - { - while((inb(AHA_CTRL_STAT_PORT)) & AHA_DF) + /* + * Now that it is idle, if we expect output, preflush the + * queue feeding to us. + */ + if (ocnt) { + while ((inb(AHA_CTRL_STAT_PORT)) & AHA_DF) inb(AHA_CMD_DATA_PORT); } - - /*******************************************************\ - * Output the command and the number of arguments given * - * for each byte, first check the port is empty. * - \*******************************************************/ - icnt++; /* include the command */ - while (icnt--) - { + /* + * Output the command and the number of arguments given + * for each byte, first check the port is empty. + */ + icnt++; + /* include the command */ + while (icnt--) { sts = inb(AHA_CTRL_STAT_PORT); - for (i=0; i< wait; i++) - { + for (i = wait; i; i--) { sts = inb(AHA_CTRL_STAT_PORT); if (!(sts & AHA_CDF)) break; + DELAY(50); } - if (i >= wait) - { - printf("aha%d: aha_cmd, cmd/data port full\n",unit); - outb(AHA_CTRL_STAT_PORT, AHA_SRST); - return(ENXIO); + if (i == 0) { + printf("aha%d: aha_cmd, cmd/data port full\n", unit); + outb(AHA_CTRL_STAT_PORT, AHA_SRST); + return (ENXIO); } - outb(AHA_CMD_DATA_PORT, (u_char)(*ic++)); + outb(AHA_CMD_DATA_PORT, (u_char) (*ic++)); } - /*******************************************************\ - * If we expect input, loop that many times, each time, * - * looking for the data register to have valid data * - \*******************************************************/ - while (ocnt--) - { + /* + * If we expect input, loop that many times, each time, + * looking for the data register to have valid data + */ + while (ocnt--) { sts = inb(AHA_CTRL_STAT_PORT); - for (i=0; i< wait; i++) - { + for (i = wait; i; i--) { sts = inb(AHA_CTRL_STAT_PORT); - if (sts & AHA_DF) + if (sts & AHA_DF) break; + DELAY(50); } - if (i >= wait) - { + if (i == 0) { printf("aha%d: aha_cmd, cmd/data port empty %d\n", - unit,ocnt); - return(ENXIO); + unit, ocnt); + return (ENXIO); } oc = inb(AHA_CMD_DATA_PORT); if (retval) *retval++ = oc; } - /*******************************************************\ - * Wait for the board to report a finised instruction * - \*******************************************************/ - i=AHA_CMD_TIMEOUT_FUDGE * delaycount; /* 1 sec? */ - while (--i) - { + /* + * Wait for the board to report a finised instruction + */ + i = 20000; + while (--i) { sts = inb(AHA_INTR_PORT); - if (sts & AHA_HACC) - { + if (sts & AHA_HACC) { break; } + DELAY(50); } - if (!i) - { - printf("aha%d: aha_cmd, host not finished(0x%x)\n",unit,sts); - return(ENXIO); + if (i == 0) { + printf("aha%d: aha_cmd, host not finished(0x%x)\n", unit, sts); + return (ENXIO); } outb(AHA_CTRL_STAT_PORT, AHA_IRST); - return(0); + return 0; } -/*******************************************************\ -* Check if the device can be found at the port given * -* and if so, set it up ready for further work * -* as an argument, takes the isa_dev structure from * -* autoconf.c * -\*******************************************************/ +/* + * Check if the device can be found at the port given + * and if so, set it up ready for further work + * as an argument, takes the isa_device structure from + * autoconf.c + */ +int ahaprobe(dev) -struct isa_dev *dev; + struct isa_device *dev; { - int unit = ahaunit; -#if defined(OSF) - static ihandler_t aha_handler[NAHA]; - static ihandler_id_t *aha_handler_id[NAHA]; - register ihandler_t *chp = &aha_handler[unit];; -#endif /* defined(OSF) */ - - /***********************************************\ - * find unit and check we have that many defined * - \***********************************************/ - dev->dev_unit = unit; - aha_base[unit] = dev->dev_addr; - if(unit >= NAHA) - { - printf("aha%d: unit number too high\n",unit); - return(0); + int unit = ahaunit; + struct aha_data *aha; + + /* + * find unit and check we have that many defined + */ + if (unit >= NAHA) { + printf("aha%d: unit number too high\n", unit); + return 0; } - /***********************************************\ - * Try initialise a unit at this location * - * sets up dma and bus speed, loads aha_int[unit]* - \***********************************************/ - if (aha_init(unit) != 0) - { - return(0); + dev->id_unit = unit; + + /* + * a quick safety check so we can be sleazy later + */ + if (sizeof(struct aha_data) > PAGESIZ) { + printf("aha struct > pagesize\n"); + return 0; } + /* + * Allocate a storage area for us + */ + if (ahadata[unit]) { + printf("aha%d: memory already allocated\n", unit); + return 0; + } + aha = malloc(sizeof(struct aha_data), M_TEMP, M_NOWAIT); + if (!aha) { + printf("aha%d: cannot malloc!\n", unit); + return 0; + } + ahadata[unit] = aha; + aha->aha_base = dev->id_iobase; + /* + * Try initialise a unit at this location + * sets up dma and bus speed, loads aha->aha_int + */ + if (aha_init(unit) != 0) { + ahadata[unit] = NULL; + free(aha, M_TEMP); + return 0; + } + /* + * Calculate the xor product of the aha struct's + * physical and virtual address. This allows us + * to change addresses within the structure + * from physical to virtual easily, as long as + * the structure is less than 1 page in size. + * This is used to recognise CCBs which are in + * this struct and which are refered to by the + * hardware using physical addresses. + * (assumes malloc returns a chunk that doesn't + * span pages) + * eventually use the hash table in aha1742.c + */ + aha->kv_phys_xor = (long int) aha ^ (KVTOPHYS(aha)); - /***********************************************\ - * If it's there, put in it's interrupt vectors * - \***********************************************/ -#if !defined(OSF) -#if defined MACH - iunit[aha_int[unit]] =unit; - ivect[aha_int[unit]] = ahaintr; - intpri[aha_int[unit]] = dev->dev_spl; - form_pic_mask(); - /*take_dev_irq(dev);*/ -#else -#ifdef __386BSD__ - dev->id_irq = (1 << aha_int[unit]); - dev->id_drq = aha_dma[unit]; -#endif __386BSD__ -#endif -#else /* !defined(OSF) */ - - dev->dev_pic = aha_dma[unit]; - chp->ih_level = dev->dev_pic; - chp->ih_handler = dev->dev_intr[0]; - chp->ih_resolver = i386_resolver; - chp->ih_rdev = dev; - chp->ih_stats.intr_type = INTR_DEVICE; - chp->ih_stats.intr_cnt = 0; - chp->ih_hparam[0].intparam = unit; - if ((aha_handler_id[unit] = handler_add(chp)) != NULL) - handler_enable(aha_handler_id[unit]); - else - panic("Unable to add aha interrupt handler"); -#endif /* !defined(OSF) */ -#ifndef __386BSD__ - printf("port=%x spl=%d\n", dev->dev_addr, dev->dev_spl); -#endif __386BSD__ - ahaunit ++; - return(1); + /* + * If it's there, put in it's interrupt vectors + */ + dev->id_irq = (1 << aha->aha_int); + dev->id_drq = aha->aha_dma; + ahaunit++; + return 0x4; } -/***********************************************\ -* Attach all the sub-devices we can find * -\***********************************************/ +/* + * Attach all the sub-devices we can find + */ +int ahaattach(dev) -struct isa_dev *dev; + struct isa_device *dev; { - int unit = dev->dev_unit; - - /***********************************************\ - * ask the adapter what subunits are present * - \***********************************************/ - scsi_attachdevs( unit, aha_scsi_dev[unit], &aha_switch); -#if defined(OSF) - aha_attached[unit]=1; -#endif /* defined(OSF) */ - return; + int unit = dev->id_unit; + struct aha_data *aha = ahadata[unit]; + + /* + * fill in the prototype scsi_link. + */ + aha->sc_link.adapter_unit = unit; + aha->sc_link.adapter_targ = aha->aha_scsi_dev; + aha->sc_link.adapter = &aha_switch; + aha->sc_link.device = &aha_dev; + + /* + * ask the adapter what subunits are present + */ + scsi_attachdevs(&(aha->sc_link)); + + return 1; } -/***********************************************\ -* Return some information to the caller about * -* the adapter and it's capabilities * -\***********************************************/ -long int aha_adapter_info(unit) -int unit; +/* + * Return some information to the caller about the adapter and its + * capabilities. + */ +u_int32 +aha_adapter_info(unit) + int unit; { - return(2); /* 2 outstanding requests at a time per device */ + return (2); /* 2 outstanding requests at a time per device */ } -/***********************************************\ -* Catch an interrupt from the adaptor * -\***********************************************/ +/* + * Catch an interrupt from the adaptor + */ +int ahaintr(unit) { struct aha_ccb *ccb; unsigned char stat; register i; + struct aha_data *aha = ahadata[unit]; #ifdef AHADEBUG - if(scsi_debug & PRINTROUTINES) - printf("ahaintr "); -#endif /*AHADEBUG*/ - /***********************************************\ - * First acknowlege the interrupt, Then if it's * - * not telling about a completed operation * - * just return. * - \***********************************************/ + printf("ahaintr "); +#endif /*AHADEBUG */ + /* + * First acknowlege the interrupt, Then if it's not telling about + * a completed operation just return. + */ stat = inb(AHA_INTR_PORT); outb(AHA_CTRL_STAT_PORT, AHA_IRST); + if (!(stat & AHA_MBIF)) + return 1; #ifdef AHADEBUG - if(scsi_debug & TRACEINTERRUPTS) - printf("int "); -#endif /*AHADEBUG*/ - if (! (stat & AHA_MBIF)) - return(1); -#ifdef AHADEBUG - if(scsi_debug & TRACEINTERRUPTS) - printf("b "); -#endif /*AHADEBUG*/ -#if defined(OSF) - if (!aha_attached[unit]) - { - return(1); - } -#endif /* defined(OSF) */ - /***********************************************\ - * If it IS then process the competed operation * - \***********************************************/ - for (i = 0; i < AHA_MBX_SIZE; i++) - { - if (aha_mbx[unit].mbi[i].stat != AHA_MBI_FREE) - { - ccb = (struct aha_ccb *)PHYSTOKV( - (_3btol(aha_mbx[unit].mbi[i].ccb_addr))); - - if((stat = aha_mbx[unit].mbi[i].stat) != AHA_MBI_OK) - { - switch(stat) - { - case AHA_MBI_ABORT: + printf("mbxin "); +#endif /*AHADEBUG */ + /* + * If it IS then process the competed operation + */ + for (i = 0; i < AHA_MBX_SIZE; i++) { + if (aha->aha_mbx.mbi[i].stat != AHA_MBI_FREE) { + ccb = (struct aha_ccb *) PHYSTOKV( + (_3btol(aha->aha_mbx.mbi[i].ccb_addr))); + + if ((stat = aha->aha_mbx.mbi[i].stat) != AHA_MBI_OK) { + switch (stat) { + case AHA_MBI_ABORT: #ifdef AHADEBUG - if(aha_debug) - printf("abort"); -#endif /*AHADEBUG*/ + if (aha_debug) + printf("abort"); +#endif /*AHADEBUG */ ccb->host_stat = AHA_ABORTED; break; - case AHA_MBI_UNKNOWN: - ccb = (struct aha_ccb *)0; + case AHA_MBI_UNKNOWN: + ccb = (struct aha_ccb *) 0; #ifdef AHADEBUG - if(aha_debug) - printf("unknown ccb for abort "); -#endif /*AHADEBUG*/ + if (aha_debug) + printf("unknown ccb for abort "); +#endif /*AHADEBUG */ /* may have missed it */ /* no such ccb known for abort */ - case AHA_MBI_ERROR: + case AHA_MBI_ERROR: break; default: @@ -722,214 +668,191 @@ ahaintr(unit) } #ifdef AHADEBUG - if( aha_debug && ccb ) - { - u_char *cp; - cp = (u_char *)(&(ccb->scsi_cmd)); - printf("op=%x %x %x %x %x %x\n", - cp[0], cp[1], cp[2], - cp[3], cp[4], cp[5]); + if (aha_debug && ccb) { + u_char *cp; + cp = (u_char *) (&(ccb->scsi_cmd)); + printf("op=%x %x %x %x %x %x\n", + cp[0], cp[1], cp[2], + cp[3], cp[4], cp[5]); printf("stat %x for mbi[%d]\n" - , aha_mbx[unit].mbi[i].stat, i); + ,aha->aha_mbx.mbi[i].stat, i); printf("addr = 0x%x\n", ccb); } -#endif /*AHADEBUG*/ +#endif /*AHADEBUG */ } - if(ccb) - { - untimeout(aha_timeout,ccb); - aha_done(unit,ccb); + if (ccb) { + untimeout(aha_timeout, ccb); + aha_done(unit, ccb); } - aha_mbx[unit].mbi[i].stat = AHA_MBI_FREE; + aha->aha_mbx.mbi[i].stat = AHA_MBI_FREE; } } - return(1); + return 1; } -/***********************************************\ -* A ccb (and hence a mbx-out is put onto the * -* free list. * -\***********************************************/ -aha_free_ccb(unit,ccb, flags) -struct aha_ccb *ccb; +/* + * A ccb (and hence a mbx-out is put onto the + * free list. + */ +void +aha_free_ccb(unit, ccb, flags) + struct aha_ccb *ccb; { + struct aha_data *aha = ahadata[unit]; unsigned int opri; - -#ifdef AHADEBUG - if(scsi_debug & PRINTROUTINES) - printf("ccb%d(0x%x)> ",unit,flags); -#endif /*AHADEBUG*/ - if (!(flags & SCSI_NOMASK)) - opri = splbio(); - - ccb->next = aha_ccb_free[unit]; - aha_ccb_free[unit] = ccb; + + if (!(flags & SCSI_NOMASK)) + opri = splbio(); + + ccb->next = aha->aha_ccb_free; + aha->aha_ccb_free = ccb; ccb->flags = CCB_FREE; - /***********************************************\ - * If there were none, wake abybody waiting for * - * one to come free, starting with queued entries* - \***********************************************/ + /* + * If there were none, wake anybody waiting for + * one to come free, starting with queued entries + */ if (!ccb->next) { - wakeup(&aha_ccb_free[unit]); + wakeup(&aha->aha_ccb_free); } - if (!(flags & SCSI_NOMASK)) + if (!(flags & SCSI_NOMASK)) splx(opri); } -/***********************************************\ -* Get a free ccb (and hence mbox-out entry) * -\***********************************************/ +/* + * Get a free ccb (and hence mbox-out entry) + */ struct aha_ccb * -aha_get_ccb(unit,flags) +aha_get_ccb(unit, flags) { + struct aha_data *aha = ahadata[unit]; unsigned opri; struct aha_ccb *rc; -#ifdef AHADEBUG - if(scsi_debug & PRINTROUTINES) - printf("aha_ccb_free)) && (!(flags & SCSI_NOSLEEP))) { + sleep(&aha->aha_ccb_free, PRIBIO); } - if (rc) - { - aha_ccb_free[unit] = aha_ccb_free[unit]->next; + if (rc) { + aha->aha_ccb_free = aha->aha_ccb_free->next; rc->flags = CCB_ACTIVE; } - if (!(flags & SCSI_NOMASK)) + if (!(flags & SCSI_NOMASK)) splx(opri); - return(rc); + return (rc); } - - -/***********************************************\ -* We have a ccb which has been processed by the * -* adaptor, now we look to see how the operation * -* went. Wake up the owner if waiting * -\***********************************************/ -aha_done(unit,ccb) -struct aha_ccb *ccb; + +/* + * We have a ccb which has been processed by the + * adaptor, now we look to see how the operation + * went. Wake up the owner if waiting + */ +void +aha_done(unit, ccb) + int unit; + struct aha_ccb *ccb; { - struct scsi_sense_data *s1,*s2; - struct scsi_xfer *xs = ccb->xfer; + struct aha_data *aha = ahadata[unit]; + struct scsi_sense_data *s1, *s2; + struct scsi_xfer *xs = ccb->xfer; -#ifdef AHADEBUG - if(scsi_debug & PRINTROUTINES ) - printf("aha_done "); -#endif /*AHADEBUG*/ - /***********************************************\ - * Otherwise, put the results of the operation * - * into the xfer and call whoever started it * - \***********************************************/ - if(!(xs->flags & INUSE)) - { - printf("aha%d: exiting but not in use!\n",unit); + SC_DEBUG(xs->sc_link, SDEV_DB2, ("aha_done\n")); + /* + * Otherwise, put the results of the operation + * into the xfer and call whoever started it + */ + if (!(xs->flags & INUSE)) { + printf("aha%d: exiting but not in use!\n", unit); Debugger(); } - if ( ( ccb->host_stat != AHA_OK - || ccb->target_stat != SCSI_OK) - && (!(xs->flags & SCSI_ERR_OK))) - { - s1 = (struct scsi_sense_data *)(((char *)(&ccb->scsi_cmd)) - + ccb->scsi_cmd_length); + if (((ccb->host_stat != AHA_OK) || (ccb->target_stat != SCSI_OK)) + && ((xs->flags & SCSI_ERR_OK) == 0)) { + /* + * We have an error, that we cannot ignore. + */ + s1 = (struct scsi_sense_data *) (((char *) (&ccb->scsi_cmd)) + + ccb->scsi_cmd_length); s2 = &(xs->sense); - if(ccb->host_stat) - { - switch(ccb->host_stat) - { - case AHA_ABORTED: - case AHA_SEL_TIMEOUT: /* No response */ + if (ccb->host_stat) { + SC_DEBUG(xs->sc_link, SDEV_DB3, ("host err 0x%x\n", + ccb->host_stat)); + switch (ccb->host_stat) { + case AHA_ABORTED: + case AHA_SEL_TIMEOUT: /* No response */ xs->error = XS_TIMEOUT; break; default: /* Other scsi protocol messes */ xs->error = XS_DRIVER_STUFFUP; -#ifdef AHADEBUG - if (aha_debug > 1) - { - printf("host_stat%x\n", - ccb->host_stat); - } -#endif /*AHADEBUG*/ + printf("aha%d:host_stat%x\n", + unit, ccb->host_stat); } - - } - else - { - switch(ccb->target_stat) - { + } else { + SC_DEBUG(xs->sc_link, SDEV_DB3, ("target err 0x%x\n", + ccb->target_stat)); + switch (ccb->target_stat) { case 0x02: - /* structure copy!!!!!*/ - *s2=*s1; + /* structure copy!!!!! */ + *s2 = *s1; xs->error = XS_SENSE; break; case 0x08: xs->error = XS_BUSY; break; default: -#ifdef AHADEBUG - if (aha_debug > 1) - { - printf("target_stat%x\n", - ccb->target_stat); - } -#endif /*AHADEBUG*/ + printf("aha%d:target_stat%x\n", + unit, ccb->target_stat); xs->error = XS_DRIVER_STUFFUP; } } - } - else /* All went correctly OR errors expected */ - { + } else { + /* All went correctly OR errors expected */ xs->resid = 0; } xs->flags |= ITSDONE; - aha_free_ccb(unit,ccb, xs->flags); - if(xs->when_done) - (*(xs->when_done))(xs->done_arg,xs->done_arg2); + aha_free_ccb(unit, ccb, xs->flags); + scsi_done(xs); } - -/***********************************************\ -* Start the board, ready for normal operation * -\***********************************************/ +/* + * Start the board, ready for normal operation + */ +int aha_init(unit) -int unit; + int unit; { + struct aha_data *aha = ahadata[unit]; unsigned char ad[3]; - volatile int i,sts; + volatile int i, sts; struct aha_config conf; struct aha_inquire inquire; struct aha_extbios extbios; - /***********************************************\ - * reset board, If it doesn't respond, assume * - * that it's not there.. good for the probe * - \***********************************************/ + /* + * reset board, If it doesn't respond, assume + * that it's not there.. good for the probe + */ - outb(AHA_CTRL_STAT_PORT, AHA_HRST|AHA_SRST); + outb(AHA_CTRL_STAT_PORT, AHA_HRST | AHA_SRST); - for (i=0; i < AHA_RESET_TIMEOUT; i++) - { - sts = inb(AHA_CTRL_STAT_PORT) ; - if ( sts == (AHA_IDLE | AHA_INIT)) + for (i = AHA_RESET_TIMEOUT; i; i--) { + sts = inb(AHA_CTRL_STAT_PORT); + if (sts == (AHA_IDLE | AHA_INIT)) break; + DELAY(1000); /* calibrated in msec */ } - if (i >= AHA_RESET_TIMEOUT) - { + if (i == 0) { #ifdef AHADEBUG if (aha_debug) printf("aha_init: No answer from adaptec board\n"); -#endif /*AHADEBUG*/ - return(ENXIO); +#endif /*AHADEBUG */ + return (ENXIO); } + /* * Assume we have a board at this stage, do an adapter inquire * to find out what type of controller it is @@ -967,514 +890,399 @@ int unit; aha_cmd(unit, 2, 0, 0, 0, AHA_MBX_ENABLE, 0, extbios.mailboxlock); } - /***********************************************\ - * Setup dma channel from jumpers and save int * - * level * - \***********************************************/ -#ifdef __386BSD__ - printf("aha%d: reading board settings, ",unit); -#define PRNT(x) printf(x) -#else __386BSD__ - printf("aha%d:",unit); + + /* + * setup dma channel from jumpers and save int + * level + */ + printf("aha%d: reading board settings, ", unit); #define PRNT(x) printf(x) -#endif __386BSD__ - DELAY(10000); /* for Bustek 545 */ - aha_cmd(unit,0, sizeof(conf), 0 ,&conf, AHA_CONF_GET); - switch(conf.chan) - { - case CHAN0: + DELAY(1000); /* for Bustek 545 */ + aha_cmd(unit, 0, sizeof(conf), 0, &conf, AHA_CONF_GET); + switch (conf.chan) { + case CHAN0: outb(0x0b, 0x0c); outb(0x0a, 0x00); - aha_dma[unit] = 0; + aha->aha_dma = 0; PRNT("dma=0 "); break; - case CHAN5: + case CHAN5: outb(0xd6, 0xc1); outb(0xd4, 0x01); - aha_dma[unit] = 5; + aha->aha_dma = 5; PRNT("dma=5 "); break; - case CHAN6: + case CHAN6: outb(0xd6, 0xc2); outb(0xd4, 0x02); - aha_dma[unit] = 6; + aha->aha_dma = 6; PRNT("dma=6 "); break; - case CHAN7: + case CHAN7: outb(0xd6, 0xc3); outb(0xd4, 0x03); - aha_dma[unit] = 7; + aha->aha_dma = 7; PRNT("dma=7 "); break; default: printf("illegal dma jumper setting\n"); - return(EIO); + return (EIO); } - switch(conf.intr) - { - case INT9: - aha_int[unit] = 9; + switch (conf.intr) { + case INT9: + aha->aha_int = 9; PRNT("int=9 "); break; - case INT10: - aha_int[unit] = 10; + case INT10: + aha->aha_int = 10; PRNT("int=10 "); break; - case INT11: - aha_int[unit] = 11; + case INT11: + aha->aha_int = 11; PRNT("int=11 "); break; - case INT12: - aha_int[unit] = 12; + case INT12: + aha->aha_int = 12; PRNT("int=12 "); break; - case INT14: - aha_int[unit] = 14; + case INT14: + aha->aha_int = 14; PRNT("int=14 "); break; - case INT15: - aha_int[unit] = 15; + case INT15: + aha->aha_int = 15; PRNT("int=15 "); break; default: printf("illegal int jumper setting\n"); - return(EIO); + return (EIO); } - /* who are we on the scsi bus */ - aha_scsi_dev[unit] = conf.scsi_dev; + /* who are we on the scsi bus? */ + aha->aha_scsi_dev = conf.scsi_dev; - /***********************************************\ - * Initialize memory transfer speed * - \***********************************************/ -/* - * XXX This code seems to BREAK more boards than it makes - * work right, we are just going to NOP this here... - */ -#if 0 - if(!(aha_set_bus_speed(unit))) - { - return(EIO); + /* + * Change the bus on/off times to not clash with other dma users. + */ + aha_cmd(unit, 1, 0, 0, 0, AHA_BUS_ON_TIME_SET, 7); + aha_cmd(unit, 1, 0, 0, 0, AHA_BUS_OFF_TIME_SET, 4); + +#ifdef TUNE_1542 + /* + * Initialize memory transfer speed + * Not compiled in by default because it breaks some machines + */ + if (!(aha_set_bus_speed(unit))) { + return (EIO); } #else printf ("\n"); -#endif - +#endif /*TUNE_1542*/ + /* + * Initialize mail box + */ + lto3b(KVTOPHYS(&aha->aha_mbx), ad); - /***********************************************\ - * Initialize mail box * - \***********************************************/ - - lto3b(KVTOPHYS(&aha_mbx[unit]), ad); - - aha_cmd(unit,4, 0, 0, 0, AHA_MBX_INIT, - AHA_MBX_SIZE, - ad[0], - ad[1], - ad[2]); - - - /***********************************************\ - * link the ccb's with the mbox-out entries and * - * into a free-list * - \***********************************************/ - for (i=0; i < AHA_MBX_SIZE; i++) { - aha_ccb[unit][i].next = aha_ccb_free[unit]; - aha_ccb_free[unit] = &aha_ccb[unit][i]; - aha_ccb_free[unit]->flags = CCB_FREE; - aha_ccb_free[unit]->mbx = &aha_mbx[unit].mbo[i]; - lto3b(KVTOPHYS(aha_ccb_free[unit]), aha_mbx[unit].mbo[i].ccb_addr); - } + aha_cmd(unit, 4, 0, 0, 0, AHA_MBX_INIT, + AHA_MBX_SIZE, + ad[0], + ad[1], + ad[2]); - /***********************************************\ - * Note that we are going and return (to probe) * - \***********************************************/ - aha_initialized[unit]++; - return(0); + /* + * link the ccb's with the mbox-out entries and + * into a free-list + * this is a kludge but it works + */ + for (i = 0; i < AHA_MBX_SIZE; i++) { + aha->aha_ccb[i].next = aha->aha_ccb_free; + aha->aha_ccb_free = &aha->aha_ccb[i]; + aha->aha_ccb_free->flags = CCB_FREE; + aha->aha_ccb_free->mbx = &aha->aha_mbx.mbo[i]; + lto3b(KVTOPHYS(aha->aha_ccb_free), aha->aha_mbx.mbo[i].ccb_addr); + } + /* + * Note that we are going and return (to probe) + */ + return 0; } - - - - -void ahaminphys(bp) -struct buf *bp; +void +ahaminphys(bp) + struct buf *bp; { -#ifdef MACH -#if !defined(OSF) - bp->b_flags |= B_NPAGES; /* can support scat/gather */ -#endif /* !defined(OSF) */ -#endif MACH -/* aha seems to explode with 17 segs (64k may require 17 segs) */ -/* on old boards so use a max of 16 segs if you have problems here*/ - if(bp->b_bcount > ((AHA_NSEG - 1) * PAGESIZ)) - { +/* aha seems to explode with 17 segs (64k may require 17 segs) */ +/* on old boards so use a max of 16 segs if you have problems here */ + if (bp->b_bcount > ((AHA_NSEG - 1) * PAGESIZ)) { bp->b_bcount = ((AHA_NSEG - 1) * PAGESIZ); } } - -/***********************************************\ -* start a scsi operation given the command and * -* the data address. Also needs the unit, target * -* and lu * -\***********************************************/ -int aha_scsi_cmd(xs) -struct scsi_xfer *xs; + +/* + * start a scsi operation given the command and + * the data address. Also needs the unit, target + * and lu + */ +int32 +aha_scsi_cmd(xs) + struct scsi_xfer *xs; { - struct scsi_sense_data *s1,*s2; + struct scsi_link *sc_link = xs->sc_link; + int unit = sc_link->adapter_unit; + struct aha_data *aha = ahadata[unit]; + struct scsi_sense_data *s1, *s2; struct aha_ccb *ccb; struct aha_scat_gath *sg; - int seg; /* scatter gather seg being worked on */ - int i = 0; - int rc = 0; - int thiskv; - int thisphys,nextphys; - int unit =xs->adapter; - int bytes_this_seg,bytes_this_page,datalen,flags; - struct iovec *iovp; - int s; - -#ifdef AHADEBUG - if(scsi_debug & PRINTROUTINES) - printf("aha_scsi_cmd "); -#endif /*AHADEBUG*/ - /***********************************************\ - * get a ccb (mbox-out) to use. If the transfer * - * is from a buf (possibly from interrupt time) * - * then we can't allow it to sleep * - \***********************************************/ + int seg; /* scatter gather seg being worked on */ + int i = 0; + int rc = 0; + int thiskv; + int thisphys, nextphys; + int bytes_this_seg, bytes_this_page, datalen, flags; + struct iovec *iovp; + int s; + + SC_DEBUG(xs->sc_link, SDEV_DB2, ("aha_scsi_cmd\n")); + /* + * get a ccb (mbox-out) to use. If the transfer + * is from a buf (possibly from interrupt time) + * then we can't allow it to sleep + */ flags = xs->flags; - if(!(flags & INUSE)) - { - printf("aha%d: not in use!\n",unit); - Debugger(); - xs->flags |= INUSE; - } - if(flags & ITSDONE) - { - printf("aha%d: Already done! check device retry code\n",unit); - Debugger(); - xs->flags &= ~ITSDONE; - } - if(xs->bp) flags |= (SCSI_NOSLEEP); /* just to be sure */ - if (!(ccb = aha_get_ccb(unit,flags))) - { + if (!(ccb = aha_get_ccb(unit, flags))) { xs->error = XS_DRIVER_STUFFUP; - return(TRY_AGAIN_LATER); + return (TRY_AGAIN_LATER); } - if (ccb->mbx->cmd != AHA_MBO_FREE) - printf("aha%d: MBO not free\n",unit); + printf("aha%d: MBO not free\n", unit); - /***********************************************\ - * Put all the arguments for the xfer in the ccb * - \***********************************************/ - ccb->xfer = xs; - if(flags & SCSI_RESET) - { - ccb->opcode = AHA_RESET_CCB; - } - else - { + /* + * Put all the arguments for the xfer in the ccb + */ + ccb->xfer = xs; + if (flags & SCSI_RESET) { + ccb->opcode = AHA_RESET_CCB; + } else { /* can't use S/G if zero length */ - ccb->opcode = (xs->datalen? - AHA_INIT_SCAT_GATH_CCB - :AHA_INITIATOR_CCB); + ccb->opcode = (xs->datalen ? + AHA_INIT_SCAT_GATH_CCB + : AHA_INITIATOR_CCB); } - ccb->target = xs->targ;; - ccb->data_out = 0; - ccb->data_in = 0; - ccb->lun = xs->lu; - ccb->scsi_cmd_length = xs->cmdlen; - ccb->req_sense_length = sizeof(ccb->scsi_sense); - - if((xs->datalen) && (!(flags & SCSI_RESET))) - { /* can use S/G only if not zero length */ - lto3b(KVTOPHYS(ccb->scat_gath), ccb->data_addr ); - sg = ccb->scat_gath ; - seg = 0; - if(flags & SCSI_DATA_UIO) - { - iovp = ((struct uio *)xs->data)->uio_iov; - datalen = ((struct uio *)xs->data)->uio_iovcnt; - while ((datalen) && (seg < AHA_NSEG)) - { - lto3b(iovp->iov_base,&(sg->seg_addr)); - lto3b(iovp->iov_len,&(sg->seg_len)); -#ifdef AHADEBUG - if(scsi_debug & SHOWSCATGATH) - printf("(0x%x@0x%x)" - ,iovp->iov_len - ,iovp->iov_base); -#endif /*AHADEBUG*/ + ccb->target = sc_link->target; + ccb->data_out = 0; + ccb->data_in = 0; + ccb->lun = sc_link->lun; + ccb->scsi_cmd_length = xs->cmdlen; + ccb->req_sense_length = sizeof(ccb->scsi_sense); + + if ((xs->datalen) && (!(flags & SCSI_RESET))) { + /* can use S/G only if not zero length */ + lto3b(KVTOPHYS(ccb->scat_gath), ccb->data_addr); + sg = ccb->scat_gath; + seg = 0; +#ifdef TFS_ONLY + if (flags & SCSI_DATA_UIO) { + iovp = ((struct uio *) xs->data)->uio_iov; + datalen = ((struct uio *) xs->data)->uio_iovcnt; + while ((datalen) && (seg < AHA_NSEG)) { + lto3b(iovp->iov_base, sg->seg_addr); + lto3b(iovp->iov_len, sg->seg_len); + SC_DEBUGN(xs->sc_link, SDEV_DB4, ("UIO(0x%x@0x%x)" + ,iovp->iov_len + ,iovp->iov_base)); sg++; iovp++; seg++; datalen--; } - } - else + } else +#endif /*TFS_ONLY */ { - /***********************************************\ - * Set up the scatter gather block * - \***********************************************/ - -#ifdef AHADEBUG - if(scsi_debug & SHOWSCATGATH) - printf("%d @0x%x:- ",xs->datalen,xs->data); -#endif /*AHADEBUG*/ - datalen = xs->datalen; - thiskv = (int)xs->data; - thisphys = KVTOPHYS(thiskv); - - while ((datalen) && (seg < AHA_NSEG)) - { - bytes_this_seg = 0; - + /* + * Set up the scatter gather block + */ + + SC_DEBUG(xs->sc_link, SDEV_DB4, + ("%d @0x%x:- ", xs->datalen, xs->data)); + datalen = xs->datalen; + thiskv = (int) xs->data; + thisphys = KVTOPHYS(thiskv); + + while ((datalen) && (seg < AHA_NSEG)) { + bytes_this_seg = 0; + /* put in the base address */ - lto3b(thisphys,&(sg->seg_addr)); - -#ifdef AHADEBUG - if(scsi_debug & SHOWSCATGATH) - printf("0x%x",thisphys); -#endif /*AHADEBUG*/ - + lto3b(thisphys, sg->seg_addr); + + SC_DEBUGN(xs->sc_link, SDEV_DB4, + ("0x%x", thisphys)); + /* do it at least once */ - nextphys = thisphys; - while ((datalen) && (thisphys == nextphys)) - /***************************************\ - * This page is contiguous (physically) * - * with the the last, just extend the * - * length * - \***************************************/ - { + nextphys = thisphys; + while ((datalen) && (thisphys == nextphys)) { + /* + * This page is contiguous (physically) + * with the the last, just extend the + * length + */ + /* check it fits on the ISA bus */ + if (thisphys > 0xFFFFFF) + { + printf("aha%d: DMA beyond" + " end Of ISA\n", unit); + xs->error = XS_DRIVER_STUFFUP; + aha_free_ccb(unit, ccb, flags); + return (HAD_ERROR); + } /** how far to the end of the page ***/ nextphys = (thisphys & (~(PAGESIZ - 1))) - + PAGESIZ; - bytes_this_page = nextphys - thisphys; + + PAGESIZ; + bytes_this_page = nextphys - thisphys; /**** or the data ****/ - bytes_this_page = min(bytes_this_page - ,datalen); - bytes_this_seg += bytes_this_page; - datalen -= bytes_this_page; - + bytes_this_page = min(bytes_this_page + ,datalen); + bytes_this_seg += bytes_this_page; + datalen -= bytes_this_page; + /**** get more ready for the next page ****/ - thiskv = (thiskv & (~(PAGESIZ - 1))) - + PAGESIZ; - if(datalen) + thiskv = (thiskv & (~(PAGESIZ - 1))) + + PAGESIZ; + if (datalen) thisphys = KVTOPHYS(thiskv); } - /***************************************\ - * next page isn't contiguous, finish the seg* - \***************************************/ -#ifdef AHADEBUG - if(scsi_debug & SHOWSCATGATH) - printf("(0x%x)",bytes_this_seg); -#endif /*AHADEBUG*/ - lto3b(bytes_this_seg,&(sg->seg_len)); + /* + * next page isn't contiguous, finish the seg + */ + SC_DEBUGN(xs->sc_link, SDEV_DB4, + ("(0x%x)", bytes_this_seg)); + lto3b(bytes_this_seg, sg->seg_len); sg++; seg++; } } - lto3b(seg * sizeof(struct aha_scat_gath),ccb->data_length); -#ifdef AHADEBUG - if(scsi_debug & SHOWSCATGATH) - printf("\n"); -#endif /*AHADEBUG*/ - if (datalen) - { /* there's still data, must have run out of segs! */ + lto3b(seg * sizeof(struct aha_scat_gath), ccb->data_length); + SC_DEBUGN(xs->sc_link, SDEV_DB4, ("\n")); + + if (datalen) { /* there's still data, must have run out of segs! */ printf("aha%d: aha_scsi_cmd, more than %d DMA segs\n", - unit,AHA_NSEG); + unit, AHA_NSEG); xs->error = XS_DRIVER_STUFFUP; - aha_free_ccb(unit,ccb,flags); - return(HAD_ERROR); + aha_free_ccb(unit, ccb, flags); + return (HAD_ERROR); } - + } else { /* No data xfer, use non S/G values */ + lto3b(0, ccb->data_addr); + lto3b(0, ccb->data_length); } - else - { /* No data xfer, use non S/G values */ - lto3b(0, ccb->data_addr ); - lto3b(0,ccb->data_length); - } - lto3b(0, ccb->link_addr ); - /***********************************************\ - * Put the scsi command in the ccb and start it * - \***********************************************/ - if(!(flags & SCSI_RESET)) + lto3b(0, ccb->link_addr); + /* + * Put the scsi command in the ccb and start it + */ + if (!(flags & SCSI_RESET)) bcopy(xs->cmd, &ccb->scsi_cmd, ccb->scsi_cmd_length); -#ifdef AHADEBUG - if(scsi_debug & SHOWCOMMANDS) - { - u_char *b = (u_char *)&ccb->scsi_cmd; - if(!(flags & SCSI_RESET)) - { - int i = 0; - printf("aha%d:%d:%d-" - ,unit - ,ccb->target - ,ccb->lun ); - while(i < ccb->scsi_cmd_length ) - { - if(i) printf(","); - printf("%x",b[i++]); - } - } - else - { - printf("aha%d:%d:%d-RESET- " - ,unit - ,ccb->target - ,ccb->lun - ); - } - } -#endif /*AHADEBUG*/ - if (!(flags & SCSI_NOMASK)) - { - s= splbio(); /* stop instant timeouts */ - timeout(aha_timeout,ccb,(xs->timeout * hz) / 1000); + if (!(flags & SCSI_NOMASK)) { + s = splbio(); /* stop instant timeouts */ + timeout(aha_timeout, ccb, (xs->timeout * hz) / 1000); aha_startmbx(ccb->mbx); - /***********************************************\ - * Usually return SUCCESSFULLY QUEUED * - \***********************************************/ + /* + * Usually return SUCCESSFULLY QUEUED + */ splx(s); -#ifdef AHADEBUG - if(scsi_debug & TRACEINTERRUPTS) - printf("sent "); -#endif /*AHADEBUG*/ - return(SUCCESSFULLY_QUEUED); + SC_DEBUG(xs->sc_link, SDEV_DB3, ("sent\n")); + return (SUCCESSFULLY_QUEUED); } aha_startmbx(ccb->mbx); -#ifdef AHADEBUG - if(scsi_debug & TRACEINTERRUPTS) - printf("cmd_sent, waiting "); -#endif /*AHADEBUG*/ - /***********************************************\ - * If we can't use interrupts, poll on completion* - \***********************************************/ - { - int done = 0; - int count = delaycount * xs->timeout / AHA_SCSI_TIMEOUT_FUDGE; - while((!done) && count) - { - i=0; - while ( (!done) && iflags & SCSI_SILENT)) - printf("aha%d: cmd fail\n",unit); - aha_abortmbx(ccb->mbx); - count = delaycount * 2000 / AHA_SCSI_TIMEOUT_FUDGE; - while((!done) && count) - { - i=0; - while ( (!done) && imbx->cmd = AHA_MBO_FREE; - } - aha_free_ccb(unit,ccb,flags); - ahaintr(unit); - xs->error = XS_DRIVER_STUFFUP; - return(HAD_ERROR); - } - ahaintr(unit); - if(xs->error) return(HAD_ERROR); - return(COMPLETE); + SC_DEBUG(xs->sc_link, SDEV_DB3, ("cmd sent, waiting\n")); - } + /* + * If we can't use interrupts, poll on completion + */ + return (aha_poll(unit, xs, ccb)); /* only during boot */ } -/***************************************************************\ -* try each speed in turn, when we find one that works, use * -* the NEXT one for a safety margin, unless that doesn't exist * -* or doesn't work. returns the nSEC value of the time used * -* or 0 if it could get a working speed ( or the NEXT speed * -* failed) * -\***************************************************************/ - -int aha_set_bus_speed(unit) -int unit; -{ - int speed; - int retval,retval2; -#ifdef EISA - speed = 0; /* start at the fastest */ -#else EISA - speed = 1; /* 100 ns can crash some ISA busses (!?!) */ -#endif EISA - while (1) - { - retval = aha_bus_speed_check(unit,speed); - if(retval == HAD_ERROR) - { - printf("no working bus speed!!!\n"); - return(0); +/* + * Poll a particular unit, looking for a particular xs + */ +int +aha_poll(unit, xs, ccb) + int unit; + struct scsi_xfer *xs; + struct aha_ccb *ccb; +{ + struct aha_data *aha = ahadata[unit]; + int done = 0; + int count = xs->timeout; + u_char stat; + + /*timeouts are in msec, so we loop in 1000uSec cycles */ + while (count) { + /* + * If we had interrupts enabled, would we + * have got an interrupt? + */ + stat = inb(AHA_INTR_PORT); + if (stat & AHA_ANY_INTR) { + ahaintr(unit); } - if(retval == 0) - { - speed++; + if (xs->flags & ITSDONE) { + break; } - else /* Go one slower to be safe */ - { /* unless eisa at 100 ns.. trust it */ - if(speed != 0) - { - speed++; - } - printf("%d nSEC ok, using ",retval); - retval2 = aha_bus_speed_check(unit,speed); - if(retval2 == HAD_ERROR) /* retval is slowest already */ - { - printf("marginal "); - retval2 = retval; - } - if(retval2) - { - printf("%d nSEC\n",retval2); - return(retval2); + DELAY(1000); /* only happens in boot so ok */ + count--; + } + if (count == 0) { + /* + * We timed out, so call the timeout handler + * manually, accout for the fact that the + * clock is not running yet by taking out the + * clock queue entry it makes + */ + aha_timeout(ccb); + + /* + * because we are polling, + * take out the timeout entry aha_timeout made + */ + untimeout(aha_timeout, ccb); + count = 2000; + while (count) { + /* + * Once again, wait for the int bit + */ + stat = inb(AHA_INTR_PORT); + if (stat & AHA_ANY_INTR) { + ahaintr(unit); } - else - { - printf(".. slower failed, abort\n",retval); - return(0); + if (xs->flags & ITSDONE) { + break; } - + DELAY(1000); /* only happens in boot so ok */ + count--; + } + if (count == 0) { + /* + * We timed out again.. this is bad + * Notice that this time there is no + * clock queue entry to remove + */ + aha_timeout(ccb); } } + if (xs->error) + return (HAD_ERROR); + return (COMPLETE); + } -/***************************************************************\ -* Set the DMA speed to the Nth speed and try an xfer. If it * -* fails return 0, if it succeeds return the nSec value selected * -* If there is no such speed return HAD_ERROR. * -\***************************************************************/ +#ifdef TUNE_1542 +/* + * Try all the speeds from slowest to fastest.. if it finds a + * speed that fails, back off one notch from the last working + * speed (unless there is no other notch). + * Returns the nSEC value of the time used + * or 0 if it could get a working speed (or the NEXT speed + * failed) + */ static struct bus_speed { char arg; @@ -1490,93 +1298,146 @@ static struct bus_speed {0xee,400}, {0xff,450} }; -static char aha_test_string[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890abcdefghijklmnopqrstuvwxyz!@"; -int aha_bus_speed_check(unit,speed) -int unit,speed; +int +aha_set_bus_speed(unit) + int unit; { - int numspeeds = sizeof(aha_bus_speeds)/sizeof(struct bus_speed); - u_char ad[3]; + int speed; + int lastworking; + int retval,retval2; + struct aha_data *aha = ahadata[unit]; - /*******************************************************\ - * Check we have such an entry * - \*******************************************************/ - if(speed >= numspeeds) return(HAD_ERROR); /* illegal speed */ - - /*******************************************************\ - * Set the dma-speed * - \*******************************************************/ - aha_cmd(unit,1, 0, 0, 0, AHA_SPEED_SET,aha_bus_speeds[speed].arg); - - /*******************************************************\ - * put the test data into the buffer and calculate * - * it's address. Read it onto the board * - \*******************************************************/ - strcpy(aha_scratch_buf,aha_test_string); - lto3b(KVTOPHYS(aha_scratch_buf),ad); - - aha_cmd(unit,3, 0, 0, 0, AHA_WRITE_FIFO, ad[0], ad[1], ad[2]); - - /*******************************************************\ - * clear the buffer then copy the contents back from the * - * board. * - \*******************************************************/ - bzero(aha_scratch_buf,54); /* 54 bytes transfered by test */ - - aha_cmd(unit,3, 0, 0, 0, AHA_READ_FIFO, ad[0], ad[1], ad[2]); - - /*******************************************************\ - * Compare the original data and the final data and * - * return the correct value depending upon the result * - \*******************************************************/ - if(strcmp(aha_test_string,aha_scratch_buf)) - { /* copy failed.. assume too fast */ - return(0); - } - else - { /* copy succeded assume speed ok */ - return(aha_bus_speeds[speed].nsecs); + lastworking = -1; + speed = 7; + while (1) { + retval = aha_bus_speed_check(unit,speed); + if(retval != 0) { + lastworking = speed; + } + if((retval == 0) || (speed == 0)) { + if(lastworking == -1) { + printf("No working bus speed for aha154X\n"); + return 0; + } + printf("%d nSEC ok, using " + ,aha_bus_speeds[lastworking].nsecs); + if(lastworking == 7) { /* is slowest already */ + printf("marginal "); + } else { + lastworking++; + } + retval2 = aha_bus_speed_check(unit,lastworking); + if(retval2 == 0) { + printf("test retry failed.. aborting.\n"); + return 0; + } + printf("%d nSEC\n",retval2); + return retval2 ; + + } + speed--; } } +/* + * Set the DMA speed to the Nth speed and try an xfer. If it + * fails return 0, if it succeeds return the nSec value selected + * If there is no such speed return HAD_ERROR. + */ +static char aha_test_string[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890abcdefghijklmnopqrstuvwxyz!@"; - -aha_timeout(struct aha_ccb *ccb) +int +aha_bus_speed_check(unit, speed) + int unit, speed; { - int unit; - int s = splbio(); + int numspeeds = sizeof(aha_bus_speeds) / sizeof(struct bus_speed); + int loopcount; + u_char ad[3]; + struct aha_data *aha = ahadata[unit]; + + /* + * Check we have such an entry + */ + if (speed >= numspeeds) + return (HAD_ERROR); /* illegal speed */ - unit = ccb->xfer->adapter; - printf("aha%d: device %d timed out ",unit ,ccb->xfer->targ); + /* + * Set the dma-speed + */ + aha_cmd(unit, 1, 0, 0, 0, AHA_SPEED_SET, aha_bus_speeds[speed].arg); - /***************************************\ - * If The ccb's mbx is not free, then * - * the board has gone south * - \***************************************/ - if(ccb->mbx->cmd != AHA_MBO_FREE) + /* + * put the test data into the buffer and calculate + * it's address. Read it onto the board + */ + lto3b(KVTOPHYS(aha_scratch_buf), ad); + for(loopcount = 2000;loopcount;loopcount--) { - printf("aha%d: not taking commands!\n",unit); + strcpy(aha_scratch_buf, aha_test_string); + + aha_cmd(unit, 3, 0, 0, 0, AHA_WRITE_FIFO, ad[0], ad[1], ad[2]); + + /* + * clear the buffer then copy the contents back from the + * board. + */ + bzero(aha_scratch_buf, 54); /* 54 bytes transfered by test */ + + aha_cmd(unit, 3, 0, 0, 0, AHA_READ_FIFO, ad[0], ad[1], ad[2]); + + /* + * Compare the original data and the final data and + * return the correct value depending upon the result + */ + if (strcmp(aha_test_string, aha_scratch_buf)) + return 0; /* failed test */ + } + /* copy succeded assume speed ok */ + + return (aha_bus_speeds[speed].nsecs); + +} +#endif /*TUNE_1542*/ + +void +aha_timeout(struct aha_ccb * ccb) +{ + int unit; + int s = splbio(); + struct aha_data *aha; + + unit = ccb->xfer->sc_link->adapter_unit; + aha = ahadata[unit]; + sc_print_addr(ccb->xfer->sc_link); + printf("timed out "); + + /* + * If The ccb's mbx is not free, then + * the board has gone south + */ + if (ccb->mbx->cmd != AHA_MBO_FREE) { + printf("\nadapter not taking commands.. frozen?!\n"); Debugger(); } - /***************************************\ - * If it has been through before, then * - * a previous abort has failed, don't * - * try abort again * - \***************************************/ - if(ccb->flags == CCB_ABORTED) /* abort timed out */ - { + /* + * If it has been through before, then + * a previous abort has failed, don't + * try abort again + */ + if (ccb->flags == CCB_ABORTED) { + /* abort timed out */ printf(" AGAIN\n"); - ccb->xfer->retries = 0; /* I MEAN IT ! */ + ccb->xfer->retries = 0; /* I MEAN IT ! */ ccb->host_stat = AHA_ABORTED; - aha_done(unit,ccb); - } - else /* abort the operation that has timed out */ - { + aha_done(unit, ccb); + } else { + /* abort the operation that has timed out */ printf("\n"); aha_abortmbx(ccb->mbx); - /* 2 secs for the abort */ - timeout(aha_timeout,ccb,2 * hz); + /* 4 secs for the abort */ + timeout(aha_timeout, ccb, 4 * hz); ccb->flags = CCB_ABORTED; - } - splx(s); + } splx(s); } +#endif /* KERNEL */ diff --git a/sys/i386/isa/aha1742.c b/sys/i386/isa/aha1742.c index 1e3e154f43..dda504207d 100644 --- a/sys/i386/isa/aha1742.c +++ b/sys/i386/isa/aha1742.c @@ -14,88 +14,74 @@ * * commenced: Sun Sep 27 18:14:01 PDT 1992 * - * $Id: aha1742.c,v 1.9 1993/08/28 03:07:40 rgrimes Exp $ + * $Id: aha1742.c,v 2.4 93/10/24 12:47:00 julian Exp Locker: julian $ */ #include -#include +#ifdef KERNEL /* don't laugh, it compiles as a program too.. look */ +#include #include #include #include #include +#include #include #include #include - -#ifdef MACH /* EITHER CMU OR OSF */ -#include -#include -#include - -#ifdef OSF /* OSF ONLY */ -#include -#include -#include -#include - -#else OSF /* CMU ONLY */ -#include -#include -#endif OSF -#endif MACH /* end of MACH specific */ - -#ifdef __386BSD__ /* 386BSD specific */ -#define isa_dev isa_device -#define dev_unit id_unit -#define dev_addr id_iobase - #include #include +#endif /*KERNEL */ #include #include -#endif __386BSD__ -/* */ +/* */ -#ifdef __386BSD__ +#ifdef KERNEL +# ifdef NetBSD +# ifdef DDB +int Debugger(); +# else /* DDB */ +#define Debugger() panic("should call debugger here (adaptec.c)") +# endif /* DDB */ +# else #include "ddb.h" #if NDDB > 0 int Debugger(); -#else NDDB +#else /* NDDB */ #define Debugger() panic("should call debugger here (adaptec.c)") -#endif NDDB -#endif __386BSD__ - -#ifdef MACH -int Debugger(); -#endif MACH +#endif /* NDDB */ +#endif /* netbsd */ +#else /* KERNEL */ +#define NAHB 1 +#endif /* kernel */ + +#ifndef NetBSD +typedef void (*timeout_t) __P((caddr_t)); +#endif typedef unsigned long int physaddr; -extern int hz; - -#ifdef MACH -extern physaddr kvtophys(); -#define PHYSTOKV(x) phystokv(x) -#define KVTOPHYS(x) kvtophys(x) -#endif MACH +extern int hz; -#ifdef __386BSD__ #define KVTOPHYS(x) vtophys(x) -#endif __386BSD__ - -extern int delaycount; /* from clock setup code */ -#define NUM_CONCURRENT 16 /* number of concurrent ops per board */ -#define AHB_NSEG 33 /* number of dma segments supported */ -#define FUDGE(X) (X>>1) /* our loops are slower than spinwait() */ -/* */ -/***********************************************************************\ -* AHA1740 standard EISA Host ID regs (Offset from slot base) * -\***********************************************************************/ -#define HID0 0xC80 /* 0,1: msb of ID2, 3-7: ID1 */ -#define HID1 0xC81 /* 0-4: ID3, 4-7: LSB ID2 */ -#define HID2 0xC82 /* product, 0=174[20] 1 = 1744 */ -#define HID3 0xC83 /* firmware revision */ + +#define AHB_ECB_MAX 32 /* store up to 32ECBs at any one time */ + /* in aha1742 H/W ( Not MAX ? ) */ +#define ECB_HASH_SIZE 32 /* when we have a physical addr. for */ + /* a ecb and need to find the ecb in */ + /* space, look it up in the hash table */ +#define ECB_HASH_SHIFT 9 /* only hash on multiples of 512 */ +#define ECB_HASH(x) ((((long int)(x))>>ECB_HASH_SHIFT) % ECB_HASH_SIZE) + +#define AHB_NSEG 33 /* number of dma segments supported */ + +/* + * AHA1740 standard EISA Host ID regs (Offset from slot base) + */ +#define HID0 0xC80 /* 0,1: msb of ID2, 3-7: ID1 */ +#define HID1 0xC81 /* 0-4: ID3, 4-7: LSB ID2 */ +#define HID2 0xC82 /* product, 0=174[20] 1 = 1744 */ +#define HID3 0xC83 /* firmware revision */ #define CHAR1(B1,B2) (((B1>>2) & 0x1F) | '@') #define CHAR2(B1,B2) (((B1<<3) & 0x18) | ((B2>>5) & 0x7)|'@') @@ -104,9 +90,9 @@ extern int delaycount; /* from clock setup code */ /* AHA1740 EISA board control registers (Offset from slot base) */ #define EBCTRL 0xC84 #define CDEN 0x01 -/***********************************************************************\ -* AHA1740 EISA board mode registers (Offset from slot base) * -\***********************************************************************/ +/* + * AHA1740 EISA board mode registers (Offset from slot base) + */ #define PORTADDR 0xCC0 #define PORTADDR_ENHANCED 0x80 #define BIOSADDR 0xCC1 @@ -123,18 +109,18 @@ extern int delaycount; /* from clock setup code */ #define INT12 0x03 #define INT14 0x05 #define INT15 0x06 -#define INTHIGH 0x08 /* int high=ACTIVE (else edge) */ +#define INTHIGH 0x08 /* int high=ACTIVE (else edge) */ #define INTEN 0x10 /**** bit definitions for SCSIDEF ****/ -#define HSCSIID 0x0F /* our SCSI ID */ -#define RSTPWR 0x10 /* reset scsi bus on power up or reset */ +#define HSCSIID 0x0F /* our SCSI ID */ +#define RSTPWR 0x10 /* reset scsi bus on power up or reset */ /**** bit definitions for BUSDEF ****/ -#define B0uS 0x00 /* give up bus immediatly */ -#define B4uS 0x01 /* delay 4uSec. */ +#define B0uS 0x00 /* give up bus immediatly */ +#define B4uS 0x01 /* delay 4uSec. */ #define B8uS 0x02 -/***********************************************************************\ -* AHA1740 ENHANCED mode mailbox control regs (Offset from slot base) * -\***********************************************************************/ +/* + * AHA1740 ENHANCED mode mailbox control regs (Offset from slot base) + */ #define MBOXOUT0 0xCD0 #define MBOXOUT1 0xCD1 #define MBOXOUT2 0xCD2 @@ -152,9 +138,9 @@ extern int delaycount; /* from clock setup code */ #define G2STAT2 0xCDC -/*******************************************************\ -* Bit definitions for the 5 control/status registers * -\*******************************************************/ +/* + * Bit definitions for the 5 control/status registers + */ #define ATTN_TARGET 0x0F #define ATTN_OPCODE 0xF0 #define OP_IMMED 0x10 @@ -181,138 +167,130 @@ extern int delaycount; /* from clock setup code */ #define G2STAT_MBOX_EMPTY 0x04 #define G2STAT2_HOST_READY 0x01 -/* */ -struct ahb_dma_seg -{ - physaddr addr; - long len; +struct ahb_dma_seg { + physaddr addr; + long len; }; -struct ahb_ecb_status -{ - u_short status; -# define ST_DON 0x0001 -# define ST_DU 0x0002 -# define ST_QF 0x0008 -# define ST_SC 0x0010 -# define ST_DO 0x0020 -# define ST_CH 0x0040 -# define ST_INT 0x0080 -# define ST_ASA 0x0100 -# define ST_SNS 0x0200 -# define ST_INI 0x0800 -# define ST_ME 0x1000 -# define ST_ECA 0x4000 - u_char ha_status; -# define HS_OK 0x00 -# define HS_CMD_ABORTED_HOST 0x04 -# define HS_CMD_ABORTED_ADAPTER 0x05 -# define HS_TIMED_OUT 0x11 -# define HS_HARDWARE_ERR 0x20 -# define HS_SCSI_RESET_ADAPTER 0x22 -# define HS_SCSI_RESET_INCOMING 0x23 - u_char targ_status; -# define TS_OK 0x00 -# define TS_CHECK_CONDITION 0x02 -# define TS_BUSY 0x08 - u_long resid_count; - u_long resid_addr; - u_short addit_status; - u_char sense_len; - u_char unused[9]; - u_char cdb[6]; +struct ahb_ecb_status { + u_short status; +#define ST_DON 0x0001 +#define ST_DU 0x0002 +#define ST_QF 0x0008 +#define ST_SC 0x0010 +#define ST_DO 0x0020 +#define ST_CH 0x0040 +#define ST_INT 0x0080 +#define ST_ASA 0x0100 +#define ST_SNS 0x0200 +#define ST_INI 0x0800 +#define ST_ME 0x1000 +#define ST_ECA 0x4000 + u_char ha_status; +#define HS_OK 0x00 +#define HS_CMD_ABORTED_HOST 0x04 +#define HS_CMD_ABORTED_ADAPTER 0x05 +#define HS_TIMED_OUT 0x11 +#define HS_HARDWARE_ERR 0x20 +#define HS_SCSI_RESET_ADAPTER 0x22 +#define HS_SCSI_RESET_INCOMING 0x23 + u_char targ_status; +#define TS_OK 0x00 +#define TS_CHECK_CONDITION 0x02 +#define TS_BUSY 0x08 + u_long resid_count; + u_long resid_addr; + u_short addit_status; + u_char sense_len; + u_char unused[9]; + u_char cdb[6]; }; -/* */ -struct ecb -{ - u_char opcode; -# define ECB_SCSI_OP 0x01 - u_char :4; - u_char options:3; - u_char :1; - short opt1; -# define ECB_CNE 0x0001 -# define ECB_DI 0x0080 -# define ECB_SES 0x0400 -# define ECB_S_G 0x1000 -# define ECB_DSB 0x4000 -# define ECB_ARS 0x8000 - short opt2; -# define ECB_LUN 0x0007 -# define ECB_TAG 0x0008 -# define ECB_TT 0x0030 -# define ECB_ND 0x0040 -# define ECB_DAT 0x0100 -# define ECB_DIR 0x0200 -# define ECB_ST 0x0400 -# define ECB_CHK 0x0800 -# define ECB_REC 0x4000 -# define ECB_NRB 0x8000 - u_short unused1; - physaddr data; - u_long datalen; - physaddr status; - physaddr chain; - short unused2; - short unused3; - physaddr sense; - u_char senselen; - u_char cdblen; - short cksum; - u_char cdb[12]; +struct ecb { + u_char opcode; +#define ECB_SCSI_OP 0x01 + u_char:4; + u_char options:3; + u_char:1; + short opt1; +#define ECB_CNE 0x0001 +#define ECB_DI 0x0080 +#define ECB_SES 0x0400 +#define ECB_S_G 0x1000 +#define ECB_DSB 0x4000 +#define ECB_ARS 0x8000 + short opt2; +#define ECB_LUN 0x0007 +#define ECB_TAG 0x0008 +#define ECB_TT 0x0030 +#define ECB_ND 0x0040 +#define ECB_DAT 0x0100 +#define ECB_DIR 0x0200 +#define ECB_ST 0x0400 +#define ECB_CHK 0x0800 +#define ECB_REC 0x4000 +#define ECB_NRB 0x8000 + u_short unused1; + physaddr data; + u_long datalen; + physaddr status; + physaddr chain; + short unused2; + short unused3; + physaddr sense; + u_char senselen; + u_char cdblen; + short cksum; + u_char cdb[12]; /*-----------------end of hardware supported fields----------------*/ - struct ecb *next; /* in free list */ - struct scsi_xfer *xs; /* the scsi_xfer for this cmd */ - int flags; + struct ecb *next; /* in free list */ + struct scsi_xfer *xs; /* the scsi_xfer for this cmd */ + int flags; #define ECB_FREE 0 #define ECB_ACTIVE 1 #define ECB_ABORTED 2 #define ECB_IMMED 4 #define ECB_IMMED_FAIL 8 - struct ahb_dma_seg ahb_dma[AHB_NSEG]; - struct ahb_ecb_status ecb_status; - struct scsi_sense_data ecb_sense; + struct ahb_dma_seg ahb_dma[AHB_NSEG]; + struct ahb_ecb_status ecb_status; + struct scsi_sense_data ecb_sense; + struct ecb *nexthash; + physaddr hashkey; /* physaddr of this struct */ }; -/* */ - -struct ahb_data -{ - int flags; +struct ahb_data { + int flags; #define AHB_INIT 0x01; - int baseport; - struct ecb ecbs[NUM_CONCURRENT]; - struct ecb *free_ecb; - int our_id; /* our scsi id */ - int vect; - struct ecb *immed_ecb; /* an outstanding immediete command */ -} ahb_data[NAHB]; - -int ahbprobe(); -int ahb_attach(); -int ahbintr(); -int ahb_scsi_cmd(); -int ahb_timeout(); + int baseport; + struct ecb *ecbhash[ECB_HASH_SIZE]; + struct ecb *free_ecb; + int our_id; /* our scsi id */ + int vect; + struct ecb *immed_ecb; /* an outstanding immediete command */ + struct scsi_link sc_link; + int numecbs; +} *ahbdata[NAHB]; + +int ahbprobe(); +int ahbprobe1 __P((struct isa_device *dev)); +int ahb_attach(); +int ahb_init __P((int unit)); +int ahbintr(); +int32 ahb_scsi_cmd(); +void ahb_timeout(); +void ahb_done(); struct ecb *cheat; -void ahbminphys(); -long int ahb_adapter_info(); - -#ifdef MACH -struct isa_driver ahbdriver = { ahbprobe, 0, ahb_attach, "ahb", 0, 0, 0}; -int (*ahbintrs[])() = {ahbintr, 0}; -#endif MACH - -#ifdef __386BSD__ -struct isa_driver ahbdriver = { ahbprobe, ahb_attach, "ahb"}; -#endif __386BSD__ +void ahb_free_ecb(); +void ahbminphys(); +struct ecb *ahb_ecb_phys_kv(); +u_int32 ahb_adapter_info(); #define MAX_SLOTS 8 -static ahb_slot = 0; /* slot last board was found in */ -static ahb_unit = 0; -int ahb_debug = 0; +static ahb_slot = 0; /* slot last board was found in */ +static ahb_unit = 0; +int ahb_debug = 0; #define AHB_SHOWECBS 0x01 #define AHB_SHOWINTS 0x02 #define AHB_SHOWCMDS 0x04 @@ -321,7 +299,15 @@ int ahb_debug = 0; #define SUCCESS 0 #define PAGESIZ 4096 -struct scsi_switch ahb_switch = +#ifdef KERNEL +struct isa_driver ahbdriver = +{ + ahbprobe, + ahb_attach, + "ahb" +}; + +struct scsi_adapter ahb_switch = { ahb_scsi_cmd, ahbminphys, @@ -329,400 +315,395 @@ struct scsi_switch ahb_switch = 0, ahb_adapter_info, "ahb", - 0,0 + { 0, 0 } +}; + +/* the below structure is so we have a default dev struct for our link struct */ +struct scsi_device ahb_dev = +{ + NULL, /* Use default error handler */ + NULL, /* have a queue, served by this */ + NULL, /* have no async handler */ + NULL, /* Use default 'done' routine */ + "ahb", + 0, + { 0, 0 } }; -/* */ -/***********************************************************************\ -* Function to send a command out through a mailbox * -\***********************************************************************/ -ahb_send_mbox( int unit - ,int opcode - ,int target - ,struct ecb *ecb) +#endif /*KERNEL */ + +#ifndef KERNEL +main() +{ + printf("ahb_data size is %d\n", sizeof(struct ahb_data)); + printf("ecb size is %d\n", sizeof(struct ecb)); +} + +#else /*KERNEL */ + +/* + * Function to send a command out through a mailbox + */ +void +ahb_send_mbox(int unit, int opcode, int target, struct ecb *ecb) { - int port = ahb_data[unit].baseport; - int spincount = FUDGE(delaycount) * 1; /* 1ms should be enough */ - int s = splbio(); - int stport = port + G2STAT; - - while( ((inb(stport) & (G2STAT_BUSY | G2STAT_MBOX_EMPTY)) - != (G2STAT_MBOX_EMPTY)) - && (spincount--)); - if(spincount == -1) - { - printf("ahb%d: board not responding\n",unit); + int port = ahbdata[unit]->baseport; + int wait = 100; /* 1ms should be enough */ + int stport = port + G2STAT; + int s = splbio(); + + while (--wait) { + if ((inb(stport) & (G2STAT_BUSY | G2STAT_MBOX_EMPTY)) + == (G2STAT_MBOX_EMPTY)) + break; + DELAY(10); + } + if (wait == 0) { + printf("ahb%d: board not responding\n", unit); Debugger(); } - - outl(port + MBOXOUT0,KVTOPHYS(ecb)); /* don't know this will work */ - outb(port + ATTN, opcode|target); + outl(port + MBOXOUT0, KVTOPHYS(ecb)); /* don't know this will work */ + outb(port + ATTN, opcode | target); splx(s); } -/***********************************************************************\ -* Function to poll for command completion when in poll mode * -\***********************************************************************/ -ahb_poll(int unit ,int wait) /* in msec */ -{ - int port = ahb_data[unit].baseport; - int spincount = FUDGE(delaycount) * wait; /* in msec */ - int stport = port + G2STAT; -int start = spincount; - -retry: - while( (spincount--) && (!(inb(stport) & G2STAT_INT_PEND))); - if(spincount == -1) - { - printf("ahb%d: board not responding\n",unit); - return(EIO); +/* + * Function to poll for command completion when in poll mode + */ +int +ahb_poll(int unit, int wait) +{ /* in msec */ + struct ahb_data *ahb = ahbdata[unit]; + int port = ahb->baseport; + int stport = port + G2STAT; + + retry: + while (--wait) { + if (inb(stport) & G2STAT_INT_PEND) + break; + DELAY(1000); + } if (wait == 0) { + printf("ahb%d: board not responding\n", unit); + return (EIO); } -if ((int)cheat != PHYSTOKV(inl(port + MBOXIN0))) -{ - printf("discarding %x ",inl(port + MBOXIN0)); - outb(port + G2CNTRL, G2CNTRL_CLEAR_EISA_INT); - spinwait(50); - goto retry; -}/* don't know this will work */ + if (cheat != ahb_ecb_phys_kv(ahb, inl(port + MBOXIN0))) { + printf("discarding %x ", inl(port + MBOXIN0)); + outb(port + G2CNTRL, G2CNTRL_CLEAR_EISA_INT); + DELAY(50000); + goto retry; + } + /* don't know this will work */ ahbintr(unit); - return(0); + return (0); } -/***********************************************************************\ -* Function to send an immediate type command to the adapter * -\***********************************************************************/ -ahb_send_immed( int unit - ,int target - ,u_long cmd) + +/* + * Function to send an immediate type command to the adapter + */ +void +ahb_send_immed(int unit, int target, u_long cmd) { - int port = ahb_data[unit].baseport; - int spincount = FUDGE(delaycount) * 1; /* 1ms should be enough */ - int s = splbio(); - int stport = port + G2STAT; - - while( ((inb(stport) & (G2STAT_BUSY | G2STAT_MBOX_EMPTY)) - != (G2STAT_MBOX_EMPTY)) - && (spincount--)); - if(spincount == -1) - { - printf("ahb%d: board not responding\n",unit); + int port = ahbdata[unit]->baseport; + int s = splbio(); + int stport = port + G2STAT; + int wait = 100; /* 1 ms enough? */ + + while (--wait) { + if ((inb(stport) & (G2STAT_BUSY | G2STAT_MBOX_EMPTY)) + == (G2STAT_MBOX_EMPTY)) + break; + DELAY(10); + } if (wait == 0) { + printf("ahb%d: board not responding\n", unit); Debugger(); } - - outl(port + MBOXOUT0,cmd); /* don't know this will work */ + outl(port + MBOXOUT0, cmd); /* don't know this will work */ outb(port + G2CNTRL, G2CNTRL_SET_HOST_READY); outb(port + ATTN, OP_IMMED | target); splx(s); } -/* */ - -/*******************************************************\ -* Check the slots looking for a board we recognise * -* If we find one, note it's address (slot) and call * -* the actual probe routine to check it out. * -\*******************************************************/ +/* + * Check the slots looking for a board we recognise + * If we find one, note it's address (slot) and call + * the actual probe routine to check it out. + */ +int ahbprobe(dev) -struct isa_dev *dev; + struct isa_device *dev; { - int port; - u_char byte1,byte2,byte3; + int port; + u_char byte1, byte2, byte3; + ahb_slot++; - while (ahb_slot<8) - { + while (ahb_slot < 8) { port = 0x1000 * ahb_slot; byte1 = inb(port + HID0); byte2 = inb(port + HID1); byte3 = inb(port + HID2); - if(byte1 == 0xff) - { + if (byte1 == 0xff) { ahb_slot++; continue; } - if ((CHAR1(byte1,byte2) == 'A') - && (CHAR2(byte1,byte2) == 'D') - && (CHAR3(byte1,byte2) == 'P') - && ((byte3 == 0 ) || (byte3 == 1))) - { - dev->dev_addr = port; - return(ahbprobe1(dev)); + if ((CHAR1(byte1, byte2) == 'A') + && (CHAR2(byte1, byte2) == 'D') + && (CHAR3(byte1, byte2) == 'P') + && ((byte3 == 0) || (byte3 == 1))) { + dev->id_iobase = port; + return ahbprobe1(dev); } ahb_slot++; } - return(0); + return 0; } -/*******************************************************\ -* Check if the device can be found at the port given * -* and if so, set it up ready for further work * -* as an argument, takes the isa_dev structure from * -* autoconf.c * -\*******************************************************/ + +/* + * Check if the device can be found at the port given + * and if so, set it up ready for further work + * as an argument, takes the isa_device structure from + * autoconf.c. + */ +int ahbprobe1(dev) -struct isa_dev *dev; + struct isa_device *dev; { - /***********************************************\ - * find unit and check we have that many defined * - \***********************************************/ - int unit = ahb_unit; -#if defined(OSF) - static ihandler_t ahb_handler[NAHB]; - static ihandler_id_t *ahb_handler_id[NAHB]; - register ihandler_t *chp = &ahb_handler[unit];; -#endif /* defined(OSF) */ - - dev->dev_unit = unit; - ahb_data[unit].baseport = dev->dev_addr; - if(unit >= NAHB) - { - printf("ahb: unit number (%d) too high\n",unit); - return(0); + /* + * find unit and check we have that many defined + */ + int unit = ahb_unit; + struct ahb_data *ahb; + + if (unit >= NAHB) { + printf("ahb: unit number (%d) too high\n", unit); + return 0; } - /***********************************************\ - * Try initialise a unit at this location * - * sets up dma and bus speed, loads ahb_data[unit].vect* - \***********************************************/ - if (ahb_init(unit) != 0) - { - return(0); + dev->id_unit = unit; + + /* + * Allocate a storage area for us + */ + if (ahbdata[unit]) { + printf("ahb%d: memory already allocated\n", unit); + return 0; } - - /***********************************************\ - * If it's there, put in it's interrupt vectors * - \***********************************************/ -#ifdef MACH - dev->dev_pic = ahb_data[unit].vect; -#if defined(OSF) /* OSF */ - chp->ih_level = dev->dev_pic; - chp->ih_handler = dev->dev_intr[0]; - chp->ih_resolver = i386_resolver; - chp->ih_rdev = dev; - chp->ih_stats.intr_type = INTR_DEVICE; - chp->ih_stats.intr_cnt = 0; - chp->ih_hparam[0].intparam = unit; - if ((ahb_handler_id[unit] = handler_add(chp)) != NULL) - handler_enable(ahb_handler_id[unit]); - else - panic("Unable to add ahb interrupt handler"); -#else /* CMU */ - take_dev_irq(dev); -#endif /* !defined(OSF) */ - printf("port=%x spl=%d\n", dev->dev_addr, dev->dev_spl); -#endif MACH -#ifdef __386BSD__ /* 386BSD */ - dev->id_irq = (1 << ahb_data[unit].vect); - dev->id_drq = -1; /* use EISA dma */ -#endif __386BSD__ + ahb = malloc(sizeof(struct ahb_data), M_TEMP, M_NOWAIT); + if (!ahb) { + printf("ahb%d: cannot malloc!\n", unit); + return 0; + } + bzero(ahb, sizeof(struct ahb_data)); + ahbdata[unit] = ahb; + ahb->baseport = dev->id_iobase; + /* + * Try initialise a unit at this location + * sets up dma and bus speed, loads ahb->vect + */ + if (ahb_init(unit) != 0) { + ahbdata[unit] = NULL; + free(ahb, M_TEMP); + return (0); + } + /* + * If it's there, put in it's interrupt vectors + */ + dev->id_irq = (1 << ahb->vect); + dev->id_drq = -1; /* use EISA dma */ ahb_unit++; - return(1); + return 0x1000; } -/***********************************************\ -* Attach all the sub-devices we can find * -\***********************************************/ +/* + * Attach all the sub-devices we can find + */ +int ahb_attach(dev) -struct isa_dev *dev; + struct isa_device *dev; { - int unit = dev->dev_unit; - - /***********************************************\ - * ask the adapter what subunits are present * - \***********************************************/ - scsi_attachdevs( unit, ahb_data[unit].our_id, &ahb_switch); -#if defined(OSF) - ahb_attached[unit]=1; -#endif /* defined(OSF) */ - return; +#ifdef NetBSD + int unit = dev->id_masunit; +#else + int unit = dev->id_unit; +#endif + struct ahb_data *ahb = ahbdata[unit]; + + /* + * fill in the prototype scsi_link. + */ + ahb->sc_link.adapter_unit = unit; + ahb->sc_link.adapter_targ = ahb->our_id; + ahb->sc_link.adapter = &ahb_switch; + ahb->sc_link.device = &ahb_dev; + + /* + * ask the adapter what subunits are present + */ + scsi_attachdevs(&(ahb->sc_link)); + + return 1; } -/***********************************************\ -* Return some information to the caller about * -* the adapter and it's capabilities * -\***********************************************/ -long int ahb_adapter_info(unit) -int unit; +/* + * Return some information to the caller about + * the adapter and it's capabilities + */ +u_int32 +ahb_adapter_info(unit) + int unit; { - return(2); /* 2 outstanding requests at a time per device */ + return (2); /* 2 outstanding requests at a time per device */ } -/***********************************************\ -* Catch an interrupt from the adaptor * -\***********************************************/ +/* + * Catch an interrupt from the adaptor + */ +int ahbintr(unit) + int unit; { - struct ecb *ecb; - unsigned char stat; - register i; - u_char ahbstat; - int target; - long int mboxval; + struct ecb *ecb; + unsigned char stat; + u_char ahbstat; + int target; + long int mboxval; + struct ahb_data *ahb = ahbdata[unit]; - int port = ahb_data[unit].baseport; + int port = ahb->baseport; #ifdef AHBDEBUG - if(scsi_debug & PRINTROUTINES) - printf("ahbintr "); -#endif /*AHBDEBUG*/ - -#if defined(OSF) - if (!ahb_attached[unit]) - { - return(1); - } -#endif /* defined(OSF) */ - while(inb(port + G2STAT) & G2STAT_INT_PEND) - { - /***********************************************\ - * First get all the information and then * - * acknowlege the interrupt * - \***********************************************/ + printf("ahbintr "); +#endif /*AHBDEBUG */ + + while (inb(port + G2STAT) & G2STAT_INT_PEND) { + /* + * First get all the information and then + * acknowlege the interrupt + */ ahbstat = inb(port + G2INTST); target = ahbstat & G2INTST_TARGET; stat = ahbstat & G2INTST_INT_STAT; - mboxval = inl(port + MBOXIN0);/* don't know this will work */ + mboxval = inl(port + MBOXIN0); /* don't know this will work */ outb(port + G2CNTRL, G2CNTRL_CLEAR_EISA_INT); #ifdef AHBDEBUG - if(scsi_debug & TRACEINTERRUPTS) - printf("status = 0x%x ",stat); -#endif /*AHBDEBUG*/ - /***********************************************\ - * Process the completed operation * - \***********************************************/ - - if(stat == AHB_ECB_OK) /* common case is fast */ - { - ecb = (struct ecb *)PHYSTOKV(mboxval); - } - else - { - switch(stat) - { - case AHB_IMMED_OK: - ecb = ahb_data[unit].immed_ecb; - ahb_data[unit].immed_ecb = 0; + printf("status = 0x%x ", stat); +#endif /*AHBDEBUG */ + /* + * Process the completed operation + */ + + if (stat == AHB_ECB_OK) { /* common case is fast */ + ecb = ahb_ecb_phys_kv(ahb, mboxval); + } else { + switch (stat) { + case AHB_IMMED_OK: + ecb = ahb->immed_ecb; + ahb->immed_ecb = 0; break; - case AHB_IMMED_ERR: - ecb = ahb_data[unit].immed_ecb; + case AHB_IMMED_ERR: + ecb = ahb->immed_ecb; ecb->flags |= ECB_IMMED_FAIL; - ahb_data[unit].immed_ecb = 0; + ahb->immed_ecb = 0; break; - case AHB_ASN: /* for target mode */ + case AHB_ASN: /* for target mode */ printf("ahb%d: Unexpected ASN interrupt(%x)\n", - unit, mboxval); + unit, mboxval); ecb = 0; break; - case AHB_HW_ERR: + case AHB_HW_ERR: printf("ahb%d: Hardware error interrupt(%x)\n", - unit, mboxval); + unit, mboxval); ecb = 0; break; - case AHB_ECB_RECOVERED: - ecb = (struct ecb *)PHYSTOKV(mboxval); + case AHB_ECB_RECOVERED: + ecb = ahb_ecb_phys_kv(ahb, mboxval); break; - case AHB_ECB_ERR: - ecb = (struct ecb *)PHYSTOKV(mboxval); + case AHB_ECB_ERR: + ecb = ahb_ecb_phys_kv(ahb, mboxval); break; default: - printf(" Unknown return from ahb%d(%x)\n",unit,ahbstat); - ecb=0; + printf(" Unknown return from ahb%d(%x)\n", unit, ahbstat); + ecb = 0; } - } - if(ecb) - { + } if (ecb) { #ifdef AHBDEBUG - if(ahb_debug & AHB_SHOWCMDS ) - { - ahb_show_scsi_cmd(ecb->xs); + if (ahb_debug & AHB_SHOWCMDS) { + show_scsi_cmd(ecb->xs); } - if((ahb_debug & AHB_SHOWECBS) && ecb) - printf("",ecb); -#endif /*AHBDEBUG*/ - untimeout(ahb_timeout,ecb); - ahb_done(unit,ecb,((stat == AHB_ECB_OK)?SUCCESS:FAIL)); + if ((ahb_debug & AHB_SHOWECBS) && ecb) + printf("", ecb); +#endif /*AHBDEBUG */ + untimeout((timeout_t)ahb_timeout, (caddr_t)ecb); + ahb_done(unit, ecb, ((stat == AHB_ECB_OK) ? SUCCESS : FAIL)); } } - return(1); + return 1; } -/***********************************************\ -* We have a ecb which has been processed by the * -* adaptor, now we look to see how the operation * -* went. * -\***********************************************/ -ahb_done(unit,ecb,state) -int unit,state; -struct ecb *ecb; +/* + * We have a ecb which has been processed by the + * adaptor, now we look to see how the operation + * went. + */ +void +ahb_done(unit, ecb, state) + int unit, state; + struct ecb *ecb; { - struct ahb_ecb_status *stat = &ecb->ecb_status; - struct scsi_sense_data *s1,*s2; - struct scsi_xfer *xs = ecb->xs; - -#ifdef AHBDEBUG - if(scsi_debug & (PRINTROUTINES | TRACEINTERRUPTS)) - printf("ahb_done "); -#endif /*AHBDEBUG*/ - /***********************************************\ - * Otherwise, put the results of the operation * - * into the xfer and call whoever started it * - \***********************************************/ - if(ecb->flags & ECB_IMMED) - { - if(ecb->flags & ECB_IMMED_FAIL) - { + struct ahb_ecb_status *stat = &ecb->ecb_status; + struct scsi_sense_data *s1, *s2; + struct scsi_xfer *xs = ecb->xs; + + SC_DEBUG(xs->sc_link, SDEV_DB2, ("ahb_done\n")); + /* + * Otherwise, put the results of the operation + * into the xfer and call whoever started it + */ + if (ecb->flags & ECB_IMMED) { + if (ecb->flags & ECB_IMMED_FAIL) { xs->error = XS_DRIVER_STUFFUP; } goto done; } - if ( (state == SUCCESS) || (xs->flags & SCSI_ERR_OK)) - { /* All went correctly OR errors expected */ + if ((state == SUCCESS) || (xs->flags & SCSI_ERR_OK)) { /* All went correctly OR errors expected */ xs->resid = 0; xs->error = 0; - } - else - { + } else { s1 = &(ecb->ecb_sense); s2 = &(xs->sense); - if(stat->ha_status) - { - switch(stat->ha_status) - { - case HS_SCSI_RESET_ADAPTER: + if (stat->ha_status) { + switch (stat->ha_status) { + case HS_SCSI_RESET_ADAPTER: break; - case HS_SCSI_RESET_INCOMING: + case HS_SCSI_RESET_INCOMING: break; - case HS_CMD_ABORTED_HOST: /* No response */ - case HS_CMD_ABORTED_ADAPTER: /* No response */ + case HS_CMD_ABORTED_HOST: /* No response */ + case HS_CMD_ABORTED_ADAPTER: /* No response */ break; - case HS_TIMED_OUT: /* No response */ + case HS_TIMED_OUT: /* No response */ #ifdef AHBDEBUG - if (ahb_debug & AHB_SHOWMISC) - { + if (ahb_debug & AHB_SHOWMISC) { printf("timeout reported back\n"); } -#endif /*AHBDEBUG*/ +#endif /*AHBDEBUG */ xs->error = XS_TIMEOUT; break; default: /* Other scsi protocol messes */ xs->error = XS_DRIVER_STUFFUP; #ifdef AHBDEBUG - if (ahb_debug & AHB_SHOWMISC) - { + if (ahb_debug & AHB_SHOWMISC) { printf("unexpected ha_status: %x\n", - stat->ha_status); + stat->ha_status); } -#endif /*AHBDEBUG*/ +#endif /*AHBDEBUG */ } - - } - else - { - switch(stat->targ_status) - { + } else { + switch (stat->targ_status) { case TS_CHECK_CONDITION: - /* structure copy!!!!!*/ - *s2=*s1; + /* structure copy!!!!! */ + *s2 = *s1; xs->error = XS_SENSE; break; case TS_BUSY: @@ -730,352 +711,339 @@ struct ecb *ecb; break; default: #ifdef AHBDEBUG - if (ahb_debug & AHB_SHOWMISC) - { + if (ahb_debug & AHB_SHOWMISC) { printf("unexpected targ_status: %x\n", - stat->targ_status); + stat->targ_status); } -#endif /*AHBDEBUG*/ +#endif /*AHBDEBUG */ xs->error = XS_DRIVER_STUFFUP; } } } done: xs->flags |= ITSDONE; - ahb_free_ecb(unit,ecb, xs->flags); - if(xs->when_done) - (*(xs->when_done))(xs->done_arg,xs->done_arg2); + ahb_free_ecb(unit, ecb, xs->flags); + scsi_done(xs); } -/***********************************************\ -* A ecb (and hence a mbx-out is put onto the * -* free list. * -\***********************************************/ -ahb_free_ecb(unit,ecb, flags) -struct ecb *ecb; +/* + * A ecb (and hence a mbx-out is put onto the + * free list. + */ +void +ahb_free_ecb(unit, ecb, flags) + int unit, flags; + struct ecb *ecb; { unsigned int opri; - -#ifdef AHBDEBUG - if(scsi_debug & PRINTROUTINES) - printf("ecb%d(0x%x)> ",unit,flags); -#endif /*AHBDEBUG*/ - if (!(flags & SCSI_NOMASK)) - opri = splbio(); - - ecb->next = ahb_data[unit].free_ecb; - ahb_data[unit].free_ecb = ecb; + struct ahb_data *ahb = ahbdata[unit]; + + if (!(flags & SCSI_NOMASK)) + opri = splbio(); + + ecb->next = ahb->free_ecb; + ahb->free_ecb = ecb; ecb->flags = ECB_FREE; - /***********************************************\ - * If there were none, wake abybody waiting for * - * one to come free, starting with queued entries* - \***********************************************/ + /* + * If there were none, wake abybody waiting for + * one to come free, starting with queued entries + */ if (!ecb->next) { - wakeup(&ahb_data[unit].free_ecb); + wakeup((caddr_t)&ahb->free_ecb); } - if (!(flags & SCSI_NOMASK)) + if (!(flags & SCSI_NOMASK)) splx(opri); } -/***********************************************\ -* Get a free ecb (and hence mbox-out entry) * -\***********************************************/ +/* + * Get a free ecb + * If there are none, see if we can allocate a + * new one. If so, put it in the hash table too + * otherwise either return an error or sleep + */ struct ecb * -ahb_get_ecb(unit,flags) +ahb_get_ecb(unit, flags) + int unit, flags; { + struct ahb_data *ahb = ahbdata[unit]; unsigned opri; - struct ecb *rc; + struct ecb *ecbp; + int hashnum; -#ifdef AHBDEBUG - if(scsi_debug & PRINTROUTINES) - printf("next; - rc->flags = ECB_ACTIVE; + if (!(flags & SCSI_NOMASK)) + opri = splbio(); + /* + * If we can and have to, sleep waiting for one to come free + * but only if we can't allocate a new one. + */ + while (!(ecbp = ahb->free_ecb)) { + if (ahb->numecbs < AHB_ECB_MAX) { + ecbp = (struct ecb *) malloc(sizeof(struct ecb), + M_TEMP, + M_NOWAIT); + if (ecbp) { + bzero(ecbp, sizeof(struct ecb)); + ahb->numecbs++; + ecbp->flags = ECB_ACTIVE; + /* + * put in the phystokv hash table + * Never gets taken out. + */ + ecbp->hashkey = KVTOPHYS(ecbp); + hashnum = ECB_HASH(ecbp->hashkey); + ecbp->nexthash = ahb->ecbhash[hashnum]; + ahb->ecbhash[hashnum] = ecbp; + } else { + printf("ahb%d: Can't malloc ECB\n", unit); + } goto gottit; + } else { + if (!(flags & SCSI_NOSLEEP)) { + tsleep((caddr_t)&ahb->free_ecb, PRIBIO, + "ahbecb", 0); + } + } + } if (ecbp) { + /* Get ECB from from free list */ + ahb->free_ecb = ecbp->next; + ecbp->flags = ECB_ACTIVE; } - if (!(flags & SCSI_NOMASK)) +gottit: if (!(flags & SCSI_NOMASK)) splx(opri); - return(rc); + + return (ecbp); } - +/* + * given a physical address, find the ecb that + * it corresponds to: + */ +struct ecb * +ahb_ecb_phys_kv(ahb, ecb_phys) + struct ahb_data *ahb; + physaddr ecb_phys; +{ + int hashnum = ECB_HASH(ecb_phys); + struct ecb *ecbp = ahb->ecbhash[hashnum]; -/***********************************************\ -* Start the board, ready for normal operation * -\***********************************************/ + while (ecbp) { + if (ecbp->hashkey == ecb_phys) + break; + ecbp = ecbp->nexthash; + } + return ecbp; +} + +/* + * Start the board, ready for normal operation + */ +int ahb_init(unit) -int unit; + int unit; { - int port = ahb_data[unit].baseport; - int intdef; - int spincount = FUDGE(delaycount) * 1000; /* 1 sec enough? */ - int i; - int stport = port + G2STAT; + struct ahb_data *ahb = ahbdata[unit]; + int port = ahb->baseport; + int intdef; + int wait = 1000; /* 1 sec enough? */ + int i; + int stport = port + G2STAT; #define NO_NO 1 #ifdef NO_NO - /***********************************************\ - * reset board, If it doesn't respond, assume * - * that it's not there.. good for the probe * - \***********************************************/ - outb(port + EBCTRL,CDEN); /* enable full card */ - outb(port + PORTADDR,PORTADDR_ENHANCED); - - outb(port + G2CNTRL,G2CNTRL_HARD_RESET); - spinwait(1); - outb(port + G2CNTRL,0); - spinwait(10); - while( ((inb(stport) & G2STAT_BUSY )) - && (spincount--)); - if(spincount == -1) - { + /* + * reset board, If it doesn't respond, assume + * that it's not there.. good for the probe + */ + outb(port + EBCTRL, CDEN); /* enable full card */ + outb(port + PORTADDR, PORTADDR_ENHANCED); + + outb(port + G2CNTRL, G2CNTRL_HARD_RESET); + DELAY(1000); + outb(port + G2CNTRL, 0); + DELAY(10000); + while (--wait) { + if ((inb(stport) & G2STAT_BUSY) == 0) + break; + DELAY(1000); + } if (wait == 0) { #ifdef AHBDEBUG if (ahb_debug & AHB_SHOWMISC) - printf("ahb_init: No answer from bt742a board\n"); -#endif /*AHBDEBUG*/ - return(ENXIO); + printf("ahb_init: No answer from aha1742 board\n"); +#endif /*AHBDEBUG */ + return (ENXIO); } i = inb(port + MBOXIN0) & 0xff; - if(i) - { - printf("self test failed, val = 0x%x\n",i); - return(EIO); + if (i) { + printf("self test failed, val = 0x%x\n", i); + return (EIO); } #endif - while( inb(stport) & G2STAT_INT_PEND) - { + while (inb(stport) & G2STAT_INT_PEND) { printf("."); outb(port + G2CNTRL, G2CNTRL_CLEAR_EISA_INT); - spinwait(10); + DELAY(10000); } - outb(port + EBCTRL,CDEN); /* enable full card */ - outb(port + PORTADDR,PORTADDR_ENHANCED); - /***********************************************\ - * Assume we have a board at this stage * - * setup dma channel from jumpers and save int * - * level * - \***********************************************/ -#ifdef __386BSD__ - printf("ahb%d: reading board settings, ",unit); -#else __386BSD__ - printf("ahb%d:",unit); -#endif __386BSD__ + outb(port + EBCTRL, CDEN); /* enable full card */ + outb(port + PORTADDR, PORTADDR_ENHANCED); + /* + * Assume we have a board at this stage + * setup dma channel from jumpers and save int + * level + */ + printf("ahb%d: reading board settings, ", unit); intdef = inb(port + INTDEF); - switch(intdef & 0x07) - { - case INT9: - ahb_data[unit].vect = 9; + switch (intdef & 0x07) { + case INT9: + ahb->vect = 9; break; - case INT10: - ahb_data[unit].vect = 10; + case INT10: + ahb->vect = 10; break; - case INT11: - ahb_data[unit].vect = 11; + case INT11: + ahb->vect = 11; break; - case INT12: - ahb_data[unit].vect = 12; + case INT12: + ahb->vect = 12; break; - case INT14: - ahb_data[unit].vect = 14; + case INT14: + ahb->vect = 14; break; - case INT15: - ahb_data[unit].vect = 15; + case INT15: + ahb->vect = 15; break; default: printf("illegal int setting\n"); - return(EIO); - } -#ifdef __386BSD__ - printf("int=%d\n",ahb_data[unit].vect); -#else __386BSD__ - printf("int=%d ",ahb_data[unit].vect); -#endif __386BSD__ - - outb(port + INTDEF ,(intdef | INTEN)); /* make sure we can interrupt */ - /* who are we on the scsi bus */ - ahb_data[unit].our_id = (inb(port + SCSIDEF) & HSCSIID); - - /***********************************************\ - * link up all our ECBs into a free list * - \***********************************************/ - for (i=0; i < NUM_CONCURRENT; i++) - { - ahb_data[unit].ecbs[i].next = ahb_data[unit].free_ecb; - ahb_data[unit].free_ecb = &ahb_data[unit].ecbs[i]; - ahb_data[unit].free_ecb->flags = ECB_FREE; + return (EIO); } + printf("int=%d\n", ahb->vect); - /***********************************************\ - * Note that we are going and return (to probe) * - \***********************************************/ - ahb_data[unit].flags |= AHB_INIT; - return( 0 ); -} + outb(port + INTDEF, (intdef | INTEN)); /* make sure we can interrupt */ + /* who are we on the scsi bus? */ + ahb->our_id = (inb(port + SCSIDEF) & HSCSIID); + + /* + * Note that we are going and return (to probe) + */ + ahb->flags |= AHB_INIT; + return (0); +} #ifndef min #define min(x,y) (x < y ? x : y) -#endif min - +#endif /* min */ -void ahbminphys(bp) -struct buf *bp; +void +ahbminphys(bp) + struct buf *bp; { -#ifdef MACH -#if !defined(OSF) - bp->b_flags |= B_NPAGES; /* can support scat/gather */ -#endif /* defined(OSF) */ -#endif MACH - if(bp->b_bcount > ((AHB_NSEG-1) * PAGESIZ)) - { - bp->b_bcount = ((AHB_NSEG-1) * PAGESIZ); + if (bp->b_bcount > ((AHB_NSEG - 1) * PAGESIZ)) { + bp->b_bcount = ((AHB_NSEG - 1) * PAGESIZ); } } - -/***********************************************\ -* start a scsi operation given the command and * -* the data address. Also needs the unit, target * -* and lu * -\***********************************************/ -int ahb_scsi_cmd(xs) -struct scsi_xfer *xs; + +/* + * start a scsi operation given the command and + * the data address. Also needs the unit, target + * and lu + */ +int32 +ahb_scsi_cmd(xs) + struct scsi_xfer *xs; { - struct scsi_sense_data *s1,*s2; struct ecb *ecb; struct ahb_dma_seg *sg; - int seg; /* scatter gather seg being worked on */ - int i = 0; - int rc = 0; - int thiskv; - physaddr thisphys,nextphys; - int unit =xs->adapter; - int bytes_this_seg,bytes_this_page,datalen,flags; - struct iovec *iovp; - int s; -#ifdef AHBDEBUG - if(scsi_debug & PRINTROUTINES) - printf("ahb_scsi_cmd "); -#endif /*AHBDEBUG*/ - /***********************************************\ - * get a ecb (mbox-out) to use. If the transfer * - * is from a buf (possibly from interrupt time) * - * then we can't allow it to sleep * - \***********************************************/ + int seg; /* scatter gather seg being worked on */ + int thiskv; + physaddr thisphys, nextphys; + int unit = xs->sc_link->adapter_unit; + int bytes_this_seg, bytes_this_page, datalen, flags; + struct ahb_data *ahb = ahbdata[unit]; + int s; + + SC_DEBUG(xs->sc_link, SDEV_DB2, ("ahb_scsi_cmd\n")); + /* + * get a ecb (mbox-out) to use. If the transfer + * is from a buf (possibly from interrupt time) + * then we can't allow it to sleep + */ flags = xs->flags; - if(xs->bp) flags |= (SCSI_NOSLEEP); /* just to be sure */ - if(flags & ITSDONE) - { - printf("ahb%d: Already done?",unit); + if (xs->bp) + flags |= (SCSI_NOSLEEP); /* just to be sure */ + if (flags & ITSDONE) { + printf("ahb%d: Already done?", unit); xs->flags &= ~ITSDONE; } - if(!(flags & INUSE)) - { - printf("ahb%d: Not in use?",unit); + if (!(flags & INUSE)) { + printf("ahb%d: Not in use?", unit); xs->flags |= INUSE; } - if (!(ecb = ahb_get_ecb(unit,flags))) - { + if (!(ecb = ahb_get_ecb(unit, flags))) { xs->error = XS_DRIVER_STUFFUP; - return(TRY_AGAIN_LATER); + return (TRY_AGAIN_LATER); } - -cheat = ecb; -#ifdef AHBDEBUG - if(ahb_debug & AHB_SHOWECBS) - printf("",ecb); - if(scsi_debug & SHOWCOMMANDS) - { - ahb_show_scsi_cmd(xs); - } -#endif /*AHBDEBUG*/ + cheat = ecb; + SC_DEBUG(xs->sc_link, SDEV_DB3, ("start ecb(%x)\n", ecb)); ecb->xs = xs; - /***********************************************\ - * If it's a reset, we need to do an 'immediate' * - * command, and store it's ccb for later * - * if there is already an immediate waiting, * - * then WE must wait * - \***********************************************/ - if(flags & SCSI_RESET) - { + /* + * If it's a reset, we need to do an 'immediate' + * command, and store it's ecb for later + * if there is already an immediate waiting, + * then WE must wait + */ + if (flags & SCSI_RESET) { ecb->flags |= ECB_IMMED; - if(ahb_data[unit].immed_ecb) - { - return(TRY_AGAIN_LATER); + if (ahb->immed_ecb) { + return (TRY_AGAIN_LATER); } - ahb_data[unit].immed_ecb = ecb; - if (!(flags & SCSI_NOMASK)) - { + ahb->immed_ecb = ecb; + if (!(flags & SCSI_NOMASK)) { s = splbio(); - ahb_send_immed(unit,xs->targ,AHB_TARG_RESET); - timeout(ahb_timeout,ecb,(xs->timeout * hz)/1000); + ahb_send_immed(unit, xs->sc_link->target, AHB_TARG_RESET); + timeout((timeout_t)ahb_timeout, (caddr_t)ecb, (xs->timeout * hz) / 1000); splx(s); - return(SUCCESSFULLY_QUEUED); - } - else - { - ahb_send_immed(unit,xs->targ,AHB_TARG_RESET); - /***********************************************\ - * If we can't use interrupts, poll on completion* - \***********************************************/ -#ifdef AHBDEBUG - if(scsi_debug & TRACEINTERRUPTS) - printf("wait "); -#endif /*AHBDEBUG*/ - if( ahb_poll(unit,xs->timeout)) - { - ahb_free_ecb(unit,ecb,flags); + return (SUCCESSFULLY_QUEUED); + } else { + ahb_send_immed(unit, xs->sc_link->target, AHB_TARG_RESET); + /* + * If we can't use interrupts, poll on completion + */ + SC_DEBUG(xs->sc_link, SDEV_DB3, ("wait\n")); + if (ahb_poll(unit, xs->timeout)) { + ahb_free_ecb(unit, ecb, flags); xs->error = XS_TIMEOUT; - return(HAD_ERROR); + return (HAD_ERROR); } - return(COMPLETE); + return (COMPLETE); } - } - /***********************************************\ - * Put all the arguments for the xfer in the ecb * - \***********************************************/ + } + /* + * Put all the arguments for the xfer in the ecb + */ ecb->opcode = ECB_SCSI_OP; - ecb->opt1 = ECB_SES|ECB_DSB|ECB_ARS; - if(xs->datalen) - { + ecb->opt1 = ECB_SES | ECB_DSB | ECB_ARS; + if (xs->datalen) { ecb->opt1 |= ECB_S_G; } - ecb->opt2 = xs->lu | ECB_NRB; - ecb->cdblen = xs->cmdlen; - ecb->sense = KVTOPHYS(&(ecb->ecb_sense)); - ecb->senselen = sizeof(ecb->ecb_sense); - ecb->status = KVTOPHYS(&(ecb->ecb_status)); - - if(xs->datalen) - { /* should use S/G only if not zero length */ - ecb->data = KVTOPHYS(ecb->ahb_dma); - sg = ecb->ahb_dma ; - seg = 0; - if(flags & SCSI_DATA_UIO) - { - iovp = ((struct uio *)xs->data)->uio_iov; - datalen = ((struct uio *)xs->data)->uio_iovcnt; + ecb->opt2 = xs->sc_link->lun | ECB_NRB; + ecb->cdblen = xs->cmdlen; + ecb->sense = KVTOPHYS(&(ecb->ecb_sense)); + ecb->senselen = sizeof(ecb->ecb_sense); + ecb->status = KVTOPHYS(&(ecb->ecb_status)); + + if (xs->datalen) { /* should use S/G only if not zero length */ + ecb->data = KVTOPHYS(ecb->ahb_dma); + sg = ecb->ahb_dma; + seg = 0; +#ifdef TFS + if (flags & SCSI_DATA_UIO) { + iovp = ((struct uio *) xs->data)->uio_iov; + datalen = ((struct uio *) xs->data)->uio_iovcnt; xs->datalen = 0; - while ((datalen) && (seg < AHB_NSEG)) - { - sg->addr = (physaddr)iovp->iov_base; - xs->datalen += sg->len = iovp->iov_len; -#ifdef AHBDEBUG - if(scsi_debug & SHOWSCATGATH) - printf("(0x%x@0x%x)" - ,iovp->iov_len - ,iovp->iov_base); -#endif /*AHBDEBUG*/ + while ((datalen) && (seg < AHB_NSEG)) { + sg->addr = (physaddr) iovp->iov_base; + xs->datalen += sg->len = iovp->iov_len; + SC_DEBUGN(xs->sc_link, SDEV_DB4, + ("(0x%x@0x%x)", iovp->iov_len + ,iovp->iov_base)); sg++; iovp++; seg++; @@ -1083,240 +1051,198 @@ cheat = ecb; } } else +#endif /*TFS */ { - /***********************************************\ - * Set up the scatter gather block * - \***********************************************/ - -#ifdef AHBDEBUG - if(scsi_debug & SHOWSCATGATH) - printf("%d @0x%x:- ",xs->datalen,xs->data); -#endif /*AHBDEBUG*/ - datalen = xs->datalen; - thiskv = (int)xs->data; - thisphys = KVTOPHYS(thiskv); - - while ((datalen) && (seg < AHB_NSEG)) - { - bytes_this_seg = 0; - + /* + * Set up the scatter gather block + */ + + SC_DEBUG(xs->sc_link, SDEV_DB4, + ("%d @0x%x:- ", xs->datalen, xs->data)); + datalen = xs->datalen; + thiskv = (int) xs->data; + thisphys = KVTOPHYS(thiskv); + + while ((datalen) && (seg < AHB_NSEG)) { + bytes_this_seg = 0; + /* put in the base address */ sg->addr = thisphys; - -#ifdef AHBDEBUG - if(scsi_debug & SHOWSCATGATH) - printf("0x%x",thisphys); -#endif /*AHBDEBUG*/ - + + SC_DEBUGN(xs->sc_link, SDEV_DB4, ("0x%x", thisphys)); + /* do it at least once */ - nextphys = thisphys; - while ((datalen) && (thisphys == nextphys)) - /*********************************************\ - * This page is contiguous (physically) with * - * the the last, just extend the length * - \*********************************************/ - { + nextphys = thisphys; + while ((datalen) && (thisphys == nextphys)) { + /* + * This page is contiguous (physically) with + * the the last, just extend the length + */ /* how far to the end of the page */ - nextphys= (thisphys & (~(PAGESIZ - 1))) - + PAGESIZ; - bytes_this_page = nextphys - thisphys; + nextphys = (thisphys & (~(PAGESIZ - 1))) + + PAGESIZ; + bytes_this_page = nextphys - thisphys; /**** or the data ****/ - bytes_this_page = min(bytes_this_page - ,datalen); - bytes_this_seg += bytes_this_page; - datalen -= bytes_this_page; - + bytes_this_page = min(bytes_this_page + ,datalen); + bytes_this_seg += bytes_this_page; + datalen -= bytes_this_page; + /* get more ready for the next page */ - thiskv = (thiskv & (~(PAGESIZ - 1))) - + PAGESIZ; - if(datalen) + thiskv = (thiskv & (~(PAGESIZ - 1))) + + PAGESIZ; + if (datalen) thisphys = KVTOPHYS(thiskv); } - /********************************************\ - * next page isn't contiguous, finish the seg * - \********************************************/ -#ifdef AHBDEBUG - if(scsi_debug & SHOWSCATGATH) - printf("(0x%x)",bytes_this_seg); -#endif /*AHBDEBUG*/ - sg->len = bytes_this_seg; + /* + * next page isn't contiguous, finish the seg + */ + SC_DEBUGN(xs->sc_link, SDEV_DB4, + ("(0x%x)", bytes_this_seg)); + sg->len = bytes_this_seg; sg++; seg++; } } /*end of iov/kv decision */ ecb->datalen = seg * sizeof(struct ahb_dma_seg); -#ifdef AHBDEBUG - if(scsi_debug & SHOWSCATGATH) - printf("\n"); -#endif /*AHBDEBUG*/ - if (datalen) - { /* there's still data, must have run out of segs! */ + SC_DEBUGN(xs->sc_link, SDEV_DB4, ("\n")); + if (datalen) { /* there's still data, must have run out of segs! */ printf("ahb_scsi_cmd%d: more than %d DMA segs\n", - unit,AHB_NSEG); + unit, AHB_NSEG); xs->error = XS_DRIVER_STUFFUP; - ahb_free_ecb(unit,ecb,flags); - return(HAD_ERROR); + ahb_free_ecb(unit, ecb, flags); + return (HAD_ERROR); } - - } - else - { /* No data xfer, use non S/G values */ - ecb->data = (physaddr)0; + } else { /* No data xfer, use non S/G values */ + ecb->data = (physaddr) 0; ecb->datalen = 0; - } - ecb->chain = (physaddr)0; - /***********************************************\ - * Put the scsi command in the ecb and start it * - \***********************************************/ + } ecb->chain = (physaddr) 0; + /* + * Put the scsi command in the ecb and start it + */ bcopy(xs->cmd, ecb->cdb, xs->cmdlen); - /***********************************************\ - * Usually return SUCCESSFULLY QUEUED * - \***********************************************/ - if (!(flags & SCSI_NOMASK)) - { + /* + * Usually return SUCCESSFULLY QUEUED + */ + if (!(flags & SCSI_NOMASK)) { s = splbio(); - ahb_send_mbox(unit,OP_START_ECB,xs->targ,ecb); - timeout(ahb_timeout,ecb,(xs->timeout * hz)/1000); + ahb_send_mbox(unit, OP_START_ECB, xs->sc_link->target, ecb); + timeout((timeout_t)ahb_timeout, (caddr_t)ecb, (xs->timeout * hz) / 1000); splx(s); -#ifdef AHBDEBUG - if(scsi_debug & TRACEINTERRUPTS) - printf("cmd_sent "); -#endif /*AHBDEBUG*/ - return(SUCCESSFULLY_QUEUED); + SC_DEBUG(xs->sc_link, SDEV_DB3, ("cmd_sent\n")); + return (SUCCESSFULLY_QUEUED); } - /***********************************************\ - * If we can't use interrupts, poll on completion* - \***********************************************/ - ahb_send_mbox(unit,OP_START_ECB,xs->targ,ecb); -#ifdef AHBDEBUG - if(scsi_debug & TRACEINTERRUPTS) - printf("cmd_wait "); -#endif /*AHBDEBUG*/ - do - { - if(ahb_poll(unit,xs->timeout)) - { - if (!(xs->flags & SCSI_SILENT)) printf("cmd fail\n"); - ahb_send_mbox(unit,OP_ABORT_ECB,xs->targ,ecb); - if(ahb_poll(unit,2000)) - { + /* + * If we can't use interrupts, poll on completion + */ + ahb_send_mbox(unit, OP_START_ECB, xs->sc_link->target, ecb); + SC_DEBUG(xs->sc_link, SDEV_DB3, ("cmd_wait\n")); + do { + if (ahb_poll(unit, xs->timeout)) { + if (!(xs->flags & SCSI_SILENT)) + printf("cmd fail\n"); + ahb_send_mbox(unit, OP_ABORT_ECB, xs->sc_link->target, ecb); + if (ahb_poll(unit, 2000)) { printf("abort failed in wait\n"); - ahb_free_ecb(unit,ecb,flags); + ahb_free_ecb(unit, ecb, flags); } xs->error = XS_DRIVER_STUFFUP; - return(HAD_ERROR); + return (HAD_ERROR); } - } while (!(xs->flags & ITSDONE));/* something (?) else finished */ - if(xs->error) - { - return(HAD_ERROR); + } while (!(xs->flags & ITSDONE)); /* something (?) else finished */ + if (xs->error) { + return (HAD_ERROR); } - return(COMPLETE); + return (COMPLETE); } - -ahb_timeout(struct ecb *ecb) +void +ahb_timeout(struct ecb * ecb) { - int unit; - int s = splbio(); + int unit; + struct ahb_data *ahb; + int s = splbio(); + + unit = ecb->xs->sc_link->adapter_unit; + ahb = ahbdata[unit]; + printf("ahb%d:%d:%d (%s%d) timed out ", unit + ,ecb->xs->sc_link->target + ,ecb->xs->sc_link->lun + ,ecb->xs->sc_link->device->name + ,ecb->xs->sc_link->dev_unit); - unit = ecb->xs->adapter; - printf("ahb%d:%d device timed out\n",unit - ,ecb->xs->targ); #ifdef AHBDEBUG - if(ahb_debug & AHB_SHOWECBS) + if (ahb_debug & AHB_SHOWECBS) ahb_print_active_ecb(unit); -#endif /*AHBDEBUG*/ - - /***************************************\ - * If it's immediate, don't try abort it * - \***************************************/ - if(ecb->flags & ECB_IMMED) - { - ecb->xs->retries = 0; /* I MEAN IT ! */ +#endif /*AHBDEBUG */ + + /* + * If it's immediate, don't try abort it + */ + if (ecb->flags & ECB_IMMED) { + ecb->xs->retries = 0; /* I MEAN IT ! */ ecb->flags |= ECB_IMMED_FAIL; - ahb_done(unit,ecb,FAIL); + ahb_done(unit, ecb, FAIL); splx(s); return; } - /***************************************\ - * If it has been through before, then * - * a previous abort has failed, don't * - * try abort again * - \***************************************/ - if(ecb->flags == ECB_ABORTED) /* abort timed out */ - { + /* + * If it has been through before, then + * a previous abort has failed, don't + * try abort again + */ + if (ecb->flags == ECB_ABORTED) { + /* + * abort timed out + */ printf("AGAIN"); - ecb->xs->retries = 0; /* I MEAN IT ! */ + ecb->xs->retries = 0; /* I MEAN IT ! */ ecb->ecb_status.ha_status = HS_CMD_ABORTED_HOST; - ahb_done(unit,ecb,FAIL); - } - else /* abort the operation that has timed out */ - { + ahb_done(unit, ecb, FAIL); + } else { /* abort the operation that has timed out */ printf("\n"); - ahb_send_mbox(unit,OP_ABORT_ECB,ecb->xs->targ,ecb); - /* 2 secs for the abort */ - timeout(ahb_timeout,ecb,2 * hz); + ahb_send_mbox(unit, OP_ABORT_ECB, ecb->xs->sc_link->target, ecb); + /* 2 secs for the abort */ + timeout((timeout_t)ahb_timeout, (caddr_t)ecb, 2 * hz); ecb->flags = ECB_ABORTED; } splx(s); } #ifdef AHBDEBUG -ahb_show_scsi_cmd(struct scsi_xfer *xs) -{ - u_char *b = (u_char *)xs->cmd; - int i = 0; - if(!(xs->flags & SCSI_RESET)) - { - printf("ahb%d:%d:%d-" - ,xs->adapter - ,xs->targ - ,xs->lu); - while(i < xs->cmdlen ) - { - if(i) printf(","); - printf("%x",b[i++]); - } - printf("-\n"); - } - else - { - printf("ahb%d:%d:%d-RESET-\n" - ,xs->adapter - ,xs->targ - ,xs->lu - ); - } -} +void ahb_print_ecb(ecb) -struct ecb *ecb; + struct ecb *ecb; { printf("ecb:%x op:%x cmdlen:%d senlen:%d\n" - ,ecb - ,ecb->opcode - ,ecb->cdblen - ,ecb->senselen); + ,ecb + ,ecb->opcode + ,ecb->cdblen + ,ecb->senselen); printf(" datlen:%d hstat:%x tstat:%x flags:%x\n" - ,ecb->datalen - ,ecb->ecb_status.ha_status - ,ecb->ecb_status.targ_status - ,ecb->flags); - ahb_show_scsi_cmd(ecb->xs); + ,ecb->datalen + ,ecb->ecb_status.ha_status + ,ecb->ecb_status.targ_status + ,ecb->flags); + show_scsi_cmd(ecb->xs); } +void ahb_print_active_ecb(int unit) { - struct ecb *ecb = ahb_data[unit].ecbs; - int i = NUM_CONCURRENT; + struct ahb_data *ahb = ahbdata[unit]; + struct ecb *ecb; + int i = 0; - while(i--) - { - if(ecb->flags != ECB_FREE) - { - ahb_print_ecb(ecb); - } - ecb++; + while (i < ECB_HASH_SIZE) { + ecb = ahb->ecbhash[i]; + while (ecb) { + if (ecb->flags != ECB_FREE) { + ahb_print_ecb(ecb); + } + ecb = ecb->nexthash; + } i++; } } -#endif /*AHBDEBUG */ +#endif /*AHBDEBUG */ +#endif /*KERNEL */ diff --git a/sys/i386/isa/bt742a.c b/sys/i386/isa/bt742a.c index ebf6504ca1..fa467530c9 100644 --- a/sys/i386/isa/bt742a.c +++ b/sys/i386/isa/bt742a.c @@ -12,7 +12,7 @@ * on the understanding that TFS is not responsible for the correct * functioning of this software in any circumstances. * - * $Id: bt742a.c,v 1.8 1993/10/12 07:15:35 rgrimes Exp $ + * $Id: bt742a.c,v 2.3 93/10/16 02:00:33 julian Exp Locker: julian $ */ /* @@ -20,69 +20,45 @@ */ #include -#include +#ifdef KERNEL /* don't laugh.. it compiles to a program too.. look */ +#include #include #include #include #include +#include #include #include #include - -#ifdef MACH /* EITHER CMU OR OSF */ -#include -#include -#include - -#ifdef OSF /* OSF ONLY */ -#include -#include -#include -#include - -#else OSF /* CMU ONLY */ -#include -#include -#endif OSF -#endif MACH /* end of MACH specific */ - -#ifdef __386BSD__ /* 386BSD specific */ -#define isa_dev isa_device -#define dev_unit id_unit -#define dev_addr id_iobase +#endif /* KERNEL */ #include #include #include -#endif __386BSD__ - -#ifdef __386BSD__ +#ifdef KERNEL #include "ddb.h" #if NDDB > 0 -int Debugger(); -#else NDDB +int Debugger(); +#else /* NDDB */ #define Debugger() panic("should call debugger here (bt742a.c)") -#endif NDDB -#endif __386BSD__ - -#ifdef MACH -int Debugger(); -#endif MACH +#endif /* NDDB */ +#else /*KERNEL */ +#define NBT 1 +#endif /*KERNEL */ extern int hz; -extern int delaycount; /* from clock setup code */ typedef unsigned long int physaddr; /* * I/O Port Interface */ -#define BT_BASE bt_base[unit] -#define BT_CTRL_STAT_PORT (BT_BASE + 0x0) /* control & status */ -#define BT_CMD_DATA_PORT (BT_BASE + 0x1) /* cmds and datas */ -#define BT_INTR_PORT (BT_BASE + 0x2) /* Intr. stat */ +#define BT_BASE bt->bt_base +#define BT_CTRL_STAT_PORT (BT_BASE + 0x0) /* control & status */ +#define BT_CMD_DATA_PORT (BT_BASE + 0x1) /* cmds and datas */ +#define BT_INTR_PORT (BT_BASE + 0x2) /* Intr. stat */ /* * BT_CTRL_STAT bits (write) @@ -132,12 +108,12 @@ typedef unsigned long int physaddr; #define BT_INQUIRE_EXTENDED 0x8D /* Adapter Setup Inquiry */ /* Follows command appeared at FirmWare 3.31 */ -#define BT_ROUND_ROBIN 0x8f /* Enable/Disable(default) round robin */ +#define BT_ROUND_ROBIN 0x8f /* Enable/Disable(default) round robin */ #define BT_DISABLE 0x00 /* Parameter value for Disable */ #define BT_ENABLE 0x01 /* Parameter value for Enable */ struct bt_cmd_buf { - u_char byte[16]; + u_char byte[16]; }; /* @@ -151,41 +127,45 @@ struct bt_cmd_buf { #define BT_MBIF 0x01 /* MBX in full */ /* - * Mail box defs + * Mail box defs etc. + * these could be bigger but we need the bt_data to fit on a single page.. */ -#define BT_MBX_SIZE 255 /* mail box size (MAX 255 MBxs) */ -#define BT_CCB_SIZE 32 /* store up to 32CCBs at any one time */ - /* in bt742a H/W ( Not MAX ? ) */ +#define BT_MBX_SIZE 16 /* mail box size (MAX 255 MBxs) */ + /* don't need that many really */ +#define BT_CCB_MAX 32 /* store up to 32CCBs at any one time */ + /* in bt742a H/W ( Not MAX ? ) */ +#define CCB_HASH_SIZE 32 /* when we have a physical addr. for */ + /* a ccb and need to find the ccb in */ + /* space, look it up in the hash table */ +#define CCB_HASH_SHIFT 9 /* only hash on multiples of 512 */ +#define CCB_HASH(x) ((((long int)(x))>>CCB_HASH_SHIFT) % CCB_HASH_SIZE) #define bt_nextmbx( wmb, mbx, mbio ) \ - if ( (wmb) == &((mbx)->mbio[BT_MBX_SIZE - 1 ]) ) { \ + if ( (wmb) == &((mbx)->mbio[BT_MBX_SIZE - 1 ]) ) \ (wmb) = &((mbx)->mbio[0]); \ - } else { \ - (wmb)++; \ - } - + else \ + (wmb)++; typedef struct bt_mbx_out { - physaddr ccb_addr; - unsigned char dummy[3]; - unsigned char cmd; + physaddr ccb_addr; + unsigned char dummy[3]; + unsigned char cmd; } BT_MBO; -typedef struct bt_mbx_in{ - physaddr ccb_addr; - unsigned char btstat; - unsigned char sdstat; - unsigned char dummy; - unsigned char stat; +typedef struct bt_mbx_in { + physaddr ccb_addr; + unsigned char btstat; + unsigned char sdstat; + unsigned char dummy; + unsigned char stat; } BT_MBI; -struct bt_mbx -{ - BT_MBO mbo[BT_MBX_SIZE]; - BT_MBI mbi[BT_MBX_SIZE]; - BT_MBO *tmbo; /* Target Mail Box out */ - BT_MBI *tmbi; /* Target Mail Box in */ +struct bt_mbx { + BT_MBO mbo[BT_MBX_SIZE]; + BT_MBI mbi[BT_MBX_SIZE]; + BT_MBO *tmbo; /* Target Mail Box out */ + BT_MBI *tmbi; /* Target Mail Box in */ }; /* @@ -196,64 +176,72 @@ struct bt_mbx #define BT_MBO_START 0x1 /* MBO activate entry */ #define BT_MBO_ABORT 0x2 /* MBO abort entry */ +/* + * mbi.stat values + */ + #define BT_MBI_FREE 0x0 /* MBI entry is free */ #define BT_MBI_OK 0x1 /* completed without error */ #define BT_MBI_ABORT 0x2 /* aborted ccb */ #define BT_MBI_UNKNOWN 0x3 /* Tried to abort invalid CCB */ #define BT_MBI_ERROR 0x4 /* Completed with error */ -extern struct bt_mbx bt_mbx[]; - #if defined(BIG_DMA) -/* #define BT_NSEG 8192*/ /* Number of scatter gather segments - to much vm */ -#define BT_NSEG 512 +WARNING...THIS WON'T WORK(won't fit on 1 page) +/* #define BT_NSEG 2048 /* Number of scatter gather segments - to much vm */ +#define BT_NSEG 128 #else #define BT_NSEG 33 -#endif /* BIG_DMA */ -struct bt_scat_gath - { - unsigned long seg_len; - physaddr seg_addr; - }; +#endif /* BIG_DMA */ + +struct bt_scat_gath { + unsigned long seg_len; + physaddr seg_addr; +}; struct bt_ccb { - unsigned char opcode; - unsigned char :3,data_in:1,data_out:1,:3; - unsigned char scsi_cmd_length; - unsigned char req_sense_length; + unsigned char opcode; + unsigned char:3, data_in:1, data_out:1,:3; + unsigned char scsi_cmd_length; + unsigned char req_sense_length; /*------------------------------------longword boundary */ - unsigned long data_length; + unsigned long data_length; /*------------------------------------longword boundary */ - physaddr data_addr; + physaddr data_addr; /*------------------------------------longword boundary */ - unsigned char dummy[2]; - unsigned char host_stat; - unsigned char target_stat; + unsigned char dummy[2]; + unsigned char host_stat; + unsigned char target_stat; /*------------------------------------longword boundary */ - unsigned char target; - unsigned char lun; - unsigned char scsi_cmd[12]; /* 12 bytes (bytes only)*/ - unsigned char dummy2[1]; - unsigned char link_id; + unsigned char target; + unsigned char lun; + unsigned char scsi_cmd[12]; /* 12 bytes (bytes only) */ + unsigned char dummy2[1]; + unsigned char link_id; /*------------------------------------4 longword boundary */ - physaddr link_addr; + physaddr link_addr; /*------------------------------------longword boundary */ - physaddr sense_ptr; + physaddr sense_ptr; +/*-----end of HW fields-------------------------------longword boundary */ + struct scsi_sense_data scsi_sense; /*------------------------------------longword boundary */ - struct scsi_sense_data scsi_sense; + struct bt_scat_gath scat_gath[BT_NSEG]; /*------------------------------------longword boundary */ - struct bt_scat_gath scat_gath[BT_NSEG]; + struct bt_ccb *next; /*------------------------------------longword boundary */ - struct bt_ccb *next; + struct scsi_xfer *xfer; /* the scsi_xfer for this cmd */ /*------------------------------------longword boundary */ - struct scsi_xfer *xfer; /* the scsi_xfer for this cmd */ + struct bt_mbx_out *mbx; /* pointer to mail box */ /*------------------------------------longword boundary */ - struct bt_mbx_out *mbx; /* pointer to mail box */ - /*------------------------------------longword boundary */ - int flags; + int flags; #define CCB_FREE 0 #define CCB_ACTIVE 1 #define CCB_ABORTED 2 + /*------------------------------------longword boundary */ + struct bt_ccb *nexthash; /* if two hash the same */ + /*------------------------------------longword boundary */ + physaddr hashkey; /*physaddr of this ccb */ + /*------------------------------------longword boundary */ }; /* @@ -262,10 +250,9 @@ struct bt_ccb { #define BT_INITIATOR_CCB 0x00 /* SCSI Initiator CCB */ #define BT_TARGET_CCB 0x01 /* SCSI Target CCB */ -#define BT_INIT_SCAT_GATH_CCB 0x02 /* SCSI Initiator with scattter gather*/ +#define BT_INIT_SCAT_GATH_CCB 0x02 /* SCSI Initiator with scattter gather */ #define BT_RESET_CCB 0x81 /* SCSI Bus reset */ - /* * bt_ccb.host_stat values */ @@ -285,37 +272,35 @@ struct bt_ccb { #define BT_INV_CCB 0x1a /* Invalid CCB or segment list */ #define BT_ABORTED 42 /* pseudo value from driver */ -struct bt_boardID -{ - u_char board_type; - u_char custom_feture; - char firm_revision; - u_char firm_version; +struct bt_boardID { + u_char board_type; + u_char custom_feture; + char firm_revision; + u_char firm_version; }; -struct bt_setup -{ - u_char sync_neg:1; - u_char parity:1; +struct bt_setup { + u_char sync_neg:1; + u_char parity:1; u_char :6; - u_char speed; - u_char bus_on; - u_char bus_off; - u_char num_mbx; - u_char mbx[3]; + u_char speed; + u_char bus_on; + u_char bus_off; + u_char num_mbx; + u_char mbx[3]; /*XXX */ + /* doesn't make sense with 32bit addresses */ struct { - u_char offset:4; - u_char period:3; - u_char valid:1; - }sync[8]; - u_char disc_sts; + u_char offset:4; + u_char period:3; + u_char valid:1; + } sync[8]; + u_char disc_sts; }; -struct bt_config -{ - u_char chan; - u_char intr; - u_char scsi_dev:3; +struct bt_config { + u_char chan; + u_char intr; + u_char scsi_dev:3; u_char :5; }; @@ -332,398 +317,385 @@ struct bt_config #define CHAN6 0x40 #define CHAN7 0x80 - - - -#ifdef MACH -extern physaddr kvtophys(); -#define PHYSTOKV(x) phystokv(x) -#define KVTOPHYS(x) kvtophys(x) -#endif MACH - -#ifdef __386BSD__ -#define KVTOPHYS(x) vtophys(x) -#endif __386BSD__ - - - -#define PAGESIZ 4096 +#define KVTOPHYS(x) vtophys(x) +#define PAGESIZ 4096 #define INVALIDATE_CACHE {asm volatile( ".byte 0x0F ;.byte 0x08" ); } +u_char bt_scratch_buf[256]; -u_char bt_scratch_buf[256]; -#ifdef MACH -caddr_t bt_base[NBT]; /* base port for each board */ -#else MACH -short bt_base[NBT]; /* base port for each board */ -#endif MACH -struct bt_mbx bt_mbx[NBT]; -struct bt_ccb *bt_ccb_free[NBT]; -struct bt_ccb bt_ccb[NBT][BT_CCB_SIZE]; -struct scsi_xfer bt_scsi_xfer[NBT]; -struct isa_dev *btinfo[NBT]; -struct bt_ccb *bt_get_ccb(); -int bt_int[NBT]; -int bt_dma[NBT]; -int bt_scsi_dev[NBT]; -int bt_initialized[NBT]; -#if defined(OSF) -int bt_attached[NBT]; -#endif /* defined(OSF) */ +struct bt_data { + short bt_base; /* base port for each board */ + struct bt_mbx bt_mbx; /* all our mailboxes */ + struct bt_ccb *bt_ccb_free; /* list of free CCBs */ + struct bt_ccb *ccbhash[CCB_HASH_SIZE]; /* phys to kv hash */ + int bt_int; /* int. read off board */ + int bt_dma; /* DMA channel read of board */ + int bt_scsi_dev; /* adapters scsi id */ + int numccbs; /* how many we have malloc'd */ + struct scsi_link sc_link; /* prototype for devs */ +} *btdata[NBT]; /***********debug values *************/ #define BT_SHOWCCBS 0x01 #define BT_SHOWINTS 0x02 #define BT_SHOWCMDS 0x04 #define BT_SHOWMISC 0x08 -int bt_debug = 0; - +int bt_debug = 0; + +#ifdef KERNEL +int btprobe(); +int btattach(); +int btintr(); +int32 bt_scsi_cmd(); +void bt_timeout(); +void bt_inquire_setup_information(); +void bt_done(); +void btminphys(); +u_int32 bt_adapter_info(); +struct bt_ccb *bt_get_ccb(); +struct bt_ccb *bt_ccb_phys_kv(); + +static int btunit = 0; + +struct isa_driver btdriver = +{ + btprobe, + btattach, + "bt" +}; -int btprobe(), btattach(); -int btintr(); +struct scsi_adapter bt_switch = +{ + bt_scsi_cmd, + btminphys, + 0, + 0, + bt_adapter_info, + "bt", + 0, 0 +}; -#ifdef MACH -struct isa_driver btdriver = { btprobe, 0, btattach, "bt", 0, 0, 0}; -int (*btintrs[])() = {btintr, 0}; -#endif MACH +/* the below structure is so we have a default dev struct for out link struct */ +struct scsi_device bt_dev = +{ + NULL, /* Use default error handler */ + NULL, /* have a queue, served by this */ + NULL, /* have no async handler */ + NULL, /* Use default 'done' routine */ + "bt", + 0, + 0, 0 +}; -#ifdef __386BSD__ -struct isa_driver btdriver = { btprobe, btattach, "bt"}; -#endif __386BSD__ +#endif /*KERNEL */ -static int btunit = 0; +#define BT_RESET_TIMEOUT 1000 +#ifndef KERNEL +main() +{ + printf("bt_data is %d bytes\n", sizeof(struct bt_data)); + printf("bt_ccb is %d bytes\n", sizeof(struct bt_ccb)); + printf("bt_mbx is %d bytes\n", sizeof(struct bt_mbx)); +} -int bt_scsi_cmd(); -int bt_timeout(); -void btminphys(); -long int bt_adapter_info(); +#else /*KERNEL */ -struct scsi_switch bt_switch = -{ - bt_scsi_cmd, - btminphys, - 0, - 0, - bt_adapter_info, - "bt", - 0,0 -}; -#define BT_CMD_TIMEOUT_FUDGE 200 /* multiplied to get Secs */ -#define BT_RESET_TIMEOUT 1000000 -#define BT_SCSI_TIMEOUT_FUDGE 20 /* divided by for mSecs */ - - -/***********************************************************************\ -* bt_cmd(unit,icnt, ocnt,wait, retval, opcode, args) * -* Activate Adapter command * -* icnt: number of args (outbound bytes written after opcode) * -* ocnt: number of expected returned bytes * -* wait: number of seconds to wait for response * -* retval: buffer where to place returned bytes * -* opcode: opcode BT_NOP, BT_MBX_INIT, BT_START_SCSI ... * -* args: parameters * -* * -* Performs an adapter command through the ports. Not to be confused * -* with a scsi command, which is read in via the dma * -* One of the adapter commands tells it to read in a scsi command * -\***********************************************************************/ -bt_cmd(unit,icnt, ocnt, wait,retval, opcode, args) - -u_char *retval; -unsigned opcode; -u_char args; +/* + * bt_cmd(unit,icnt, ocnt,wait, retval, opcode, args) + * + * Activate Adapter command + * icnt: number of args (outbound bytes written after opcode) + * ocnt: number of expected returned bytes + * wait: number of seconds to wait for response + * retval: buffer where to place returned bytes + * opcode: opcode BT_NOP, BT_MBX_INIT, BT_START_SCSI ... + * args: parameters + * + * Performs an adapter command through the ports. Not to be confused with a + * scsi command, which is read in via the dma; one of the adapter commands + * tells it to read in a scsi command. + */ +int +bt_cmd(unit, icnt, ocnt, wait, retval, opcode, args) + u_char *retval; + unsigned opcode; + u_char args; { - unsigned *ic = &opcode; - u_char oc; - register i; - int sts; - - /*******************************************************\ - * multiply the wait argument by a big constant * - * zero defaults to 1 * - \*******************************************************/ - if(!wait) - wait = BT_CMD_TIMEOUT_FUDGE * delaycount; + struct bt_data *bt = btdata[unit]; + unsigned *ic = &opcode; + u_char oc; + register i; + int sts; + + /* + * multiply the wait argument by a big constant + * zero defaults to 1 + */ + if (wait) + wait *= 100000; else - wait *= BT_CMD_TIMEOUT_FUDGE * delaycount; - /*******************************************************\ - * Wait for the adapter to go idle, unless it's one of * - * the commands which don't need this * - \*******************************************************/ - if (opcode != BT_MBX_INIT && opcode != BT_START_SCSI) - { - i = BT_CMD_TIMEOUT_FUDGE * delaycount; /* 1 sec?*/ - while (--i) - { + wait = 100000; + /* + * Wait for the adapter to go idle, unless it's one of + * the commands which don't need this + */ + if (opcode != BT_MBX_INIT && opcode != BT_START_SCSI) { + i = 100000; /* 1 sec? */ + while (--i) { sts = inb(BT_CTRL_STAT_PORT); - if (sts & BT_IDLE) - { + if (sts & BT_IDLE) { break; } + DELAY(10); } - if (!i) - { - printf("bt%d: bt_cmd, host not idle(0x%x)\n",unit,sts); - return(ENXIO); + if (i == 0) { + printf("bt%d: bt_cmd, host not idle(0x%x)\n", unit, sts); + return (ENXIO); } } - /*******************************************************\ - * Now that it is idle, if we expect output, preflush the* - * queue feeding to us. * - \*******************************************************/ - if (ocnt) - { - while((inb(BT_CTRL_STAT_PORT)) & BT_DF) + /* + * Now that it is idle, if we expect output, preflush the + * queue feeding to us. + */ + if (ocnt) { + while ((inb(BT_CTRL_STAT_PORT)) & BT_DF) inb(BT_CMD_DATA_PORT); } - - /*******************************************************\ - * Output the command and the number of arguments given * - * for each byte, first check the port is empty. * - \*******************************************************/ - icnt++; /* include the command */ - while (icnt--) - { + /* + * Output the command and the number of arguments given + * for each byte, first check the port is empty. + */ + icnt++; + /* include the command */ + while (icnt--) { sts = inb(BT_CTRL_STAT_PORT); - for (i=0; i< wait; i++) - { + for (i = wait; i; i--) { sts = inb(BT_CTRL_STAT_PORT); if (!(sts & BT_CDF)) break; + DELAY(10); } - if (i >= wait) - { - printf("bt%d: bt_cmd, cmd/data port full\n",unit); - outb(BT_CTRL_STAT_PORT, BT_SRST); - return(ENXIO); + if (i == 0) { + printf("bt%d: bt_cmd, cmd/data port full\n", unit); + outb(BT_CTRL_STAT_PORT, BT_SRST); + return (ENXIO); } - outb(BT_CMD_DATA_PORT, (u_char)(*ic++)); + outb(BT_CMD_DATA_PORT, (u_char) (*ic++)); } - /*******************************************************\ - * If we expect input, loop that many times, each time, * - * looking for the data register to have valid data * - \*******************************************************/ - while (ocnt--) - { + /* + * If we expect input, loop that many times, each time, + * looking for the data register to have valid data + */ + while (ocnt--) { sts = inb(BT_CTRL_STAT_PORT); - for (i=0; i< wait; i++) - { + for (i = wait; i; i--) { sts = inb(BT_CTRL_STAT_PORT); - if (sts & BT_DF) + if (sts & BT_DF) break; + DELAY(10); } - if (i >= wait) - { + if (i == 0) { printf("bt%d: bt_cmd, cmd/data port empty %d\n", - unit,ocnt); - return(ENXIO); + unit, ocnt); + return (ENXIO); } oc = inb(BT_CMD_DATA_PORT); if (retval) *retval++ = oc; } - /*******************************************************\ - * Wait for the board to report a finised instruction * - \*******************************************************/ - i=BT_CMD_TIMEOUT_FUDGE * delaycount; /* 1 sec? */ - while (--i) - { + /* + * Wait for the board to report a finised instruction + */ + i = 100000; /* 1 sec? */ + while (--i) { sts = inb(BT_INTR_PORT); - if (sts & BT_HACC) - { + if (sts & BT_HACC) { break; } + DELAY(10); } - if (!i) - { - printf("bt%d: bt_cmd, host not finished(0x%x)\n",unit,sts); - return(ENXIO); + if (i == 0) { + printf("bt%d: bt_cmd, host not finished(0x%x)\n", unit, sts); + return (ENXIO); } outb(BT_CTRL_STAT_PORT, BT_IRST); - return(0); + return (0); } -/*******************************************************\ -* Check if the device can be found at the port given * -* and if so, set it up ready for further work * -* as an argument, takes the isa_dev structure from * -* autoconf.c * -\*******************************************************/ - +/* + * Check if the device can be found at the port given + * and if so, set it up ready for further work + * as an argument, takes the isa_device structure from + * autoconf.c + */ +int btprobe(dev) -struct isa_dev *dev; + struct isa_device *dev; { - /***********************************************\ - * find unit and check we have that many defined * - \***********************************************/ + /* + * find unit and check we have that many defined + */ int unit = btunit; -#if defined(OSF) - static ihandler_t bt_handler[NBT]; - static ihandler_id_t *bt_handler_id[NBT]; - register ihandler_t *chp = &bt_handler[unit];; -#endif /* defined(OSF) */ - - dev->dev_unit = unit; - bt_base[unit] = dev->dev_addr; - if(unit >= NBT) - { - printf("bt%d: unit number too high\n",unit); - return(0); + struct bt_data *bt; + + if (unit >= NBT) { + printf("bt%d: unit number too high\n", unit); + return 0; } - /***********************************************\ - * Try initialise a unit at this location * - * sets up dma and bus speed, loads bt_int[unit]* - \***********************************************/ - if (bt_init(unit) != 0) - { - return(0); + /* + * Allocate a storage area for us + */ + if (btdata[unit]) { + printf("bt%d: memory already allocated\n", unit); + return 0; } - - /***********************************************\ - * If it's there, put in it's interrupt vectors * - \***********************************************/ -#ifdef MACH - dev->dev_pic = bt_int[unit]; -#if defined(OSF) /* OSF */ - chp->ih_level = dev->dev_pic; - chp->ih_handler = dev->dev_intr[0]; - chp->ih_resolver = i386_resolver; - chp->ih_rdev = dev; - chp->ih_stats.intr_type = INTR_DEVICE; - chp->ih_stats.intr_cnt = 0; - chp->ih_hparam[0].intparam = unit; - if ((bt_handler_id[unit] = handler_add(chp)) != NULL) - handler_enable(bt_handler_id[unit]); - else - panic("Unable to add bt interrupt handler"); -#else /* CMU */ - take_dev_irq(dev); -#endif /* !defined(OSF) */ - printf("port=%x spl=%d\n", dev->dev_addr, dev->dev_spl); -#endif MACH -#ifdef __386BSD__ /* 386BSD */ - dev->id_irq = (1 << bt_int[unit]); - dev->id_drq = bt_dma[unit]; -#endif __386BSD__ + bt = malloc(sizeof(struct bt_data), M_TEMP, M_NOWAIT); + if (!bt) { + printf("bt%d: cannot malloc!\n", unit); + return 0; + } + bzero(bt, sizeof(struct bt_data)); + btdata[unit] = bt; + bt->bt_base = dev->id_iobase; + + /* + * Try initialise a unit at this location + * sets up dma and bus speed, loads bt->bt_int + */ + if (bt_init(unit) != 0) { + btdata[unit] = NULL; + free(bt, M_TEMP); + return 0; + } + /* + * If it's there, put in it's interrupt vectors + */ dev->id_unit = unit; + dev->id_irq = (1 << bt->bt_int); + dev->id_drq = bt->bt_dma; btunit++; - return(1); + return 1; } -/***********************************************\ -* Attach all the sub-devices we can find * -\***********************************************/ +/* + * Attach all the sub-devices we can find + */ +int btattach(dev) -struct isa_dev *dev; + struct isa_device *dev; { - int unit = dev->dev_unit; - - - /***********************************************\ - * ask the adapter what subunits are present * - \***********************************************/ - scsi_attachdevs( unit, bt_scsi_dev[unit], &bt_switch); -#if defined(OSF) - bt_attached[unit]=1; -#endif /* defined(OSF) */ - return; + int unit = dev->id_unit; + struct bt_data *bt = btdata[unit]; + + /* + * fill in the prototype scsi_link. + */ + bt->sc_link.adapter_unit = unit; + bt->sc_link.adapter_targ = bt->bt_scsi_dev; + bt->sc_link.adapter = &bt_switch; + bt->sc_link.device = &bt_dev; + + /* + * ask the adapter what subunits are present + */ + scsi_attachdevs(&(bt->sc_link)); + return 1; } -/***********************************************\ -* Return some information to the caller about * -* the adapter and it's capabilities * -\***********************************************/ -long int bt_adapter_info(unit) -int unit; +/* + * Return some information to the caller about the adapter and its + * capabilities. + */ +u_int32 +bt_adapter_info(unit) + int unit; { - return(2); /* 2 outstanding requests at a time per device */ + return (2); /* 2 outstanding requests at a time per device */ } -/***********************************************\ -* Catch an interrupt from the adaptor * -\***********************************************/ +/* + * Catch an interrupt from the adaptor + */ +int btintr(unit) + int unit; { - BT_MBI *wmbi; + struct bt_data *bt = btdata[unit]; + BT_MBI *wmbi; struct bt_mbx *wmbx; struct bt_ccb *ccb; unsigned char stat; - int i,wait; - int found = 0; + int i, wait; + int found = 0; #ifdef UTEST - if(scsi_debug & PRINTROUTINES) - printf("btintr "); + printf("btintr "); #endif - /***********************************************\ - * First acknowlege the interrupt, Then if it's * - * not telling about a completed operation * - * just return. * - \***********************************************/ + /* + * First acknowlege the interrupt, Then if it's + * not telling about a completed operation + * just return. + */ stat = inb(BT_INTR_PORT); /* Mail Box out empty ? */ - if ( stat & BT_MBOA ) { - printf("bt%d: Available Free mbo post\n",unit); - /* Disable MBO available interrupt */ - outb(BT_CMD_DATA_PORT,BT_MBO_INTR_EN); - wait = BT_CMD_TIMEOUT_FUDGE * delaycount; - for (i=0; i< wait; i++) - { + if (stat & BT_MBOA) { + printf("bt%d: Available Free mbo post\n", unit); + /* Disable MBO available interrupt */ + outb(BT_CMD_DATA_PORT, BT_MBO_INTR_EN); + wait = 100000; /* 1 sec enough? */ + for (i = wait; i; i--) { if (!(inb(BT_CTRL_STAT_PORT) & BT_CDF)) break; + DELAY(10); } - if (i >= wait) - { - printf("bt%d: bt_intr, cmd/data port full\n",unit); - outb(BT_CTRL_STAT_PORT, BT_SRST); + if (i == 0) { + printf("bt%d: bt_intr, cmd/data port full\n", unit); + outb(BT_CTRL_STAT_PORT, BT_SRST); return 1; } outb(BT_CMD_DATA_PORT, 0x00); /* Disable */ - wakeup(&bt_mbx[unit]); + wakeup(&bt->bt_mbx); outb(BT_CTRL_STAT_PORT, BT_IRST); return 1; } - if (! (stat & BT_MBIF)) { + if (!(stat & BT_MBIF)) { outb(BT_CTRL_STAT_PORT, BT_IRST); return 1; } -#if defined(OSF) - if (!bt_attached[unit]) - { - return(1); - } -#endif /* defined(OSF) */ - /***********************************************\ - * If it IS then process the competed operation * - \***********************************************/ - wmbx = &bt_mbx[unit]; + /* + * If it IS then process the competed operation + */ + wmbx = &bt->bt_mbx; wmbi = wmbx->tmbi; -AGAIN: - while ( wmbi->stat != BT_MBI_FREE ) { + AGAIN: + while (wmbi->stat != BT_MBI_FREE) { + ccb = bt_ccb_phys_kv(bt, (wmbi->ccb_addr)); + if (!ccb) { + wmbi->stat = BT_MBI_FREE; + printf("bt: BAD CCB ADDR!\n"); + continue; + } found++; - ccb = (struct bt_ccb *)PHYSTOKV((wmbi->ccb_addr)); - if((stat = wmbi->stat) != BT_MBI_OK) - { - switch(stat) - { - case BT_MBI_ABORT: + if ((stat = wmbi->stat) != BT_MBI_OK) { + switch (stat) { + case BT_MBI_ABORT: #ifdef UTEST - if(bt_debug & BT_SHOWMISC) + if (bt_debug & BT_SHOWMISC) printf("abort "); #endif ccb->host_stat = BT_ABORTED; break; - case BT_MBI_UNKNOWN: - ccb = (struct bt_ccb *)0; + case BT_MBI_UNKNOWN: + ccb = (struct bt_ccb *) 0; #ifdef UTEST - if(bt_debug & BT_SHOWMISC) + if (bt_debug & BT_SHOWMISC) printf("unknown ccb for abort"); #endif break; - case BT_MBI_ERROR: + case BT_MBI_ERROR: break; default: @@ -731,40 +703,36 @@ AGAIN: } #ifdef UTEST - if((bt_debug & BT_SHOWCMDS ) && ccb) - { - u_char *cp; + if ((bt_debug & BT_SHOWCMDS) && ccb) { + u_char *cp; cp = ccb->scsi_cmd; - printf("op=%x %x %x %x %x %x\n", - cp[0], cp[1], cp[2], - cp[3], cp[4], cp[5]); + printf("op=%x %x %x %x %x %x\n", + cp[0], cp[1], cp[2], + cp[3], cp[4], cp[5]); printf("stat %x for mbi addr = 0x%08x\n" - , wmbi->stat, wmbi ); + ,wmbi->stat, wmbi); printf("addr = 0x%x\n", ccb); } -#endif +#endif } wmbi->stat = BT_MBI_FREE; - if(ccb) - { - untimeout(bt_timeout,ccb); - bt_done(unit,ccb); + if (ccb) { + untimeout(bt_timeout, ccb); + bt_done(unit, ccb); } - - /* Set the IN mail Box pointer for next */ - bt_nextmbx( wmbi, wmbx, mbi ); + /* Set the IN mail Box pointer for next */ bt_nextmbx(wmbi, wmbx, mbi); } - if ( !found ) { - for ( i = 0; i < BT_MBX_SIZE; i++) { - if ( wmbi->stat != BT_MBI_FREE ) { - found ++; + if (!found) { + for (i = 0; i < BT_MBX_SIZE; i++) { + if (wmbi->stat != BT_MBI_FREE) { + found++; break; } - bt_nextmbx( wmbi, wmbx, mbi ); + bt_nextmbx(wmbi, wmbx, mbi); } - if ( !found ) { + if (!found) { printf("bt%d: mbi at 0x%08x should be found, stat=%02x..resync\n", - unit, wmbi, stat ); + unit, wmbi, stat); } else { found = 0; goto AGAIN; @@ -772,846 +740,772 @@ AGAIN: } wmbx->tmbi = wmbi; outb(BT_CTRL_STAT_PORT, BT_IRST); - return(1); + return 1; } -/***********************************************\ -* A ccb (and hence a mbx-out is put onto the * -* free list. * -\***********************************************/ -bt_free_ccb(unit,ccb, flags) -struct bt_ccb *ccb; +/* + * A ccb is put onto the free list. + */ +void +bt_free_ccb(unit, ccb, flags) + struct bt_ccb *ccb; { + struct bt_data *bt = btdata[unit]; unsigned int opri; -#ifdef UTEST - if(scsi_debug & PRINTROUTINES) - printf("ccb%d(0x%x)> ",unit,flags); -#endif - if (!(flags & SCSI_NOMASK)) - opri = splbio(); + if (!(flags & SCSI_NOMASK)) + opri = splbio(); - ccb->next = bt_ccb_free[unit]; - bt_ccb_free[unit] = ccb; + ccb->next = bt->bt_ccb_free; + bt->bt_ccb_free = ccb; ccb->flags = CCB_FREE; - /***********************************************\ - * If there were none, wake abybody waiting for * - * one to come free, starting with queued entries* - \***********************************************/ + /* + * If there were none, wake anybody waiting for one to come free, + * starting with queued entries. + */ if (!ccb->next) { - wakeup(&bt_ccb_free[unit]); + wakeup(&bt->bt_ccb_free); } - if (!(flags & SCSI_NOMASK)) + + if (!(flags & SCSI_NOMASK)) splx(opri); } -/***********************************************\ -* Get a free ccb * -\***********************************************/ +/* + * Get a free ccb + * + * If there are none, see if we can allocate a new one. If so, put it in + * the hash table too otherwise either return an error or sleep. + */ struct bt_ccb * -bt_get_ccb(unit,flags) +bt_get_ccb(unit, flags) { - unsigned opri; - struct bt_ccb *rc; + struct bt_data *bt = btdata[unit]; + unsigned opri; + struct bt_ccb *ccbp; struct bt_mbx *wmbx; /* Mail Box pointer specified unit */ - BT_MBO *wmbo; /* Out Mail Box pointer */ + BT_MBO *wmbo; /* Out Mail Box pointer */ + int hashnum; -#ifdef UTEST - if(scsi_debug & PRINTROUTINES) - printf("bt_ccb_free)) { + if (bt->numccbs < BT_CCB_MAX) { + if (ccbp = (struct bt_ccb *) malloc(sizeof(struct bt_ccb), + M_TEMP, + M_NOWAIT)) { + bzero(ccbp, sizeof(struct bt_ccb)); + bt->numccbs++; + ccbp->flags = CCB_ACTIVE; + /* + * put in the phystokv hash table + * Never gets taken out. + */ + ccbp->hashkey = KVTOPHYS(ccbp); + hashnum = CCB_HASH(ccbp->hashkey); + ccbp->nexthash = bt->ccbhash[hashnum]; + bt->ccbhash[hashnum] = ccbp; + } else { + printf("bt%d: Can't malloc CCB\n", unit); + } + goto gottit; + } else { + if (!(flags & SCSI_NOSLEEP)) { + sleep(&bt->bt_ccb_free, PRIBIO); + } + } } - if (rc) - { + if (ccbp) { /* Get CCB from from free list */ - bt_ccb_free[unit] = rc->next; - rc->flags = CCB_ACTIVE; -#ifdef HE - /* Get the Target OUT mail Box pointer */ - wmbx = &bt_mbx[unit]; - wmbo = wmbx->tmbo; - while ( wmbo->cmd != BT_MBO_FREE ) { - /* Enable MBO available interrupt */ - outb(BT_CMD_DATA_PORT,BT_MBO_INTR_EN); - printf("Wait free mbo.."); /* AMURAI */ - sleep( wmbx, PRIBIO); - printf("Got free mbo\n"); /* AMURAI */ - } - - /* Link CCB to the Mail Box */ - rc->mbx = wmbo; - wmbo->ccb_addr = KVTOPHYS(rc); - - /* Set the OUT mail Box pointer for next */ - bt_nextmbx( wmbo, wmbx, mbo ); - wmbx->tmbo = wmbo; -#endif + bt->bt_ccb_free = ccbp->next; + ccbp->flags = CCB_ACTIVE; } - if (!(flags & SCSI_NOMASK)) + gottit: + if (!(flags & SCSI_NOMASK)) splx(opri); - - return(rc); + + return (ccbp); +} + +/* + * given a physical address, find the ccb that + * it corresponds to: + */ +struct bt_ccb * +bt_ccb_phys_kv(bt, ccb_phys) + struct bt_data *bt; + physaddr ccb_phys; +{ + int hashnum = CCB_HASH(ccb_phys); + struct bt_ccb *ccbp = bt->ccbhash[hashnum]; + + while (ccbp) { + if (ccbp->hashkey == ccb_phys) + break; + ccbp = ccbp->nexthash; + } + return ccbp; } -/***********************************************\ -* Get a MBO and then Send it * -\***********************************************/ -BT_MBO *bt_send_mbo( int unit, - int flags, - int cmd, - struct bt_ccb *ccb ) + +/* + * Get a MBO and then Send it + */ +BT_MBO * +bt_send_mbo(int unit, int flags, int cmd, struct bt_ccb *ccb) { - unsigned opri; - BT_MBO *wmbo; /* Mail Box Out pointer */ - struct bt_mbx *wmbx; /* Mail Box pointer specified unit */ - int i, wait; + struct bt_data *bt = btdata[unit]; + unsigned opri; + BT_MBO *wmbo; /* Mail Box Out pointer */ + struct bt_mbx *wmbx; /* Mail Box pointer specified unit */ + int i, wait; - wmbx = &bt_mbx[unit]; + wmbx = &bt->bt_mbx; - if (!(flags & SCSI_NOMASK)) - opri = splbio(); + if (!(flags & SCSI_NOMASK)) + opri = splbio(); /* Get the Target OUT mail Box pointer and move to Next */ wmbo = wmbx->tmbo; - wmbx->tmbo = ( wmbo == &( wmbx->mbo[BT_MBX_SIZE - 1 ] ) ? - &(wmbx->mbo[0]) : wmbo + 1 ); + wmbx->tmbo = (wmbo == &(wmbx->mbo[BT_MBX_SIZE - 1]) ? + &(wmbx->mbo[0]) : wmbo + 1); /* - * Check the outmail box is free or not + * Check the outmail box is free or not. * Note: Under the normal operation, it shuld NOT happen to wait. - */ - while ( wmbo->cmd != BT_MBO_FREE ) { - - wait = BT_CMD_TIMEOUT_FUDGE * delaycount; - /* Enable MBO available interrupt */ - outb(BT_CMD_DATA_PORT,BT_MBO_INTR_EN); - for (i=0; i< wait; i++) - { + */ + while (wmbo->cmd != BT_MBO_FREE) { + wait = 100000; /* 1 sec enough? */ + /* Enable MBO available interrupt */ + outb(BT_CMD_DATA_PORT, BT_MBO_INTR_EN); + for (i = wait; i; i--) { if (!(inb(BT_CTRL_STAT_PORT) & BT_CDF)) break; + DELAY(10); } - if (i >= wait) - { - printf("bt%d: bt_send_mbo, cmd/data port full\n",unit); - outb(BT_CTRL_STAT_PORT, BT_SRST); - return( (BT_MBO *)0 ); + if (i == 0) { + printf("bt%d: bt_send_mbo, cmd/data port full\n", unit); + outb(BT_CTRL_STAT_PORT, BT_SRST); + return ((BT_MBO *) 0); } outb(BT_CMD_DATA_PORT, 0x01); /* Enable */ - sleep( wmbx, PRIBIO); + sleep(wmbx, PRIBIO); /*XXX *//*can't do this! */ + /* May be servicing an int */ } - /* Link CCB to the Mail Box */ - wmbo->ccb_addr = KVTOPHYS(ccb); - ccb->mbx = wmbo; - wmbo->cmd = cmd; + wmbo->ccb_addr = KVTOPHYS(ccb); + ccb->mbx = wmbo; + wmbo->cmd = cmd; - /* Send it ! */ + /* Send it! */ outb(BT_CMD_DATA_PORT, BT_START_SCSI); - if (!(flags & SCSI_NOMASK)) + if (!(flags & SCSI_NOMASK)) splx(opri); - return(wmbo); + return (wmbo); } -/***********************************************\ -* We have a ccb which has been processed by the * -* adaptor, now we look to see how the operation * -* went. Wake up the owner if waiting * -\***********************************************/ -bt_done(unit,ccb) -struct bt_ccb *ccb; -{ - struct scsi_sense_data *s1,*s2; - struct scsi_xfer *xs = ccb->xfer; -#ifdef UTEST - if(scsi_debug & (PRINTROUTINES | TRACEINTERRUPTS)) - printf("bt_done "); -#endif - /***********************************************\ - * Otherwise, put the results of the operation * - * into the xfer and call whoever started it * - \***********************************************/ - if ( ( ccb->host_stat != BT_OK - || ccb->target_stat != SCSI_OK) - && (!(xs->flags & SCSI_ERR_OK))) - { +/* + * We have a ccb which has been processed by the + * adaptor, now we look to see how the operation + * went. Wake up the owner if waiting + */ +void +bt_done(unit, ccb) + int unit; + struct bt_ccb *ccb; +{ + struct bt_data *bt = btdata[unit]; + struct scsi_sense_data *s1, *s2; + struct scsi_xfer *xs = ccb->xfer; + + SC_DEBUG(xs->sc_link, SDEV_DB2, ("bt_done\n")); + /* + * Otherwise, put the results of the operation + * into the xfer and call whoever started it + */ + if ((ccb->host_stat != BT_OK || ccb->target_stat != SCSI_OK) + && (!(xs->flags & SCSI_ERR_OK))) { s1 = &(ccb->scsi_sense); s2 = &(xs->sense); - if(ccb->host_stat) - { - switch(ccb->host_stat) - { - case BT_ABORTED: /* No response */ - case BT_SEL_TIMEOUT: /* No response */ -#ifdef UTEST - if (bt_debug & BT_SHOWMISC) - { - printf("timeout reported back\n"); - } -#endif + if (ccb->host_stat) { + switch (ccb->host_stat) { + case BT_ABORTED: /* No response */ + case BT_SEL_TIMEOUT: /* No response */ + SC_DEBUG(xs->sc_link, SDEV_DB3, + ("timeout reported back\n")); xs->error = XS_TIMEOUT; break; default: /* Other scsi protocol messes */ xs->error = XS_DRIVER_STUFFUP; -#ifdef UTEST - if (bt_debug & BT_SHOWMISC) - { - printf("unexpected host_stat: %x\n", - ccb->host_stat); - } -#endif + SC_DEBUG(xs->sc_link, SDEV_DB3, + ("unexpected host_stat: %x\n", + ccb->host_stat)); } - - } - else - { - switch(ccb->target_stat) - { + } else { + switch (ccb->target_stat) { case 0x02: - /* structure copy!!!!!*/ - *s2=*s1; + *s2 = *s1; xs->error = XS_SENSE; break; case 0x08: xs->error = XS_BUSY; break; default: -#ifdef UTEST - if (bt_debug & BT_SHOWMISC) - { - printf("unexpected target_stat: %x\n", - ccb->target_stat); - } -#endif + SC_DEBUG(xs->sc_link, SDEV_DB3, + ("unexpected target_stat: %x\n", + ccb->target_stat)); xs->error = XS_DRIVER_STUFFUP; } } - } - else /* All went correctly OR errors expected */ - { + } else { /* All went correctly OR errors expected */ xs->resid = 0; } xs->flags |= ITSDONE; - bt_free_ccb(unit,ccb, xs->flags); - if(xs->when_done) - (*(xs->when_done))(xs->done_arg,xs->done_arg2); + bt_free_ccb(unit, ccb, xs->flags); + scsi_done(xs); } -/***********************************************\ -* Start the board, ready for normal operation * -\***********************************************/ +/* + * Start the board, ready for normal operation + */ +int bt_init(unit) -int unit; + int unit; { + struct bt_data *bt = btdata[unit]; unsigned char ad[4]; - volatile int i,sts; - struct bt_config conf; + volatile int i, sts; + struct bt_config conf; - /***********************************************\ - * reset board, If it doesn't respond, assume * - * that it's not there.. good for the probe * - \***********************************************/ + /* + * reset board, If it doesn't respond, assume + * that it's not there.. good for the probe + */ - outb(BT_CTRL_STAT_PORT, BT_HRST|BT_SRST); + outb(BT_CTRL_STAT_PORT, BT_HRST | BT_SRST); - for (i=0; i < BT_RESET_TIMEOUT; i++) - { - sts = inb(BT_CTRL_STAT_PORT) ; - if ( sts == (BT_IDLE | BT_INIT)) + for (i = BT_RESET_TIMEOUT; i; i--) { + sts = inb(BT_CTRL_STAT_PORT); + if (sts == (BT_IDLE | BT_INIT)) break; + DELAY(1000); } - if (i >= BT_RESET_TIMEOUT) - { -#ifdef UTEST - if (bt_debug & BT_SHOWMISC) - printf("bt_init: No answer from bt742a board\n"); + if (i == 0) { +#ifdef UTEST + printf("bt_init: No answer from bt742a board\n"); #endif - return(ENXIO); + return (ENXIO); } - - /***********************************************\ - * Assume we have a board at this stage * - * setup dma channel from jumpers and save int * - * level * - \***********************************************/ -#ifdef __386BSD__ - printf("bt%d: reading board settings, ",unit); -#else __386BSD__ - printf("bt%d:",unit); -#endif __386BSD__ - - bt_cmd(unit,0, sizeof(conf), 0 ,&conf, BT_CONF_GET); - switch(conf.chan) - { - case EISADMA: - bt_dma[unit] = -1; + /* + * Assume we have a board at this stage + * setup dma channel from jumpers and save int + * level + */ + printf("bt%d: reading board settings, ", unit); + + bt_cmd(unit, 0, sizeof(conf), 0, &conf, BT_CONF_GET); + switch (conf.chan) { + case EISADMA: + bt->bt_dma = -1; break; - case CHAN0: + case CHAN0: outb(0x0b, 0x0c); outb(0x0a, 0x00); - bt_dma[unit] = 0; + bt->bt_dma = 0; break; - case CHAN5: + case CHAN5: outb(0xd6, 0xc1); outb(0xd4, 0x01); - bt_dma[unit] = 5; + bt->bt_dma = 5; break; - case CHAN6: + case CHAN6: outb(0xd6, 0xc2); outb(0xd4, 0x02); - bt_dma[unit] = 6; + bt->bt_dma = 6; break; - case CHAN7: + case CHAN7: outb(0xd6, 0xc3); outb(0xd4, 0x03); - bt_dma[unit] = 7; + bt->bt_dma = 7; break; default: - printf("illegal dma setting %x\n",conf.chan); - return(EIO); + printf("illegal dma setting %x\n", conf.chan); + return (EIO); } - if (bt_dma[unit] == -1) + if (bt->bt_dma == -1) printf("eisa dma, "); else - printf("dma=%d, ",bt_dma[unit]); + printf("dma=%d, ", bt->bt_dma); - switch(conf.intr) - { - case INT9: - bt_int[unit] = 9; + switch (conf.intr) { + case INT9: + bt->bt_int = 9; break; - case INT10: - bt_int[unit] = 10; + case INT10: + bt->bt_int = 10; break; - case INT11: - bt_int[unit] = 11; + case INT11: + bt->bt_int = 11; break; - case INT12: - bt_int[unit] = 12; + case INT12: + bt->bt_int = 12; break; - case INT14: - bt_int[unit] = 14; + case INT14: + bt->bt_int = 14; break; - case INT15: - bt_int[unit] = 15; + case INT15: + bt->bt_int = 15; break; default: printf("illegal int setting\n"); - return(EIO); + return (EIO); } -#ifdef __386BSD__ - printf("int=%d\n",bt_int[unit]); -#else - printf("int=%d ",bt_int[unit]); -#endif __386BSD__ + printf("int=%d\n", bt->bt_int); /* who are we on the scsi bus */ - bt_scsi_dev[unit] = conf.scsi_dev; - /***********************************************\ - * Initialize mail box * - \***********************************************/ - *((physaddr *)ad) = KVTOPHYS(&bt_mbx[unit]); - bt_cmd(unit,5, 0, 0, 0, BT_MBX_INIT_EXTENDED - , BT_MBX_SIZE - , ad[0] - , ad[1] - , ad[2] - , ad[3]); - - /***********************************************\ - * Set Pointer chain null for just in case * - * Link the ccb's into a free-list W/O mbox * - * Initilize Mail Box stat to Free * - \***********************************************/ - if ( bt_ccb_free[unit] != (struct bt_ccb *)0 ) { + bt->bt_scsi_dev = conf.scsi_dev; + /* + * Initialize mail box + */ + *((physaddr *) ad) = KVTOPHYS(&bt->bt_mbx); + bt_cmd(unit, 5, 0, 0, 0, BT_MBX_INIT_EXTENDED + ,BT_MBX_SIZE + ,ad[0] + ,ad[1] + ,ad[2] + ,ad[3]); + + /* + * Set Pointer chain null for just in case + * Link the ccb's into a free-list W/O mbox + * Initialize mail box status to free + */ + if (bt->bt_ccb_free != (struct bt_ccb *) 0) { printf("bt%d: bt_ccb_free is NOT initialized but init here\n", - unit); - bt_ccb_free[unit] = (struct bt_ccb *)0; - } - for (i=0; i < BT_CCB_SIZE; i++) { - bt_ccb[unit][i].next = bt_ccb_free[unit]; - bt_ccb_free[unit] = &bt_ccb[unit][i]; - bt_ccb_free[unit]->flags = CCB_FREE; + unit); + bt->bt_ccb_free = (struct bt_ccb *) 0; } - for (i=0; i < BT_MBX_SIZE; i++) { - bt_mbx[unit].mbo[i].cmd = BT_MBO_FREE; - bt_mbx[unit].mbi[i].stat = BT_MBI_FREE; + for (i = 0; i < BT_MBX_SIZE; i++) { + bt->bt_mbx.mbo[i].cmd = BT_MBO_FREE; + bt->bt_mbx.mbi[i].stat = BT_MBI_FREE; } - - /***********************************************\ - * Set up Initial mail box for round-robin * - \***********************************************/ - bt_mbx[unit].tmbo = &bt_mbx[unit].mbo[0]; - bt_mbx[unit].tmbi = &bt_mbx[unit].mbi[0]; - bt_inquire_setup_information( unit ); - - /* Enable round-robin scheme - appeared at FirmWare 3.31 */ - bt_cmd(unit, 1, 0, 0, 0, BT_ROUND_ROBIN, BT_ENABLE ); - - /***********************************************\ - * Note that we are going and return (to probe) * - \***********************************************/ - bt_initialized[unit]++; - return( 0 ); + /* + * Set up initial mail box for round-robin operation. + */ + bt->bt_mbx.tmbo = &bt->bt_mbx.mbo[0]; + bt->bt_mbx.tmbi = &bt->bt_mbx.mbi[0]; + bt_inquire_setup_information(unit); + + /* Enable round-robin scheme - appeared at firmware rev. 3.31 */ + bt_cmd(unit, 1, 0, 0, 0, BT_ROUND_ROBIN, BT_ENABLE); + + /* + * Note that we are going and return (to probe) + */ + return 0; } -bt_inquire_setup_information( unit ) -int unit; + +void +bt_inquire_setup_information(unit) + int unit; { + struct bt_data *bt = btdata[unit]; struct bt_setup setup; struct bt_boardID bID; int i; - /* Inquire Board ID to Bt742 for FirmWare Version */ - bt_cmd(unit, 0, sizeof(bID), 0, &bID, BT_INQUIRE ); + /* Inquire Board ID to Bt742 for firmware version */ + bt_cmd(unit, 0, sizeof(bID), 0, &bID, BT_INQUIRE); printf("bt%d: version %c.%c, ", - unit, bID.firm_revision, bID.firm_version ); + unit, bID.firm_revision, bID.firm_version); - /* Ask setup information to Bt742 */ - bt_cmd(unit, 1, sizeof(setup), 0, &setup, BT_SETUP_GET, sizeof(setup) ); + /* Obtain setup information from Bt742. */ + bt_cmd(unit, 1, sizeof(setup), 0, &setup, BT_SETUP_GET, sizeof(setup)); - if ( setup.sync_neg ) { + if (setup.sync_neg) { printf("sync, "); } else { printf("async, "); } - - if ( setup.parity ) { + if (setup.parity) { printf("parity, "); } else { printf("no parity, "); } + printf("%d mbxs, %d ccbs\n", setup.num_mbx, bt->numccbs); - printf("%d mbxs, %d ccbs\n", setup.num_mbx, - sizeof(bt_ccb)/(sizeof(struct bt_ccb) * NBT) ); - - for ( i = 0; i < 8; i++ ) { - if( !setup.sync[i].offset && + for (i = 0; i < 8; i++) { + if (!setup.sync[i].offset && !setup.sync[i].period && - !setup.sync[i].valid ) + !setup.sync[i].valid) continue; printf("bt%d: dev%02d Offset=%d,Transfer period=%d, Synchronous? %s", - unit, i, - setup.sync[i].offset, setup.sync[i].period, - setup.sync[i].valid ? "Yes" : "No" ); + unit, i, + setup.sync[i].offset, setup.sync[i].period, + setup.sync[i].valid ? "Yes" : "No"); } - } - #ifndef min #define min(x,y) (x < y ? x : y) -#endif min - +#endif /* min */ -void btminphys(bp) -struct buf *bp; +void +btminphys(bp) + struct buf *bp; { -#ifdef MACH -#if !defined(OSF) - bp->b_flags |= B_NPAGES; /* can support scat/gather */ -#endif /* defined(OSF) */ -#endif MACH - if(bp->b_bcount > ((BT_NSEG-1) * PAGESIZ)) - { - bp->b_bcount = ((BT_NSEG-1) * PAGESIZ); + if (bp->b_bcount > ((BT_NSEG - 1) * PAGESIZ)) { + bp->b_bcount = ((BT_NSEG - 1) * PAGESIZ); } } - -/***********************************************\ -* start a scsi operation given the command and * -* the data address. Also needs the unit, target * -* and lu * -\***********************************************/ -int bt_scsi_cmd(xs) -struct scsi_xfer *xs; + +/* + * start a scsi operation given the command and the data address. Also needs + * the unit, target and lu. + */ +int32 +bt_scsi_cmd(xs) + struct scsi_xfer *xs; { - struct scsi_sense_data *s1,*s2; - struct bt_ccb *ccb; - struct bt_scat_gath *sg; - int seg; /* scatter gather seg being worked on */ - int i = 0; - int rc = 0; + struct scsi_sense_data *s1, *s2; + struct bt_ccb *ccb; + struct bt_scat_gath *sg; + int seg; /* scatter gather seg being worked on */ + int i = 0; + int c = 0; int thiskv; - physaddr thisphys,nextphys; - int unit =xs->adapter; - int bytes_this_seg,bytes_this_page,datalen,flags; - struct iovec *iovp; + physaddr thisphys, nextphys; + int unit = xs->sc_link->adapter_unit; + int bytes_this_seg, bytes_this_page, datalen, flags; + struct iovec *iovp; + struct bt_data *bt = btdata[unit]; BT_MBO *mbo; -#ifdef UTEST - if(scsi_debug & PRINTROUTINES) - printf("bt_scsi_cmd "); -#endif - /***********************************************\ - * get a ccb (mbox-out) to use. If the transfer * - * is from a buf (possibly from interrupt time) * - * then we can't allow it to sleep * - \***********************************************/ + SC_DEBUG(xs->sc_link, SDEV_DB2, ("bt_scsi_cmd\n")); + /* + * get a ccb (mbox-out) to use. If the transfer + * is from a buf (possibly from interrupt time) + * then we can't allow it to sleep + */ flags = xs->flags; - if(xs->bp) flags |= (SCSI_NOSLEEP); /* just to be sure */ - if(flags & ITSDONE) - { - printf("bt%d: Already done?\n",unit); + if (xs->bp) + flags |= (SCSI_NOSLEEP); /* just to be sure */ + if (flags & ITSDONE) { + printf("bt%d: Already done?\n", unit); xs->flags &= ~ITSDONE; } - if(!(flags & INUSE)) - { - printf("bt%d: Not in use?\n",unit); + if (!(flags & INUSE)) { + printf("bt%d: Not in use?\n", unit); xs->flags |= INUSE; } - if (!(ccb = bt_get_ccb(unit,flags))) - { + if (!(ccb = bt_get_ccb(unit, flags))) { xs->error = XS_DRIVER_STUFFUP; - return(TRY_AGAIN_LATER); + return (TRY_AGAIN_LATER); } -#ifdef UTEST - if(bt_debug & BT_SHOWCCBS) - printf("",ccb); -#endif - /***********************************************\ - * Put all the arguments for the xfer in the ccb * - \***********************************************/ - ccb->xfer = xs; - if(flags & SCSI_RESET) - { - ccb->opcode = BT_RESET_CCB; - } - else - { + SC_DEBUG(xs->sc_link, SDEV_DB3, + ("start ccb(%x)\n", ccb)); + /* + * Put all the arguments for the xfer in the ccb + */ + ccb->xfer = xs; + if (flags & SCSI_RESET) { + ccb->opcode = BT_RESET_CCB; + } else { /* can't use S/G if zero length */ - ccb->opcode = (xs->datalen? - BT_INIT_SCAT_GATH_CCB - :BT_INITIATOR_CCB); + ccb->opcode = (xs->datalen ? + BT_INIT_SCAT_GATH_CCB + : BT_INITIATOR_CCB); } - ccb->target = xs->targ;; - ccb->data_out = 0; - ccb->data_in = 0; - ccb->lun = xs->lu; - ccb->scsi_cmd_length = xs->cmdlen; - ccb->sense_ptr = KVTOPHYS(&(ccb->scsi_sense)); - ccb->req_sense_length = sizeof(ccb->scsi_sense); - - if((xs->datalen) && (!(flags & SCSI_RESET))) - { /* can use S/G only if not zero length */ + ccb->target = xs->sc_link->target; + ccb->data_out = 0; + ccb->data_in = 0; + ccb->lun = xs->sc_link->lun; + ccb->scsi_cmd_length = xs->cmdlen; + ccb->sense_ptr = KVTOPHYS(&(ccb->scsi_sense)); + ccb->req_sense_length = sizeof(ccb->scsi_sense); + + if ((xs->datalen) && (!(flags & SCSI_RESET))) { /* can use S/G only if not zero length */ ccb->data_addr = KVTOPHYS(ccb->scat_gath); - sg = ccb->scat_gath ; - seg = 0; - if(flags & SCSI_DATA_UIO) - { - iovp = ((struct uio *)xs->data)->uio_iov; - datalen = ((struct uio *)xs->data)->uio_iovcnt; + sg = ccb->scat_gath; + seg = 0; +#ifdef TFS + if (flags & SCSI_DATA_UIO) { + iovp = ((struct uio *) xs->data)->uio_iov; + datalen = ((struct uio *) xs->data)->uio_iovcnt; xs->datalen = 0; - while ((datalen) && (seg < BT_NSEG)) - { - sg->seg_addr = (physaddr)iovp->iov_base; - xs->datalen += sg->seg_len = iovp->iov_len; -#ifdef UTEST - if(scsi_debug & SHOWSCATGATH) - printf("(0x%x@0x%x)" - ,iovp->iov_len - ,iovp->iov_base); -#endif + while ((datalen) && (seg < BT_NSEG)) { + sg->seg_addr = (physaddr) iovp->iov_base; + xs->datalen += sg->seg_len = iovp->iov_len; + SC_DEBUGN(xs->sc_link, SDEV_DB4, ("(0x%x@0x%x)" + ,iovp->iov_len, iovp->iov_base)); sg++; iovp++; seg++; datalen--; } - } - else + } else +#endif /* TFS */ { - /***********************************************\ - * Set up the scatter gather block * - \***********************************************/ - -#ifdef UTEST - if(scsi_debug & SHOWSCATGATH) - printf("%d @0x%x:- ",xs->datalen,xs->data); -#endif - datalen = xs->datalen; - thiskv = (int)xs->data; - thisphys = KVTOPHYS(thiskv); - - while ((datalen) && (seg < BT_NSEG)) - { - bytes_this_seg = 0; - + /* + * Set up the scatter gather block + */ + + SC_DEBUG(xs->sc_link, SDEV_DB4, + ("%d @0x%x:- ", xs->datalen, xs->data)); + datalen = xs->datalen; + thiskv = (int) xs->data; + thisphys = KVTOPHYS(thiskv); + + while ((datalen) && (seg < BT_NSEG)) { + bytes_this_seg = 0; + /* put in the base address */ sg->seg_addr = thisphys; - -#ifdef UTEST - if(scsi_debug & SHOWSCATGATH) - printf("0x%x",thisphys); -#endif - + + SC_DEBUGN(xs->sc_link, SDEV_DB4, + ("0x%x", thisphys)); + /* do it at least once */ - nextphys = thisphys; + nextphys = thisphys; while ((datalen) && (thisphys == nextphys)) - /*********************************************\ - * This page is contiguous (physically) with * - * the the last, just extend the length * - \*********************************************/ + /* + * This page is contiguous (physically) with + * the the last, just extend the length + */ { /* how far to the end of the page */ - nextphys= (thisphys & (~(PAGESIZ - 1))) - + PAGESIZ; - bytes_this_page = nextphys - thisphys; + nextphys = (thisphys & (~(PAGESIZ - 1))) + + PAGESIZ; + bytes_this_page = nextphys - thisphys; /**** or the data ****/ - bytes_this_page = min(bytes_this_page - ,datalen); - bytes_this_seg += bytes_this_page; - datalen -= bytes_this_page; - + bytes_this_page = min(bytes_this_page + ,datalen); + bytes_this_seg += bytes_this_page; + datalen -= bytes_this_page; + /* get more ready for the next page */ - thiskv = (thiskv & (~(PAGESIZ - 1))) - + PAGESIZ; - if(datalen) + thiskv = (thiskv & (~(PAGESIZ - 1))) + + PAGESIZ; + if (datalen) thisphys = KVTOPHYS(thiskv); } - /********************************************\ - * next page isn't contiguous, finish the seg * - \********************************************/ -#ifdef UTEST - if(scsi_debug & SHOWSCATGATH) - printf("(0x%x)",bytes_this_seg); -#endif - sg->seg_len = bytes_this_seg; + /* + * next page isn't contiguous, finish the seg + */ + SC_DEBUGN(xs->sc_link, SDEV_DB4, + ("(0x%x)", bytes_this_seg)); + sg->seg_len = bytes_this_seg; sg++; seg++; } - } /*end of iov/kv decision */ + } + /* end of iov/kv decision */ ccb->data_length = seg * sizeof(struct bt_scat_gath); -#ifdef UTEST - if(scsi_debug & SHOWSCATGATH) - printf("\n"); -#endif - if (datalen) - { /* there's still data, must have run out of segs! */ + SC_DEBUGN(xs->sc_link, SDEV_DB4, ("\n")); + if (datalen) { + /* + * there's still data, must have run out of segs! + */ printf("bt%d: bt_scsi_cmd, more than %d DMA segs\n", - unit,BT_NSEG); + unit, BT_NSEG); xs->error = XS_DRIVER_STUFFUP; - bt_free_ccb(unit,ccb,flags); - return(HAD_ERROR); + bt_free_ccb(unit, ccb, flags); + return (HAD_ERROR); } - - } - else - { /* No data xfer, use non S/G values */ - ccb->data_addr = (physaddr)0; + } else { /* No data xfer, use non S/G values */ + ccb->data_addr = (physaddr) 0; ccb->data_length = 0; } ccb->link_id = 0; - ccb->link_addr = (physaddr)0; - /***********************************************\ - * Put the scsi command in the ccb and start it * - \***********************************************/ - if(!(flags & SCSI_RESET)) - { + ccb->link_addr = (physaddr) 0; + /* + * Put the scsi command in the ccb and start it + */ + if (!(flags & SCSI_RESET)) { bcopy(xs->cmd, ccb->scsi_cmd, ccb->scsi_cmd_length); } -#ifdef UTEST - if(scsi_debug & SHOWCOMMANDS) - { - u_char *b = ccb->scsi_cmd; - if(!(flags & SCSI_RESET)) - { - int i = 0; - printf("bt%d:%d:%d-" - ,unit - ,ccb->target - ,ccb->lun); - while(i < ccb->scsi_cmd_length ) - { - if(i) printf(","); - printf("%x",b[i++]); - } - printf("-\n"); - } - else - { - printf("bt%d:%d:%d-RESET- " - ,unit - ,ccb->target - ,ccb->lun - ); - } - } -#endif - if ( bt_send_mbo( unit, flags, BT_MBO_START, ccb ) == (BT_MBO *)0 ) - { + if (bt_send_mbo(unit, flags, BT_MBO_START, ccb) == (BT_MBO *) 0) { xs->error = XS_DRIVER_STUFFUP; - bt_free_ccb(unit,ccb,flags); - return(TRY_AGAIN_LATER); + bt_free_ccb(unit, ccb, flags); + return (TRY_AGAIN_LATER); } - /***********************************************\ - * Usually return SUCCESSFULLY QUEUED * - \***********************************************/ -#ifdef UTEST - if(scsi_debug & TRACEINTERRUPTS) - printf("cmd_sent "); -#endif - if (!(flags & SCSI_NOMASK)) - { - timeout(bt_timeout,ccb,(xs->timeout * hz) / 1000); - return(SUCCESSFULLY_QUEUED); - } else - /***********************************************\ - * If we can't use interrupts, poll on completion* - \***********************************************/ - { - int done = 0; - int count = delaycount * xs->timeout / BT_SCSI_TIMEOUT_FUDGE; - struct bt_mbx *wmbx = &bt_mbx[unit]; - BT_MBI *wmbi = wmbx->tmbi; - unsigned char stat; -#ifdef UTEST - if(scsi_debug & TRACEINTERRUPTS) - printf("wait "); -#endif - while((!done) && count) - { - stat = inb(BT_INTR_PORT) & (BT_ANY_INTR | BT_MBIF ); - if ( !( stat & BT_ANY_INTR ) || - ( wmbi->stat == BT_MBI_FREE )|| - (PHYSTOKV(wmbi->ccb_addr) - != (int)ccb ) ) { - count--; - continue; - } - wmbi->stat = BT_MBI_FREE; - bt_done(unit,ccb); - done ++; - outb(BT_CTRL_STAT_PORT, BT_IRST); - /* Set the IN mail Box pointer for next */ - bt_nextmbx( wmbi, wmbx, mbi ); - wmbx->tmbi = wmbi; + /* + * Usually return SUCCESSFULLY QUEUED + */ + SC_DEBUG(xs->sc_link, SDEV_DB3, ("cmd_sent\n")); + if (!(flags & SCSI_NOMASK)) { + timeout(bt_timeout, ccb, (xs->timeout * hz) / 1000); + return (SUCCESSFULLY_QUEUED); + } + /* + * If we can't use interrupts, poll on completion + */ + return (bt_poll(unit, xs, ccb)); +} + +/* + * Poll a particular unit, looking for a particular xs + */ +int +bt_poll(unit, xs, ccb) + int unit; + struct scsi_xfer *xs; + struct bt_ccb *ccb; +{ + struct bt_data *bt = btdata[unit]; + int done = 0; + int count = xs->timeout; + u_char stat; + + /* timeouts are in msec, so we loop in 1000 usec cycles */ + while (count) { + /* + * If we had interrupts enabled, would we + * have got an interrupt? + */ + stat = inb(BT_INTR_PORT); + if (stat & BT_ANY_INTR) { + btintr(unit); } - if (!count && !done) - { -#ifdef UTEST - if (!(xs->flags & SCSI_SILENT)) - printf("cmd fail\n"); -#endif - bt_send_mbo( unit, flags, BT_MBO_ABORT, ccb ); - count = delaycount * 2000 / BT_SCSI_TIMEOUT_FUDGE; - while((!done) && count) - { - if ( !( stat & BT_ANY_INTR ) || - ( wmbi->stat == BT_MBI_FREE )|| - ( PHYSTOKV(wmbi->ccb_addr ) - != (int)ccb ) ) { - count--; - continue; - } - wmbi->stat = BT_MBI_FREE; - bt_done(unit,ccb); - done ++; - outb(BT_CTRL_STAT_PORT, BT_IRST); - /* Set the IN mail Box pointer for next */ - bt_nextmbx( wmbi, wmbx, mbi ); - wmbx->tmbi = wmbi; + if (xs->flags & ITSDONE) { + break; + } + DELAY(1000); /* only happens in boot so ok */ + count--; + } + if (count == 0) { + /* + * We timed out, so call the timeout handler manually, + * accounting for the fact that the clock is not running yet + * by taking out the clock queue entry it makes. + */ + bt_timeout(ccb); + + /* + * because we are polling, take out the timeout entry + * bt_timeout made + */ + untimeout(bt_timeout, ccb); + count = 2000; + while (count) { + /* + * Once again, wait for the int bit + */ + stat = inb(BT_INTR_PORT); + if (stat & BT_ANY_INTR) { + btintr(unit); } - if(!count && !done) - { - printf("bt%d: abort failed in wait\n", unit); - ccb->mbx->cmd = BT_MBO_FREE; + if (xs->flags & ITSDONE) { + break; } - bt_free_ccb(unit,ccb,flags); - xs->error = XS_DRIVER_STUFFUP; - return(HAD_ERROR); + DELAY(1000); /* only happens in boot so ok */ + count--; + } + if (count == 0) { + /* + * We timed out again... This is bad. Notice that + * this time there is no clock queue entry to remove. + */ + bt_timeout(ccb); } - if(xs->error) return(HAD_ERROR); - return(COMPLETE); } + if (xs->error) + return (HAD_ERROR); + return (COMPLETE); } - -bt_timeout(struct bt_ccb *ccb) +void +bt_timeout(struct bt_ccb * ccb) { - int unit; - int s = splbio(); + int unit; + struct bt_data *bt; + int s = splbio(); + + unit = ccb->xfer->sc_link->adapter_unit; + bt = btdata[unit]; + printf("bt%d:%d:%d (%s%d) timed out ", unit + ,ccb->xfer->sc_link->target + ,ccb->xfer->sc_link->lun + ,ccb->xfer->sc_link->device->name + ,ccb->xfer->sc_link->dev_unit); - unit = ccb->xfer->adapter; - printf("bt%d: %d device timed out\n",unit - ,ccb->xfer->targ); #ifdef UTEST - if(bt_debug & BT_SHOWCCBS) - bt_print_active_ccbs(unit); + bt_print_active_ccbs(unit); #endif - /***************************************\ - * If The ccb's mbx is not free, then * - * the board has gone Far East ? * - \***************************************/ - if((struct bt_ccb *)PHYSTOKV(ccb->mbx->ccb_addr)==ccb && - ccb->mbx->cmd != BT_MBO_FREE ) - { - printf("bt%d: not taking commands!\n" - ,unit); - Debugger(); - } - /***************************************\ - * If it has been through before, then * - * a previous abort has failed, don't * - * try abort again * - \***************************************/ - if(ccb->flags == CCB_ABORTED) /* abort timed out */ - { - printf("bt%d: Abort Operation has timed out\n",unit); - ccb->xfer->retries = 0; /* I MEAN IT ! */ - ccb->host_stat = BT_ABORTED; - bt_done(unit,ccb); + /* + * If the ccb's mbx is not free, then the board has gone Far East? + */ + if (bt_ccb_phys_kv(bt, ccb->mbx->ccb_addr) == ccb && + ccb->mbx->cmd != BT_MBO_FREE) { + printf("bt%d: not taking commands!\n", unit); + Debugger(); } - else /* abort the operation that has timed out */ - { - printf("bt%d: Try to abort\n",unit); - bt_send_mbo( unit, ~SCSI_NOMASK, - BT_MBO_ABORT, ccb ); - /* 2 secs for the abort */ - timeout(bt_timeout,ccb,2 * hz); + /* + * If it has been through before, then + * a previous abort has failed, don't + * try abort again + */ + if (ccb->flags == CCB_ABORTED) { + /* + * abort timed out + */ + printf("bt%d: Abort Operation has timed out\n", unit); + ccb->xfer->retries = 0; /* I MEAN IT ! */ + ccb->host_stat = BT_ABORTED; + bt_done(unit, ccb); + } else { /* abort the operation that has timed out */ + printf("bt%d: Try to abort\n", unit); + bt_send_mbo(unit, ~SCSI_NOMASK, + BT_MBO_ABORT, ccb); + /* 2 secs for the abort */ + timeout(bt_timeout, ccb, 2 * hz); ccb->flags = CCB_ABORTED; } splx(s); } #ifdef UTEST +void bt_print_ccb(ccb) -struct bt_ccb *ccb; + struct bt_ccb *ccb; { printf("ccb:%x op:%x cmdlen:%d senlen:%d\n" - ,ccb - ,ccb->opcode - ,ccb->scsi_cmd_length - ,ccb->req_sense_length); + ,ccb + ,ccb->opcode + ,ccb->scsi_cmd_length + ,ccb->req_sense_length); printf(" datlen:%d hstat:%x tstat:%x flags:%x\n" - ,ccb->data_length - ,ccb->host_stat - ,ccb->target_stat - ,ccb->flags); + ,ccb->data_length + ,ccb->host_stat + ,ccb->target_stat + ,ccb->flags); } +void bt_print_active_ccbs(int unit) { - struct bt_ccb *ccb; - ccb = &(bt_ccb[unit][0]); - int i = BT_CCB_SIZE; - - while(i--) - { - if(ccb->flags != CCB_FREE) - bt_print_ccb(ccb); - ccb++; + struct bt_data *bt = btdata[unit]; + struct bt_ccb *ccb; + int i = 0; + + while (i < CCB_HASH_SIZE) { + ccb = bt->ccbhash[i]; + while (ccb) { + if (ccb->flags != CCB_FREE) + bt_print_ccb(ccb); + ccb = ccb->nexthash; + } + i++; } } -#endif /*UTEST*/ +#endif /*UTEST */ +#endif /*KERNEL */ diff --git a/sys/i386/isa/ultra14f.c b/sys/i386/isa/ultra14f.c index 0d9b08ca9c..76dc115185 100644 --- a/sys/i386/isa/ultra14f.c +++ b/sys/i386/isa/ultra14f.c @@ -1,5 +1,6 @@ /* * Ported for use with the UltraStor 14f by Gary Close (gclose@wvnvms.wvnet.edu) + * Slight fixes to timeouts to run with the 34F * Thanks to Julian Elischer for advice and help with this port. * * Written by Julian Elischer (julian@tfs.com) @@ -18,274 +19,241 @@ * commenced: Sun Sep 27 18:14:01 PDT 1992 * slight mod to make work with 34F as well: Wed Jun 2 18:05:48 WST 1993 * - * $Id: ultra14f.c,v 1.10 1993/10/14 00:07:04 rgrimes Exp $ + * $Id: ultra14f.c,v 2.3 93/10/16 02:01:08 julian Exp Locker: julian $ */ - + #include + +#ifdef KERNEL /* don't laugh.. this compiles to a program too.. look */ #include #include #include #include #include +#include #include #include #include -#ifdef MACH /* EITHER CMU OR OSF */ -#include -#include -#include - -#ifdef OSF /* OSF ONLY */ -#include -#include -#include -#include - -#else OSF /* CMU ONLY */ -#include -#include -#endif OSF -#endif MACH /* end of MACH specific */ - -#ifdef __386BSD__ /* 386BSD specific */ -#define isa_dev isa_device -#define dev_unit id_unit -#define dev_addr id_iobase - #include #include +#endif /*KERNEL */ #include #include -#endif __386BSD__ -/* */ +/* */ -#ifdef __386BSD__ +#ifdef KERNEL #include "ddb.h" #if NDDB > 0 int Debugger(); -#else NDDB +#else /* NDDB */ #define Debugger() panic("should call debugger here") -#endif NDDB -#endif __386BSD__ - -#ifdef MACH -int Debugger(); -#endif MACH +#endif /* NDDB */ +#else /*KERNEL */ +#define NUHA 1 +#endif /*KERNEL */ + +typedef struct { + unsigned char addr[4]; +} physaddr; +typedef struct { + unsigned char len[4]; +} physlen; -typedef struct {unsigned char addr[4]; } physaddr; -typedef struct {unsigned char len[4]; } physlen; +#define KVTOPHYS(x) vtophys(x) +#define UHA_MSCP_MAX 32 /* store up to 32MSCPs at any one time + * MAX = ? + */ +#define MSCP_HASH_SIZE 32 /* when we have a physical addr. for + * a mscp and need to find the mscp in + * space, look it up in the hash table + */ +#define MSCP_HASH_SHIFT 9 /* only hash on multiples of 512 */ +#define MSCP_HASH(x) ((((long int)(x))>>MSCP_HASH_SHIFT) % MSCP_HASH_SIZE) -#ifdef MACH -extern physaddr kvtophys(); -#define PHYSTOKV(x) phystokv(x) -#define KVTOPHYS(x) kvtophys(x) -#endif MACH +extern int hz; +#define UHA_NSEG 33 /* number of dma segments supported */ -#ifdef __386BSD__ -#define KVTOPHYS(x) vtophys(x) -#endif __386BSD__ - -extern int hz; -extern int delaycount; /* from clock setup code */ -#define NUM_CONCURRENT 16 /* number of concurrent ops per board */ -#define UHA_NSEG 33 /* number of dma segments supported */ -#define FUDGE(X) (X>>1) /* our loops are slower than spinwait() */ -/* */ /************************** board definitions *******************************/ /* * I/O Port Interface -*/ - #define UHA_LMASK (0x000) /* local doorbell mask reg */ - #define UHA_LINT (0x001) /* local doorbell int/stat reg */ - #define UHA_SMASK (0x002) /* system doorbell mask reg */ - #define UHA_SINT (0x003) /* system doorbell int/stat reg */ - #define UHA_ID0 (0x004) /* product id reg 0 */ - #define UHA_ID1 (0x005) /* product id reg 1 */ - #define UHA_CONF1 (0x006) /* config reg 1 */ - #define UHA_CONF2 (0x007) /* config reg 2 */ - #define UHA_OGM0 (0x008) /* outgoing mail ptr 0 least sig */ - #define UHA_OGM1 (0x009) /* outgoing mail ptr 1 least mid */ - #define UHA_OGM2 (0x00a) /* outgoing mail ptr 2 most mid */ - #define UHA_OGM3 (0x00b) /* outgoing mail ptr 3 most sig */ - #define UHA_ICM0 (0x00c) /* incoming mail ptr 0 */ - #define UHA_ICM1 (0x00d) /* incoming mail ptr 1 */ - #define UHA_ICM2 (0x00e) /* incoming mail ptr 2 */ - #define UHA_ICM3 (0x00f) /* incoming mail ptr 3 */ - - /* -* UHA_LMASK bits (read only) -*/ - -#define UHA_LDIE 0x80 /* local doorbell int enabled */ -#define UHA_SRSTE 0x40 /* soft reset enabled */ -#define UHA_ABORTEN 0x10 /* abort MSCP enabled */ -#define UHA_OGMINTEN 0x01 /* outgoing mail interrupt enabled */ + */ +#define UHA_LMASK (0x000) /* local doorbell mask reg */ +#define UHA_LINT (0x001) /* local doorbell int/stat reg */ +#define UHA_SMASK (0x002) /* system doorbell mask reg */ +#define UHA_SINT (0x003) /* system doorbell int/stat reg */ +#define UHA_ID0 (0x004) /* product id reg 0 */ +#define UHA_ID1 (0x005) /* product id reg 1 */ +#define UHA_CONF1 (0x006) /* config reg 1 */ +#define UHA_CONF2 (0x007) /* config reg 2 */ +#define UHA_OGM0 (0x008) /* outgoing mail ptr 0 least sig */ +#define UHA_OGM1 (0x009) /* outgoing mail ptr 1 least mid */ +#define UHA_OGM2 (0x00a) /* outgoing mail ptr 2 most mid */ +#define UHA_OGM3 (0x00b) /* outgoing mail ptr 3 most sig */ +#define UHA_ICM0 (0x00c) /* incoming mail ptr 0 */ +#define UHA_ICM1 (0x00d) /* incoming mail ptr 1 */ +#define UHA_ICM2 (0x00e) /* incoming mail ptr 2 */ +#define UHA_ICM3 (0x00f) /* incoming mail ptr 3 */ /* -* UHA_LINT bits (read) -*/ + * UHA_LMASK bits (read only) + */ -#define UHA_LDIP 0x80 /* local doorbell int pending */ +#define UHA_LDIE 0x80 /* local doorbell int enabled */ +#define UHA_SRSTE 0x40 /* soft reset enabled */ +#define UHA_ABORTEN 0x10 /* abort MSCP enabled */ +#define UHA_OGMINTEN 0x01 /* outgoing mail interrupt enabled */ /* -* UHA_LINT bits (write) -*/ + * UHA_LINT bits (read) + */ -#define UHA_ADRST 0x40 /* adapter soft reset */ -#define UHA_SBRST 0x20 /* scsi bus reset */ -#define UHA_ASRST 0x60 /* adapter and scsi reset */ -#define UHA_ABORT 0x10 /* abort MSCP */ -#define UHA_OGMINT 0x01 /* tell adapter to get mail */ +#define UHA_LDIP 0x80 /* local doorbell int pending */ /* -* UHA_SMASK bits (read) -*/ + * UHA_LINT bits (write) + */ -#define UHA_SINTEN 0x80 /* system doorbell interupt Enabled */ -#define UHA_ABORT_COMPLETE_EN 0x10 /* abort MSCP command complete int Enabled */ -#define UHA_ICM_ENABLED 0x01 /* ICM interrupt enabled */ +#define UHA_ADRST 0x40 /* adapter soft reset */ +#define UHA_SBRST 0x20 /* scsi bus reset */ +#define UHA_ASRST 0x60 /* adapter and scsi reset */ +#define UHA_ABORT 0x10 /* abort MSCP */ +#define UHA_OGMINT 0x01 /* tell adapter to get mail */ /* -* UHA_SMASK bits (write) -*/ + * UHA_SMASK bits (read) + */ -#define UHA_ENSINT 0x80 /* enable system doorbell interrupt */ -#define UHA_EN_ABORT_COMPLETE 0x10 /* enable abort MSCP complete int */ -#define UHA_ENICM 0x01 /* enable ICM interrupt */ +#define UHA_SINTEN 0x80 /* system doorbell interupt Enabled */ +#define UHA_ABORT_COMPLETE_EN 0x10 /* abort MSCP command complete int Enabled */ +#define UHA_ICM_ENABLED 0x01 /* ICM interrupt enabled */ /* -* UHA_SINT bits (read) -*/ + * UHA_SMASK bits (write) + */ -#define UHA_SINTP 0x80 /* system doorbell int pending */ -#define UHA_ABORT_SUCC 0x10 /* abort MSCP successful */ -#define UHA_ABORT_FAIL 0x18 /* abort MSCP failed */ +#define UHA_ENSINT 0x80 /* enable system doorbell interrupt */ +#define UHA_EN_ABORT_COMPLETE 0x10 /* enable abort MSCP complete int */ +#define UHA_ENICM 0x01 /* enable ICM interrupt */ /* -* UHA_SINT bits (write) -*/ + * UHA_SINT bits (read) + */ + +#define UHA_SINTP 0x80 /* system doorbell int pending */ +#define UHA_ABORT_SUCC 0x10 /* abort MSCP successful */ +#define UHA_ABORT_FAIL 0x18 /* abort MSCP failed */ + +/* + * UHA_SINT bits (write) + */ -#define UHA_ABORT_ACK 0x18 /* acknowledge status and clear */ -#define UHA_ICM_ACK 0x01 /* acknowledge ICM and clear */ +#define UHA_ABORT_ACK 0x18 /* acknowledge status and clear */ +#define UHA_ICM_ACK 0x01 /* acknowledge ICM and clear */ /* -* UHA_CONF1 bits (read only) -*/ - -#define UHA_DMA_CH5 0x00 /* DMA channel 5 */ -#define UHA_DMA_CH6 0x40 /* 6 */ -#define UHA_DMA_CH7 0x80 /* 7 */ -#define UHA_IRQ15 0x00 /* IRQ 15 */ -#define UHA_IRQ14 0x10 /* 14 */ -#define UHA_IRQ11 0x20 /* 11 */ -#define UHA_IRQ10 0x30 /* 10 */ - -/*********************************** -* ha_status error codes -\***********************************/ - -#define UHA_NO_ERR 0x00 /* No error supposedly */ -#define UHA_SBUS_ABORT_ERR 0x84 /* scsi bus abort error */ -#define UHA_SBUS_TIMEOUT 0x91 /* scsi bus selection timeout */ -#define UHA_SBUS_OVER_UNDER 0x92 /* scsi bus over/underrun */ -#define UHA_BAD_SCSI_CMD 0x96 /* illegal scsi command */ -#define UHA_AUTO_SENSE_ERR 0x9b /* auto request sense err */ -#define UHA_SBUS_RES_ERR 0xa3 /* scsi bus reset error */ -#define UHA_BAD_SG_LIST 0xff /* invalid scatter gath list */ - -/* */ - -struct uha_dma_seg -{ - physaddr addr; - physlen len; + * UHA_CONF1 bits (read only) + */ + +#define UHA_DMA_CH5 0x00 /* DMA channel 5 */ +#define UHA_DMA_CH6 0x40 /* 6 */ +#define UHA_DMA_CH7 0x80 /* 7 */ +#define UHA_IRQ15 0x00 /* IRQ 15 */ +#define UHA_IRQ14 0x10 /* 14 */ +#define UHA_IRQ11 0x20 /* 11 */ +#define UHA_IRQ10 0x30 /* 10 */ + +/* + * ha_status error codes + */ + +#define UHA_NO_ERR 0x00 /* No error supposedly */ +#define UHA_SBUS_ABORT_ERR 0x84 /* scsi bus abort error */ +#define UHA_SBUS_TIMEOUT 0x91 /* scsi bus selection timeout */ +#define UHA_SBUS_OVER_UNDER 0x92 /* scsi bus over/underrun */ +#define UHA_BAD_SCSI_CMD 0x96 /* illegal scsi command */ +#define UHA_AUTO_SENSE_ERR 0x9b /* auto request sense err */ +#define UHA_SBUS_RES_ERR 0xa3 /* scsi bus reset error */ +#define UHA_BAD_SG_LIST 0xff /* invalid scatter gath list */ + +struct uha_dma_seg { + physaddr addr; + physlen len; }; -/* */ -struct mscp -{ - unsigned char opcode:3; - #define U14_HAC 0x01 /*host adapter command*/ - #define U14_TSP 0x02 /*target scsi pass through command*/ - #define U14_SDR 0x04 /*scsi device reset*/ - unsigned char xdir:2; /*xfer direction*/ - #define U14_SDET 0x00 /*determined by scsi command*/ - #define U14_SDIN 0x01 /*scsi data in*/ - #define U14_SDOUT 0x02 /*scsi data out*/ - #define U14_NODATA 0x03 /*no data xfer*/ - unsigned char dcn:1; /*disable disconnect for this command*/ - unsigned char ca:1; /*Cache control*/ - unsigned char sgth:1; /*scatter gather flag*/ - unsigned char target:3; - unsigned char chan:2; /*scsi channel (always 0 for 14f)*/ - unsigned char lun:3; - physaddr data; - physlen datalen; - physaddr link; - unsigned char link_id; - unsigned char sg_num; /*number of scat gath segs */ - /*in s-g list if sg flag is*/ - /*set. starts at 1, 8bytes per*/ - unsigned char senselen; - unsigned char cdblen; - unsigned char cdb[12]; - unsigned char ha_status; - unsigned char targ_status; - physaddr sense; /* if 0 no auto sense */ +struct mscp { + unsigned char opcode:3; +#define U14_HAC 0x01 /* host adapter command */ +#define U14_TSP 0x02 /* target scsi pass through command */ +#define U14_SDR 0x04 /* scsi device reset */ + unsigned char xdir:2; /* xfer direction */ +#define U14_SDET 0x00 /* determined by scsi command */ +#define U14_SDIN 0x01 /* scsi data in */ +#define U14_SDOUT 0x02 /* scsi data out */ +#define U14_NODATA 0x03 /* no data xfer */ + unsigned char dcn:1; /* disable disconnect for this command */ + unsigned char ca:1; /* cache control */ + unsigned char sgth:1; /* scatter gather flag */ + unsigned char target:3; + unsigned char chan:2; /* scsi channel (always 0 for 14f) */ + unsigned char lun:3; + physaddr data; + physlen datalen; + physaddr link; + unsigned char link_id; + unsigned char sg_num; /*number of scat gath segs */ + /*in s-g list if sg flag is */ + /*set. starts at 1, 8bytes per */ + unsigned char senselen; + unsigned char cdblen; + unsigned char cdb[12]; + unsigned char ha_status; + unsigned char targ_status; + physaddr sense; /* if 0 no auto sense */ /*-----------------end of hardware supported fields----------------*/ - struct mscp *next; /* in free list */ - struct scsi_xfer *xs; /* the scsi_xfer for this cmd */ - int flags; + struct mscp *next; /* in free list */ + struct scsi_xfer *xs; /* the scsi_xfer for this cmd */ + int flags; #define MSCP_FREE 0 #define MSCP_ACTIVE 1 #define MSCP_ABORTED 2 - struct uha_dma_seg uha_dma[UHA_NSEG]; - struct scsi_sense_data mscp_sense; + struct uha_dma_seg uha_dma[UHA_NSEG]; + struct scsi_sense_data mscp_sense; + struct mscp *nexthash; + long int hashkey; }; -/* */ - -struct uha_data -{ +struct uha_data { int flags; #define UHA_INIT 0x01; int baseport; - struct mscp mscps[NUM_CONCURRENT]; - struct mscp *free_mscp; - int our_id; /* our scsi id */ + struct mscp *mscphash[MSCP_HASH_SIZE]; + struct mscp *free_mscp; + int our_id; /* our scsi id */ int vect; - int dma; -} uha_data[NUHA]; + int dma; + int nummscps; + struct scsi_link sc_link; +} *uhadata[NUHA]; int uhaprobe(); int uha_attach(); int uhaintr(); -int uha_scsi_cmd(); -int uha_timeout(); -int uha_abort(); -struct mscp *cheat; +int32 uha_scsi_cmd(); +void uha_timeout(); +void uha_free_mscp(); +int uha_abort(); void uhaminphys(); -long int uha_adapter_info(); +void uha_done(); +u_int32 uha_adapter_info(); +struct mscp *uha_mscp_phys_kv(); +struct mscp *cheat; unsigned long int scratch; - -#ifdef MACH -struct isa_driver uhadriver = { uhaprobe, 0, uha_attach, "uha", 0, 0, 0}; -int (*uhaintrs[])() = {uhaintr, 0}; -#endif MACH - -#ifdef __386BSD__ -struct isa_driver uhadriver = { uhaprobe, uha_attach, "uha"}; -#endif __386BSD__ - -static uha_unit = 0; -#ifdef UHADEBUG -int uha_debug = 0; -#endif /*UHADEBUG*/ +static uha_unit = 0; #define UHA_SHOWMSCPS 0x01 #define UHA_SHOWINTS 0x02 #define UHA_SHOWCMDS 0x04 @@ -294,7 +262,15 @@ int uha_debug = 0; #define SUCCESS 0 #define PAGESIZ 4096 -struct scsi_switch uha_switch = +#ifdef KERNEL +struct isa_driver uhadriver = +{ + uhaprobe, + uha_attach, + "uha" +}; + +struct scsi_adapter uha_switch = { uha_scsi_cmd, uhaminphys, @@ -302,401 +278,447 @@ struct scsi_switch uha_switch = 0, uha_adapter_info, "uha", - 0,0 + 0, 0 }; -/* */ -/***********************************************************************\ -* Function to send a command out through a mailbox * -\***********************************************************************/ -uha_send_mbox( int unit - ,struct mscp *mscp) +/* the below structure is so we have a default dev struct for out link struct */ +struct scsi_device uha_dev = { - int port = uha_data[unit].baseport; - int spincount = FUDGE(delaycount) * 1000; /* 1s should be enough */ + NULL, /* Use default error handler */ + NULL, /* have a queue, served by this */ + NULL, /* have no async handler */ + NULL, /* Use default 'done' routine */ + "uha", + 0, + 0, 0 +}; + +#endif /*KERNEL */ + +#ifndef KERNEL +main() +{ + printf("uha_data is %d bytes\n", sizeof(struct uha_data)); + printf("mscp is %d bytes\n", sizeof(struct mscp)); +} + +#else /*KERNEL*/ +/* + * Function to send a command out through a mailbox + */ +void +uha_send_mbox(int unit, struct mscp *mscp) +{ + struct uha_data *uha = uhadata[unit]; + int port = uha->baseport; + int spincount = 100000; /* 1s should be enough */ int s = splbio(); - - while( ((inb(port + UHA_LINT) & (UHA_LDIP)) - != (0)) - && (spincount--)); - if(spincount == -1) - { - printf("uha%d: uha_send_mbox, board not responding\n",unit); + + while (--spincount) { + if ((inb(port + UHA_LINT) & UHA_LDIP) == 0) + break; + DELAY(100); + } + if (spincount == 0) { + printf("uha%d: uha_send_mbox, board not responding\n", unit); Debugger(); } - - outl(port + UHA_OGM0,KVTOPHYS(mscp)); + outl(port + UHA_OGM0, KVTOPHYS(mscp)); outb(port + UHA_LINT, (UHA_OGMINT)); splx(s); } -/***********************************************************************\ -* Function to send abort to 14f * -\***********************************************************************/ - -uha_abort( int unit - ,struct mscp *mscp) +/* + * Function to send abort to 14f + */ +int +uha_abort(int unit, struct mscp *mscp) { - int port = uha_data[unit].baseport; - int spincount = FUDGE(delaycount) * 1; - int abortcount = FUDGE(delaycount) * 2000; - int s = splbio(); - - while(((inb(port + UHA_LINT) & (UHA_LDIP)) - != (0)) - && (spincount--)); - if(spincount == -1); + struct uha_data *uha = uhadata[unit]; + int port = uha->baseport; + int spincount = 100; /* 1 mSec */ + int abortcount = 200000; /*2 secs */ + int s = splbio(); + + while (--spincount) { + if ((inb(port + UHA_LINT) & UHA_LDIP) == 0) + break; + DELAY(10); + } + if (spincount == 0); { - printf("uha%d: uha_abort, board not responding\n",unit); + printf("uha%d: uha_abort, board not responding\n", unit); Debugger(); } + outl(port + UHA_OGM0, KVTOPHYS(mscp)); + outb(port + UHA_LINT, UHA_ABORT); - outl(port + UHA_OGM0,KVTOPHYS(mscp)); - outb(port + UHA_LINT,UHA_ABORT); - - while((abortcount--) && (!(inb(port + UHA_SINT) & UHA_ABORT_FAIL))); - if(abortcount == -1) - { - printf("uha%d: uha_abort, board not responding\n",unit); - Debugger(); + while (--abortcount) { + if (inb(port + UHA_SINT) & UHA_ABORT_FAIL) + break; + DELAY(10); } - if((inb(port + UHA_SINT) & 0x10) != 0) - { - outb(port + UHA_SINT,UHA_ABORT_ACK); - return(1); + if (abortcount == 0) { + printf("uha%d: uha_abort, board not responding\n", unit); + Debugger(); } - else - { - outb(port + UHA_SINT,UHA_ABORT_ACK); - return(0); + if ((inb(port + UHA_SINT) & 0x10) != 0) { + outb(port + UHA_SINT, UHA_ABORT_ACK); + return (1); + } else { + outb(port + UHA_SINT, UHA_ABORT_ACK); + return (0); } } -/***********************************************************************\ -* Function to poll for command completion when in poll mode * -\***********************************************************************/ -uha_poll(int unit ,int wait) /* in msec */ +/* + * Function to poll for command completion when in poll mode. + * + * wait = timeout in msec + */ +int +uha_poll(int unit, int wait) { - int port = uha_data[unit].baseport; - int spincount = FUDGE(delaycount) * wait; /* in msec */ - int stport = port + UHA_SINT; - int start = spincount; - -retry: - while( (spincount--) && (!(inb(stport) & UHA_SINTP))); - if(spincount == -1) - { - printf("uha%d: uha_poll, board not responding\n",unit); - return(EIO); + struct uha_data *uha = uhadata[unit]; + int port = uha->baseport; + int stport = port + UHA_SINT; + + retry: + while (--wait) { + if (inb(stport) & UHA_SINTP) + break; + DELAY(1000); /* 1 mSec per loop */ + } + if (wait == 0) { + printf("uha%d: uha_poll, board not responding\n", unit); + return (EIO); } -if ((int)cheat != PHYSTOKV(inl(port + UHA_ICM0))) -{ - printf("uha%d: discarding %x\n",unit,inl(port + UHA_ICM0)); - outb(port + UHA_SINT, UHA_ICM_ACK); - spinwait(50); - goto retry; -}/* don't know this will work */ uhaintr(unit); - return(0); + return (0); } -/*******************************************************\ -* Check if the device can be found at the port given * -* and if so, set it up ready for further work * -* as an argument, takes the isa_dev structure from * -* autoconf.c * -\*******************************************************/ +/* + * Check if the device can be found at the port given and if so, set it up + * ready for further work as an argument, takes the isa_device structure + * from autoconf.c + */ +int uhaprobe(dev) -struct isa_dev *dev; + struct isa_device *dev; { - int unit = uha_unit; - dev->dev_unit = unit; - uha_data[unit].baseport = dev->dev_addr; - if(unit >= NUHA) - { - printf("uha%d: unit number too high\n",unit); - return(0); - } - - /*try and initialize unit at this location*/ - if (uha_init(unit) != 0) - { - return(0); - } + int unit = uha_unit; + struct uha_data *uha; - /* if its there put in it's interrupt and DRQ vectors */ + dev->id_unit = unit; - dev->id_irq = (1 << uha_data[unit].vect); - dev->id_drq = uha_data[unit].dma; + /* + * find unit and check we have that many defined + */ + if (unit >= NUHA) { + printf("uha: unit number (%d) too high\n", unit); + return (0); + } + dev->id_unit = unit; + + /* + * Allocate a storage area for us + */ + if (uhadata[unit]) { + printf("uha%d: memory already allocated\n", unit); + return 0; + } + uha = malloc(sizeof(struct uha_data), M_TEMP, M_NOWAIT); + if (!uha) { + printf("uha%d: cannot malloc!\n", unit); + return 0; + } + bzero(uha, sizeof(struct uha_data)); + uhadata[unit] = uha; + uha->baseport = dev->id_iobase; + /* + * Try initialise a unit at this location + * sets up dma and bus speed, loads uha->vect + */ + if (uha_init(unit) != 0) { + uhadata[unit] = NULL; + free(uha, M_TEMP); + return (0); + } + /* if it's there put in its interrupt and DRQ vectors */ + dev->id_irq = (1 << uha->vect); + dev->id_drq = uha->dma; - - uha_unit ++; -return(1); + uha_unit++; + return (16); } -/***********************************************\ -* Attach all the sub-devices we can find * -\***********************************************/ +/* + * Attach all the sub-devices we can find + */ +int uha_attach(dev) -struct isa_dev *dev; + struct isa_device *dev; { - int unit = dev->dev_unit; - - - /***********************************************\ - * ask the adapter what subunits are present * - \***********************************************/ - scsi_attachdevs( unit, uha_data[unit].our_id, &uha_switch); - -#if defined(OSF) - uha_attached[unit]=1; -#endif /* defined(OSF) */ - return; + int unit = dev->id_unit; + struct uha_data *uha = uhadata[unit]; + + /* + * fill in the prototype scsi_link. + */ + uha->sc_link.adapter_unit = unit; + uha->sc_link.adapter_targ = uha->our_id; + uha->sc_link.adapter = &uha_switch; + uha->sc_link.device = &uha_dev; + + /* + * ask the adapter what subunits are present + */ + scsi_attachdevs(&(uha->sc_link)); + + return 1; } -/***********************************************\ -* Return some information to the caller about * -* the adapter and it's capabilities * -\***********************************************/ -long int uha_adapter_info(unit) -int unit; +/* + * Return some information to the caller about + * the adapter and it's capabilities + */ +u_int32 +uha_adapter_info(unit) + int unit; { - return(2); /* 2 outstanding requests at a time per device */ + return (2); /* 2 outstanding requests at a time per device */ } -/***********************************************\ -* Catch an interrupt from the adaptor * -\***********************************************/ +/* + * Catch an interrupt from the adaptor + */ +int uhaintr(unit) { - struct mscp *mscp; - u_char uhastat; - unsigned long int mboxval; - - int port = uha_data[unit].baseport; + struct uha_data *uha = uhadata[unit]; + struct mscp *mscp; + u_char uhastat; + unsigned long int mboxval; + int port = uha->baseport; #ifdef UHADEBUG - if(scsi_debug & PRINTROUTINES) - printf("uhaintr "); -#endif /*UHADEBUG*/ - -#if defined(OSF) - if (!uha_attached[unit]) - { - return(1); - } -#endif /* defined(OSF) */ - while(inb(port + UHA_SINT) & UHA_SINTP) - { - /***********************************************\ - * First get all the information and then * - * acknowlege the interrupt * - \***********************************************/ + printf("uhaintr "); +#endif /*UHADEBUG */ + + while (inb(port + UHA_SINT) & UHA_SINTP) { + /* + * First get all the information and then + * acknowledge the interrupt + */ uhastat = inb(port + UHA_SINT); mboxval = inl(port + UHA_ICM0); - outb(port + UHA_SINT,UHA_ICM_ACK); - -#ifdef UHADEBUG - if(scsi_debug & TRACEINTERRUPTS) - printf("status = 0x%x ",uhastat); -#endif /*UHADEBUG*/ - /***********************************************\ - * Process the completed operation * - \***********************************************/ - - mscp = (struct mscp *)(PHYSTOKV(mboxval)); + outb(port + UHA_SINT, UHA_ICM_ACK); #ifdef UHADEBUG - if(uha_debug & UHA_SHOWCMDS ) - { - uha_show_scsi_cmd(mscp->xs); - } - if((uha_debug & UHA_SHOWMSCPS) && mscp) - printf("",mscp); -#endif /*UHADEBUG*/ - untimeout(uha_timeout,mscp); + printf("status = 0x%x ", uhastat); +#endif /*UHADEBUG*/ + /* + * Process the completed operation + */ + + mscp = uha_mscp_phys_kv(uha, mboxval); + if (!mscp) { + printf("uha: BAD MSCP RETURNED\n"); + return (0); /* whatever it was, it'll timeout */ + } + untimeout(uha_timeout, mscp); - uha_done(unit,mscp); + uha_done(unit, mscp); } - return(1); + return (1); } -/***********************************************\ -* We have a mscp which has been processed by the * -* adaptor, now we look to see how the operation * -* went. * -\***********************************************/ - -uha_done(unit,mscp) -int unit; -struct mscp *mscp; +/* + * We have a mscp which has been processed by the adaptor, now we look to see + * how the operation went. + */ +void +uha_done(unit, mscp) + int unit; + struct mscp *mscp; { - struct scsi_sense_data *s1,*s2; - struct scsi_xfer *xs = mscp->xs; - -#ifdef UHADEBUG - if(scsi_debug & (PRINTROUTINES | TRACEINTERRUPTS)) - printf("uha_done "); -#endif /*UHADEBUG*/ - /***********************************************\ - * Otherwise, put the results of the operation * - * into the xfer and call whoever started it * - \***********************************************/ - if ( (mscp->ha_status == UHA_NO_ERR) || (xs->flags & SCSI_ERR_OK)) - { /* All went correctly OR errors expected */ + struct uha_data *uha = uhadata[unit]; + struct scsi_sense_data *s1, *s2; + struct scsi_xfer *xs = mscp->xs; + + SC_DEBUG(xs->sc_link, SDEV_DB2, ("uha_done\n")); + /* + * Otherwise, put the results of the operation + * into the xfer and call whoever started it + */ + if ((mscp->ha_status == UHA_NO_ERR) || (xs->flags & SCSI_ERR_OK)) { /* All went correctly OR errors expected */ xs->resid = 0; xs->error = 0; - } - else - { + } else { s1 = &(mscp->mscp_sense); s2 = &(xs->sense); - if(mscp->ha_status != UHA_NO_ERR) - { - switch(mscp->ha_status) - { - case UHA_SBUS_TIMEOUT: /* No response */ -#ifdef UHADEBUG - if (uha_debug & UHA_SHOWMISC) - { - printf("timeout reported back\n"); - } -#endif /*UHADEBUG*/ + if (mscp->ha_status != UHA_NO_ERR) { + switch (mscp->ha_status) { + case UHA_SBUS_TIMEOUT: /* No response */ + SC_DEBUG(xs->sc_link, SDEV_DB3, + ("timeout reported back\n")); xs->error = XS_TIMEOUT; break; - case UHA_SBUS_OVER_UNDER: -#ifdef UHADEBUG - if (uha_debug & UHA_SHOWMISC) - { - printf("scsi bus xfer over/underrun\n"); - } -#endif /*UHADEBUG*/ + case UHA_SBUS_OVER_UNDER: + SC_DEBUG(xs->sc_link, SDEV_DB3, + ("scsi bus xfer over/underrun\n")); xs->error = XS_DRIVER_STUFFUP; break; - case UHA_BAD_SG_LIST: -#ifdef UHADEBUG - if (uha_debug & UHA_SHOWMISC) - { - printf("bad sg list reported back\n"); - } -#endif /*UHADEBUG*/ + case UHA_BAD_SG_LIST: + SC_DEBUG(xs->sc_link, SDEV_DB3, + ("bad sg list reported back\n")); xs->error = XS_DRIVER_STUFFUP; break; - default: /* Other scsi protocol messes */ + default: /* Other scsi protocol messes */ xs->error = XS_DRIVER_STUFFUP; -#ifdef UHADEBUG - if (uha_debug & UHA_SHOWMISC) - { - printf("unexpected ha_status: %x\n", - mscp->ha_status); - } -#endif /*UHADEBUG*/ + SC_DEBUG(xs->sc_link, SDEV_DB3, + ("unexpected ha_status: %x\n", + mscp->ha_status)); } - - } - else - { + } else { if (mscp->targ_status != 0) -/**************************************************************************\ -* I have no information for any possible value of target status field * -* other than 0 means no error!! So I guess any error is unexpected in that * -* event!! * -\**************************************************************************/ +/* + * I have no information for any possible value of target status field + * other than 0 means no error!! So I guess any error is unexpected in that + * event!! + */ - { -#ifdef UHADEBUG - if (uha_debug & UHA_SHOWMISC) - { - printf("unexpected targ_status: %x\n", - mscp->targ_status); - } -#endif /*UHADEBUG*/ + { + SC_DEBUG(xs->sc_link, SDEV_DB3, + ("unexpected targ_status: %x\n", + mscp->targ_status)); xs->error = XS_DRIVER_STUFFUP; } } - } -done: xs->flags |= ITSDONE; - uha_free_mscp(unit,mscp, xs->flags); - if(xs->when_done) - (*(xs->when_done))(xs->done_arg,xs->done_arg2); + } + done: + xs->flags |= ITSDONE; + uha_free_mscp(unit, mscp, xs->flags); + scsi_done(xs); } -/***********************************************\ -* A mscp (and hence a mbx-out is put onto the * -* free list. * -\***********************************************/ -uha_free_mscp(unit,mscp, flags) -struct mscp *mscp; +/* + * A mscp (and hence a mbx-out) is put onto the free list. + */ +void +uha_free_mscp(unit, mscp, flags) + struct mscp *mscp; { + struct uha_data *uha = uhadata[unit]; unsigned int opri; - -#ifdef UHADEBUG - if(scsi_debug & PRINTROUTINES) - printf("mscp%d(0x%x)> ",unit,flags); -#endif /*UHADEBUG*/ - if (!(flags & SCSI_NOMASK)) + + if (!(flags & SCSI_NOMASK)) opri = splbio(); - mscp->next = uha_data[unit].free_mscp; - uha_data[unit].free_mscp = mscp; + mscp->next = uha->free_mscp; + uha->free_mscp = mscp; mscp->flags = MSCP_FREE; - /***********************************************\ - * If there were none, wake abybody waiting for * - * one to come free, starting with queued entries* - \***********************************************/ + /* + * If there were none, wake abybody waiting for + * one to come free, starting with queued entries + */ if (!mscp->next) { - wakeup(&uha_data[unit].free_mscp); + wakeup(&uha->free_mscp); } - if (!(flags & SCSI_NOMASK)) + if (!(flags & SCSI_NOMASK)) splx(opri); } -/***********************************************\ -* Get a free mscp (and hence mbox-out entry) * -\***********************************************/ +/* + * Get a free mscp + * + * If there are none, see if we can allocate a new one. If so, put it in the + * hash table too otherwise either return an error or sleep. + */ struct mscp * -uha_get_mscp(unit,flags) +uha_get_mscp(unit, flags) + int unit, flags; { + struct uha_data *uha = uhadata[unit]; unsigned opri; - struct mscp *rc; + struct mscp *mscpp; + int hashnum; -#ifdef UHADEBUG - if(scsi_debug & PRINTROUTINES) - printf("free_mscp)) { + if (uha->nummscps < UHA_MSCP_MAX) { + if (mscpp = (struct mscp *)malloc(sizeof(struct mscp), + M_TEMP, + M_NOWAIT)) { + bzero(mscpp, sizeof(struct mscp)); + uha->nummscps++; + mscpp->flags = MSCP_ACTIVE; + /* + * put in the phystokv hash table + * Never gets taken out. + */ + mscpp->hashkey = KVTOPHYS(mscpp); + hashnum = MSCP_HASH(mscpp->hashkey); + mscpp->nexthash = uha->mscphash[hashnum]; + uha->mscphash[hashnum] = mscpp; + } else { + printf("uha%d: Can't malloc MSCP\n", unit); + } + goto gottit; + } else { + if (!(flags & SCSI_NOSLEEP)) { + sleep(&uha->free_mscp, PRIBIO); + } + } } - if (rc) - { - uha_data[unit].free_mscp = rc->next; - rc->flags = MSCP_ACTIVE; + if (mscpp) { + /* Get MSCP from from free list */ + uha->free_mscp = mscpp->next; + mscpp->flags = MSCP_ACTIVE; } - if (!(flags & SCSI_NOMASK)) + gottit: + if (!(flags & SCSI_NOMASK)) splx(opri); - return(rc); + + return (mscpp); } - +/* + * given a physical address, find the mscp that it corresponds to. + */ +struct mscp * +uha_mscp_phys_kv(uha, mscp_phys) + struct uha_data *uha; + long int mscp_phys; +{ + int hashnum = MSCP_HASH(mscp_phys); + struct mscp *mscpp = uha->mscphash[hashnum]; -/***********************************************\ -* Start the board, ready for normal operation * -\***********************************************/ + while (mscpp) { + if (mscpp->hashkey == mscp_phys) + break; + mscpp = mscpp->nexthash; + } + return mscpp; +} +/* + * Start the board, ready for normal operation + */ +int uha_init(unit) -int unit; -{ + int unit; +{ + struct uha_data *uha = uhadata[unit]; unsigned char ad[4]; volatile unsigned char model; volatile unsigned char submodel; @@ -705,20 +727,17 @@ int unit; unsigned char dma_ch; unsigned char irq_ch; unsigned char uha_id; - int port = uha_data[unit].baseport; - int i; - int resetcount = FUDGE(delaycount) * 4000; + int port = uha->baseport; + int i; + int resetcount = 4000; /* 4 secs? */ model = inb(port + UHA_ID0); submodel = inb(port + UHA_ID1); - if ((model != 0x56) & (submodel != 0x40)) { -#ifdef UHADEBUG - printf("uha%d: uha_init, board not responding\n",unit); -#endif /*UHADEBUG*/ - return(ENXIO); - } - - printf("uha%d: reading board settings, ",unit); + if ((model != 0x56) & (submodel != 0x40)) { + printf("uha%d: uha_init, board not responding\n", unit); + return (ENXIO); + } + printf("uha%d: reading board settings, ", unit); config_reg1 = inb(port + UHA_CONF1); config_reg2 = inb(port + UHA_CONF2); @@ -726,307 +745,256 @@ int unit; irq_ch = (config_reg1 & 0x30); uha_id = (config_reg2 & 0x07); - switch(dma_ch) - { - case UHA_DMA_CH5: - uha_data[unit].dma = 5; + switch (dma_ch) { + case UHA_DMA_CH5: + uha->dma = 5; printf("dma=5 "); break; - case UHA_DMA_CH6: - uha_data[unit].dma = 6; + case UHA_DMA_CH6: + uha->dma = 6; printf("dma=6 "); break; - case UHA_DMA_CH7: - uha_data[unit].dma = 7; + case UHA_DMA_CH7: + uha->dma = 7; printf("dma=7 "); break; default: printf("illegal dma jumper setting\n"); - return(EIO); + return (EIO); } - switch(irq_ch) - { - case UHA_IRQ10: - uha_data[unit].vect = 10; + switch (irq_ch) { + case UHA_IRQ10: + uha->vect = 10; printf("int=10 "); break; - case UHA_IRQ11: - uha_data[unit].vect = 11; + case UHA_IRQ11: + uha->vect = 11; printf("int=11 "); break; - case UHA_IRQ14: - uha_data[unit].vect = 14; + case UHA_IRQ14: + uha->vect = 14; printf("int=14 "); break; - case UHA_IRQ15: - uha_data[unit].vect = 15; + case UHA_IRQ15: + uha->vect = 15; printf("int=15 "); break; default: printf("illegal int jumper setting\n"); - return(EIO); + return (EIO); } + /* who are we on the scsi bus */ - printf("id=%x\n",uha_id); - uha_data[unit].our_id = uha_id; - - - /***********************************************\ - * link up all our MSCPs into a free list * - \***********************************************/ - for (i=0; i < NUM_CONCURRENT; i++) - { - uha_data[unit].mscps[i].next = uha_data[unit].free_mscp; - uha_data[unit].free_mscp = &uha_data[unit].mscps[i]; - uha_data[unit].free_mscp->flags = MSCP_FREE; + printf("id=%x\n", uha_id); + uha->our_id = uha_id; + + /* + * Note that we are going and return (to probe) + */ + outb(port + UHA_LINT, UHA_ASRST); + while (--resetcount) { + if (inb(port + UHA_LINT)); + break; + DELAY(1000); /* 1 mSec per loop */ } - - /***********************************************\ - * Note that we are going and return (to probe) * - \***********************************************/ - outb(port + UHA_LINT, UHA_ASRST); - while( (resetcount--) && (!(inb(port + UHA_LINT)))); - if(resetcount == -1) - { - printf("uha%d: board timed out during reset\n",unit); - return(ENXIO); + if (resetcount == 0) { + printf("uha%d: board timed out during reset\n", unit); + return (ENXIO); } - - outb(port + UHA_SMASK, 0x81); /* make sure interrupts are enabled */ - uha_data[unit].flags |= UHA_INIT; - return(0); + outb(port + UHA_SMASK, 0x81); /* make sure interrupts are enabled */ + uha->flags |= UHA_INIT; + return (0); } - - #ifndef min #define min(x,y) (x < y ? x : y) -#endif min +#endif /* min */ - -void uhaminphys(bp) -struct buf *bp; +void +uhaminphys(bp) + struct buf *bp; { -#ifdef MACH -#if !defined(OSF) - bp->b_flags |= B_NPAGES; /* can support scat/gather */ -#endif /* defined(OSF) */ -#endif MACH - if(bp->b_bcount > ((UHA_NSEG-1) * PAGESIZ)) - { - bp->b_bcount = ((UHA_NSEG-1) * PAGESIZ); + if (bp->b_bcount > ((UHA_NSEG - 1) * PAGESIZ)) { + bp->b_bcount = ((UHA_NSEG - 1) * PAGESIZ); } } -/***********************************************\ -* start a scsi operation given the command and * -* the data address. Also needs the unit, target * -* and lu * -\***********************************************/ -int uha_scsi_cmd(xs) -struct scsi_xfer *xs; +/* + * start a scsi operation given the command and the data address. Also + * needs the unit, target and lu. + */ +int32 +uha_scsi_cmd(xs) + struct scsi_xfer *xs; { - struct scsi_sense_data *s1,*s2; - struct mscp *mscp; - struct uha_dma_seg *sg; - int seg; /* scatter gather seg being worked on */ - int i = 0; - int rc = 0; + struct scsi_sense_data *s1, *s2; + struct mscp *mscp; + struct uha_dma_seg *sg; + int seg; /* scatter gather seg being worked on */ + int i = 0; + int rc = 0; int thiskv; - unsigned long int thisphys,nextphys; - int unit =xs->adapter; - int bytes_this_seg,bytes_this_page,datalen,flags; - struct iovec *iovp; + unsigned long int thisphys, nextphys; + int unit = xs->sc_link->adapter_unit; + int bytes_this_seg, bytes_this_page, datalen, flags; + struct iovec *iovp; + struct uha_data *uha = uhadata[unit]; int s; unsigned int stat; - int port = uha_data[unit].baseport; + int port = uha->baseport; unsigned long int templen; - -#ifdef UHADEBUG - if(scsi_debug & PRINTROUTINES) - printf("uha_scsi_cmd "); -#endif /*UHADEBUG*/ - /***********************************************\ - * get a mscp (mbox-out) to use. If the transfer * - * is from a buf (possibly from interrupt time) * - * then we can't allow it to sleep * - \***********************************************/ + SC_DEBUG(xs->sc_link, SDEV_DB2, ("uha_scsi_cmd\n")); + /* + * get a mscp (mbox-out) to use. If the transfer + * is from a buf (possibly from interrupt time) + * then we can't allow it to sleep + */ flags = xs->flags; - if(xs->bp) flags |= (SCSI_NOSLEEP); /* just to be sure */ - if(flags & ITSDONE) - { - printf("uha%d: Already done?",unit); + if (xs->bp) + flags |= (SCSI_NOSLEEP); /* just to be sure */ + if (flags & ITSDONE) { + printf("uha%d: Already done?", unit); xs->flags &= ~ITSDONE; } - if(!(flags & INUSE)) - { - printf("uha%d: Not in use?",unit); + if (!(flags & INUSE)) { + printf("uha%d: Not in use?", unit); xs->flags |= INUSE; } - if (!(mscp = uha_get_mscp(unit,flags))) - { + if (!(mscp = uha_get_mscp(unit, flags))) { xs->error = XS_DRIVER_STUFFUP; - return(TRY_AGAIN_LATER); + return (TRY_AGAIN_LATER); } - -cheat = mscp; -#ifdef UHADEBUG - if(uha_debug & UHA_SHOWMSCPS) - printf("",mscp); - if(scsi_debug & SHOWCOMMANDS) - { - uha_show_scsi_cmd(xs); - } -#endif /*UHADEBUG*/ + cheat = mscp; + SC_DEBUG(xs->sc_link, SDEV_DB3, ("start mscp(%x)\n", mscp)); mscp->xs = xs; - /***********************************************\ - * Put all the arguments for the xfer in the mscp * - \***********************************************/ - if (flags & SCSI_RESET) - { + /* + * Put all the arguments for the xfer in the mscp + */ + if (flags & SCSI_RESET) { mscp->opcode = 0x04; mscp->ca = 0x01; - } - else - { + } else { mscp->opcode = 0x02; mscp->ca = 0x01; - } - - if (flags & SCSI_DATA_IN) - { + } + if (flags & SCSI_DATA_IN) { mscp->xdir = 0x01; } - if (flags & SCSI_DATA_OUT) - { + if (flags & SCSI_DATA_OUT) { mscp->xdir = 0x02; } - - if (xs->lu != 0) - { +#ifdef GOTTABEJOKING + if (xs->sc_link->lun != 0) { xs->error = XS_DRIVER_STUFFUP; - uha_free_mscp(unit,mscp,flags); - return(HAD_ERROR); + uha_free_mscp(unit, mscp, flags); + return (HAD_ERROR); } - - mscp->dcn = 0x00; - mscp->chan = 0x00; - mscp->target = xs->targ; - mscp->lun = xs->lu; - mscp->link.addr[0] = 0x00; - mscp->link.addr[1] = 0x00; - mscp->link.addr[2] = 0x00; - mscp->link.addr[3] = 0x00; - mscp->link_id = 0x00; - mscp->cdblen = xs->cmdlen; - scratch = KVTOPHYS(&(mscp->mscp_sense)); - mscp->sense.addr[0] = (scratch & 0xff); - mscp->sense.addr[1] = ((scratch >> 8) & 0xff); - mscp->sense.addr[2] = ((scratch >> 16) & 0xff); - mscp->sense.addr[3] = ((scratch >> 24) & 0xff); - mscp->senselen = sizeof(mscp->mscp_sense); - mscp->ha_status = 0x00; - mscp->targ_status = 0x00; - - if(xs->datalen) - { /* should use S/G only if not zero length */ - scratch = KVTOPHYS(mscp->uha_dma); - mscp->data.addr[0] = (scratch & 0xff); - mscp->data.addr[1] = ((scratch >> 8) & 0xff); - mscp->data.addr[2] = ((scratch >> 16) & 0xff); - mscp->data.addr[3] = ((scratch >> 24) & 0xff); - sg = mscp->uha_dma ; - seg = 0; - mscp->sgth = 0x01; - - if(flags & SCSI_DATA_UIO) - { - iovp = ((struct uio *)xs->data)->uio_iov; - datalen = ((struct uio *)xs->data)->uio_iovcnt; +#endif + mscp->dcn = 0x00; + mscp->chan = 0x00; + mscp->target = xs->sc_link->target; + mscp->lun = xs->sc_link->lun; + mscp->link.addr[0] = 0x00; + mscp->link.addr[1] = 0x00; + mscp->link.addr[2] = 0x00; + mscp->link.addr[3] = 0x00; + mscp->link_id = 0x00; + mscp->cdblen = xs->cmdlen; + scratch = KVTOPHYS(&(mscp->mscp_sense)); + mscp->sense.addr[0] = (scratch & 0xff); + mscp->sense.addr[1] = ((scratch >> 8) & 0xff); + mscp->sense.addr[2] = ((scratch >> 16) & 0xff); + mscp->sense.addr[3] = ((scratch >> 24) & 0xff); + mscp->senselen = sizeof(mscp->mscp_sense); + mscp->ha_status = 0x00; + mscp->targ_status = 0x00; + + if (xs->datalen) { /* should use S/G only if not zero length */ + scratch = KVTOPHYS(mscp->uha_dma); + mscp->data.addr[0] = (scratch & 0xff); + mscp->data.addr[1] = ((scratch >> 8) & 0xff); + mscp->data.addr[2] = ((scratch >> 16) & 0xff); + mscp->data.addr[3] = ((scratch >> 24) & 0xff); + sg = mscp->uha_dma; + seg = 0; + mscp->sgth = 0x01; + +#ifdef TFS + if (flags & SCSI_DATA_UIO) { + iovp = ((struct uio *) xs->data)->uio_iov; + datalen = ((struct uio *) xs->data)->uio_iovcnt; xs->datalen = 0; - while ((datalen) && (seg < UHA_NSEG)) - { - scratch = (unsigned long)iovp->iov_base; - sg->addr.addr[0] = (scratch & 0xff); + while ((datalen) && (seg < UHA_NSEG)) { + scratch = (unsigned long) iovp->iov_base; + sg->addr.addr[0] = (scratch & 0xff); sg->addr.addr[1] = ((scratch >> 8) & 0xff); sg->addr.addr[2] = ((scratch >> 16) & 0xff); sg->addr.addr[3] = ((scratch >> 24) & 0xff); - xs->datalen += *(unsigned long *)sg->len.len = iovp->iov_len; -#ifdef UHADEBUG - if(scsi_debug & SHOWSCATGATH) - printf("(0x%x@0x%x)" - ,iovp->iov_len - ,iovp->iov_base); -#endif /*UHADEBUG*/ + xs->datalen += *(unsigned long *) sg->len.len = iovp->iov_len; + SC_DEBUGN(xs->sc_link, SDEV_DB4, ("(0x%x@0x%x)", + iovp->iov_len, + iovp->iov_base)); sg++; iovp++; seg++; datalen--; } - } - else + } else +#endif /*TFS */ { - /***********************************************\ - * Set up the scatter gather block * - \***********************************************/ - -#ifdef UHADEBUG - if(scsi_debug & SHOWSCATGATH) - printf("%d @0x%x:- ",xs->datalen,xs->data); -#endif /*UHADEBUG*/ - datalen = xs->datalen; - thiskv = (int)xs->data; - thisphys = KVTOPHYS(thiskv); - templen = 0; - - while ((datalen) && (seg < UHA_NSEG)) - { - bytes_this_seg = 0; - + /* + * Set up the scatter gather block + */ + + SC_DEBUG(xs->sc_link, SDEV_DB4, + ("%d @0x%x:- ", xs->datalen, xs->data)); + datalen = xs->datalen; + thiskv = (int) xs->data; + thisphys = KVTOPHYS(thiskv); + templen = 0; + + while ((datalen) && (seg < UHA_NSEG)) { + bytes_this_seg = 0; + /* put in the base address */ sg->addr.addr[0] = (thisphys & 0xff); sg->addr.addr[1] = ((thisphys >> 8) & 0xff); sg->addr.addr[2] = ((thisphys >> 16) & 0xff); sg->addr.addr[3] = ((thisphys >> 24) & 0xff); - -#ifdef UHADEBUG - if(scsi_debug & SHOWSCATGATH) - printf("0x%x",thisphys); -#endif /*UHADEBUG*/ - + + SC_DEBUGN(xs->sc_link, SDEV_DB4, ("0x%x", thisphys)); + /* do it at least once */ - nextphys = thisphys; + nextphys = thisphys; while ((datalen) && (thisphys == nextphys)) - /*********************************************\ - * This page is contiguous (physically) with * - * the the last, just extend the length * - \*********************************************/ + /* + * This page is contiguous (physically) with + * the the last, just extend the length + */ { /* how far to the end of the page */ nextphys = (thisphys & (~(PAGESIZ - 1))) - + PAGESIZ; + + PAGESIZ; bytes_this_page = nextphys - thisphys; /**** or the data ****/ bytes_this_page = min(bytes_this_page - ,datalen); - bytes_this_seg += bytes_this_page; - datalen -= bytes_this_page; - + ,datalen); + bytes_this_seg += bytes_this_page; + datalen -= bytes_this_page; + /* get more ready for the next page */ - thiskv = (thiskv & (~(PAGESIZ - 1))) - + PAGESIZ; - if(datalen) + thiskv = (thiskv & (~(PAGESIZ - 1))) + + PAGESIZ; + if (datalen) thisphys = KVTOPHYS(thiskv); } - /********************************************\ - * next page isn't contiguous, finish the seg * - \********************************************/ -#ifdef UHADEBUG - if(scsi_debug & SHOWSCATGATH) - printf("(0x%x)",bytes_this_seg); -#endif /*UHADEBUG*/ + /* + * next page isn't contiguous, finish the seg + */ + SC_DEBUGN(xs->sc_link, SDEV_DB4, + ("(0x%x)", bytes_this_seg)); sg->len.len[0] = (bytes_this_seg & 0xff); sg->len.len[1] = ((bytes_this_seg >> 8) & 0xff); sg->len.len[2] = ((bytes_this_seg >> 16) & 0xff); @@ -1035,29 +1003,24 @@ cheat = mscp; sg++; seg++; } - } /*end of iov/kv decision */ + } + + /* end of iov/kv decision */ mscp->datalen.len[0] = (templen & 0xff); mscp->datalen.len[1] = ((templen >> 8) & 0xff); mscp->datalen.len[2] = ((templen >> 16) & 0xff); mscp->datalen.len[3] = ((templen >> 24) & 0xff); mscp->sg_num = seg; -#ifdef UHADEBUG - if(scsi_debug & SHOWSCATGATH) - printf("\n"); -#endif /*UHADEBUG*/ - if (datalen) - { /* there's still data, must have run out of segs! */ + SC_DEBUGN(xs->sc_link, SDEV_DB4, ("\n")); + if (datalen) { /* there's still data, must have run out of segs! */ printf("uha%d: uha_scsi_cmd, more than %d DMA segs\n", - unit,UHA_NSEG); + unit, UHA_NSEG); xs->error = XS_DRIVER_STUFFUP; - uha_free_mscp(unit,mscp,flags); - return(HAD_ERROR); + uha_free_mscp(unit, mscp, flags); + return (HAD_ERROR); } - - } - else - { /* No data xfer, use non S/G values */ + } else { /* No data xfer, use non S/G values */ mscp->data.addr[0] = 0x00; mscp->data.addr[1] = 0x00; mscp->data.addr[2] = 0x00; @@ -1068,142 +1031,119 @@ cheat = mscp; mscp->datalen.len[3] = 0x00; mscp->xdir = 0x03; mscp->sgth = 0x00; - mscp->sg_num = 0x00; + mscp->sg_num = 0x00; } - /***********************************************\ - * Put the scsi command in the mscp and start it * - \***********************************************/ - bcopy(xs->cmd, mscp->cdb, xs->cmdlen); + /* + * Put the scsi command in the mscp and start it + */ + bcopy(xs->cmd, mscp->cdb, xs->cmdlen); - /***********************************************\ - * Usually return SUCCESSFULLY QUEUED * - \***********************************************/ - if (!(flags & SCSI_NOMASK)) - { + /* + * Usually return SUCCESSFULLY QUEUED + */ + if (!(flags & SCSI_NOMASK)) { s = splbio(); - uha_send_mbox(unit,mscp); - timeout(uha_timeout,mscp,(xs->timeout * hz) / 1000); + uha_send_mbox(unit, mscp); + timeout(uha_timeout, mscp, (xs->timeout * hz) / 1000); splx(s); -#ifdef UHADEBUG - if(scsi_debug & TRACEINTERRUPTS) - printf("cmd_sent "); -#endif /*UHADEBUG*/ - return(SUCCESSFULLY_QUEUED); + SC_DEBUG(xs->sc_link, SDEV_DB3, ("cmd_sent\n")); + return (SUCCESSFULLY_QUEUED); } - /***********************************************\ - * If we can't use interrupts, poll on completion* - \***********************************************/ - uha_send_mbox(unit,mscp); -#ifdef UHADEBUG - if(scsi_debug & TRACEINTERRUPTS) - printf("cmd_wait "); -#endif /*UHADEBUG*/ - do - { - if(uha_poll(unit,xs->timeout)) - { + + /* + * If we can't use interrupts, poll on completion + */ + uha_send_mbox(unit, mscp); + SC_DEBUG(xs->sc_link, SDEV_DB3, ("cmd_wait\n")); + do { + if (uha_poll(unit, xs->timeout)) { if (!(xs->flags & SCSI_SILENT)) - printf("uha%d: cmd fail\n",unit); - if(!(uha_abort(unit,mscp))) - { - printf("uha%d: abort failed in wait\n",unit); - uha_free_mscp(unit,mscp,flags); + printf("uha%d: cmd fail\n", unit); + if (!(uha_abort(unit, mscp))) { + printf("uha%d: abort failed in wait\n", unit); + uha_free_mscp(unit, mscp, flags); } xs->error = XS_DRIVER_STUFFUP; - return(HAD_ERROR); + return (HAD_ERROR); } - } while (!(xs->flags & ITSDONE));/* something (?) else finished */ - if(xs->error) - { - return(HAD_ERROR); } - return(COMPLETE); + while (!(xs->flags & ITSDONE)); /* something (?) else finished */ + if (xs->error) { + return (HAD_ERROR); + } + return (COMPLETE); } - +void uha_timeout(struct mscp *mscp) { int unit; - int s = splbio(); - int port = uha_data[unit].baseport; + struct uha_data *uha; + int s = splbio(); + /*int port = uha->baseport; */ + + unit = mscp->xs->sc_link->adapter_unit; + uha = uhadata[unit]; + printf("uha%d:%d:%d (%s%d) timed out ", unit + ,mscp->xs->sc_link->target + ,mscp->xs->sc_link->lun + ,mscp->xs->sc_link->device->name + ,mscp->xs->sc_link->dev_unit); - unit = mscp->xs->adapter; - printf("uha%d:%d device timed out\n",unit - ,mscp->xs->targ); #ifdef UHADEBUG - if(uha_debug & UHA_SHOWMSCPS) - uha_print_active_mscp(unit); -#endif /*UHADEBUG*/ + uha_print_active_mscp(unit); +#endif /*UHADEBUG */ - if((uha_abort(unit,mscp) !=1) || (mscp->flags = MSCP_ABORTED)) - { + if ((uha_abort(unit, mscp) != 1) || (mscp->flags = MSCP_ABORTED)) { printf("AGAIN"); - mscp->xs->retries = 0; /* I MEAN IT ! */ - uha_done(unit,mscp,FAIL); - } - else /* abort the operation that has timed out */ - { + mscp->xs->retries = 0; /* I MEAN IT ! */ + uha_done(unit, mscp, FAIL); + } else { /* abort the operation that has timed out */ printf("\n"); - timeout(uha_timeout,mscp,2 * hz); + timeout(uha_timeout, mscp, 2 * hz); mscp->flags = MSCP_ABORTED; } splx(s); } -uha_show_scsi_cmd(struct scsi_xfer *xs) -{ - u_char *b = (u_char *)xs->cmd; - int i = 0; - if(!(xs->flags & SCSI_RESET)) - { - printf("uha%d:%d:%d-" - ,xs->adapter - ,xs->targ - ,xs->lu); - while(i < xs->cmdlen ) - { - if(i) printf(","); - printf("%x",b[i++]); - } - printf("-\n"); - } - else - { - printf("uha%d:%d:%d-RESET-\n" - ,xs->adapter - ,xs->targ - ,xs->lu - ); - } -} +#ifdef UHADEBUG +void uha_print_mscp(mscp) -struct mscp *mscp; + struct mscp *mscp; { printf("mscp:%x op:%x cmdlen:%d senlen:%d\n" - ,mscp - ,mscp->opcode - ,mscp->cdblen - ,mscp->senselen); + ,mscp + ,mscp->opcode + ,mscp->cdblen + ,mscp->senselen); printf(" sg:%d sgnum:%x datlen:%d hstat:%x tstat:%x flags:%x\n" - ,mscp->sgth - ,mscp->sg_num - ,mscp->datalen - ,mscp->ha_status - ,mscp->targ_status - ,mscp->flags); - uha_show_scsi_cmd(mscp->xs); + ,mscp->sgth + ,mscp->sg_num + ,mscp->datalen + ,mscp->ha_status + ,mscp->targ_status + ,mscp->flags); + show_scsi_cmd(mscp->xs); } +void uha_print_active_mscp(int unit) { - struct mscp *mscp = uha_data[unit].mscps; - int i = NUHA; + struct uha_data *uha = uhadata[unit]; + struct mscp *mscp; + int i = 0; - while(i--) - { - if(mscp->flags != MSCP_FREE) - uha_print_mscp(mscp); - mscp++; + while (i < MSCP_HASH_SIZE) { + mscp = uha->mscphash[i]; + while (mscp) { + if (mscp->flags != MSCP_FREE) { + uha_print_mscp(mscp); + } + mscp = mscp->nexthash; + } + i++; } } +#endif /*UHADEBUG */ +#endif /*KERNEL */ diff --git a/sys/i386/isa/wd.c b/sys/i386/isa/wd.c index beb4d7d302..95c3db6251 100644 --- a/sys/i386/isa/wd.c +++ b/sys/i386/isa/wd.c @@ -34,7 +34,7 @@ * SUCH DAMAGE. * * from: @(#)wd.c 7.2 (Berkeley) 5/9/91 - * $Id: wd.c,v 1.11 1993/10/16 13:46:31 rgrimes Exp $ + * $Id: wd.c,v 1.12 1993/11/17 23:25:20 wollman Exp $ */ /* TODO:peel out buffer at low ipl, speed improvement */ @@ -1137,7 +1137,7 @@ wdioctl(dev_t dev, int cmd, caddr_t addr, int flag) auio.uio_segflg = 0; auio.uio_offset = fop->df_startblk * du->dk_dd.d_secsize; - error = physio(wdformat, &rwdbuf[unit], dev, B_WRITE, + error = physio(wdformat, &rwdbuf[unit], 0, dev, B_WRITE, minphys, &auio); fop->df_count -= auio.uio_resid; fop->df_reg[0] = du->dk_status; diff --git a/sys/i386/isa/wx.c b/sys/i386/isa/wx.c index 9964aa108a..4d8dbc3a98 100644 --- a/sys/i386/isa/wx.c +++ b/sys/i386/isa/wx.c @@ -36,7 +36,7 @@ static int wdtest = 0; * SUCH DAMAGE. * * from: @(#)wx.c 7.2 (Berkeley) 5/9/91 - * $Id: wx.c,v 1.2 1993/10/26 23:04:38 nate Exp $ + * $Id: wx.c,v 1.3 1993/11/03 18:04:15 nate Exp $ */ /* TODO:peel out buffer at low ipl, speed improvement */ @@ -1123,7 +1123,7 @@ wdioctl(dev_t dev, int cmd, caddr_t addr, int flag) auio.uio_segflg = 0; auio.uio_offset = fop->df_startblk * du->dk_dd.d_secsize; - error = physio(wdformat, &rwdbuf[unit], dev, B_WRITE, + error = physio(wdformat, &rwdbuf[unit], 0, dev, B_WRITE, minphys, &auio); fop->df_count -= auio.uio_resid; fop->df_reg[0] = du->dk_status; diff --git a/sys/kern/kern__physio.c b/sys/kern/kern__physio.c index 0995b1b604..18727647d0 100644 --- a/sys/kern/kern__physio.c +++ b/sys/kern/kern__physio.c @@ -45,7 +45,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id$ + * $Id: kern__physio.c,v 1.2 1993/10/16 15:24:06 rgrimes Exp $ */ #include "param.h" @@ -58,7 +58,7 @@ #include "vm/vm.h" #include "specdev.h" -static physio(int (*)(), int, int, int, caddr_t, int *, struct proc *); +int physio(int (*)(), int, struct buf *, int, int, caddr_t, int *, struct proc *); /* * Driver interface to do "raw" I/O in the address space of a @@ -77,25 +77,29 @@ rawwrite(dev, uio) return (uioapply(physio, cdevsw[major(dev)].d_strategy, dev, uio)); } -static physio(strat, dev, off, rw, base, len, p) +int physio(strat, dev, bp, off, rw, base, len, p) int (*strat)(); dev_t dev; + struct buf *bp; int rw, off; caddr_t base; int *len; struct proc *p; { - register struct buf *bp; int amttodo = *len, error, amtdone; vm_prot_t ftype; static zero; caddr_t adr; + int bp_alloc = (bp == 0); rw = rw == UIO_READ ? B_READ : 0; /* create and build a buffer header for a transfer */ - bp = (struct buf *)malloc(sizeof(*bp), M_TEMP, M_NOWAIT); - bzero((char *)bp, sizeof(*bp)); /* 09 Sep 92*/ + + if (bp_alloc) { + bp = (struct buf *)malloc(sizeof(*bp), M_TEMP, M_NOWAIT); + bzero((char *)bp, sizeof(*bp)); /* 09 Sep 92*/ + } bp->b_flags = B_BUSY | B_PHYS | rw; bp->b_proc = p; bp->b_dev = dev; @@ -112,11 +116,13 @@ static physio(strat, dev, off, rw, base, len, p) /* first, check if accessible */ if (rw == B_READ && !useracc(base, bp->b_bcount, B_WRITE)) { - free(bp, M_TEMP); + if (bp_alloc) + free(bp, M_TEMP); return (EFAULT); } if (rw == B_WRITE && !useracc(base, bp->b_bcount, B_READ)) { - free(bp, M_TEMP); + if (bp_alloc) + free(bp, M_TEMP); return (EFAULT); } @@ -147,7 +153,8 @@ static physio(strat, dev, off, rw, base, len, p) } while (amttodo && (bp->b_flags & B_ERROR) == 0 && amtdone > 0); error = bp->b_error; - free(bp, M_TEMP); + if (bp_alloc) + free(bp, M_TEMP); *len = amttodo; return (error); } diff --git a/sys/kern/kern_subr.c b/sys/kern/kern_subr.c index aa48658f3f..904f8a1f33 100644 --- a/sys/kern/kern_subr.c +++ b/sys/kern/kern_subr.c @@ -31,7 +31,7 @@ * SUCH DAMAGE. * * from: @(#)kern_subr.c 7.7 (Berkeley) 4/15/91 - * $Id$ + * $Id: kern_subr.c,v 1.2 1993/10/16 15:24:30 rgrimes Exp $ */ #include "param.h" @@ -117,7 +117,7 @@ uioapply(func, arg1, arg2, uio) continue; } cnt1 = cnt; - error = (*func)(arg1, arg2, uio->uio_offset, uio->uio_rw, + error = (*func)(arg1, arg2, NULL, uio->uio_offset, uio->uio_rw, iov->iov_base, &cnt1, uio->uio_procp); cnt -= cnt1; iov->iov_base += cnt; diff --git a/sys/scsi/README b/sys/scsi/README index fbd1e6e415..b110930549 100644 --- a/sys/scsi/README +++ b/sys/scsi/README @@ -1,46 +1,55 @@ This release consists of the following files -(relative to the base of the kernel tree) - - -MAKEDEV - -scsi -scsi/README -scsi/scsiconf.h -scsi/scsiconf.c -scsi/scsi_all.h - -scsi/scsi_disk.h -scsi/sd.c - -sys/mtio.h (modified) -scsi/scsi_tape.h -scsi/st.c - -sys/sgio.h -scsi/scsi_generic.h -scsi/sg.c /* port not complete */ - -sys/chio.h -scsi/scsi_changer.h -scsi/ch.c - -sys/cdio.h -scsi/scsi_cd.h -scsi/cd.c - -i386/conf/SCSITEST -i386/isa/aha1542.c - -i386/conf/AHBTEST -i386/isa/aha1742.c - -i386/conf/UHATEST -i386/isa/ultra14f.c - -i386/conf/BTTEST -i386/isa/bt742a.c - +(relative to the base of the source tree ) + +share/man/man4/scsi.4 <-useful general info +share/man/man4/uk.4 +share/man/man4/su.4 +share/man/man4/ch.4 +share/man/man4/cd.4 +share/man/man4/sd.4 +share/man/man4/st.4 <--READ THIS IF YOU USE TAPES! +sbin/scsi/procargs.c +sbin/scsi/scsi.c +sbin/scsi/scsi.1 +sbin/scsi/Makefile +sbin/st/Makefile +sbin/st/st.1 +sbin/st/st.c +sys/sys/chio.h +sys/sys/cdio.h +sys/sys/mtio.h +sys/sys/scsiio.h +sys/i386/conf/EXAMPLE +sys/i386/isa/ultra14f.c <-runs 14f and 34f +sys/i386/isa/ultra_all.c.beta <-beta version, runs 14f,24f and 34f +sys/i386/isa/bt742a.c +sys/i386/isa/aha1742.c +sys/i386/isa/aha1542.c +sys/scsi/syspatches +sys/scsi/syspatches/conf.c +sys/scsi/syspatches/user_scsi.diffs +sys/scsi/syspatches/MAKEDEV.diff +sys/scsi/syspatches/isa.c.patch +sys/scsi/syspatches/README +sys/scsi/uk.c +sys/scsi/su.c +sys/scsi/st.c +sys/scsi/sd.c +sys/scsi/ch.c +sys/scsi/cd.c +sys/scsi/scsi_ioctl.c +sys/scsi/scsi_base.c +sys/scsi/scsiconf.c +sys/scsi/scsi_tape.h +sys/scsi/scsi_disk.h +sys/scsi/scsi_changer.h +sys/scsi/scsi_cd.h +sys/scsi/scsi_all.h +sys/scsi/scsi_debug.h +sys/scsi/scsiconf.h +sys/scsi/README <--this file + +notice sys/scsi/sg.c and sys/sys/sgio.h have been removed ---------------------------------------------------------------- @@ -54,34 +63,22 @@ generic scsi tape cd-rom (plays music under the xcplayer (?) program) AEG Character recognition devices * Calera Character recognition devices * -Kodak IL900 scanner * +Generic scsi-II scanners * Exabyte tape changer device. -GENERIC SCSI DEVICES (user generated scsi commands) (port not complete) +GENERIC SCSI DEVICES (user generated scsi commands) ---------------------------------------------------------------- There are also working bottom end drivers for: ---------------------------------------------------------------- adaptec 1542 (and 1742 in 1542 mode) -bustec 742a (apparently works for VESA version) -adaptec 174x +bustec 742a (apparently works for VESA version (445S?))(and 747?) +adaptec 174x (note NOT 27xx) Ultrastore 14f (works for 34f (VESA version)) +Ultrastore 24f RSN (Beta version included here) ---------------------------------------------------------------- -Work is proceeding on the following bottom end drivers: ----------------------------------------------------------------- -Future Domain (1680)** hosler@tfs.com & me -Future Domain (8 bit)**** rpr@oce.nl -WD7000** terry@icarus.weber.edu -seagate st01/st02**** overby@aspen.cray.com ? ----------------------------------------------------------------- -* drivers not made public (proprietary.. proof that the concept works though) -** driver not yet released but working. -*** just a dream so far. -**** some amount more than just a dream so far. - - ################## Using the scsi system ################## ------------minor numbers--------------- This scsi system does not allocate minor numbers to devices depending @@ -98,19 +95,18 @@ That would not change their minor numbers. THE EXCEPTION TO THIS IS IN THE GENERIC SCSI DRIVER. in which case the following mapping applies: -BB LLL TTT B= scsi bus number, T = target number, L = LUN. -(yes I know it's strange but it's SGI compatible) +BB TTT LLL B= scsi bus number, T = target number, L = LUN. It is possible to run two different TYPES of scsi adapters at the same time and have st0 on one and st1 on another. (for example) There is a scheme supported in which scsi devices can be 'wired in' even if they are not present or powered on at probe time. (see scsiconf.c) +In addition, the scsi(1) command allows the operator ask for a +reprobe at any time. Newly found devices will be configured in. Any +device that does not map to a known device type is attached to the +'unknown' (uk) driver. ---------------getting started------------ -It should be possible to use the /dev entries for as0 as if they were -/dev entries for sd0 and the old as bootblocks should -continue to work if you are using an adaptec 1542b. --------------making devices------------ A changed version of /dev/MAKEDEV is supplied that @@ -120,25 +116,7 @@ e.g. cd /dev sh MAKEDEV sd0 sd1 sd2 st0 st1 cd0 - -The tape devices are as follows: -rst0 basic raw device, will rewind on close -nrst0 will not rewind on close -erst0 will rewind and EJECTon close -nerst0 will not rewind and WILL eject (some devices may rewind anyhow) - -------------future enhancements-------------- -Some people have indicated that they would like to have the SCSI ID -encoded into the minor number in some way, and -this may be supported at some timein the future, using -minor numbers greater than 128. (or maybe a different major number) - - -I will also be writing (probably) a generic scsi-error -handling routine that will be table driven, so that the routine can -be removed from each individual driver. With enough care, -two similar devices with different error codes (quite common) could run -the same driver but use different error tables. +see st(1) and st(4) for info on tape devices. --------------file layout------------------- Originally I had all scsi definitions in one file: scsi.h @@ -159,18 +137,22 @@ scsi-changer.h commands medium changer devices --- CHAPTER 16 User accessable structures (e.g. ioctl definitions) have been placed in sys/cdio, sys/sgio and sys/chio (based after sys/mtio for the ioctls for mag tapes (including st). +General scsi ioctls are found in sys/scsiio.h. -----------cd-rom----------------- The cd rom driver ha been tested by a number of people and -grefen@wilbur.zdv.uni-mainz.de has completed the audio play +grefen@convex.com has completed the audio play functions. (xcdplayer was available from the 'from_ref' directory on agate) At this time it is possible audio play is broken on cdroms and I will be unable to fix it until I get one to test. +***IMPORTANT*** +Cdrom audio is only suported at all for cdroms that use SCSI2 audio +definitions. -------------media changer--------------- -Once again courtesy of grefen@wilbur.zdv.uni-mainz.de. +Once again courtesy of grefen@convex.com (in germany) I have not tested this but he assures me it's ready for testing. If anyone has an exabyte tape changer or similar, contact the author for information regarding the control interface @@ -178,20 +160,6 @@ and program. WARNING: This has not been tested for a LONG TIME! ------------booting from an AHA-174x--------- -For some reason I have not yet worked out, -the BIOS-based bootblocks I have posted will not boot -from the aha1742 in extended mode. (it can't be serious -because the MACH version works) This is in fact not a -problem because the aha1742 driver will force the board into extended -mode during probe, so it can be left in standard mode during the boot. -During the next reboot, the bios will place it back in standard mode -ready for the NEXT boot. - -[Update: This has apparently been fixed in the newest NetBSD/FreeBSD -releases ] - - ---------recent changes----------- Removed all bitfields from machine independent sections to make @@ -206,4 +174,23 @@ have particular problems so they can be handled specially. many bug-fixes and cleanups. -$Id$ +---------even more recent changes:-------- + +rewrote almost the entire thing.. + + + +------Mon Oct 11 22:20:25 WST 1993------ + +Code is now all KNF (or close to it). + +A new structure has been introduced.. +Called scsi_link, one of these exists for every bus/target/lun +that has a driver attached to it. +It has links to the adapter and to the driver, as well as status +information of global interest. (e.g. if the device is in use). +The use of this new structure has allowed the compaction of a +lot of duplicated code into a single copy (now in scsi_base.c) +and makes more simple the USER level scsi implimentation. + + diff --git a/sys/scsi/cd.c b/sys/scsi/cd.c index f5de591ef9..68b09ba716 100644 --- a/sys/scsi/cd.c +++ b/sys/scsi/cd.c @@ -14,7 +14,7 @@ * * Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992 * - * $Id: cd.c,v 1.10 1993/09/21 05:30:35 rgrimes Exp $ + * $Id: cd.c,v 2.3 93/10/11 11:49:49 julian Exp Locker: julian $ */ #define SPLCD splbio @@ -40,898 +40,697 @@ #include /* rw_big and start_stop come from there */ #include -long int cdstrats,cdqueues; - +int32 cdstrats, cdqueues; #include #if NDDB > 0 -int Debugger(); -#else NDDB > 0 +int Debugger(); +#else /* NDDB > 0 */ #define Debugger() -#endif NDDB > 0 - +#endif /* NDDB > 0 */ #define PAGESIZ 4096 -#define SECSIZE 2048 /* XXX */ /* default only */ +#define SECSIZE 2048 /* XXX */ /* default only */ #define CDOUTSTANDING 2 -#define CDQSIZE 4 -#define CD_RETRIES 4 +#define CDRETRIES 1 #define UNITSHIFT 3 #define PARTITION(z) (minor(z) & 0x07) #define RAW_PART 3 #define UNIT(z) ( (minor(z) >> UNITSHIFT) ) +extern int hz; +errval cdstrategy(); -extern int hz; -int cd_done(); -int cdstrategy(); -int cd_debug = 0; - - -struct cd_data +void cdstart(); +struct scsi_device cd_switch = { - int flags; -#define CDVALID 0x02 /* PARAMS LOADED */ -#define CDINIT 0x04 /* device has been init'd */ -#define CDWAIT 0x08 /* device has someone waiting */ -#define CDHAVELABEL 0x10 /* have read the label */ - struct scsi_switch *sc_sw; /* address of scsi low level switch */ - int ctlr; /* so they know which one we want */ - int targ; /* our scsi target ID */ - int lu; /* out scsi lu */ - int cmdscount; /* cmds allowed outstanding by board*/ - struct cd_parms - { - int blksize; - u_long disksize; /* total number sectors */ - }params; - struct disklabel disklabel; - int partflags[MAXPARTITIONS]; /* per partition flags */ + NULL, /* use default error handler */ + cdstart, /* we have a queue, which is started by this */ + NULL, /* we do not have an async handler */ + NULL, /* use default 'done' routine */ + "cd", /* we are to be refered to by this name */ + 0, /* no device specific flags */ + 0, 0 /* spares not used */ +}; + +struct cd_data { + u_int32 flags; +#define CDINIT 0x04 /* device has been init'd */ + struct scsi_link *sc_link; /* address of scsi low level switch */ + u_int32 cmdscount; /* cmds allowed outstanding by board */ + struct cd_parms { + u_int32 blksize; + u_long disksize; /* total number sectors */ + } params; + struct disklabel disklabel; + u_int32 partflags[MAXPARTITIONS]; /* per partition flags */ #define CDOPEN 0x01 - int openparts; /* one bit for each open partition */ - int xfer_block_wait; - struct scsi_xfer *free_xfer; - struct scsi_xfer scsi_xfer[CDOUTSTANDING]; /* XXX */ - struct buf buf_queue; + u_int32 openparts; /* one bit for each open partition */ + u_int32 xfer_block_wait; + struct buf buf_queue; }; #define CD_STOP 0 #define CD_START 1 #define CD_EJECT -2 -struct cd_driver -{ - int size; - struct cd_data **cd_data; -}*cd_driver; - -static int next_cd_unit = 0; -/***********************************************************************\ -* The routine called by the low level scsi routine when it discovers * -* A device suitable for this driver * -\***********************************************************************/ -int cdattach(ctlr,targ,lu,scsi_switch) -struct scsi_switch *scsi_switch; +struct cd_driver { + u_int32 size; + struct cd_data **cd_data; +} cd_driver; + +static u_int32 next_cd_unit = 0; + +/* + * The routine called by the low level scsi routine when it discovers + * A device suitable for this driver + */ +int +cdattach(sc_link) + struct scsi_link *sc_link; { - int unit,i; - unsigned char *tbl; - struct cd_data *cd, **cdrealloc; - struct cd_parms *dp; - -#ifdef CDDEBUG - if(scsi_debug & PRINTROUTINES) printf("cdattach: "); -#endif /*CDDEBUG*/ - /*******************************************************\ - * Check if we have resources allocated yet, if not * - * allocate and initialize them * - \*******************************************************/ - if (next_cd_unit == 0) - { - cd_driver = - malloc(sizeof(struct cd_driver),M_DEVBUF,M_NOWAIT); - if(!cd_driver) - { - printf("cd%d: malloc failed for cd_driver\n",unit); - return(0); - } - bzero(cd_driver,sizeof(cd_driver)); - cd_driver->size = 0; - } - /*******************************************************\ - * allocate the resources for another drive * - * if we have already allocate a cd_data pointer we must * - * copy the old pointers into a new region that is * - * larger and release the old region, aka realloc * - \*******************************************************/ + u_int32 unit, i; + unsigned char *tbl; + struct cd_data *cd, **cdrealloc; + struct cd_parms *dp; + + SC_DEBUG(sc_link, SDEV_DB2, ("cdattach ")); + + /* + * Fill out any more info in the + * Link structure that we can + */ unit = next_cd_unit++; + sc_link->device = &cd_switch; + sc_link->dev_unit = unit; + /* + * allocate the resources for another drive + * if we have already allocate a cd_data pointer we must + * copy the old pointers into a new region that is + * larger and release the old region, aka realloc + */ /* XXX * This if will always be true for now, but future code may * preallocate more units to reduce overhead. This would be * done by changing the malloc to be (next_cd_unit * x) and - * the cd_driver->size++ to be +x + * the cd_driver.size++ to be +x */ - if(unit >= cd_driver->size) - { + if (unit >= cd_driver.size) { cdrealloc = - malloc(sizeof(cd_driver->cd_data) * next_cd_unit, - M_DEVBUF,M_NOWAIT); - if(!cdrealloc) - { - printf("cd%d: malloc failed for cdrealloc\n",unit); - return(0); + malloc(sizeof(cd_driver.cd_data) * next_cd_unit, + M_DEVBUF, M_NOWAIT); + if (!cdrealloc) { + printf("cd%d: malloc failed for cdrealloc\n", unit); + return (0); } /* Make sure we have something to copy before we copy it */ - bzero(cdrealloc,sizeof(cd_driver->cd_data) * next_cd_unit); - if(cd_driver->size) - { - bcopy(cd_driver->cd_data,cdrealloc, - sizeof(cd_driver->cd_data) * cd_driver->size); - free(cd_driver->cd_data,M_DEVBUF); + bzero(cdrealloc, sizeof(cd_driver.cd_data) * next_cd_unit); + if (cd_driver.size) { + bcopy(cd_driver.cd_data, cdrealloc, + sizeof(cd_driver.cd_data) * cd_driver.size); + free(cd_driver.cd_data, M_DEVBUF); } - cd_driver->cd_data = cdrealloc; - cd_driver->cd_data[unit] = NULL; - cd_driver->size++; - } - if(cd_driver->cd_data[unit]) - { - printf("cd%d: Already has storage!\n",unit); - return(0); + cd_driver.cd_data = cdrealloc; + cd_driver.cd_data[unit] = NULL; + cd_driver.size++; } - /*******************************************************\ - * allocate the per drive data area * - \*******************************************************/ - cd = cd_driver->cd_data[unit] = - malloc(sizeof(struct cd_data),M_DEVBUF,M_NOWAIT); - if(!cd) - { - printf("cd%d: malloc failed for cd_data\n",unit); - return(0); + if (cd_driver.cd_data[unit]) { + printf("cd%d: Already has storage!\n", unit); + return (0); } - bzero(cd,sizeof(struct cd_data)); - dp = &(cd->params); - /*******************************************************\ - * Store information needed to contact our base driver * - \*******************************************************/ - cd->sc_sw = scsi_switch; - cd->ctlr = ctlr; - cd->targ = targ; - cd->lu = lu; - cd->cmdscount = CDOUTSTANDING; /* XXX (ask the board) */ - - i = cd->cmdscount; - while(i-- ) - { - cd->scsi_xfer[i].next = cd->free_xfer; - cd->free_xfer = &cd->scsi_xfer[i]; + /* + * allocate the per drive data area + */ + cd = cd_driver.cd_data[unit] = + malloc(sizeof(struct cd_data), M_DEVBUF, M_NOWAIT); + if (!cd) { + printf("cd%d: malloc failed for cd_data\n", unit); + return (0); } - /*******************************************************\ - * Use the subdriver to request information regarding * - * the drive. We cannot use interrupts yet, so the * - * request must specify this. * - \*******************************************************/ - cd_get_parms(unit, SCSI_NOSLEEP | SCSI_NOMASK); - if(dp->disksize) - { + bzero(cd, sizeof(struct cd_data)); + dp = &(cd->params); + /* + * Store information needed to contact our base driver + */ + cd->sc_link = sc_link; + /* only allow 1 outstanding command on tapes */ + sc_link->opennings = cd->cmdscount = CDOUTSTANDING; + + /* + * Use the subdriver to request information regarding + * the drive. We cannot use interrupts yet, so the + * request must specify this. + */ + cd_get_parms(unit, SCSI_NOSLEEP | SCSI_NOMASK); + if (dp->disksize) { printf("cd%d: cd present.[%d x %d byte records]\n", - unit, - cd->params.disksize, - cd->params.blksize); - } - else - { + unit, + cd->params.disksize, + cd->params.blksize); + } else { printf("cd%d: drive empty\n", unit); } cd->flags |= CDINIT; - return; + return (1); } -/*******************************************************\ -* open the device. Make sure the partition info * -* is a up-to-date as can be. * -\*******************************************************/ +/* + * open the device. Make sure the partition info is a up-to-date as can be. + */ +errval cdopen(dev) { - int errcode = 0; - int unit, part; + errval errcode = 0; + u_int32 unit, part; struct cd_parms cd_parms; struct cd_data *cd; + struct scsi_link *sc_link; + u_int32 heldflags; unit = UNIT(dev); part = PARTITION(dev); -#ifdef CDDEBUG - if(scsi_debug & (PRINTROUTINES | TRACEOPENS)) - printf("cdopen: dev=0x%x (unit %d (of %d),partition %d)\n" - ,dev,unit,cd_driver->size,part); -#endif /*CDDEBUG*/ - /*******************************************************\ - * Check the unit is legal * - \*******************************************************/ - if ( unit >= cd_driver->size ) - { - return(ENXIO); + /* + * Check the unit is legal + */ + if (unit >= cd_driver.size) { + return (ENXIO); } - cd = cd_driver->cd_data[unit]; - /*******************************************************\ - * Make sure the device has been initialised * - \*******************************************************/ + cd = cd_driver.cd_data[unit]; + /* + * Make sure the device has been initialised + */ if ((cd == NULL) || (!(cd->flags & CDINIT))) - return(ENXIO); - - /*******************************************************\ - * If it's been invalidated, and not everybody has * - * closed it then forbid re-entry. * - * (may have changed media) * - \*******************************************************/ - if ((! (cd->flags & CDVALID)) - && ( cd->openparts)) - return(ENXIO); - - /*******************************************************\ - * Check that it is still responding and ok. * - * if the media has been changed this will result in a * - * "unit attention" error which the error code will * - * disregard because the CDVALID flag is not yet set * - \*******************************************************/ - cd_test_ready(unit, SCSI_SILENT); - - /*******************************************************\ - * Next time actually take notice of error returns * - \*******************************************************/ - if (cd_test_ready(unit, SCSI_SILENT) != 0) { -#ifdef CDDEBUG - if(scsi_debug & TRACEOPENS) - printf("not ready\n"); -#endif /*CDDEBUG*/ - return(ENXIO); + return (ENXIO); + + sc_link = cd->sc_link; + SC_DEBUG(sc_link, SDEV_DB1, + ("cdopen: dev=0x%x (unit %d (of %d),partition %d)\n", + dev, unit, cd_driver.size, part)); + /* + * If it's been invalidated, and not everybody has closed it then + * forbid re-entry. (may have changed media) + */ + if ((!(sc_link->flags & SDEV_MEDIA_LOADED)) + && (cd->openparts)) + return (ENXIO); + + /* + * Check that it is still responding and ok. + * if the media has been changed this will result in a + * "unit attention" error which the error code will + * disregard because the SDEV_MEDIA_LOADED flag is not yet set + */ + scsi_test_unit_ready(sc_link, SCSI_SILENT); + + /* + * Next time actually take notice of error returns + */ + sc_link->flags |= SDEV_OPEN; /* unit attn errors are now errors */ + if (scsi_test_unit_ready(sc_link, SCSI_SILENT) != 0) { + SC_DEBUG(sc_link, SDEV_DB3, ("not ready\n")); + errcode = ENXIO; + goto bad; + } + SC_DEBUG(sc_link, SDEV_DB3, ("Device present\n")); + /* + * In case it is a funny one, tell it to start + * not needed for some drives + */ + scsi_start_unit(sc_link, CD_START); + scsi_prevent(sc_link, PR_PREVENT, SCSI_SILENT); + SC_DEBUG(sc_link, SDEV_DB3, ("started ")); + /* + * Load the physical device parameters + */ + if (cd_get_parms(unit, 0)) { + errcode = ENXIO; + goto bad; } -#ifdef CDDEBUG - if(scsi_debug & TRACEOPENS) - printf("Device present\n"); -#endif /*CDDEBUG*/ - /*******************************************************\ - * In case it is a funny one, tell it to start * - * not needed for some drives * - \*******************************************************/ - cd_start_unit(unit,part,CD_START); - cd_prevent_unit(unit,PR_PREVENT,SCSI_SILENT); -#ifdef CDDEBUG - if(scsi_debug & TRACEOPENS) - printf("started "); -#endif /*CDDEBUG*/ - /*******************************************************\ - * Load the physical device parameters * - \*******************************************************/ - cd_get_parms(unit, 0); -#ifdef CDDEBUG - if(scsi_debug & TRACEOPENS) - printf("Params loaded "); -#endif /*CDDEBUG*/ - /*******************************************************\ - * Load the partition info if not already loaded * - \*******************************************************/ + SC_DEBUG(sc_link, SDEV_DB3, ("Params loaded ")); + /* + * Make up some partition information + */ cdgetdisklabel(unit); -#ifdef CDDEBUG - if(scsi_debug & TRACEOPENS) - printf("Disklabel fabricated "); -#endif /*CDDEBUG*/ - /*******************************************************\ - * Check the partition is legal * - \*******************************************************/ - if (( part >= cd->disklabel.d_npartitions ) - && (part != RAW_PART)) - { -#ifdef CDDEBUG - if(scsi_debug & TRACEOPENS) - printf("partition %d > %d\n",part - ,cd->disklabel.d_npartitions); -#endif /*CDDEBUG*/ - cd_prevent_unit(unit,PR_ALLOW,SCSI_SILENT); - return(ENXIO); + SC_DEBUG(sc_link, SDEV_DB3, ("Disklabel fabricated ")); + /* + * Check the partition is legal + */ + if ((part >= cd->disklabel.d_npartitions) + && (part != RAW_PART)) { + SC_DEBUG(sc_link, SDEV_DB3, ("partition %d > %d\n", part + ,cd->disklabel.d_npartitions)); + errcode = ENXIO; + goto bad; } - /*******************************************************\ - * Check that the partition exists * - \*******************************************************/ - if (( cd->disklabel.d_partitions[part].p_fstype != FS_UNUSED ) - || (part == RAW_PART)) - { - cd->partflags[part] |= CDOPEN; - cd->openparts |= (1 << part); -#ifdef CDDEBUG - if(scsi_debug & TRACEOPENS) - printf("open complete\n"); -#endif /*CDDEBUG*/ - cd->flags |= CDVALID; + /* + * Check that the partition exists + */ + if ((cd->disklabel.d_partitions[part].p_fstype == FS_UNUSED) + && (part != RAW_PART)) { + SC_DEBUG(sc_link, SDEV_DB3, ("part %d type UNUSED\n", part)); + errcode = ENXIO; + goto bad; } - else - { -#ifdef CDDEBUG - if(scsi_debug & TRACEOPENS) - printf("part %d type UNUSED\n",part); -#endif /*CDDEBUG*/ - cd_prevent_unit(unit,PR_ALLOW,SCSI_SILENT); - return(ENXIO); + cd->partflags[part] |= CDOPEN; + cd->openparts |= (1 << part); + SC_DEBUG(sc_link, SDEV_DB3, ("open complete\n")); + sc_link->flags |= SDEV_MEDIA_LOADED; + return (0); + bad: + + /* + * if we would have been the only open + * then leave things back as they were + */ + if (!(cd->openparts)) { + sc_link->flags &= ~SDEV_OPEN; + scsi_prevent(sc_link, PR_ALLOW, SCSI_SILENT); } - return(0); + return (errcode); } -/*******************************************************\ -* Get ownership of a scsi_xfer structure * -* If need be, sleep on it, until it comes free * -\*******************************************************/ -struct scsi_xfer *cd_get_xs(unit,flags) -int flags; -int unit; +/* + * close the device.. only called if we are the LAST + * occurence of an open device + */ +errval +cdclose(dev) + dev_t dev; { - struct scsi_xfer *xs; + u_int8 unit, part; + u_int32 old_priority; struct cd_data *cd; - int s; - - cd = cd_driver->cd_data[unit]; - if(flags & (SCSI_NOSLEEP | SCSI_NOMASK)) - { - if (xs = cd->free_xfer) - { - cd->free_xfer = xs->next; - xs->flags = 0; - } - } - else - { - s = SPLCD(); - while (!(xs = cd->free_xfer)) - { - cd->xfer_block_wait++; /* someone waiting! */ - sleep((caddr_t)&cd->free_xfer, PRIBIO+1); - cd->xfer_block_wait--; - } - cd->free_xfer = xs->next; - splx(s); - xs->flags = 0; - } - return(xs); -} + struct scsi_link *sc_link; -/*******************************************************\ -* Free a scsi_xfer, wake processes waiting for it * -\*******************************************************/ -cd_free_xs(unit,xs,flags) -struct scsi_xfer *xs; -int unit; -int flags; -{ - struct cd_data *cd; - int s; - - cd = cd_driver->cd_data[unit]; - if(flags & SCSI_NOMASK) - { - if (cd->xfer_block_wait) - { - printf("cd%d: doing a wakeup from NOMASK mode\n", unit); - wakeup((caddr_t)&cd->free_xfer); - } - xs->next = cd->free_xfer; - cd->free_xfer = xs; - } - else - { - s = SPLCD(); - if (cd->xfer_block_wait) - wakeup((caddr_t)&cd->free_xfer); - xs->next = cd->free_xfer; - cd->free_xfer = xs; - splx(s); + unit = UNIT(dev); + part = PARTITION(dev); + cd = cd_driver.cd_data[unit]; + sc_link = cd->sc_link; + SC_DEBUG(sc_link, SDEV_DB2, ("cd%d: closing part %d\n", unit, part)); + cd->partflags[part] &= ~CDOPEN; + cd->openparts &= ~(1 << part); + + /* + * If we were the last open of the entire device, release it. + */ + if (!(cd->openparts)) { + scsi_prevent(sc_link, PR_ALLOW, SCSI_SILENT); + cd->sc_link->flags &= ~SDEV_OPEN; } + return (0); } -/*******************************************************\ -* trim the size of the transfer if needed, * -* called by physio * -* basically the smaller of our max and the scsi driver's* -* minphys (note we have no max ourselves) * -\*******************************************************/ -/* Trim buffer length if buffer-size is bigger than page size */ -void cdminphys(bp) -struct buf *bp; +/* + * trim the size of the transfer if needed, + * called by physio + * basically the smaller of our max and the scsi driver's + * minphys (note we have no max ourselves) + * + * Trim buffer length if buffer-size is bigger than page size + */ +void +cdminphys(bp) + struct buf *bp; { - (*(cd_driver->cd_data[UNIT(bp->b_dev)]->sc_sw->scsi_minphys))(bp); + (*(cd_driver.cd_data[UNIT(bp->b_dev)]->sc_link->adapter->scsi_minphys)) (bp); } -/*******************************************************\ -* Actually translate the requested transfer into * -* one the physical driver can understand * -* The transfer is described by a buf and will include * -* only one physical transfer. * -\*******************************************************/ - -int cdstrategy(bp) -struct buf *bp; +/* + * Actually translate the requested transfer into one the physical driver can + * understand. The transfer is described by a buf and will include only one + * physical transfer. + */ +errval +cdstrategy(bp) + struct buf *bp; { - struct buf *dp; - unsigned int opri; - struct cd_data *cd; - int unit; + struct buf *dp; + u_int32 opri; + u_int32 unit = UNIT((bp->b_dev)); + struct cd_data *cd = cd_driver.cd_data[unit]; cdstrats++; - unit = UNIT((bp->b_dev)); - cd = cd_driver->cd_data[unit]; -#ifdef CDDEBUG - if(scsi_debug & PRINTROUTINES) printf("\ncdstrategy "); - if(scsi_debug & SHOWREQUESTS) printf("cd%d: %d bytes @ blk%d\n", - unit,bp->b_bcount,bp->b_blkno); -#endif /*CDDEBUG*/ + SC_DEBUG(cd->sc_link, SDEV_DB2, ("\ncdstrategy ")); + SC_DEBUG(cd->sc_link, SDEV_DB1, ("cd%d: %d bytes @ blk%d\n", + unit, bp->b_bcount, bp->b_blkno)); cdminphys(bp); - /*******************************************************\ - * If the device has been made invalid, error out * - * maybe the media changed * - \*******************************************************/ - if(!(cd->flags & CDVALID)) - { + /* + * If the device has been made invalid, error out + * maybe the media changed + */ + if (!(cd->sc_link->flags & SDEV_MEDIA_LOADED)) { bp->b_error = EIO; goto bad; } - /*******************************************************\ - * can't ever write to a CD * - \*******************************************************/ + /* + * can't ever write to a CD + */ if ((bp->b_flags & B_READ) == 0) { bp->b_error = EROFS; goto bad; } - /*******************************************************\ - * If it's a null transfer, return immediatly * - \*******************************************************/ + /* + * If it's a null transfer, return immediatly + */ if (bp->b_bcount == 0) { goto done; } - - /*******************************************************\ - * Decide which unit and partition we are talking about * - \*******************************************************/ - if(PARTITION(bp->b_dev) != RAW_PART) - { - if (!(cd->flags & CDHAVELABEL)) - { - bp->b_error = EIO; - goto bad; - } + /* + * Decide which unit and partition we are talking about + */ + if (PARTITION(bp->b_dev) != RAW_PART) { /* * do bounds checking, adjust transfer. if error, process. * if end of partition, just return */ - if (bounds_check_with_label(bp,&cd->disklabel,1) <= 0) + if (bounds_check_with_label(bp, &cd->disklabel, 1) <= 0) goto done; /* otherwise, process transfer request */ } - opri = SPLCD(); dp = &cd->buf_queue; - /*******************************************************\ - * Place it in the queue of disk activities for this disk* - \*******************************************************/ + /* + * Place it in the queue of disk activities for this disk + */ disksort(dp, bp); - /*******************************************************\ - * Tell the device to get going on the transfer if it's * - * not doing anything, otherwise just wait for completion* - \*******************************************************/ + /* + * Tell the device to get going on the transfer if it's + * not doing anything, otherwise just wait for completion + */ cdstart(unit); splx(opri); return; -bad: + bad: bp->b_flags |= B_ERROR; -done: + done: - /*******************************************************\ - * Correctly set the buf to indicate a completed xfer * - \*******************************************************/ - bp->b_resid = bp->b_bcount; + /* + * Correctly set the buf to indicate a completed xfer + */ + bp->b_resid = bp->b_bcount; biodone(bp); - return; + return (0); } -/***************************************************************\ -* cdstart looks to see if there is a buf waiting for the device * -* and that the device is not already busy. If both are true, * -* It deques the buf and creates a scsi command to perform the * -* transfer in the buf. The transfer request will call cd_done * -* on completion, which will in turn call this routine again * -* so that the next queued transfer is performed. * -* The bufs are queued by the strategy routine (cdstrategy) * -* * -* This routine is also called after other non-queued requests * -* have been made of the scsi driver, to ensure that the queue * -* continues to be drained. * -* * -* must be called at the correct (highish) spl level * -\***************************************************************/ -/* cdstart() is called at SPLCD from cdstrategy and cd_done*/ +/* + * cdstart looks to see if there is a buf waiting for the device + * and that the device is not already busy. If both are true, + * It deques the buf and creates a scsi command to perform the + * transfer in the buf. The transfer request will call scsi_done + * on completion, which will in turn call this routine again + * so that the next queued transfer is performed. + * The bufs are queued by the strategy routine (cdstrategy) + * + * This routine is also called after other non-queued requests + * have been made of the scsi driver, to ensure that the queue + * continues to be drained. + * + * must be called at the correct (highish) spl level + * cdstart() is called at SPLCD from cdstrategy and scsi_done + */ +void cdstart(unit) -int unit; + u_int32 unit; { - register struct buf *bp = 0; - register struct buf *dp; - struct scsi_xfer *xs; - struct scsi_rw_big cmd; - int blkno, nblk; - struct cd_data *cd; - struct partition *p ; - -#ifdef CDDEBUG - if(scsi_debug & PRINTROUTINES) printf("cdstart%d ",unit); -#endif /*CDDEBUG*/ - cd = cd_driver->cd_data[unit]; - /*******************************************************\ - * See if there is a buf to do and we are not already * - * doing one * - \*******************************************************/ - if(!cd->free_xfer) - { - return; /* none for us, unit already underway */ + register struct buf *bp = 0; + register struct buf *dp; + struct scsi_rw_big cmd; + u_int32 blkno, nblk; + struct partition *p; + struct cd_data *cd = cd_driver.cd_data[unit]; + struct scsi_link *sc_link = cd->sc_link; + + SC_DEBUG(sc_link, SDEV_DB2, ("cdstart%d ", unit)); + /* + * See if there is a buf to do and we are not already + * doing one + */ + if (!sc_link->opennings) { + return; /* no room for us, unit already underway */ } - - if(cd->xfer_block_wait) /* there is one, but a special waits */ - { - return; /* give the special that's waiting a chance to run */ + if (sc_link->flags & SDEV_WAITING) { /* is room, but a special waits */ + return; /* give the special that's waiting a chance to run */ } - - dp = &cd->buf_queue; - if ((bp = dp->b_actf) != NULL) /* yes, an assign */ - { + if ((bp = dp->b_actf) != NULL) { /* yes, an assign */ dp->b_actf = bp->av_forw; - } - else - { + } else { return; } - - xs=cd_get_xs(unit,0); /* ok we can grab it */ - xs->flags = INUSE; /* Now ours */ - /***************************************************************\ - * Should reject all queued entries if CDVALID is not true * - \***************************************************************/ - if(!(cd->flags & CDVALID)) - { - goto bad; /* no I/O.. media changed or something */ + /* + * Should reject all queued entries if SDEV_MEDIA_LOADED is not true. + */ + if (!(sc_link->flags & SDEV_MEDIA_LOADED)) { + goto bad; /* no I/O.. media changed or something */ } - - /*******************************************************\ - * We have a buf, now we should move the data into * - * a scsi_xfer definition and try start it * - * * - * First, translate the block to absolute * - * and put it in terms of the logical blocksize of the * - * device.. * - * really a bit silly until we have real partitions, but.* - \*******************************************************/ - blkno = bp->b_blkno / (cd->params.blksize/512); - if(PARTITION(bp->b_dev) != RAW_PART) - { + /* + * We have a buf, now we should make a command + * + * First, translate the block to absolute and put it in terms of the + * logical blocksize of the device. Really a bit silly until we have + * real partitions, but. + */ + blkno = bp->b_blkno / (cd->params.blksize / 512); + if (PARTITION(bp->b_dev) != RAW_PART) { p = cd->disklabel.d_partitions + PARTITION(bp->b_dev); blkno += p->p_offset; } nblk = (bp->b_bcount + (cd->params.blksize - 1)) / (cd->params.blksize); - /* what if something asks for 512 bytes not on a 2k boundary? *//*XXX*/ + /* what if something asks for 512 bytes not on a 2k boundary? *//*XXX */ - /*******************************************************\ - * Fill out the scsi command * - \*******************************************************/ + /* + * Fill out the scsi command + */ bzero(&cmd, sizeof(cmd)); - cmd.op_code = READ_BIG; - cmd.addr_3 = (blkno & 0xff000000) >> 24; - cmd.addr_2 = (blkno & 0xff0000) >> 16; - cmd.addr_1 = (blkno & 0xff00) >> 8; - cmd.addr_0 = blkno & 0xff; - cmd.length2 = (nblk & 0xff00) >> 8; - cmd.length1 = (nblk & 0xff); - /*******************************************************\ - * Fill out the scsi_xfer structure * - * Note: we cannot sleep as we may be an interrupt * - \*******************************************************/ - xs->flags |= SCSI_NOSLEEP; - xs->adapter = cd->ctlr; - xs->targ = cd->targ; - xs->lu = cd->lu; - xs->retries = CD_RETRIES; - xs->timeout = 10000;/* 10000 millisecs for a disk !*/ - xs->cmd = (struct scsi_generic *)&cmd; - xs->cmdlen = sizeof(cmd); - xs->resid = bp->b_bcount; - xs->when_done = cd_done; - xs->done_arg = unit; - xs->done_arg2 = (int)xs; - xs->error = XS_NOERROR; - xs->bp = bp; - xs->data = (u_char *)bp->b_un.b_addr; - xs->datalen = bp->b_bcount; - - /*******************************************************\ - * Pass all this info to the scsi driver. * - \*******************************************************/ - if ( (*(cd->sc_sw->scsi_cmd))(xs) != SUCCESSFULLY_QUEUED) - { - printf("cd%d: oops not queued",unit); - goto bad; - } - cdqueues++; - return; -bad: xs->error = XS_DRIVER_STUFFUP; - cd_done(unit,xs); -} - -/*******************************************************\ -* This routine is called by the scsi interrupt when * -* the transfer is complete. (or failed) * -\*******************************************************/ -int cd_done(unit,xs) -int unit; -struct scsi_xfer *xs; -{ - struct buf *bp; - int retval; - struct cd_data *cd = cd_driver->cd_data[unit]; - -#ifdef CDDEBUG - if(scsi_debug & PRINTROUTINES) printf("cd_done%d ",unit); -#endif /*CDDEBUG*/ -#ifdef PARANOIA - if (! (xs->flags & INUSE)) /* paranoia always pays off */ - panic("scsi_xfer not in use!"); -#endif /*PARANOIA*/ - if(!(bp = xs->bp)) - { - wakeup(xs); - return 0; - } - switch(xs->error) - { - case XS_NOERROR: - bp->b_error = 0; - bp->b_resid = 0; - break; - - case XS_SENSE: - retval = (cd_interpret_sense(unit,xs)); - if(retval) - { - bp->b_flags |= B_ERROR; - bp->b_error = retval; - } - break; - - case XS_TIMEOUT: - printf("cd%d timeout\n",unit); - - case XS_BUSY: - /***********************************\ - * Just resubmit it straight back to * - * the SCSI driver to try it again * - \***********************************/ - if(xs->retries--) - { - xs->error = XS_NOERROR; - xs->flags &= ~ITSDONE; - if ((*(cd->sc_sw->scsi_cmd))(xs) - == SUCCESSFULLY_QUEUED) - { /* shhh! don't wake the job, ok? */ - /* don't tell cdstart either, */ - return 0; - } - /* xs->error is set by the scsi driver */ - } /* Fall through */ - - case XS_DRIVER_STUFFUP: - bp->b_flags |= B_ERROR; + cmd.op_code = READ_BIG; + cmd.addr_3 = (blkno & 0xff000000) >> 24; + cmd.addr_2 = (blkno & 0xff0000) >> 16; + cmd.addr_1 = (blkno & 0xff00) >> 8; + cmd.addr_0 = blkno & 0xff; + cmd.length2 = (nblk & 0xff00) >> 8; + cmd.length1 = (nblk & 0xff); + + /* + * Call the routine that chats with the adapter. + * Note: we cannot sleep as we may be an interrupt + */ + if (scsi_scsi_cmd(sc_link, + (struct scsi_generic *) &cmd, + sizeof(cmd), + (u_char *) bp->b_un.b_addr, + bp->b_bcount, + CDRETRIES, + 30000, + bp, + SCSI_NOSLEEP | ((bp->b_flags & B_READ) ? + SCSI_DATA_IN : SCSI_DATA_OUT)) + != SUCCESSFULLY_QUEUED) { + bad: + printf("cd%d: oops not queued", unit); bp->b_error = EIO; - break; - default: - printf("cd%d: unknown error category from scsi driver\n" - ,unit); - } - biodone(bp); - cd_free_xs(unit,xs,0); - cdstart(unit); /* If there's anything waiting.. do it */ - return 0; + bp->b_flags |= B_ERROR; + biodone(bp); + return; + } + cdqueues++; } -/*******************************************************\ -* Perform special action on behalf of the user * -* Knows about the internals of this device * -\*******************************************************/ +/* + * Perform special action on behalf of the user. + * Knows about the internals of this device + */ +errval cdioctl(dev_t dev, int cmd, caddr_t addr, int flag) { - int error = 0; - unsigned int opri; - unsigned char unit, part; + errval error = 0; + u_int32 opri; + u_int8 unit, part; register struct cd_data *cd; - - /*******************************************************\ - * Find the device that the user is talking about * - \*******************************************************/ + /* + * Find the device that the user is talking about + */ unit = UNIT(dev); part = PARTITION(dev); - cd = cd_driver->cd_data[unit]; -#ifdef CDDEBUG - if(scsi_debug & PRINTROUTINES) printf("cdioctl%d ",unit); -#endif /*CDDEBUG*/ - - /*******************************************************\ - * If the device is not valid.. abandon ship * - \*******************************************************/ - if (!(cd_driver->cd_data[unit]->flags & CDVALID)) - return(EIO); - switch(cmd) - { + cd = cd_driver.cd_data[unit]; + SC_DEBUG(cd->sc_link, SDEV_DB2, ("cdioctl 0x%x ", cmd)); + + /* + * If the device is not valid.. abandon ship + */ + if (!(cd->sc_link->flags & SDEV_MEDIA_LOADED)) + return (EIO); + switch (cmd) { case DIOCSBAD: - error = EINVAL; + error = EINVAL; break; case DIOCGDINFO: - *(struct disklabel *)addr = cd->disklabel; + *(struct disklabel *) addr = cd->disklabel; break; - case DIOCGPART: - ((struct partinfo *)addr)->disklab = &cd->disklabel; - ((struct partinfo *)addr)->part = - &cd->disklabel.d_partitions[PARTITION(dev)]; - break; - - case DIOCWDINFO: - case DIOCSDINFO: - if ((flag & FWRITE) == 0) - error = EBADF; - else - error = setdisklabel(&cd->disklabel, - (struct disklabel *)addr, - /*(cd->flags & DKFL_BSDLABEL) ? cd->openparts : */0, - 0); - if (error == 0) { - cd->flags |= CDHAVELABEL; - } - break; + case DIOCGPART: + ((struct partinfo *) addr)->disklab = &cd->disklabel; + ((struct partinfo *) addr)->part = + &cd->disklabel.d_partitions[PARTITION(dev)]; + break; + + /* + * a bit silly, but someone might want to test something on a + * section of cdrom. + */ + case DIOCWDINFO: + case DIOCSDINFO: + if ((flag & FWRITE) == 0) + error = EBADF; + else + error = setdisklabel(&cd->disklabel, + (struct disklabel *) addr, + 0, + 0); + if (error == 0) + break; - case DIOCWLABEL: - error = EBADF; - break; + case DIOCWLABEL: + error = EBADF; + break; case CDIOCPLAYTRACKS: { - struct ioc_play_track *args - = (struct ioc_play_track *)addr; - struct cd_mode_data data; - if(error = cd_get_mode(unit,&data,AUDIO_PAGE)) + struct ioc_play_track *args + = (struct ioc_play_track *) addr; + struct cd_mode_data data; + if (error = cd_get_mode(unit, &data, AUDIO_PAGE)) break; data.page.audio.flags &= ~CD_PA_SOTC; data.page.audio.flags |= CD_PA_IMMED; - if(error = cd_set_mode(unit,&data)) + if (error = cd_set_mode(unit, &data)) break; - return(cd_play_tracks(unit - ,args->start_track - ,args->start_index - ,args->end_track - ,args->end_index - )); + return (cd_play_tracks(unit + ,args->start_track + ,args->start_index + ,args->end_track + ,args->end_index + )); } break; case CDIOCPLAYMSF: { - struct ioc_play_msf *args - = (struct ioc_play_msf *)addr; - struct cd_mode_data data; - if(error = cd_get_mode(unit,&data,AUDIO_PAGE)) + struct ioc_play_msf *args + = (struct ioc_play_msf *) addr; + struct cd_mode_data data; + if (error = cd_get_mode(unit, &data, AUDIO_PAGE)) break; data.page.audio.flags &= ~CD_PA_SOTC; data.page.audio.flags |= CD_PA_IMMED; - if(error = cd_set_mode(unit,&data)) + if (error = cd_set_mode(unit, &data)) break; - return(cd_play_msf(unit - ,args->start_m - ,args->start_s - ,args->start_f - ,args->end_m - ,args->end_s - ,args->end_f - )); + return (cd_play_msf(unit + ,args->start_m + ,args->start_s + ,args->start_f + ,args->end_m + ,args->end_s + ,args->end_f + )); } break; case CDIOCPLAYBLOCKS: { - struct ioc_play_blocks *args - = (struct ioc_play_blocks *)addr; - struct cd_mode_data data; - if(error = cd_get_mode(unit,&data,AUDIO_PAGE)) + struct ioc_play_blocks *args + = (struct ioc_play_blocks *) addr; + struct cd_mode_data data; + if (error = cd_get_mode(unit, &data, AUDIO_PAGE)) break; data.page.audio.flags &= ~CD_PA_SOTC; data.page.audio.flags |= CD_PA_IMMED; - if(error = cd_set_mode(unit,&data)) + if (error = cd_set_mode(unit, &data)) break; - return(cd_play(unit,args->blk,args->len)); - + return (cd_play(unit, args->blk, args->len)); } break; case CDIOCREADSUBCHANNEL: { struct ioc_read_subchannel *args - = (struct ioc_read_subchannel *)addr; + = (struct ioc_read_subchannel *) addr; struct cd_sub_channel_info data; - int len=args->data_len; - if(len>sizeof(data)|| - lendata_len; + if (len > sizeof(data) || + len < sizeof(struct cd_sub_channel_header)) { + error = EINVAL; break; } - if(error = cd_read_subchannel(unit,args->address_format, - args->data_format,args->track,&data,len)) { + if (error = cd_read_subchannel(unit, args->address_format, + args->data_format, args->track, &data, len)) { break; } - len=MIN(len,((data.header.data_len[0]<<8)+data.header.data_len[1]+ - sizeof(struct cd_sub_channel_header))); - if(copyout(&data,args->data,len)!=0) { - error=EFAULT; + len = MIN(len, ((data.header.data_len[0] << 8) + data.header.data_len[1] + + sizeof(struct cd_sub_channel_header))); + if (copyout(&data, args->data, len) != 0) { + error = EFAULT; } } break; case CDIOREADTOCHEADER: { struct ioc_toc_header th; - if( error = cd_read_toc(unit,0,0,&th,sizeof(th))) + if (error = cd_read_toc(unit, 0, 0, &th, sizeof(th))) break; - th.len=(th.len&0xff)<<8+((th.len>>8)&0xff); - bcopy(&th,addr,sizeof(th)); + th.len = (th.len & 0xff) << 8 + ((th.len >> 8) & 0xff); + bcopy(&th, addr, sizeof(th)); } break; case CDIOREADTOCENTRYS: { - struct ioc_read_toc_entry *te= - (struct ioc_read_toc_entry *)addr; + struct ioc_read_toc_entry *te = + (struct ioc_read_toc_entry *) addr; struct cd_toc_entry data[65]; struct ioc_toc_header *th; - int len=te->data_len; - th=(struct ioc_toc_header *)data; - - if(len>sizeof(data) || lenaddress_format, - te->starting_track, - data, - len)) + u_int32 len = te->data_len; + th = (struct ioc_toc_header *) data; + + if (len > sizeof(data) || len < sizeof(struct cd_toc_entry)) { + error = EINVAL; break; - len=MIN(len,((((th->len&0xff)<<8)+((th->len>>8)))+ - sizeof(*th))); - if(copyout(th,te->data,len)!=0) { - error=EFAULT; } - + if (error = cd_read_toc(unit, te->address_format, + te->starting_track, + data, + len)) + break; + len = MIN(len, ((((th->len & 0xff) << 8) + ((th->len >> 8))) + + sizeof(*th))); + if (copyout(th, te->data, len) != 0) { + error = EFAULT; + } } break; case CDIOCSETPATCH: { - struct ioc_patch *arg = (struct ioc_patch *)addr; - struct cd_mode_data data; - if(error = cd_get_mode(unit,&data,AUDIO_PAGE)) + struct ioc_patch *arg = (struct ioc_patch *) addr; + struct cd_mode_data data; + if (error = cd_get_mode(unit, &data, AUDIO_PAGE)) break; data.page.audio.port[LEFT_PORT].channels = arg->patch[0]; data.page.audio.port[RIGHT_PORT].channels = arg->patch[1]; data.page.audio.port[2].channels = arg->patch[2]; data.page.audio.port[3].channels = arg->patch[3]; - if(error = cd_set_mode(unit,&data)) - break; + if (error = cd_set_mode(unit, &data)) + break; /* eh? */ } break; case CDIOCGETVOL: { - struct ioc_vol *arg = (struct ioc_vol *)addr; - struct cd_mode_data data; - if(error = cd_get_mode(unit,&data,AUDIO_PAGE)) + struct ioc_vol *arg = (struct ioc_vol *) addr; + struct cd_mode_data data; + if (error = cd_get_mode(unit, &data, AUDIO_PAGE)) break; arg->vol[LEFT_PORT] = data.page.audio.port[LEFT_PORT].volume; arg->vol[RIGHT_PORT] = data.page.audio.port[RIGHT_PORT].volume; @@ -941,148 +740,146 @@ cdioctl(dev_t dev, int cmd, caddr_t addr, int flag) break; case CDIOCSETVOL: { - struct ioc_vol *arg = (struct ioc_vol *)addr; - struct cd_mode_data data; - if(error = cd_get_mode(unit,&data,AUDIO_PAGE)) + struct ioc_vol *arg = (struct ioc_vol *) addr; + struct cd_mode_data data; + if (error = cd_get_mode(unit, &data, AUDIO_PAGE)) break; data.page.audio.port[LEFT_PORT].volume = arg->vol[LEFT_PORT]; data.page.audio.port[RIGHT_PORT].volume = arg->vol[RIGHT_PORT]; data.page.audio.port[2].volume = arg->vol[2]; data.page.audio.port[3].volume = arg->vol[3]; - if(error = cd_set_mode(unit,&data)) + if (error = cd_set_mode(unit, &data)) break; } break; case CDIOCSETMONO: { - struct ioc_vol *arg = (struct ioc_vol *)addr; - struct cd_mode_data data; - if(error = cd_get_mode(unit,&data,AUDIO_PAGE)) + struct ioc_vol *arg = (struct ioc_vol *) addr; + struct cd_mode_data data; + if (error = cd_get_mode(unit, &data, AUDIO_PAGE)) break; - data.page.audio.port[LEFT_PORT].channels = LEFT_CHANNEL|RIGHT_CHANNEL|4|8; - data.page.audio.port[RIGHT_PORT].channels = LEFT_CHANNEL|RIGHT_CHANNEL; + data.page.audio.port[LEFT_PORT].channels = LEFT_CHANNEL | RIGHT_CHANNEL | 4 | 8; + data.page.audio.port[RIGHT_PORT].channels = LEFT_CHANNEL | RIGHT_CHANNEL; data.page.audio.port[2].channels = 0; data.page.audio.port[3].channels = 0; - if(error = cd_set_mode(unit,&data)) + if (error = cd_set_mode(unit, &data)) break; } break; case CDIOCSETSTERIO: { - struct ioc_vol *arg = (struct ioc_vol *)addr; - struct cd_mode_data data; - if(error = cd_get_mode(unit,&data,AUDIO_PAGE)) + struct ioc_vol *arg = (struct ioc_vol *) addr; + struct cd_mode_data data; + if (error = cd_get_mode(unit, &data, AUDIO_PAGE)) break; data.page.audio.port[LEFT_PORT].channels = LEFT_CHANNEL; data.page.audio.port[RIGHT_PORT].channels = RIGHT_CHANNEL; data.page.audio.port[2].channels = 0; data.page.audio.port[3].channels = 0; - if(error = cd_set_mode(unit,&data)) + if (error = cd_set_mode(unit, &data)) break; } break; case CDIOCSETMUTE: { - struct ioc_vol *arg = (struct ioc_vol *)addr; - struct cd_mode_data data; - if(error = cd_get_mode(unit,&data,AUDIO_PAGE)) + struct ioc_vol *arg = (struct ioc_vol *) addr; + struct cd_mode_data data; + if (error = cd_get_mode(unit, &data, AUDIO_PAGE)) break; data.page.audio.port[LEFT_PORT].channels = 0; data.page.audio.port[RIGHT_PORT].channels = 0; data.page.audio.port[2].channels = 0; data.page.audio.port[3].channels = 0; - if(error = cd_set_mode(unit,&data)) + if (error = cd_set_mode(unit, &data)) break; } break; case CDIOCSETLEFT: { - struct ioc_vol *arg = (struct ioc_vol *)addr; - struct cd_mode_data data; - if(error = cd_get_mode(unit,&data,AUDIO_PAGE)) + struct ioc_vol *arg = (struct ioc_vol *) addr; + struct cd_mode_data data; + if (error = cd_get_mode(unit, &data, AUDIO_PAGE)) break; data.page.audio.port[LEFT_PORT].channels = LEFT_CHANNEL; data.page.audio.port[RIGHT_PORT].channels = LEFT_CHANNEL; data.page.audio.port[2].channels = 0; data.page.audio.port[3].channels = 0; - if(error = cd_set_mode(unit,&data)) + if (error = cd_set_mode(unit, &data)) break; } break; case CDIOCSETRIGHT: { - struct ioc_vol *arg = (struct ioc_vol *)addr; - struct cd_mode_data data; - if(error = cd_get_mode(unit,&data,AUDIO_PAGE)) + struct ioc_vol *arg = (struct ioc_vol *) addr; + struct cd_mode_data data; + if (error = cd_get_mode(unit, &data, AUDIO_PAGE)) break; data.page.audio.port[LEFT_PORT].channels = RIGHT_CHANNEL; data.page.audio.port[RIGHT_PORT].channels = RIGHT_CHANNEL; data.page.audio.port[2].channels = 0; data.page.audio.port[3].channels = 0; - if(error = cd_set_mode(unit,&data)) + if (error = cd_set_mode(unit, &data)) break; } break; case CDIOCRESUME: - error = cd_pause(unit,1); + error = cd_pause(unit, 1); break; case CDIOCPAUSE: - error = cd_pause(unit,0); + error = cd_pause(unit, 0); break; case CDIOCSTART: - error = cd_start_unit(unit,part,CD_START); + error = scsi_start_unit(cd->sc_link, 0); break; case CDIOCSTOP: - error = cd_start_unit(unit,part,CD_STOP); + error = scsi_start_unit(cd->sc_link, 0); break; case CDIOCEJECT: - error = cd_start_unit(unit,part,CD_EJECT); + error = scsi_start_unit(cd->sc_link, 0); break; case CDIOCSETDEBUG: - scsi_debug = 0xfff; cd_debug = 0xfff; + cd->sc_link->flags |= (SDEV_DB1 | SDEV_DB2); break; case CDIOCCLRDEBUG: - scsi_debug = 0; cd_debug = 0; + cd->sc_link->flags &= ~(SDEV_DB1 | SDEV_DB2); break; case CDIOCRESET: - return(cd_reset(unit)); + return (cd_reset(unit)); break; default: - error = ENOTTY; + if(part == RAW_PART) + error = scsi_do_ioctl(cd->sc_link,cmd,addr,flag); + else + error = ENOTTY; break; } return (error); } - -/*******************************************************\ -* Load the label information on the named device * -* * -* EVENTUALLY take information about different * -* data tracks from the TOC and put it in the disklabel * -\*******************************************************/ -int cdgetdisklabel(unit) -unsigned char unit; +/* + * Load the label information on the named device + * Actually fabricate a disklabel + * + * EVENTUALLY take information about different + * data tracks from the TOC and put it in the disklabel + */ +errval +cdgetdisklabel(unit) + u_int8 unit; { - /*unsigned int n, m;*/ - char *errstring; - struct dos_partition *dos_partition_p; + /*unsigned int n, m; */ + char *errstring; struct cd_data *cd; - cd = cd_driver->cd_data[unit]; - /*******************************************************\ - * If the info is already loaded, use it * - \*******************************************************/ - if(cd->flags & CDHAVELABEL) return; - - bzero(&cd->disklabel,sizeof(struct disklabel)); - /*******************************************************\ - * make partition 3 the whole disk in case of failure * - * then get pdinfo * - \*******************************************************/ - strncpy(cd->disklabel.d_typename,"scsi cd_rom",16); - strncpy(cd->disklabel.d_packname,"ficticious",16); - cd->disklabel.d_secsize = cd->params.blksize; /* as long as it's not 0 */ + cd = cd_driver.cd_data[unit]; + + bzero(&cd->disklabel, sizeof(struct disklabel)); + /* + * make partition 0 the whole disk + */ + strncpy(cd->disklabel.d_typename, "scsi cd_rom", 16); + strncpy(cd->disklabel.d_packname, "ficticious", 16); + cd->disklabel.d_secsize = cd->params.blksize; /* as long as it's not 0 */ cd->disklabel.d_nsectors = 100; cd->disklabel.d_ntracks = 1; cd->disklabel.d_ncylinders = (cd->params.disksize / 100) + 1; @@ -1092,129 +889,118 @@ unsigned char unit; cd->disklabel.d_interleave = 1; cd->disklabel.d_flags = D_REMOVABLE; + /* + * remember that comparisons with the partition are done + * assuming the blocks are 512 bytes so fudge it. + */ cd->disklabel.d_npartitions = 1; - cd->disklabel.d_partitions[0].p_offset = 0; - cd->disklabel.d_partitions[0].p_size - = cd->params.disksize * (cd->params.blksize / 512); - cd->disklabel.d_partitions[0].p_fstype = 9; + cd->disklabel.d_partitions[0].p_offset = 0; + cd->disklabel.d_partitions[0].p_size + = cd->params.disksize * (cd->params.blksize / 512); + cd->disklabel.d_partitions[0].p_fstype = 9; cd->disklabel.d_magic = DISKMAGIC; cd->disklabel.d_magic2 = DISKMAGIC; cd->disklabel.d_checksum = dkcksum(&(cd->disklabel)); - /*******************************************************\ - * Signal to other users and routines that we now have a * - * disklabel that represents the media (maybe) * - \*******************************************************/ - cd->flags |= CDHAVELABEL; - return(ESUCCESS); -} - -/*******************************************************\ -* Get scsi driver to send a "are you ready" command * -\*******************************************************/ -cd_test_ready(unit,flags) -int unit,flags; -{ - struct scsi_test_unit_ready scsi_cmd; - - bzero(&scsi_cmd, sizeof(scsi_cmd)); - scsi_cmd.op_code = TEST_UNIT_READY; - - return (cd_scsi_cmd(unit, - &scsi_cmd, - sizeof(scsi_cmd), - 0, - 0, - 100000, - NULL, - flags)); + /* + * Signal to other users and routines that we now have a + * disklabel that represents the media (maybe) + */ + return (ESUCCESS); } - -/*******************************************************\ -* Find out form the device what it's capacity is * -\*******************************************************/ +/* + * Find out from the device what it's capacity is + */ +u_int32 cd_size(unit, flags) { - struct scsi_read_cd_cap_data rdcap; - struct scsi_read_cd_capacity scsi_cmd; - int size; - int blksize; - - /*******************************************************\ - * make up a scsi command and ask the scsi driver to do * - * it for you. * - \*******************************************************/ + struct scsi_read_cd_cap_data rdcap; + struct scsi_read_cd_capacity scsi_cmd; + u_int32 size; + u_int32 blksize; + struct cd_data *cd = cd_driver.cd_data[unit]; + + /* + * make up a scsi command and ask the scsi driver to do + * it for you. + */ bzero(&scsi_cmd, sizeof(scsi_cmd)); scsi_cmd.op_code = READ_CD_CAPACITY; - /*******************************************************\ - * If the command works, interpret the result as a 4 byte* - * number of blocks * - \*******************************************************/ - if (cd_scsi_cmd(unit, - &scsi_cmd, - sizeof(scsi_cmd), - &rdcap, - sizeof(rdcap), - 2000, - NULL, - flags) != 0) - { + /* + * If the command works, interpret the result as a 4 byte + * number of blocks and a blocksize + */ + if (scsi_scsi_cmd(cd->sc_link, + (struct scsi_generic *) &scsi_cmd, + sizeof(scsi_cmd), + (u_char *) & rdcap, + sizeof(rdcap), + CDRETRIES, + 20000, /* might be a disk-changer */ + NULL, + SCSI_DATA_IN | flags) != 0) { printf("cd%d: could not get size\n", unit); - return(0); + return (0); } else { - size = rdcap.addr_0 + 1 ; + size = rdcap.addr_0 + 1; size += rdcap.addr_1 << 8; size += rdcap.addr_2 << 16; size += rdcap.addr_3 << 24; - blksize = rdcap.length_0 ; + blksize = rdcap.length_0; blksize += rdcap.length_1 << 8; blksize += rdcap.length_2 << 16; blksize += rdcap.length_3 << 24; } -#ifdef CDDEBUG - if(cd_debug)printf("cd%d: %d %d byte blocks\n",unit,size,blksize); -#endif /*CDDEBUG*/ - cd_driver->cd_data[unit]->params.disksize = size; - cd_driver->cd_data[unit]->params.blksize = blksize; - return(size); + if (blksize < 512) + blksize = 2048; /* some drives lie ! */ + if (size < 100) + size = 400000; /* ditto */ + SC_DEBUG(cd->sc_link, SDEV_DB3, ("cd%d: %d %d byte blocks\n" + ,unit, size, blksize)); + cd->params.disksize = size; + cd->params.blksize = blksize; + return (size); } - - -/*******************************************************\ -* Get the requested page into the buffer given * -\*******************************************************/ -cd_get_mode(unit,data,page) -int unit; -struct cd_mode_data *data; -int page; + +/* + * Get the requested page into the buffer given + */ +errval +cd_get_mode(unit, data, page) + u_int32 unit; + struct cd_mode_data *data; + u_int32 page; { struct scsi_mode_sense scsi_cmd; - int retval; + errval retval; bzero(&scsi_cmd, sizeof(scsi_cmd)); - bzero(data,sizeof(*data)); + bzero(data, sizeof(*data)); scsi_cmd.op_code = MODE_SENSE; scsi_cmd.page = page; scsi_cmd.length = sizeof(*data) & 0xff; - retval = cd_scsi_cmd(unit, - &scsi_cmd, - sizeof(scsi_cmd), - data, - sizeof(*data), - 20000, /* should be immed */ - NULL, - 0); + retval = scsi_scsi_cmd(cd_driver.cd_data[unit]->sc_link, + (struct scsi_generic *) &scsi_cmd, + sizeof(scsi_cmd), + (u_char *) data, + sizeof(*data), + CDRETRIES, + 20000, /* should be immed */ + NULL, + SCSI_DATA_IN); return (retval); } -/*******************************************************\ -* Get the requested page into the buffer given * -\*******************************************************/ -cd_set_mode(unit,data) -int unit; -struct cd_mode_data *data; + +/* + * Get the requested page into the buffer given + */ +errval +cd_set_mode(unit, data) + u_int32 unit; + struct cd_mode_data *data; { struct scsi_mode_select scsi_cmd; @@ -1223,25 +1009,26 @@ struct cd_mode_data *data; scsi_cmd.byte2 |= SMS_PF; scsi_cmd.length = sizeof(*data) & 0xff; data->header.data_length = 0; - /*show_mem(data,sizeof(*data));*/ - return (cd_scsi_cmd(unit, - &scsi_cmd, - sizeof(scsi_cmd), - data, - sizeof(*data), - 20000, /* should be immed */ - NULL, - 0) - ); + return (scsi_scsi_cmd(cd_driver.cd_data[unit]->sc_link, + (struct scsi_generic *) &scsi_cmd, + sizeof(scsi_cmd), + (u_char *) data, + sizeof(*data), + CDRETRIES, + 20000, /* should be immed */ + NULL, + SCSI_DATA_OUT)); } -/*******************************************************\ -* Get scsi driver to send a "start playing" command * -\*******************************************************/ -cd_play(unit,blk,len) -int unit,blk,len; + +/* + * Get scsi driver to send a "start playing" command + */ +errval +cd_play(unit, blk, len) + u_int32 unit, blk, len; { struct scsi_play scsi_cmd; - int retval; + errval retval; bzero(&scsi_cmd, sizeof(scsi_cmd)); scsi_cmd.op_code = PLAY; @@ -1251,24 +1038,26 @@ int unit,blk,len; scsi_cmd.blk_addr[3] = blk & 0xff; scsi_cmd.xfer_len[0] = (len >> 8) & 0xff; scsi_cmd.xfer_len[1] = len & 0xff; - retval = cd_scsi_cmd(unit, - &scsi_cmd, - sizeof(scsi_cmd), - 0, - 0, - 200000, /* should be immed */ - NULL, - 0); - return(retval); + return (scsi_scsi_cmd(cd_driver.cd_data[unit]->sc_link, + (struct scsi_generic *) &scsi_cmd, + sizeof(scsi_cmd), + 0, + 0, + CDRETRIES, + 200000, /* should be immed */ + NULL, + 0)); } -/*******************************************************\ -* Get scsi driver to send a "start playing" command * -\*******************************************************/ -cd_play_big(unit,blk,len) -int unit,blk,len; + +/* + * Get scsi driver to send a "start playing" command + */ +errval +cd_play_big(unit, blk, len) + u_int32 unit, blk, len; { struct scsi_play_big scsi_cmd; - int retval; + errval retval; bzero(&scsi_cmd, sizeof(scsi_cmd)); scsi_cmd.op_code = PLAY_BIG; @@ -1280,24 +1069,26 @@ int unit,blk,len; scsi_cmd.xfer_len[1] = (len >> 16) & 0xff; scsi_cmd.xfer_len[2] = (len >> 8) & 0xff; scsi_cmd.xfer_len[3] = len & 0xff; - retval = cd_scsi_cmd(unit, - &scsi_cmd, - sizeof(scsi_cmd), - 0, - 0, - 20000, /* should be immed */ - NULL, - 0); - return(retval); + return (scsi_scsi_cmd(cd_driver.cd_data[unit]->sc_link, + (struct scsi_generic *) &scsi_cmd, + sizeof(scsi_cmd), + 0, + 0, + CDRETRIES, + 20000, /* should be immed */ + NULL, + 0)); } -/*******************************************************\ -* Get scsi driver to send a "start playing" command * -\*******************************************************/ -cd_play_tracks(unit,strack,sindex,etrack,eindex) -int unit,strack,sindex,etrack,eindex; + +/* + * Get scsi driver to send a "start playing" command + */ +errval +cd_play_tracks(unit, strack, sindex, etrack, eindex) + u_int32 unit, strack, sindex, etrack, eindex; { struct scsi_play_track scsi_cmd; - int retval; + errval retval; bzero(&scsi_cmd, sizeof(scsi_cmd)); scsi_cmd.op_code = PLAY_TRACK; @@ -1305,47 +1096,52 @@ int unit,strack,sindex,etrack,eindex; scsi_cmd.start_index = sindex; scsi_cmd.end_track = etrack; scsi_cmd.end_index = eindex; - retval = cd_scsi_cmd(unit, - &scsi_cmd, - sizeof(scsi_cmd), - 0, - 0, - 20000, /* should be immed */ - NULL, - 0); - return(retval); + return (scsi_scsi_cmd(cd_driver.cd_data[unit]->sc_link, + (struct scsi_generic *) &scsi_cmd, + sizeof(scsi_cmd), + 0, + 0, + CDRETRIES, + 20000, /* should be immed */ + NULL, + 0)); } -/*******************************************************\ -* Get scsi driver to send a "play msf" command * -\*******************************************************/ -cd_play_msf(unit,startm,starts,startf,endm,ends,endf) -int unit,startm,starts,startf,endm,ends,endf; + +/* + * Get scsi driver to send a "play msf" command + */ +errval +cd_play_msf(unit, startm, starts, startf, endm, ends, endf) + u_int32 unit, startm, starts, startf, endm, ends, endf; { struct scsi_play_msf scsi_cmd; bzero(&scsi_cmd, sizeof(scsi_cmd)); scsi_cmd.op_code = PLAY_MSF; - scsi_cmd.start_m=startm; - scsi_cmd.start_s=starts; - scsi_cmd.start_f=startf; - scsi_cmd.end_m=endm; - scsi_cmd.end_s=ends; - scsi_cmd.end_f=endf; - - return (cd_scsi_cmd(unit, - &scsi_cmd, - sizeof(scsi_cmd), - 0, - 0, - 2000, - NULL, - 0)); + scsi_cmd.start_m = startm; + scsi_cmd.start_s = starts; + scsi_cmd.start_f = startf; + scsi_cmd.end_m = endm; + scsi_cmd.end_s = ends; + scsi_cmd.end_f = endf; + + return (scsi_scsi_cmd(cd_driver.cd_data[unit]->sc_link, + (struct scsi_generic *) &scsi_cmd, + sizeof(scsi_cmd), + 0, + 0, + CDRETRIES, + 2000, + NULL, + 0)); } -/*******************************************************\ -* Get scsi driver to send a "start up" command * -\*******************************************************/ -cd_pause(unit,go) -int unit,go; + +/* + * Get scsi driver to send a "start up" command + */ +errval +cd_pause(unit, go) + u_int32 unit, go; { struct scsi_pause scsi_cmd; @@ -1353,534 +1149,132 @@ int unit,go; scsi_cmd.op_code = PAUSE; scsi_cmd.resume = go; - return (cd_scsi_cmd(unit, - &scsi_cmd, - sizeof(scsi_cmd), - 0, - 0, - 2000, - NULL, - 0)); -} -/*******************************************************\ -* Get scsi driver to send a "RESET" command * -\*******************************************************/ -cd_reset(unit) -int unit; -{ - return(cd_scsi_cmd(unit, - 0, - 0, - 0, - 0, - 2000, - NULL, - SCSI_RESET)); + return (scsi_scsi_cmd(cd_driver.cd_data[unit]->sc_link, + (struct scsi_generic *) &scsi_cmd, + sizeof(scsi_cmd), + 0, + 0, + CDRETRIES, + 2000, + NULL, + 0)); } -/*******************************************************\ -* Get scsi driver to send a "start up" command * -\*******************************************************/ -cd_start_unit(unit,part,type) -{ - struct scsi_start_stop scsi_cmd; - struct cd_data *cd = cd_driver->cd_data[unit]; - if(type==CD_EJECT - /*&& (cd->openparts == 0)*/)/* trouble is WE have it open *//*XXX*/ - { - cd_prevent_unit(unit,PR_ALLOW,0); - } - - bzero(&scsi_cmd, sizeof(scsi_cmd)); - scsi_cmd.op_code = START_STOP; - scsi_cmd.how |= (type==CD_START)?SSS_START:0; - scsi_cmd.how |= (type==CD_EJECT)?SSS_LOEJ:0; - - if (cd_scsi_cmd(unit, - &scsi_cmd, - sizeof(scsi_cmd), - 0, - 0, - 2000, - NULL, - 0) != 0) { - return(ENXIO); - } else - return(0); -} -/*******************************************************\ -* Prevent or allow the user to remove the disk * -\*******************************************************/ -cd_prevent_unit(unit,type,flags) -int unit,type,flags; +/* + * Get scsi driver to send a "RESET" command + */ +errval +cd_reset(unit) + u_int32 unit; { - struct scsi_prevent scsi_cmd; - struct cd_data *cd = cd_driver->cd_data[unit]; - - if(type==PR_PREVENT - || ( type==PR_ALLOW && cd->openparts == 0 ))/*XXX*/ - { - bzero(&scsi_cmd, sizeof(scsi_cmd)); - scsi_cmd.op_code = PREVENT_ALLOW; - scsi_cmd.how = type; - if (cd_scsi_cmd(unit, - &scsi_cmd, - sizeof(struct scsi_prevent), - 0, - 0, - 5000, - NULL, - 0) != 0) - { - if(!(flags & SCSI_SILENT)) - printf("cd%d: cannot prevent/allow\n", unit); - return(0); - } - } - return(1); + return (scsi_scsi_cmd(cd_driver.cd_data[unit]->sc_link, + 0, + 0, + 0, + 0, + CDRETRIES, + 2000, + NULL, + SCSI_RESET)); } -/******************************************************\ -* Read Subchannel * -\******************************************************/ - -cd_read_subchannel(unit,mode,format,track,data,len) -int unit,mode,format,len; -struct cd_sub_channel_info *data; +/* + * Read subchannel + */ +errval +cd_read_subchannel(unit, mode, format, track, data, len) + u_int32 unit, mode, format, len; + struct cd_sub_channel_info *data; { struct scsi_read_subchannel scsi_cmd; - int error; + errval error; - bzero(&scsi_cmd,sizeof(scsi_cmd)); + bzero(&scsi_cmd, sizeof(scsi_cmd)); - scsi_cmd.op_code=READ_SUBCHANNEL; - if(mode==CD_MSF_FORMAT) + scsi_cmd.op_code = READ_SUBCHANNEL; + if (mode == CD_MSF_FORMAT) scsi_cmd.byte2 |= CD_MSF; - scsi_cmd.byte3=SRS_SUBQ; - scsi_cmd.subchan_format=format; - scsi_cmd.track=track; - scsi_cmd.data_len[0]=(len)>>8; - scsi_cmd.data_len[1]=(len)&0xff; - return cd_scsi_cmd(unit, - &scsi_cmd, - sizeof(struct scsi_read_subchannel), - data, + scsi_cmd.byte3 = SRS_SUBQ; + scsi_cmd.subchan_format = format; + scsi_cmd.track = track; + scsi_cmd.data_len[0] = (len) >> 8; + scsi_cmd.data_len[1] = (len) & 0xff; + return (scsi_scsi_cmd(cd_driver.cd_data[unit]->sc_link, + (struct scsi_generic *) &scsi_cmd, + sizeof(struct scsi_read_subchannel), + (u_char *) data, len, + CDRETRIES, 5000, NULL, - 0); + SCSI_DATA_IN)); } -/*******************************************************\ -* Read Table of contents * -\*******************************************************/ -cd_read_toc(unit,mode,start,data,len) -int unit,mode,start,len; -struct cd_toc_entry *data; +/* + * Read table of contents + */ +errval +cd_read_toc(unit, mode, start, data, len) + u_int32 unit, mode, start, len; + struct cd_toc_entry *data; { struct scsi_read_toc scsi_cmd; - int error; - int ntoc; - - bzero(&scsi_cmd,sizeof(scsi_cmd)); + errval error; + u_int32 ntoc; + + bzero(&scsi_cmd, sizeof(scsi_cmd)); /*if(len!=sizeof(struct ioc_toc_header)) - ntoc=((len)-sizeof(struct ioc_toc_header))/sizeof(struct cd_toc_entry); - else*/ - ntoc=len; - - scsi_cmd.op_code=READ_TOC; - if(mode==CD_MSF_FORMAT) - scsi_cmd.byte2 |= CD_MSF; - scsi_cmd.from_track=start; - scsi_cmd.data_len[0]=(ntoc)>>8; - scsi_cmd.data_len[1]=(ntoc)&0xff; - return cd_scsi_cmd(unit, - &scsi_cmd, - sizeof(struct scsi_read_toc), - data, - len, - 5000, + * ntoc=((len)-sizeof(struct ioc_toc_header))/sizeof(struct cd_toc_entry); + * else */ + ntoc = len; + + scsi_cmd.op_code = READ_TOC; + if (mode == CD_MSF_FORMAT) + scsi_cmd.byte2 |= CD_MSF; + scsi_cmd.from_track = start; + scsi_cmd.data_len[0] = (ntoc) >> 8; + scsi_cmd.data_len[1] = (ntoc) & 0xff; + return (scsi_scsi_cmd(cd_driver.cd_data[unit]->sc_link, + (struct scsi_generic *) &scsi_cmd, + sizeof(struct scsi_read_toc), + (u_char *) data, + len, + CDRETRIES, + 5000, NULL, - 0); + SCSI_DATA_IN)); } - #define b2tol(a) (((unsigned)(a##_1) << 8) + (unsigned)a##_0 ) -/*******************************************************\ -* Get the scsi driver to send a full inquiry to the * -* device and use the results to fill out the disk * -* parameter structure. * -\*******************************************************/ - -int cd_get_parms(unit, flags) -{ - struct cd_data *cd = cd_driver->cd_data[unit]; - - /*******************************************************\ - * First check if we have it all loaded * - \*******************************************************/ - if(cd->flags & CDVALID) return(0); - /*******************************************************\ - * give a number of sectors so that sec * trks * cyls * - * is <= disk_size * - \*******************************************************/ - if(cd_size(unit, flags)) - { - cd->flags |= CDVALID; - return(0); - } - else - { - return(ENXIO); - } -} - -/*******************************************************\ -* close the device.. only called if we are the LAST * -* occurence of an open device * -\*******************************************************/ -cdclose(dev) -dev_t dev; -{ - unsigned char unit, part; - unsigned int old_priority; - - unit = UNIT(dev); - part = PARTITION(dev); -#ifdef CDDEBUG - if(scsi_debug & TRACEOPENS) - printf("cd%d: closing part %d\n",unit,part); -#endif - cd_driver->cd_data[unit]->partflags[part] &= ~CDOPEN; - cd_driver->cd_data[unit]->openparts &= ~(1 << part); - cd_prevent_unit(unit,PR_ALLOW,SCSI_SILENT); - return(0); -} - -/*******************************************************\ -* ask the scsi driver to perform a command for us. * -* Call it through the switch table, and tell it which * -* sub-unit we want, and what target and lu we wish to * -* talk to. Also tell it where to find the command * -* how long int is. * -* Also tell it where to read/write the data, and how * -* long the data is supposed to be * -\*******************************************************/ -int cd_scsi_cmd(unit,scsi_cmd,cmdlen,data_addr,datalen,timeout,bp,flags) - -int unit,flags; -struct scsi_generic *scsi_cmd; -int cmdlen; -int timeout; -u_char *data_addr; -int datalen; -struct buf *bp; +/* + * Get the scsi driver to send a full inquiry to the device and use the + * results to fill out the disk parameter structure. + */ +errval +cd_get_parms(unit, flags) { - struct scsi_xfer *xs; - int retval; - int s; - struct cd_data *cd = cd_driver->cd_data[unit]; - -#ifdef CDDEBUG - if(scsi_debug & PRINTROUTINES) printf("\ncd_scsi_cmd%d ",unit); -#endif /*CDDEBUG*/ -#ifdef PARANOID - if(!(cd->sc_sw)) /* If we have a scsi driver */ - { - /* !? how'd we GET here? */ - panic("attempt to run bad cd device"); - } -#endif /*PARANOID*/ - xs = cd_get_xs(unit,flags); /* should wait unless booting */ - if(!xs) - { - printf("cd%d: scsi_cmd controller busy" - " (this should never happen)\n",unit); - return(EBUSY); - } - xs->flags |= INUSE; - /*******************************************************\ - * Fill out the scsi_xfer structure * - \*******************************************************/ - xs->flags |= flags; - xs->adapter = cd->ctlr; - xs->targ = cd->targ; - xs->lu = cd->lu; - xs->retries = CD_RETRIES; - xs->timeout = timeout; - xs->cmd = scsi_cmd; - xs->cmdlen = cmdlen; - xs->data = data_addr; - xs->datalen = datalen; - xs->resid = datalen; - xs->when_done = (flags & SCSI_NOMASK) - ?(int (*)())0 - :cd_done; - xs->done_arg = unit; - xs->done_arg2 = (int)xs; - xs->bp = bp; -retry: xs->error = XS_NOERROR; - /*******************************************************\ - * Do the transfer. If we are polling we will return: * - * COMPLETE, Was poll, and cd_done has been called * - * HAD_ERROR, Was poll and an error was encountered * - * TRY_AGAIN_LATER, Adapter short resources, try again * - * * - * if under full steam (interrupts) it will return: * - * SUCCESSFULLY_QUEUED, will do a wakeup when complete * - * HAD_ERROR, had an erro before it could queue * - * TRY_AGAIN_LATER, (as for polling) * - * After the wakeup, we must still check if it succeeded * - * * - * If we have a bp however, all the error proccessing * - * and the buffer code both expect us to return straight * - * to them, so as soon as the command is queued, return * - \*******************************************************/ - retval = (*(cd->sc_sw->scsi_cmd))(xs); - if(bp) return retval; /* will sleep (or not) elsewhere */ - - /*******************************************************\ - * Only here for non I/O cmds. It's cheaper to process * - * the error status here than at interrupt time so * - * sd_done will have done nothing except wake us up. * - \*******************************************************/ - switch(retval) - { - case SUCCESSFULLY_QUEUED: - s = splbio(); - while(!(xs->flags & ITSDONE)) - sleep(xs,PRIBIO+1); - splx(s); - /* Fall through to check the result */ - - case HAD_ERROR: - switch(xs->error) - { - case XS_NOERROR: /* usually this one */ - retval = ESUCCESS; - break; - - case XS_SENSE: - retval = (cd_interpret_sense(unit,xs)); - break; - case XS_BUSY: - /* should sleep here 1 sec */ - /* fall through */ - case XS_TIMEOUT: - if(xs->retries-- ) - { - xs->flags &= ~ITSDONE; - goto retry; - } - /* fall through */ - case XS_DRIVER_STUFFUP: - retval = EIO; - break; - default: - retval = EIO; - printf("cd%d: unknown error category from scsi driver\n" - ,unit); - } - break; - case COMPLETE: - retval = ESUCCESS; - break; + struct cd_data *cd = cd_driver.cd_data[unit]; - case TRY_AGAIN_LATER: - if(xs->retries-- ) - { - if(tsleep( 0,PRIBIO + 2,"retry",hz * 2)) - { - xs->flags &= ~ITSDONE; - goto retry; - } - } - /* fall through */ - default: - retval = EIO; - } - - /*******************************************************\ - * we have finished doing the command, free the struct * - * and check if anyone else needs it * - \*******************************************************/ - cd_free_xs(unit,xs,flags); - cdstart(unit); /* check if anything is waiting for the xs */ - return(retval); -} -/***************************************************************\ -* Look at the returned sense and act on the error and detirmine * -* The unix error number to pass back... (0 = report no error) * -\***************************************************************/ - -int cd_interpret_sense(unit,xs) -int unit; -struct scsi_xfer *xs; -{ - struct scsi_sense_data *sense; - int key; - int silent; - int info; - struct cd_data *cd = cd_driver->cd_data[unit]; - - static char *error_mes[] = { "soft error (corrected)", - "not ready", "medium error", - "non-media hardware failure", "illegal request", - "unit attention", "readonly device", - "no data found", "vendor unique", - "copy aborted", "command aborted", - "search returned equal", "volume overflow", - "verify miscompare", "unknown error key" - }; - - /***************************************************************\ - * If the flags say errs are ok, then always return ok. * - \***************************************************************/ - if (xs->flags & SCSI_ERR_OK) return(ESUCCESS); - silent = (xs->flags & SCSI_SILENT); - - sense = &(xs->sense); -#ifdef CDDEBUG - if(cd_debug) - { - int count = 0; - printf("code%x valid%x\n" - ,sense->error_code & SSD_ERRCODE - ,sense->error_code & SSD_ERRCODE_VALID ? 1 : 0); - printf("seg%x key%x ili%x eom%x fmark%x\n" - ,sense->ext.extended.segment - ,sense->ext.extended.flags & SSD_KEY - ,sense->ext.extended.flags & SSD_ILI ? 1 : 0 - ,sense->ext.extended.flags & SSD_EOM ? 1 : 0 - ,sense->ext.extended.flags & SSD_FILEMARK ? 1 : 0); - printf("info: %x %x %x %x followed by %d extra bytes\n" - ,sense->ext.extended.info[0] - ,sense->ext.extended.info[1] - ,sense->ext.extended.info[2] - ,sense->ext.extended.info[3] - ,sense->ext.extended.extra_len); - printf("extra: "); - while(count < sense->ext.extended.extra_len) - { - printf ("%x ",sense->ext.extended.extra_bytes[count++]); - } - printf("\n"); - } -#endif /*CDDEBUG*/ - switch(sense->error_code & SSD_ERRCODE) - { - /***************************************************************\ - * If it's code 70, use the extended stuff and interpret the key * - \***************************************************************/ - case 0x71:/* delayed error */ - printf("cd%d: DELAYED ERROR, key = 0x%x\n",unit,key); - case 0x70: - if(sense->error_code & SSD_ERRCODE_VALID) - { - info = ntohl(*((long *)sense->ext.extended.info)); - } - else - { - info = 0; - } - - key=sense->ext.extended.flags & SSD_KEY; - - if (!silent) - { - printf("cd%d: %s", unit, error_mes[key - 1]); - if(sense->error_code & SSD_ERRCODE_VALID) - { - switch (key) - { - case 0x2: /* NOT READY */ - case 0x5: /* ILLEGAL REQUEST */ - case 0x6: /* UNIT ATTENTION */ - case 0x7: /* DATA PROTECT */ - break; - case 0x8: /* BLANK CHECK */ - printf(", requested size: %d (decimal)", - info); - break; - default: - printf(", info = %d (decimal)", info); - } - } - printf("\n"); - } - - switch (key) - { - case 0x0: /* NO SENSE */ - case 0x1: /* RECOVERED ERROR */ - xs->resid = 0; - case 0xc: /* EQUAL */ - return(ESUCCESS); - case 0x2: /* NOT READY */ - cd->flags &= ~(CDVALID | CDHAVELABEL); - return(ENODEV); - case 0x5: /* ILLEGAL REQUEST */ - return(EINVAL); - case 0x6: /* UNIT ATTENTION */ - cd->flags &= ~(CDVALID | CDHAVELABEL); - if (cd->openparts) - { - return(EIO); - } - return(ESUCCESS); - case 0x7: /* DATA PROTECT */ - return(EACCES); - case 0xd: /* VOLUME OVERFLOW */ - return(ENOSPC); - case 0x8: /* BLANK CHECK */ - return(ESUCCESS); - default: - return(EIO); - } - /*******************************\ - * Not code 70, just report it * - \*******************************/ - default: - if(!silent) - { - printf("cd%d: error code %d", unit, - sense->error_code & SSD_ERRCODE); - if(sense->error_code & SSD_ERRCODE_VALID) - { - printf(" at block no. %d (decimal)", - (sense->ext.unextended.blockhi <<16) - + (sense->ext.unextended.blockmed <<8) - + (sense->ext.unextended.blocklow )); - } - printf("\n"); - } - return(EIO); + /* + * First check if we have it all loaded + */ + if (cd->sc_link->flags & SDEV_MEDIA_LOADED) + return (0); + /* + * give a number of sectors so that sec * trks * cyls + * is <= disk_size + */ + if (cd_size(unit, flags)) { + cd->sc_link->flags |= SDEV_MEDIA_LOADED; + return (0); + } else { + return (ENXIO); } } - - - int cdsize(dev_t dev) { return (-1); } - -#if 0 -show_mem(address,num) -unsigned char *address; -int num; -{ - int x,y; - printf("------------------------------"); - for (y = 0; y @@ -17,965 +18,464 @@ #include #include -#if defined(OSF) -#define SECSIZE 512 -#endif /* defined(OSF) */ - #include #include #include - -struct scsi_xfer ch_scsi_xfer[NCH]; -int ch_xfer_block_wait[NCH]; - +struct scsi_xfer ch_scsi_xfer[NCH]; +u_int32 ch_xfer_block_wait[NCH]; #define PAGESIZ 4096 #define STQSIZE 4 -#define CH_RETRIES 4 - +#define CHRETRIES 2 #define MODE(z) ( (minor(z) & 0x0F) ) #define UNIT(z) ( (minor(z) >> 4) ) -#ifndef MACH #define ESUCCESS 0 -#endif MACH -int ch_info_valid[NCH]; /* the info about the device is valid */ -int ch_initialized[NCH] ; -int ch_debug = 1; +errval chattach(); -int chattach(); -int ch_done(); -struct ch_data +/* + * This driver is so simple it uses all the default services + */ +struct scsi_device ch_switch = { - int flags; - struct scsi_switch *sc_sw; /* address of scsi low level switch */ - int ctlr; /* so they know which one we want */ - int targ; /* our scsi target ID */ - int lu; /* out scsi lu */ - short chmo; /* Offset of first CHM */ - short chms; /* No. of CHM */ - short slots; /* No. of Storage Elements */ - short sloto; /* Offset of first SE */ - short imexs; /* No. of Import/Export Slots */ - short imexo; /* Offset of first IM/EX */ - short drives; /* No. of CTS */ - short driveo; /* Offset of first CTS */ - short rot; /* CHM can rotate */ - u_long op_matrix; /* possible opertaions */ - u_short lsterr; /* details of lasterror */ - u_char stor; /* posible Storage locations */ -}ch_data[NCH]; + NULL, + NULL, + NULL, + NULL, + "ch", + 0, + 0, 0 +}; + +struct ch_data { + u_int32 flags; + struct scsi_link *sc_link; /* all the inter level info */ + u_int16 chmo; /* Offset of first CHM */ + u_int16 chms; /* No. of CHM */ + u_int16 slots; /* No. of Storage Elements */ + u_int16 sloto; /* Offset of first SE */ + u_int16 imexs; /* No. of Import/Export Slots */ + u_int16 imexo; /* Offset of first IM/EX */ + u_int16 drives; /* No. of CTS */ + u_int16 driveo; /* Offset of first CTS */ + u_int16 rot; /* CHM can rotate */ + u_long op_matrix; /* possible opertaions */ + u_int16 lsterr; /* details of lasterror */ + u_char stor; /* posible Storage locations */ + u_int32 initialized; +} ch_data[NCH]; #define CH_OPEN 0x01 #define CH_KNOWN 0x02 -static int next_ch_unit = 0; -/***********************************************************************\ -* The routine called by the low level scsi routine when it discovers * -* A device suitable for this driver * -\***********************************************************************/ +static u_int32 next_ch_unit = 0; -int chattach(ctlr,targ,lu,scsi_switch) -struct scsi_switch *scsi_switch; +/* + * The routine called by the low level scsi routine when it discovers + * a device suitable for this driver. + */ +errval +chattach(sc_link) + struct scsi_link *sc_link; { - int unit,i,stat; + u_int32 unit, i, stat; unsigned char *tbl; - if(scsi_debug & PRINTROUTINES) printf("chattach: "); - /*******************************************************\ - * Check we have the resources for another drive * - \*******************************************************/ + SC_DEBUG(sc_link, SDEV_DB2, ("chattach: ")); + /* + * Check we have the resources for another drive + */ unit = next_ch_unit++; - if( unit >= NCH) - { - printf("Too many scsi changers..(%d > %d) reconfigure kernel\n",(unit + 1),NCH); - return(0); - } - /*******************************************************\ - * Store information needed to contact our base driver * - \*******************************************************/ - ch_data[unit].sc_sw = scsi_switch; - ch_data[unit].ctlr = ctlr; - ch_data[unit].targ = targ; - ch_data[unit].lu = lu; - - /*******************************************************\ - * Use the subdriver to request information regarding * - * the drive. We cannot use interrupts yet, so the * - * request must specify this. * - \*******************************************************/ - if((ch_mode_sense(unit, SCSI_NOSLEEP | SCSI_NOMASK /*| SCSI_SILENT*/))) - { - printf("ch%d: scsi changer, %d slot(s) %d drive(s) %d arm(s) %d i/e-slot(s)\n", - unit, ch_data[unit].slots, ch_data[unit].drives, ch_data[unit].chms, ch_data[unit].imexs); - stat=CH_KNOWN; + if (unit >= NCH) { + printf("Too many scsi changers..(%d > %d) reconfigure kernel\n", (unit + 1), NCH); + return (0); } - else - { + /* + * Store information needed to contact our base driver + */ + ch_data[unit].sc_link = sc_link; + sc_link->device = &ch_switch; + sc_link->dev_unit = unit; + + /* + * Use the subdriver to request information regarding + * the drive. We cannot use interrupts yet, so the + * request must specify this. + */ + if ((ch_mode_sense(unit, SCSI_NOSLEEP | SCSI_NOMASK /*| SCSI_SILENT */ ))) { printf("ch%d: scsi changer :- offline\n", unit); - stat=CH_OPEN; + stat = CH_OPEN; + } else { + printf("ch%d: scsi changer, %d slot(s) %d drive(s) %d arm(s) %d i/e-slot(s)\n", + unit, ch_data[unit].slots, ch_data[unit].drives, ch_data[unit].chms, ch_data[unit].imexs); + stat = CH_KNOWN; } - ch_initialized[unit] = stat; + ch_data[unit].initialized = 1; return; } - - -/*******************************************************\ -* open the device. * -\*******************************************************/ +/* + * open the device. + */ +errval chopen(dev) { - int errcode = 0; - int unit,mode; + errval errcode = 0; + u_int32 unit, mode; + struct scsi_link *sc_link; unit = UNIT(dev); mode = MODE(dev); - /*******************************************************\ - * Check the unit is legal * - \*******************************************************/ - if ( unit >= NCH ) - { - printf("ch%d: ch %d > %d\n",unit,unit,NCH); - errcode = ENXIO; - return(errcode); - } - /*******************************************************\ - * Only allow one at a time * - \*******************************************************/ - if(ch_data[unit].flags & CH_OPEN) - { - printf("ch%d: already open\n",unit); + /* + * Check the unit is legal + */ + if (unit >= NCH) { + printf("ch%d: ch %d > %d\n", unit, unit, NCH); errcode = ENXIO; - goto bad; + return (errcode); } - - if(ch_debug||(scsi_debug & (PRINTROUTINES | TRACEOPENS))) - printf("chopen: dev=0x%x (unit %d (of %d))\n" - , dev, unit, NCH); - /*******************************************************\ - * Make sure the device has been initialised * - \*******************************************************/ - - if (!ch_initialized[unit]) - return(ENXIO); - if (ch_initialized[unit]!=CH_KNOWN) { - if((ch_mode_sense(unit, SCSI_NOSLEEP | SCSI_NOMASK /*| SCSI_SILENT*/))) - { - ch_initialized[unit]=CH_KNOWN; - } - else - { - printf("ch%d: scsi changer :- offline\n", unit); - return(ENXIO); - } + /* + * Only allow one at a time + */ + if (ch_data[unit].flags & CH_OPEN) { + printf("ch%d: already open\n", unit); + return ENXIO; } - /*******************************************************\ - * Check that it is still responding and ok. * - \*******************************************************/ - - if(ch_debug || (scsi_debug & TRACEOPENS)) - printf("device is "); - if (!(ch_req_sense(unit, 0))) - { - errcode = ENXIO; - if(ch_debug || (scsi_debug & TRACEOPENS)) - printf("not responding\n"); - goto bad; + /* + * Make sure the device has been initialised + */ + if (!ch_data[unit].initialized) + return (ENXIO); + + sc_link = ch_data[unit].sc_link; + + SC_DEBUG(sc_link, SDEV_DB1, ("chopen: dev=0x%x (unit %d (of %d))\n" + ,dev, unit, NCH)); + /* + * Catch any unit attention errors. + */ + scsi_test_unit_ready(sc_link, SCSI_SILENT); + + sc_link->flags |= SDEV_OPEN; + /* + * Check that it is still responding and ok. + */ + if (errcode = (scsi_test_unit_ready(sc_link, 0))) { + printf("ch%d: not ready\n", unit); + sc_link->flags &= ~SDEV_OPEN; + return errcode; } - if(ch_debug || (scsi_debug & TRACEOPENS)) - printf("ok\n"); - - if(!(ch_test_ready(unit,0))) - { - printf("ch%d: not ready\n",unit); - return(EIO); + /* + * Make sure data is loaded + */ + if (errcode = (ch_mode_sense(unit, SCSI_NOSLEEP | SCSI_NOMASK))) { + printf("ch%d: scsi changer :- offline\n", unit); + sc_link->flags &= ~SDEV_OPEN; + return (errcode); } - - ch_info_valid[unit] = TRUE; - - /*******************************************************\ - * Load the physical device parameters * - \*******************************************************/ - ch_data[unit].flags = CH_OPEN; - return(errcode); -bad: - return(errcode); + return 0; } -/*******************************************************\ -* close the device.. only called if we are the LAST * -* occurence of an open device * -\*******************************************************/ +/* + * close the device.. only called if we are the LAST + * occurence of an open device + */ +errval chclose(dev) { - unsigned char unit,mode; + unsigned char unit, mode; + struct scsi_link *sc_link; unit = UNIT(dev); mode = MODE(dev); + sc_link = ch_data[unit].sc_link; - if(scsi_debug & TRACEOPENS) - printf("Closing device"); + SC_DEBUG(sc_link, SDEV_DB1, ("Closing device")); ch_data[unit].flags = 0; - return(0); -} - - - -/***************************************************************\ -* chstart * -* This routine is also called after other non-queued requests * -* have been made of the scsi driver, to ensure that the queue * -* continues to be drained. * -\***************************************************************/ -/* chstart() is called at splbio */ -chstart(unit) -{ - int drivecount; - register struct buf *bp = 0; - register struct buf *dp; - struct scsi_xfer *xs; - int blkno, nblk; - - - if(scsi_debug & PRINTROUTINES) printf("chstart%d ",unit); - /*******************************************************\ - * See if there is a buf to do and we are not already * - * doing one * - \*******************************************************/ - xs=&ch_scsi_xfer[unit]; - if(xs->flags & INUSE) - { - return; /* unit already underway */ - } - if(ch_xfer_block_wait[unit]) /* a special awaits, let it proceed first */ - { - wakeup(&ch_xfer_block_wait[unit]); - return; - } - - return; - + sc_link->flags &= ~SDEV_OPEN; + return (0); } - -/*******************************************************\ -* This routine is called by the scsi interrupt when * -* the transfer is complete. -\*******************************************************/ -int ch_done(unit,xs) -int unit; -struct scsi_xfer *xs; -{ - struct buf *bp; - int retval; - - if(ch_debug||(scsi_debug & PRINTROUTINES)) printf("ch_done%d ",unit); - if (! (xs->flags & INUSE)) - panic("scsi_xfer not in use!"); - wakeup(xs); -} -/*******************************************************\ -* Perform special action on behalf of the user * -* Knows about the internals of this device * -\*******************************************************/ +/* + * Perform special action on behalf of the user + * Knows about the internals of this device + */ +errval chioctl(dev, cmd, arg, mode) -dev_t dev; -int cmd; -caddr_t arg; + dev_t dev; + u_int32 cmd; + caddr_t arg; { - /* struct ch_cmd_buf *args;*/ + /* struct ch_cmd_buf *args; */ union scsi_cmd *scsi_cmd; - register i,j; - unsigned int opri; - int errcode = 0; + register i, j; + u_int32 opri; + errval errcode = 0; unsigned char unit; - int number,flags,ret; - - /*******************************************************\ - * Find the device that the user is talking about * - \*******************************************************/ - flags = 0; /* give error messages, act on errors etc. */ + u_int32 number, flags; + errval ret; + struct scsi_link *sc_link; + + /* + * Find the device that the user is talking about + */ + flags = 0; /* give error messages, act on errors etc. */ unit = UNIT(dev); - - switch(cmd) - { - case CHIOOP: { - struct chop *ch=(struct chop *) arg; - if (ch_debug) - printf("[chtape_chop: %x]\n", ch->ch_op); - - switch ((short)(ch->ch_op)) { - case CHGETPARAM: - ch->u.getparam.chmo= ch_data[unit].chmo; - ch->u.getparam.chms= ch_data[unit].chms; - ch->u.getparam.sloto= ch_data[unit].sloto; - ch->u.getparam.slots= ch_data[unit].slots; - ch->u.getparam.imexo= ch_data[unit].imexo; - ch->u.getparam.imexs= ch_data[unit].imexs; - ch->u.getparam.driveo= ch_data[unit].driveo; - ch->u.getparam.drives= ch_data[unit].drives; - ch->u.getparam.rot= ch_data[unit].rot; - ch->result=0; - return 0; - break; - case CHPOSITION: - return ch_position(unit,&ch->result,ch->u.position.chm, - ch->u.position.to, - flags); - case CHMOVE: - return ch_move(unit,&ch->result, ch->u.position.chm, - ch->u.move.from, ch->u.move.to, - flags); - case CHGETELEM: - return ch_getelem(unit,&ch->result, ch->u.get_elem_stat.type, - ch->u.get_elem_stat.from, &ch->u.get_elem_stat.elem_data, - flags); - default: - return EINVAL; + sc_link = ch_data[unit].sc_link; + + switch (cmd) { + case CHIOOP:{ + struct chop *ch = (struct chop *) arg; + SC_DEBUG(sc_link, SDEV_DB2, + ("[chtape_chop: %x]\n", ch->ch_op)); + + switch ((short) (ch->ch_op)) { + case CHGETPARAM: + ch->u.getparam.chmo = ch_data[unit].chmo; + ch->u.getparam.chms = ch_data[unit].chms; + ch->u.getparam.sloto = ch_data[unit].sloto; + ch->u.getparam.slots = ch_data[unit].slots; + ch->u.getparam.imexo = ch_data[unit].imexo; + ch->u.getparam.imexs = ch_data[unit].imexs; + ch->u.getparam.driveo = ch_data[unit].driveo; + ch->u.getparam.drives = ch_data[unit].drives; + ch->u.getparam.rot = ch_data[unit].rot; + ch->result = 0; + return 0; + break; + case CHPOSITION: + return ch_position(unit, &ch->result, ch->u.position.chm, + ch->u.position.to, + flags); + case CHMOVE: + return ch_move(unit, &ch->result, ch->u.position.chm, + ch->u.move.from, ch->u.move.to, + flags); + case CHGETELEM: + return ch_getelem(unit, &ch->result, ch->u.get_elem_stat.type, + ch->u.get_elem_stat.from, &ch->u.get_elem_stat.elem_data, + flags); + default: + return EINVAL; + } } - - } default: - return EINVAL; + return scsi_do_ioctl(sc_link, cmd, arg, mode); } - - return(ret?ESUCCESS:EIO); + return (ret ? ESUCCESS : EIO); } -ch_getelem(unit,stat,type,from,data,flags) -int unit,from,flags; -short *stat; -char *data; +errval +ch_getelem(unit, stat, type, from, data, flags) + u_int32 unit, from, flags; + short *stat; + char *data; { struct scsi_read_element_status scsi_cmd; - char elbuf[32]; - int ret; + char elbuf[32]; + errval ret; bzero(&scsi_cmd, sizeof(scsi_cmd)); scsi_cmd.op_code = READ_ELEMENT_STATUS; scsi_cmd.byte2 = type; - scsi_cmd.starting_element_addr[0]=(from>>8)&0xff; - scsi_cmd.starting_element_addr[1]=from&0xff; - scsi_cmd.number_of_elements[1]=1; - scsi_cmd.allocation_length[2]=32; - - if ((ret=ch_scsi_cmd(unit, - &scsi_cmd, - sizeof(scsi_cmd), - elbuf, - 32, - 100000, - flags) !=ESUCCESS)) { - *stat=ch_data[unit].lsterr; - bcopy(elbuf+16,data,16); - return ret; - } - bcopy(elbuf+16,data,16); /*Just a hack sh */ + scsi_cmd.starting_element_addr[0] = (from >> 8) & 0xff; + scsi_cmd.starting_element_addr[1] = from & 0xff; + scsi_cmd.number_of_elements[1] = 1; + scsi_cmd.allocation_length[2] = 32; + + if ((ret = scsi_scsi_cmd(ch_data[unit].sc_link, + (struct scsi_generic *) &scsi_cmd, + sizeof(scsi_cmd), + (u_char *) elbuf, + 32, + CHRETRIES, + 100000, + NULL, + SCSI_DATA_IN | flags) != ESUCCESS)) { + *stat = ch_data[unit].lsterr; + bcopy(elbuf + 16, data, 16); + return ret; + } + bcopy(elbuf + 16, data, 16); /*Just a hack sh */ return ret; } -ch_move(unit,stat,chm,from,to,flags) -int unit,chm,from,to,flags; -short *stat; +errval +ch_move(unit, stat, chm, from, to, flags) + u_int32 unit, chm, from, to, flags; + short *stat; { struct scsi_move_medium scsi_cmd; - int ret; + errval ret; bzero(&scsi_cmd, sizeof(scsi_cmd)); scsi_cmd.op_code = MOVE_MEDIUM; - scsi_cmd.transport_element_address[0]=(chm>>8)&0xff; - scsi_cmd.transport_element_address[1]=chm&0xff; - scsi_cmd.source_address[0]=(from>>8)&0xff; - scsi_cmd.source_address[1]=from&0xff; - scsi_cmd.destination_address[0]=(to>>8)&0xff; - scsi_cmd.destination_address[1]=to&0xff; - scsi_cmd.invert=(chm&CH_INVERT)?1:0; - if ((ret=ch_scsi_cmd(unit, - &scsi_cmd, - sizeof(scsi_cmd), - NULL, - 0, - 100000, - flags) !=ESUCCESS)) { - *stat=ch_data[unit].lsterr; - return ret; - } + scsi_cmd.transport_element_address[0] = (chm >> 8) & 0xff; + scsi_cmd.transport_element_address[1] = chm & 0xff; + scsi_cmd.source_address[0] = (from >> 8) & 0xff; + scsi_cmd.source_address[1] = from & 0xff; + scsi_cmd.destination_address[0] = (to >> 8) & 0xff; + scsi_cmd.destination_address[1] = to & 0xff; + scsi_cmd.invert = (chm & CH_INVERT) ? 1 : 0; + if ((ret = scsi_scsi_cmd(ch_data[unit].sc_link, + (struct scsi_generic *) &scsi_cmd, + sizeof(scsi_cmd), + NULL, + 0, + CHRETRIES, + 100000, + NULL, + flags) != ESUCCESS)) { + *stat = ch_data[unit].lsterr; + return ret; + } return ret; } -ch_position(unit,stat,chm,to,flags) -int unit,chm,to,flags; -short *stat; +errval +ch_position(unit, stat, chm, to, flags) + u_int32 unit, chm, to, flags; + short *stat; { struct scsi_position_to_element scsi_cmd; - int ret; + errval ret; bzero(&scsi_cmd, sizeof(scsi_cmd)); scsi_cmd.op_code = POSITION_TO_ELEMENT; - scsi_cmd.transport_element_address[0]=(chm>>8)&0xff; - scsi_cmd.transport_element_address[1]=chm&0xff; - scsi_cmd.source_address[0]=(to>>8)&0xff; - scsi_cmd.source_address[1]=to&0xff; - scsi_cmd.invert=(chm&CH_INVERT)?1:0; - if ((ret=ch_scsi_cmd(unit, - &scsi_cmd, - sizeof(scsi_cmd), - NULL, - 0, - 100000, - flags) !=ESUCCESS)) { - *stat=ch_data[unit].lsterr; - return ret; - } - return ret; -} - -/*******************************************************\ -* Check with the device that it is ok, (via scsi driver)* -\*******************************************************/ -ch_req_sense(unit, flags) -int flags; -{ - struct scsi_sense_data sense; - struct scsi_sense scsi_cmd; - - bzero(&scsi_cmd, sizeof(scsi_cmd)); - scsi_cmd.op_code = REQUEST_SENSE; - scsi_cmd.length = sizeof(sense); - - if (ch_scsi_cmd(unit, - &scsi_cmd, - sizeof(struct scsi_sense), - &sense, - sizeof(sense), - 100000, - flags | SCSI_DATA_IN) != 0) - { - return(FALSE); + scsi_cmd.transport_element_address[0] = (chm >> 8) & 0xff; + scsi_cmd.transport_element_address[1] = chm & 0xff; + scsi_cmd.source_address[0] = (to >> 8) & 0xff; + scsi_cmd.source_address[1] = to & 0xff; + scsi_cmd.invert = (chm & CH_INVERT) ? 1 : 0; + if ((ret = scsi_scsi_cmd(ch_data[unit].sc_link, + (struct scsi_generic *) &scsi_cmd, + sizeof(scsi_cmd), + NULL, + 0, + CHRETRIES, + 100000, + NULL, + flags) != ESUCCESS)) { + *stat = ch_data[unit].lsterr; + return ret; } - else - return(TRUE); -} - -/*******************************************************\ -* Get scsi driver to send a "are you ready" command * -\*******************************************************/ -ch_test_ready(unit,flags) -int unit,flags; -{ - struct scsi_test_unit_ready scsi_cmd; - - bzero(&scsi_cmd, sizeof(scsi_cmd)); - scsi_cmd.op_code = TEST_UNIT_READY; - - if (ch_scsi_cmd(unit, - &scsi_cmd, - sizeof(struct scsi_test_unit_ready), - 0, - 0, - 100000, - flags) != 0) { - return(FALSE); - } else - return(TRUE); + return ret; } - #ifdef __STDC__ #define b2tol(a) (((unsigned)(a##_1) << 8) + (unsigned)a##_0 ) #else #define b2tol(a) (((unsigned)(a/**/_1) << 8) + (unsigned)a/**/_0 ) #endif -/*******************************************************\ -* Get the scsi driver to send a full inquiry to the * -* device and use the results to fill out the global * -* parameter structure. * -\*******************************************************/ +/* + * Get the scsi driver to send a full inquiry to the + * device and use the results to fill out the global + * parameter structure. + */ +errval ch_mode_sense(unit, flags) -int unit,flags; + u_int32 unit, flags; { struct scsi_mode_sense scsi_cmd; - u_char scsi_sense[128]; /* Can't use scsi_mode_sense_data because of */ - /* missing block descriptor */ + u_char scsi_sense[128]; /* Can't use scsi_mode_sense_data because of + * missing block descriptor + */ u_char *b; - int i,l; - - /*******************************************************\ - * First check if we have it all loaded * - \*******************************************************/ - if (ch_info_valid[unit]==CH_KNOWN) return(TRUE); - /*******************************************************\ - * First do a mode sense * - \*******************************************************/ - ch_info_valid[unit] &= ~CH_KNOWN; - for(l=1;l>=0;l--) { - bzero(&scsi_cmd, sizeof(scsi_cmd)); - scsi_cmd.op_code = MODE_SENSE; - scsi_cmd.byte2 = SMS_DBD; - scsi_cmd.page = 0x3f; /* All Pages */ - scsi_cmd.length = sizeof(scsi_sense); - /*******************************************************\ - * do the command, but we don't need the results * - * just print them for our interest's sake * - \*******************************************************/ - if (ch_scsi_cmd(unit, - &scsi_cmd, - sizeof(struct scsi_mode_sense), - &scsi_sense, - sizeof(scsi_sense), - 5000, - flags | SCSI_DATA_IN) == 0) { - ch_info_valid[unit] = CH_KNOWN; - break; - } - } - if (ch_info_valid[unit]!=CH_KNOWN) { - if(!(flags & SCSI_SILENT)) + int32 i, l; + errval errcode; + struct scsi_link *sc_link = ch_data[unit].sc_link; + + /* + * First check if we have it all loaded + */ + if (sc_link->flags & SDEV_MEDIA_LOADED) + return 0; + + /* + * First do a mode sense + */ + /* sc_link->flags &= ~SDEV_MEDIA_LOADED; *//*XXX */ + bzero(&scsi_cmd, sizeof(scsi_cmd)); + scsi_cmd.op_code = MODE_SENSE; + scsi_cmd.byte2 = SMS_DBD; + scsi_cmd.page = 0x3f; /* All Pages */ + scsi_cmd.length = sizeof(scsi_sense); + + /* + * Read in the pages + */ + if (errcode = scsi_scsi_cmd(sc_link, + (struct scsi_generic *) &scsi_cmd, + sizeof(struct scsi_mode_sense), + (u_char *) & scsi_sense, + sizeof (scsi_sense), + CHRETRIES, + 5000, + NULL, + flags | SCSI_DATA_IN) != 0) { + if (!(flags & SCSI_SILENT)) printf("ch%d: could not mode sense\n", unit); - return(FALSE); + return (errcode); } - l=scsi_sense[0]-3; - b=&scsi_sense[4]; - /*****************************\ - * To avoid alignment problems * - \*****************************/ -/*FIX THIS FOR MSB */ + sc_link->flags |= SDEV_MEDIA_LOADED; + l = scsi_sense[0] - 3; + b = &scsi_sense[4]; + + /* + * To avoid alignment problems + */ +/* XXX - FIX THIS FOR MSB */ #define p2copy(valp) (valp[1]+ (valp[0]<<8));valp+=2 #define p4copy(valp) (valp[3]+ (valp[2]<<8) + (valp[1]<<16) + (valp[0]<<24));valp+=4 #if 0 - printf("\nmode_sense %d\n",l); - for(i=0;iopcode); - if(ch_data[unit].sc_sw) /* If we have a scsi driver */ - { - - xs = &(ch_scsi_xfer[unit]); - if(!(flags & SCSI_NOMASK)) - s = splbio(); - ch_xfer_block_wait[unit]++; /* there is someone waiting */ - while (xs->flags & INUSE) - { - sleep(&ch_xfer_block_wait[unit],PRIBIO+1); - } - ch_xfer_block_wait[unit]--; - xs->flags = INUSE; - if(!(flags & SCSI_NOMASK)) - splx(s); - - /*******************************************************\ - * Fill out the scsi_xfer structure * - \*******************************************************/ - xs->flags |= flags; - xs->adapter = ch_data[unit].ctlr; - xs->targ = ch_data[unit].targ; - xs->lu = ch_data[unit].lu; - xs->retries = CH_RETRIES; - xs->timeout = timeout; - xs->cmd = scsi_cmd; - xs->cmdlen = cmdlen; - xs->data = data_addr; - xs->datalen = datalen; - xs->resid = datalen; - xs->when_done = (flags & SCSI_NOMASK) - ?(int (*)())0 - :ch_done; - xs->done_arg = unit; - xs->done_arg2 = (int)xs; -retry: xs->error = XS_NOERROR; - xs->bp = 0; - ch_data[unit].lsterr=0; - retval = (*(ch_data[unit].sc_sw->scsi_cmd))(xs); - switch(retval) - { - case SUCCESSFULLY_QUEUED: - while(!(xs->flags & ITSDONE)) - sleep(xs,PRIBIO+1); - - case HAD_ERROR: - case COMPLETE: - switch(xs->error) - { - case XS_NOERROR: - retval = ESUCCESS; - break; - case XS_SENSE: - retval = (ch_interpret_sense(unit,xs)); - break; - case XS_DRIVER_STUFFUP: - retval = EIO; - break; - case XS_TIMEOUT: - if(xs->retries-- ) - { - xs->flags &= ~ITSDONE; - goto retry; - } - retval = EIO; - break; - case XS_BUSY: - if(xs->retries-- ) - { - xs->flags &= ~ITSDONE; - goto retry; - } - retval = EIO; - break; - default: - retval = EIO; - printf("ch%d: unknown error category from scsi driver\n" - ,unit); - break; - } + for (i = 0; i < l;) { + u_int32 pc = (*b++) & 0x3f; + u_int32 pl = *b++; + u_char *bb = b; + switch (pc) { + case 0x1d: + ch_data[unit].chmo = p2copy(bb); + ch_data[unit].chms = p2copy(bb); + ch_data[unit].sloto = p2copy(bb); + ch_data[unit].slots = p2copy(bb); + ch_data[unit].imexo = p2copy(bb); + ch_data[unit].imexs = p2copy(bb); + ch_data[unit].driveo = p2copy(bb); + ch_data[unit].drives = p2copy(bb); break; - case TRY_AGAIN_LATER: - if(xs->retries-- ) - { - xs->flags &= ~ITSDONE; - goto retry; - } - retval = EIO; + case 0x1e: + ch_data[unit].rot = (*b) & 1; + break; + case 0x1f: + ch_data[unit].stor = *b & 0xf; + bb += 2; + ch_data[unit].stor = p4copy(bb); break; default: - retval = EIO; - } - xs->flags = 0; /* it's free! */ - chstart(unit); - } - else - { - printf("ch%d: not set up\n",unit); - return(EINVAL); - } - return(retval); -} -/***************************************************************\ -* Look at the returned sense and act on the error and detirmine * -* The unix error number to pass back... (0 = report no error) * -\***************************************************************/ - -int ch_interpret_sense(unit,xs) -int unit; -struct scsi_xfer *xs; -{ - struct scsi_sense_data *sense; - int key; - int silent = xs->flags & SCSI_SILENT; - - /***************************************************************\ - * If errors are ok, report a success * - \***************************************************************/ - if(xs->flags & SCSI_ERR_OK) return(ESUCCESS); - - /***************************************************************\ - * Get the sense fields and work out what CLASS * - \***************************************************************/ - sense = &(xs->sense); - switch(sense->error_code & SSD_ERRCODE) - { - /***************************************************************\ - * If it's class 7, use the extended stuff and interpret the key * - \***************************************************************/ - case 0x70: - { - key=sense->ext.extended.flags & SSD_KEY; - if(sense->ext.extended.flags & SSD_ILI) - if(!silent) - { - printf("length error "); - } - if(sense->error_code & SSD_ERRCODE_VALID) - xs->resid = ntohl(*((long *)sense->ext.extended.info)); - if(xs->bp) - { - xs->bp->b_flags |= B_ERROR; - return(ESUCCESS); - } - if(sense->ext.extended.flags & SSD_EOM) - if(!silent) printf("end of medium "); - if(sense->ext.extended.flags & SSD_FILEMARK) - if(!silent) printf("filemark "); - if(ch_debug) - { - printf("code%x valid%x\n" - ,sense->error_code & SSD_ERRCODE - ,sense->error_code & SSD_ERRCODE_VALID); - printf("seg%x key%x ili%x eom%x fmark%x\n" - ,sense->ext.extended.segment - ,sense->ext.extended.flags & SSD_KEY - ,sense->ext.extended.flags & SSD_ILI - ,sense->ext.extended.flags & SSD_EOM - ,sense->ext.extended.flags & SSD_FILEMARK); - printf("info: %x %x %x %x followed by %d extra bytes\n" - ,sense->ext.extended.info[0] - ,sense->ext.extended.info[1] - ,sense->ext.extended.info[2] - ,sense->ext.extended.info[3] - ,sense->ext.extended.extra_len); - printf("extra: %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x\n" - ,sense->ext.extended.extra_bytes[0] - ,sense->ext.extended.extra_bytes[1] - ,sense->ext.extended.extra_bytes[2] - ,sense->ext.extended.extra_bytes[3] - ,sense->ext.extended.extra_bytes[4] - ,sense->ext.extended.extra_bytes[5] - ,sense->ext.extended.extra_bytes[6] - ,sense->ext.extended.extra_bytes[7] - ,sense->ext.extended.extra_bytes[8] - ,sense->ext.extended.extra_bytes[9] - ,sense->ext.extended.extra_bytes[10] - ,sense->ext.extended.extra_bytes[11] - ,sense->ext.extended.extra_bytes[12] - ,sense->ext.extended.extra_bytes[13] - ,sense->ext.extended.extra_bytes[14] - ,sense->ext.extended.extra_bytes[15]); - - } - switch(key) - { - case 0x0: - return(ESUCCESS); - case 0x1: - if(!silent) - { - printf("ch%d: soft error(corrected)", unit); - if(sense->error_code & SSD_ERRCODE_VALID) - { - printf(" block no. %d (decimal)", - (sense->ext.extended.info[0] <<24)| - (sense->ext.extended.info[1] <<16)| - (sense->ext.extended.info[2] <<8)| - (sense->ext.extended.info[3] )); - } - printf("\n"); - } - return(ESUCCESS); - case 0x2: - if(!silent) printf("ch%d: not ready\n", unit); - ch_data[unit].lsterr=(sense->ext.extended.info[12]<<8)| - sense->ext.extended.info[13] ; - return(ENODEV); - case 0x3: - if(!silent) - { - printf("ch%d: medium error", unit); - if(sense->error_code & SSD_ERRCODE_VALID) - { - printf(" block no. %d (decimal)", - (sense->ext.extended.info[0] <<24)| - (sense->ext.extended.info[1] <<16)| - (sense->ext.extended.info[2] <<8)| - (sense->ext.extended.info[3] )); - } - printf("\n"); - } - return(EIO); - case 0x4: - if(!silent) printf("ch%d: non-media hardware failure\n", - unit); - ch_data[unit].lsterr=(sense->ext.extended.info[12]<<8)| - sense->ext.extended.info[13] ; - return(EIO); - case 0x5: - if(!silent) printf("ch%d: illegal request\n", unit); - ch_data[unit].lsterr=(sense->ext.extended.info[12]<<8)| - sense->ext.extended.info[13] ; - return(EINVAL); - case 0x6: - if(!silent) printf("ch%d: Unit attention\n", unit); - ch_data[unit].lsterr=(sense->ext.extended.info[12]<<8)| - sense->ext.extended.info[13] ; - ch_info_valid[unit] = FALSE; - if (ch_data[unit].flags & CH_OPEN) /* TEMP!!!! */ - return(EIO); - else - return(ESUCCESS); - case 0x7: - if(!silent) - { - printf("ch%d: attempted protection violation" - , unit); - if(sense->error_code & SSD_ERRCODE_VALID) - { - printf(" block no. %d (decimal)\n", - (sense->ext.extended.info[0] <<24)| - (sense->ext.extended.info[1] <<16)| - (sense->ext.extended.info[2] <<8)| - (sense->ext.extended.info[3] )); - } - printf("\n"); - } - return(EACCES); - case 0x8: - if(!silent) - { - printf("ch%d: block wrong state (worm)" - , unit); - if(sense->error_code & SSD_ERRCODE_VALID) - { - printf(" block no. %d (decimal)", - (sense->ext.extended.info[0] <<24)| - (sense->ext.extended.info[1] <<16)| - (sense->ext.extended.info[2] <<8)| - (sense->ext.extended.info[3] )); - } - printf("\n"); - } - return(EIO); - case 0x9: - if(!silent) printf("ch%d: vendor unique\n", unit); - return(EIO); - case 0xa: - if(!silent) printf("ch%d: copy aborted\n", unit); - return(EIO); - case 0xb: - if(!silent) printf("ch%d: command aborted\n", unit); - ch_data[unit].lsterr=(sense->ext.extended.info[12]<<8)| - sense->ext.extended.info[13] ; - return(EIO); - case 0xc: - if(!silent) - { - printf("ch%d: search returned", unit); - if(sense->error_code & SSD_ERRCODE_VALID) - { - printf(" block no. %d (decimal)", - (sense->ext.extended.info[0] <<24)| - (sense->ext.extended.info[1] <<16)| - (sense->ext.extended.info[2] <<8)| - (sense->ext.extended.info[3] )); - } - printf("\n"); - } - return(ESUCCESS); - case 0xd: - if(!silent) printf("ch%d: volume overflow\n", unit); - return(ENOSPC); - case 0xe: - if(!silent) - { - printf("ch%d: verify miscompare", unit); - if(sense->error_code & SSD_ERRCODE_VALID) - { - printf(" block no. %d (decimal)", - (sense->ext.extended.info[0] <<24)| - (sense->ext.extended.info[1] <<16)| - (sense->ext.extended.info[2] <<8)| - (sense->ext.extended.info[3] )); - } - printf("\n"); - } - return(EIO); - case 0xf: - if(!silent) printf("ch%d: unknown error key\n", unit); - return(EIO); - } - break; - } - /***************************************************************\ - * If it's NOT class 7, just report it. * - \***************************************************************/ - default: - { - if(!silent) - { - printf("ch%d: error code %d", - unit, - sense->error_code & SSD_ERRCODE); - if(sense->error_code & SSD_ERRCODE_VALID) - { - printf(" block no. %d (decimal)", - (sense->ext.unextended.blockhi <<16), - + (sense->ext.unextended.blockmed <<8), - + (sense->ext.unextended.blocklow )); - } - printf("\n"); - } + break; } - return(EIO); + b += pl; + i += pl + 2; } + SC_DEBUG(sc_link, SDEV_DB2, + (" cht(%d-%d)slot(%d-%d)imex(%d-%d)cts(%d-%d) %s rotate\n", + ch_data[unit].chmo, ch_data[unit].chms, + ch_data[unit].sloto, ch_data[unit].slots, + ch_data[unit].imexo, ch_data[unit].imexs, + ch_data[unit].driveo, ch_data[unit].drives, + ch_data[unit].rot ? "can" : "can't")); + return (0); } - - - diff --git a/sys/scsi/scsi_all.h b/sys/scsi/scsi_all.h index 8de19b04d6..2e7bdcff7e 100644 --- a/sys/scsi/scsi_all.h +++ b/sys/scsi/scsi_all.h @@ -18,12 +18,11 @@ * * Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992 * - * $Id: scsi_all.h,v 1.4 1993/08/21 20:01:51 rgrimes Exp $ + * $Id: scsi_all.h,v 2.0 93/10/06 21:10:28 julian Exp Locker: julian $ */ -#ifndef _SCSI_SCSI_ALL_H_ -#define _SCSI_SCSI_ALL_H_ 1 - +#ifndef _SCSI_SCSI_ALL_H +#define _SCSI_SCSI_ALL_H 1 /* * SCSI command format */ @@ -31,10 +30,10 @@ /* * Define dome bits that are in ALL (or a lot of) scsi commands */ -#define SCSI_CTL_LINK 0x01 -#define SCSI_CTL_FLAG 0x02 -#define SCSI_CTL_VENDOR 0xC0 -#define SCSI_CMD_LUN 0xA0 /*these two should not be needed*/ +#define SCSI_CTL_LINK 0x01 +#define SCSI_CTL_FLAG 0x02 +#define SCSI_CTL_VENDOR 0xC0 +#define SCSI_CMD_LUN 0xA0 /* these two should not be needed */ #define SCSI_CMD_LUN_SHIFT 5 /* LUN in the cmd is no longer SCSI */ @@ -103,7 +102,7 @@ struct scsi_mode_sense struct scsi_mode_sense_big { u_char op_code; - u_char byte2; /* same bits as small version */ + u_char byte2; /* same bits as small version */ u_char page; /* same bits as small version */ u_char unused[4]; u_char length[2]; @@ -124,7 +123,7 @@ struct scsi_mode_select struct scsi_mode_select_big { u_char op_code; - u_char byte2; /* same bits as small version */ + u_char byte2; /* same bits as small version */ u_char unused[5]; u_char length[2]; u_char control; @@ -159,6 +158,19 @@ struct scsi_prevent #define PR_PREVENT 0x01 #define PR_ALLOW 0x00 +struct scsi_changedef +{ + u_char op_code; + u_char byte2; + u_char unused1; + u_char how; + u_char unused[4]; + u_char datalen; + u_char control; +}; +#define SC_SCSI_1 0x01 +#define SC_SCSI_2 0x03 + /* * Opcodes */ @@ -173,6 +185,7 @@ struct scsi_prevent #define RELEASE 0x17 #define PREVENT_ALLOW 0x1e #define POSITION_TO_ELEMENT 0x2b +#define CHANGE_DEFINITION 0x40 #define MODE_SENSE_BIG 0x54 #define MODE_SELECT_BIG 0x55 #define MOVE_MEDIUM 0xa5 @@ -234,62 +247,62 @@ struct scsi_inquiry_data struct scsi_sense_data { - u_char error_code; /* same bits as new version */ +/* 1*/ u_char error_code; /* same bits as new version */ union { struct { - u_char blockhi; - u_char blockmed; - u_char blocklow; +/* 2*/ u_char blockhi; +/* 3*/ u_char blockmed; +/* 4*/ u_char blocklow; } unextended; struct { - u_char segment; - u_char flags; /* same bits as new version */ - u_char info[4]; - u_char extra_len; +/* 2*/ u_char segment; +/* 3*/ u_char flags; /* same bits as new version */ +/* 7*/ u_char info[4]; +/* 8*/ u_char extra_len; /* allocate enough room to hold new stuff - ( by increasing 16 to 26 below) */ - u_char extra_bytes[26]; + ( by increasing 16 to 24 below) */ +/*32*/ u_char extra_bytes[24]; } extended; }ext; -}; +}; /* total of 32 bytes */ struct scsi_sense_data_new { - u_char error_code; +/* 1*/ u_char error_code; #define SSD_ERRCODE 0x7F #define SSD_ERRCODE_VALID 0x80 union { - struct /* this is depreciated, the standard says "DON'T"*/ + struct /* this is deprecated, the standard says "DON'T"*/ { - u_char blockhi; - u_char blockmed; - u_char blocklow; +/* 2*/ u_char blockhi; +/* 3*/ u_char blockmed; +/* 4*/ u_char blocklow; } unextended; struct { - u_char segment; - u_char flags; +/* 2*/ u_char segment; +/* 3*/ u_char flags; #define SSD_KEY 0x0F #define SSD_ILI 0x20 #define SSD_EOM 0x40 #define SSD_FILEMARK 0x80 - u_char info[4]; - u_char extra_len; - u_char cmd_spec_info[4]; - u_char add_sense_code; - u_char add_sense_code_qual; - u_char fru; - u_char sense_key_spec_1; +/* 7*/ u_char info[4]; +/* 8*/ u_char extra_len; +/*12*/ u_char cmd_spec_info[4]; +/*13*/ u_char add_sense_code; +/*14*/ u_char add_sense_code_qual; +/*15*/ u_char fru; +/*16*/ u_char sense_key_spec_1; #define SSD_SCS_VALID 0x80 - u_char sense_key_spec_2; - u_char sense_key_spec_3; - u_char extra_bytes[16]; +/*17*/ u_char sense_key_spec_2; +/*18*/ u_char sense_key_spec_3; +/*32*/ u_char extra_bytes[14]; } extended; }ext; -}; +}; /* total of 32 bytes */ struct blk_desc { @@ -324,4 +337,4 @@ struct scsi_mode_header_big #define SCSI_CHECK 0x02 #define SCSI_BUSY 0x08 #define SCSI_INTERM 0x10 -#endif /* _SCSI_SCSI_ALL_H_ */ +#endif /*_SCSI_SCSI_ALL_H*/ diff --git a/sys/scsi/scsi_base.c b/sys/scsi/scsi_base.c new file mode 100644 index 0000000000..a1361ec256 --- /dev/null +++ b/sys/scsi/scsi_base.c @@ -0,0 +1,852 @@ +/* + * Written By Julian ELischer + * Copyright julian Elischer 1993. + * Permission is granted to use or redistribute this file in any way as long + * as this notice remains. Julian Elischer does not guarantee that this file + * is totally correct for any given task and users of this file must + * accept responsibility for any damage that occurs from the application of this + * file. + * + * Written by Julian Elischer (julian@dialix.oz.au) + * $Id: scsi_base.c,v 2.4 93/10/16 00:58:43 julian Exp Locker: julian $ + */ + +#define SPLSD splbio +#define ESUCCESS 0 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef NetBSD +#ifdef DDB +int Debugger(); +#else /* DDB */ +#define Debugger() +#endif /* DDB */ +#else /* NetBSD */ +#include +#if NDDB > 0 +int Debugger(); +#else /* NDDB > 0 */ +#define Debugger() +#endif /* NDDB > 0 */ +#endif + +void sc_print_addr __P((struct scsi_link *sc_link)); + +struct scsi_xfer *next_free_xs; + +/* + * Get a scsi transfer structure for the caller. Charge the structure + * to the device that is referenced by the sc_link structure. If the + * sc_link structure has no 'credits' then the device already has the + * maximum number or outstanding operations under way. In this stage, + * wait on the structure so that when one is freed, we are awoken again + * If the SCSI_NOSLEEP flag is set, then do not wait, but rather, return + * a NULL pointer, signifying that no slots were available + * Note in the link structure, that we are waiting on it. + */ + +struct scsi_xfer * +get_xs(sc_link, flags) + struct scsi_link *sc_link; /* who to charge the xs to */ + u_int32 flags; /* if this call can sleep */ +{ + struct scsi_xfer *xs; + u_int32 s; + + SC_DEBUG(sc_link, SDEV_DB3, ("get_xs\n")); + s = splbio(); + while (!sc_link->opennings) { + SC_DEBUG(sc_link, SDEV_DB3, ("sleeping\n")); + if (flags & SCSI_NOSLEEP) { + splx(s); + return 0; + } + sc_link->flags |= SDEV_WAITING; + sleep(sc_link, PRIBIO); + } + sc_link->opennings--; + if (xs = next_free_xs) { + next_free_xs = xs->next; + splx(s); + } else { + splx(s); + SC_DEBUG(sc_link, SDEV_DB3, ("making\n")); + xs = malloc(sizeof(*xs), M_TEMP, + ((flags & SCSI_NOSLEEP) ? M_NOWAIT : M_WAITOK)); + if (xs == NULL) { + sc_print_addr(sc_link); + printf("cannot allocate scsi xs\n"); + return (NULL); + } + } + SC_DEBUG(sc_link, SDEV_DB3, ("returning\n")); + xs->sc_link = sc_link; + return (xs); +} + +/* + * Given a scsi_xfer struct, and a device (referenced through sc_link) + * return the struct to the free pool and credit the device with it + * If another process is waiting for an xs, do a wakeup, let it proceed + */ +void +free_xs(xs, sc_link, flags) + struct scsi_xfer *xs; + struct scsi_link *sc_link; /* who to credit for returning it */ + u_int32 flags; +{ + xs->next = next_free_xs; + next_free_xs = xs; + + SC_DEBUG(sc_link, SDEV_DB3, ("free_xs\n")); + /* if was 0 and someone waits, wake them up */ + if ((!sc_link->opennings++) && (sc_link->flags & SDEV_WAITING)) { + wakeup(sc_link); + } else { + if (sc_link->device->start) { + SC_DEBUG(sc_link, SDEV_DB2, ("calling private start()\n")); + (*(sc_link->device->start)) (sc_link->dev_unit); + } + } +} + +/* + * Find out from the device what its capacity is. + */ +u_int32 +scsi_size(sc_link, flags) + struct scsi_link *sc_link; + u_int32 flags; +{ + struct scsi_read_cap_data rdcap; + struct scsi_read_capacity scsi_cmd; + u_int32 size; + + /* + * make up a scsi command and ask the scsi driver to do + * it for you. + */ + bzero(&scsi_cmd, sizeof(scsi_cmd)); + scsi_cmd.op_code = READ_CAPACITY; + + /* + * If the command works, interpret the result as a 4 byte + * number of blocks + */ + if (scsi_scsi_cmd(sc_link, + (struct scsi_generic *) &scsi_cmd, + sizeof(scsi_cmd), + (u_char *) & rdcap, + sizeof(rdcap), + 2, + 20000, + NULL, + flags | SCSI_DATA_IN) != 0) { + + sc_print_addr(sc_link); + printf("could not get size\n"); + return (0); + } else { + size = rdcap.addr_0 + 1; + size += rdcap.addr_1 << 8; + size += rdcap.addr_2 << 16; + size += rdcap.addr_3 << 24; + } + return (size); +} + +/* + * Get scsi driver to send a "are you ready?" command + */ +errval +scsi_test_unit_ready(sc_link, flags) + struct scsi_link *sc_link; + u_int32 flags; +{ + struct scsi_test_unit_ready scsi_cmd; + + bzero(&scsi_cmd, sizeof(scsi_cmd)); + scsi_cmd.op_code = TEST_UNIT_READY; + + return (scsi_scsi_cmd(sc_link, + (struct scsi_generic *) &scsi_cmd, + sizeof(scsi_cmd), + 0, + 0, + 2, + 100000, + NULL, + flags)); +} + +/* + * Do a scsi operation, asking a device to run as SCSI-II if it can. + */ +errval +scsi_change_def(sc_link, flags) + struct scsi_link *sc_link; + u_int32 flags; +{ + struct scsi_changedef scsi_cmd; + + bzero(&scsi_cmd, sizeof(scsi_cmd)); + scsi_cmd.op_code = CHANGE_DEFINITION; + scsi_cmd.how = SC_SCSI_2; + + return (scsi_scsi_cmd(sc_link, + (struct scsi_generic *) &scsi_cmd, + sizeof(scsi_cmd), + 0, + 0, + 2, + 100000, + NULL, + flags)); +} + +/* + * Do a scsi operation asking a device what it is + * Use the scsi_cmd routine in the switch table. + */ +errval +scsi_inquire(sc_link, inqbuf, flags) + struct scsi_link *sc_link; + struct scsi_inquiry_data *inqbuf; + u_int32 flags; +{ + struct scsi_inquiry scsi_cmd; + + bzero(&scsi_cmd, sizeof(scsi_cmd)); + scsi_cmd.op_code = INQUIRY; + scsi_cmd.length = sizeof(struct scsi_inquiry_data); + + return (scsi_scsi_cmd(sc_link, + (struct scsi_generic *) &scsi_cmd, + sizeof(scsi_cmd), + (u_char *) inqbuf, + sizeof(struct scsi_inquiry_data), + 2, + 100000, + NULL, + SCSI_DATA_IN | flags)); +} + +/* + * Prevent or allow the user to remove the media + */ +errval +scsi_prevent(sc_link, type, flags) + struct scsi_link *sc_link; + u_int32 type, flags; +{ + struct scsi_prevent scsi_cmd; + + bzero(&scsi_cmd, sizeof(scsi_cmd)); + scsi_cmd.op_code = PREVENT_ALLOW; + scsi_cmd.how = type; + return (scsi_scsi_cmd(sc_link, + (struct scsi_generic *) &scsi_cmd, + sizeof(scsi_cmd), + 0, + 0, + 2, + 5000, + NULL, + flags)); +} + +/* + * Get scsi driver to send a "start up" command + */ +errval +scsi_start_unit(sc_link, flags) + struct scsi_link *sc_link; + u_int32 flags; +{ + struct scsi_start_stop scsi_cmd; + + bzero(&scsi_cmd, sizeof(scsi_cmd)); + scsi_cmd.op_code = START_STOP; + scsi_cmd.how = SSS_START; + + return (scsi_scsi_cmd(sc_link, + (struct scsi_generic *) &scsi_cmd, + sizeof(scsi_cmd), + 0, + 0, + 2, + 6000, + NULL, + flags)); +} + +/* + * This routine is called by the scsi interrupt when the transfer is complete. + */ +void +scsi_done(xs) + struct scsi_xfer *xs; +{ + struct scsi_link *sc_link = xs->sc_link; + struct buf *bp = xs->bp; + errval retval; + + SC_DEBUG(sc_link, SDEV_DB2, ("scsi_done\n")); +#ifdef SCSIDEBUG + if (sc_link->flags & SDEV_DB1) + { + show_scsi_cmd(xs); + } +#endif /*SCSIDEBUG */ + /* + * If it's a user level request, bypass all usual completion processing, + * let the user work it out.. We take reponsibility for freeing the + * xs when the user returns. (and restarting the device's queue). + */ + if (xs->flags & SCSI_USER) { + biodone(xs->bp); +#ifdef NOTNOW + SC_DEBUG(sc_link, SDEV_DB3, ("calling user done()\n")); + scsi_user_done(xs); /* to take a copy of the sense etc. */ + SC_DEBUG(sc_link, SDEV_DB3, ("returned from user done()\n ")); +#endif + free_xs(xs, sc_link, SCSI_NOSLEEP); /* restarts queue too */ + SC_DEBUG(sc_link, SDEV_DB3, ("returning to adapter\n")); + return; + } + /* + * If the device has it's own done routine, call it first. + * If it returns a legit error value, return that, otherwise + * it wants us to continue with normal processing. + */ + + if (sc_link->device->done) { + SC_DEBUG(sc_link, SDEV_DB2, ("calling private done()\n")); + retval = (*sc_link->device->done) (xs); + if (retval == -1) { + free_xs(xs, sc_link, SCSI_NOSLEEP); /*XXX */ + return; /* it did it all, finish up */ + } + if (retval == -2) { + return; /* it did it all, finish up */ + } + SC_DEBUG(sc_link, SDEV_DB3, ("continuing with generic done()\n")); + } + if ((bp = xs->bp) == NULL) { + /* + * if it's a normal upper level request, then ask + * the upper level code to handle error checking + * rather than doing it here at interrupt time + */ + wakeup(xs); + return; + } + /* + * Go and handle errors now. + * If it returns -1 then we should RETRY + */ + if ((retval = sc_err1(xs)) == -1) { + if ((*(sc_link->adapter->scsi_cmd)) (xs) + == SUCCESSFULLY_QUEUED) { /* don't wake the job, ok? */ + return; + } + xs->flags |= ITSDONE; + } + free_xs(xs, sc_link, SCSI_NOSLEEP); /* does a start if needed */ + biodone(bp); +} + +/* + * ask the scsi driver to perform a command for us. + * tell it where to read/write the data, and how + * long the data is supposed to be. If we have a buf + * to associate with the transfer, we need that too. + */ +errval +scsi_scsi_cmd(sc_link, scsi_cmd, cmdlen, data_addr, datalen, + retries, timeout, bp, flags) + struct scsi_link *sc_link; + struct scsi_generic *scsi_cmd; + u_int32 cmdlen; + u_char *data_addr; + u_int32 datalen; + u_int32 retries; + u_int32 timeout; + struct buf *bp; + u_int32 flags; +{ + struct scsi_xfer *xs; + errval retval; + u_int32 s; + + if (bp) flags |= SCSI_NOSLEEP; + SC_DEBUG(sc_link, SDEV_DB2, ("scsi_cmd\n")); + + xs = get_xs(sc_link, flags); /* should wait unless booting */ + if (!xs) return (ENOMEM); + /* + * Fill out the scsi_xfer structure. We don't know whose context + * the cmd is in, so copy it. + */ + bcopy(scsi_cmd, &(xs->cmdstore), cmdlen); + xs->flags = INUSE | flags; + xs->sc_link = sc_link; + xs->retries = retries; + xs->timeout = timeout; + xs->cmd = &xs->cmdstore; + xs->cmdlen = cmdlen; + xs->data = data_addr; + xs->datalen = datalen; + xs->resid = datalen; + xs->bp = bp; +/*XXX*/ /*use constant not magic number */ + if (datalen && ((caddr_t) data_addr < (caddr_t) 0xfe000000)) { + if (bp) { + printf("Data buffered space not in kernel context\n"); +#ifdef SCSIDEBUG + show_scsi_cmd(xs); +#endif /* SCSIDEBUG */ + retval = EFAULT; + goto bad; + } + xs->data = malloc(datalen, M_TEMP, M_WAITOK); + /* I think waiting is ok *//*XXX */ + switch (flags & (SCSI_DATA_IN | SCSI_DATA_OUT)) { + case 0: + printf("No direction flags, assuming both\n"); +#ifdef SCSIDEBUG + show_scsi_cmd(xs); +#endif /* SCSIDEBUG */ + case SCSI_DATA_IN | SCSI_DATA_OUT: /* weird */ + case SCSI_DATA_OUT: + bcopy(data_addr, xs->data, datalen); + break; + case SCSI_DATA_IN: + bzero(xs->data, datalen); + } + } +retry: + xs->error = XS_NOERROR; +#ifdef PARANOID + if (datalen && ((caddr_t) xs->data < (caddr_t) 0xfe000000)) { + printf("It's still wrong!\n"); + } +#endif /*PARANOID*/ +#ifdef SCSIDEBUG + if (sc_link->flags & SDEV_DB3) show_scsi_xs(xs); +#endif /* SCSIDEBUG */ + /* + * Do the transfer. If we are polling we will return: + * COMPLETE, Was poll, and scsi_done has been called + * TRY_AGAIN_LATER, Adapter short resources, try again + * + * if under full steam (interrupts) it will return: + * SUCCESSFULLY_QUEUED, will do a wakeup when complete + * TRY_AGAIN_LATER, (as for polling) + * After the wakeup, we must still check if it succeeded + * + * If we have a bp however, all the error proccessing + * and the buffer code both expect us to return straight + * to them, so as soon as the command is queued, return + */ + + retval = (*(sc_link->adapter->scsi_cmd)) (xs); + + switch (retval) { + case SUCCESSFULLY_QUEUED: + if (bp) + return retval; /* will sleep (or not) elsewhere */ + s = splbio(); + while (!(xs->flags & ITSDONE)) + sleep(xs, PRIBIO + 1); + splx(s); + /* fall through to check success of completed command */ + case COMPLETE: /* Polling command completed ok */ +/*XXX*/ case HAD_ERROR: /* Polling command completed with error */ + SC_DEBUG(sc_link, SDEV_DB3, ("back in cmd()\n")); + if ((retval = sc_err1(xs)) == -1) + goto retry; + break; + + case TRY_AGAIN_LATER: /* adapter resource shortage */ + SC_DEBUG(sc_link, SDEV_DB3, ("will try again \n")); + /* should sleep 1 sec here */ + if (xs->retries--) { + xs->flags &= ~ITSDONE; + goto retry; + } + default: + retval = EIO; + } + /* + * If we had to copy the data out of the user's context, + * then do the other half (copy it back or whatever) + * and free the memory buffer + */ + if (datalen && (xs->data != data_addr)) { + switch (flags & (SCSI_DATA_IN | SCSI_DATA_OUT)) { + case 0: + case SCSI_DATA_IN | SCSI_DATA_OUT: /* weird */ + case SCSI_DATA_IN: + bcopy(xs->data, data_addr, datalen); + break; + } + free(xs->data, M_TEMP); + } + /* + * we have finished with the xfer stuct, free it and + * check if anyone else needs to be started up. + */ +bad: + free_xs(xs, sc_link, flags); /* includes the 'start' op */ + if (bp && retval) { + bp->b_error = retval; + bp->b_flags |= B_ERROR; + biodone(bp); + } + return (retval); +} + +errval +sc_err1(xs) + struct scsi_xfer *xs; +{ + struct buf *bp = xs->bp; + errval retval; + + SC_DEBUG(xs->sc_link, SDEV_DB3, ("sc_err1,err = 0x%x \n", xs->error)); + /* + * If it has a buf, we might be working with + * a request from the buffer cache or some other + * piece of code that requires us to process + * errors at inetrrupt time. We have probably + * been called by scsi_done() + */ + switch (xs->error) { + case XS_NOERROR: /* nearly always hit this one */ + retval = ESUCCESS; + if (bp) { + bp->b_error = 0; + bp->b_resid = 0; + } + break; + + case XS_SENSE: + if (bp) { + bp->b_error = 0; + bp->b_resid = 0; + if (retval = (scsi_interpret_sense(xs))) { + bp->b_flags |= B_ERROR; + bp->b_error = retval; + bp->b_resid = bp->b_bcount; + } + SC_DEBUG(xs->sc_link, SDEV_DB3, + ("scsi_interpret_sense (bp) returned %d\n", retval)); + } else { + retval = (scsi_interpret_sense(xs)); + SC_DEBUG(xs->sc_link, SDEV_DB3, + ("scsi_interpret_sense (no bp) returned %d\n", retval)); + } + break; + + case XS_BUSY: + /*should somehow arange for a 1 sec delay here (how?) */ + case XS_TIMEOUT: + /* + * If we can, resubmit it to the adapter. + */ + if (xs->retries--) { + xs->error = XS_NOERROR; + xs->flags &= ~ITSDONE; + goto retry; + } + /* fall through */ + case XS_DRIVER_STUFFUP: + if (bp) { + bp->b_flags |= B_ERROR; + bp->b_error = EIO; + } + retval = EIO; + break; + default: + retval = EIO; + sc_print_addr(xs->sc_link); + printf("unknown error category from scsi driver\n"); + } + return retval; +retry: + return (-1); +} + +/* + * Look at the returned sense and act on the error, determining + * the unix error number to pass back. (0 = report no error) + * + * THIS IS THE DEFAULT ERROR HANDLER + */ +errval +scsi_interpret_sense(xs) + struct scsi_xfer *xs; +{ + struct scsi_sense_data *sense; + struct scsi_link *sc_link = xs->sc_link; + u_int32 key; + u_int32 silent; + u_int32 info; + errval errcode; + + static char *error_mes[] = + {"soft error (corrected)", + "not ready", "medium error", + "non-media hardware failure", "illegal request", + "unit attention", "readonly device", + "no data found", "vendor unique", + "copy aborted", "command aborted", + "search returned equal", "volume overflow", + "verify miscompare", "unknown error key" + }; + + /* + * If the flags say errs are ok, then always return ok. + */ + if (xs->flags & SCSI_ERR_OK) + return (ESUCCESS); + + sense = &(xs->sense); +#ifdef SCSIDEBUG + if (sc_link->flags & SDEV_DB1) { + u_int32 count = 0; + printf("code%x valid%x ", + sense->error_code & SSD_ERRCODE, + sense->error_code & SSD_ERRCODE_VALID ? 1 : 0); + printf("seg%x key%x ili%x eom%x fmark%x\n", + sense->ext.extended.segment, + sense->ext.extended.flags & SSD_KEY, + sense->ext.extended.flags & SSD_ILI ? 1 : 0, + sense->ext.extended.flags & SSD_EOM ? 1 : 0, + sense->ext.extended.flags & SSD_FILEMARK ? 1 : 0); + printf("info: %x %x %x %x followed by %d extra bytes\n", + sense->ext.extended.info[0], + sense->ext.extended.info[1], + sense->ext.extended.info[2], + sense->ext.extended.info[3], + sense->ext.extended.extra_len); + printf("extra: "); + while (count < sense->ext.extended.extra_len) { + printf("%x ", sense->ext.extended.extra_bytes[count++]); + } + printf("\n"); + } +#endif /*SCSIDEBUG */ + /* + * If the device has it's own error handler, call it first. + * If it returns a legit error value, return that, otherwise + * it wants us to continue with normal error processing. + */ + if (sc_link->device->err_handler) { + SC_DEBUG(sc_link, SDEV_DB2, ("calling private err_handler()\n")); + errcode = (*sc_link->device->err_handler) (xs); + if (errcode != -1) + return errcode; /* errcode >= 0 better ? */ + } + /* otherwise use the default */ + silent = (xs->flags & SCSI_SILENT); + switch (sense->error_code & SSD_ERRCODE) { + /* + * If it's code 70, use the extended stuff and interpret the key + */ + case 0x71: /* delayed error */ + sc_print_addr(sc_link); + key = sense->ext.extended.flags & SSD_KEY; + printf(" DELAYED ERROR, key = 0x%x\n", key); + case 0x70: + if (sense->error_code & SSD_ERRCODE_VALID) { + info = ntohl(*((long *) sense->ext.extended.info)); + } else { + info = 0; + } + key = sense->ext.extended.flags & SSD_KEY; + + if (key && !silent) { + sc_print_addr(sc_link); + printf("%s", error_mes[key - 1]); + if (sense->error_code & SSD_ERRCODE_VALID) { + switch (key) { + case 0x2: /* NOT READY */ + case 0x5: /* ILLEGAL REQUEST */ + case 0x6: /* UNIT ATTENTION */ + case 0x7: /* DATA PROTECT */ + break; + case 0x8: /* BLANK CHECK */ + printf(", requested size: %d (decimal)", + info); + break; + default: + printf(", info = %d (decimal)", info); + } + } + printf("\n"); + } + switch (key) { + case 0x0: /* NO SENSE */ + case 0x1: /* RECOVERED ERROR */ + if (xs->resid == xs->datalen) + xs->resid = 0; /* not short read */ + case 0xc: /* EQUAL */ + return (ESUCCESS); + case 0x2: /* NOT READY */ + sc_link->flags &= ~SDEV_MEDIA_LOADED; + return (EBUSY); + case 0x5: /* ILLEGAL REQUEST */ + return (EINVAL); + case 0x6: /* UNIT ATTENTION */ + sc_link->flags &= ~SDEV_MEDIA_LOADED; + if (sc_link->flags & SDEV_OPEN) { + return (EIO); + } else { + return 0; + } + case 0x7: /* DATA PROTECT */ + return (EACCES); + case 0xd: /* VOLUME OVERFLOW */ + return (ENOSPC); + case 0x8: /* BLANK CHECK */ + return (ESUCCESS); + default: + return (EIO); + } + /* + * Not code 70, just report it + */ + default: + if (!silent) { + sc_print_addr(sc_link); + printf("error code %d", + sense->error_code & SSD_ERRCODE); + if (sense->error_code & SSD_ERRCODE_VALID) { + printf(" at block no. %d (decimal)", + (sense->ext.unextended.blockhi << 16) + + (sense->ext.unextended.blockmed << 8) + + (sense->ext.unextended.blocklow)); + } + printf("\n"); + } + return (EIO); + } +} + +/* + * Utility routines often used in SCSI stuff + */ + +/* + * convert a physical address to 3 bytes, + * MSB at the lowest address, + * LSB at the highest. + */ +void +lto3b(val, bytes) + int val; + u_char *bytes; +{ + *bytes++ = (val & 0xff0000) >> 16; + *bytes++ = (val & 0xff00) >> 8; + *bytes = val & 0xff; +} + +/* + * The reverse of lto3b + */ +int +_3btol(bytes) + u_char *bytes; +{ + u_int32 rc; + rc = (*bytes++ << 16); + rc += (*bytes++ << 8); + rc += *bytes; + return ((int) rc); +} + +/* + * Print out the scsi_link structure's address info. + */ + +void +sc_print_addr(sc_link) + struct scsi_link *sc_link; +{ + + printf("%s%d(%s%d:%d:%d): ", sc_link->device->name, sc_link->dev_unit, + sc_link->adapter->name, sc_link->adapter_unit, + sc_link->target, sc_link->lun); +} +#ifdef SCSIDEBUG +/* + * Given a scsi_xfer, dump the request, in all it's glory + */ +void +show_scsi_xs(xs) + struct scsi_xfer *xs; +{ + printf("xs(0x%x): ", xs); + printf("flg(0x%x)", xs->flags); + printf("sc_link(0x%x)", xs->sc_link); + printf("retr(0x%x)", xs->retries); + printf("timo(0x%x)", xs->timeout); + printf("cmd(0x%x)", xs->cmd); + printf("len(0x%x)", xs->cmdlen); + printf("data(0x%x)", xs->data); + printf("len(0x%x)", xs->datalen); + printf("res(0x%x)", xs->resid); + printf("err(0x%x)", xs->error); + printf("bp(0x%x)", xs->bp); + show_scsi_cmd(xs); +} + +void +show_scsi_cmd(struct scsi_xfer *xs) +{ + u_char *b = (u_char *) xs->cmd; + int i = 0; + + sc_print_addr(xs->sc_link); + printf("command: "); + + if (!(xs->flags & SCSI_RESET)) { + while (i < xs->cmdlen) { + if (i) + printf(","); + printf("%x", b[i++]); + } + printf("-[%d bytes]\n", xs->datalen); + if (xs->datalen) + show_mem(xs->data, min(64, xs->datalen)); + } else { + printf("-RESET-\n"); + } +} + +void +show_mem(address, num) + unsigned char *address; + u_int32 num; +{ + u_int32 x, y; + printf("------------------------------"); + for (y = 0; y < num; y += 1) { + if (!(y % 16)) + printf("\n%03d: ", y); + printf("%02x ", *address++); + } + printf("\n------------------------------\n"); +} +#endif /*SCSIDEBUG */ diff --git a/sys/scsi/scsi_cd.h b/sys/scsi/scsi_cd.h index e9e80ded5a..0a4759b8a7 100644 --- a/sys/scsi/scsi_cd.h +++ b/sys/scsi/scsi_cd.h @@ -14,11 +14,10 @@ * * Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992 * - * $Id: scsi_cd.h,v 1.4 1993/08/21 20:01:52 rgrimes Exp $ + * $Id: scsi_cd.h,v 1.6 93/08/26 21:09:19 julian Exp Locker: julian $ */ - -#ifndef _SCSI_SCSI_CD_H_ -#define _SCSI_SCSI_CD_H_ 1 +#ifndef _SCSI_SCSI_CD_H +#define _SCSI_SCSI_CD_H 1 /* * Define two bits always in the same place in byte 2 (flag byte) @@ -142,6 +141,7 @@ struct scsi_read_toc u_char data_len[2]; u_char control; }; +; struct scsi_read_cd_capacity { @@ -225,5 +225,5 @@ struct cd_mode_data struct blk_desc blk_desc; union cd_pages page; }; +#endif /*_SCSI_SCSI_CD_H*/ -#endif /* _SCSI_SCSI_CD_H_ */ diff --git a/sys/scsi/scsi_changer.h b/sys/scsi/scsi_changer.h index dda22eea72..85819c8e63 100644 --- a/sys/scsi/scsi_changer.h +++ b/sys/scsi/scsi_changer.h @@ -19,11 +19,10 @@ * * Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992 * - * $Id: scsi_changer.h,v 1.4 1993/08/21 20:01:53 rgrimes Exp $ + * $Id: scsi_changer.h,v 1.5 93/08/26 21:09:22 julian Exp Locker: julian $ */ - -#ifndef _SCSI_SCSI_CHANGER_H_ -#define _SCSI_SCSI_CHANGER_H_ 1 +#ifndef _SCSI_SCSI_CHANGER_H +#define _SCSI_SCSI_CHANGER_H 1 /* * SCSI command format @@ -95,5 +94,5 @@ struct element_status_page u_char rsvd; u_char byte_count_of_descriptor_data[3]; }; +#endif /*_SCSI_SCSI_CHANGER_H*/ -#endif /* _SCSI_SCSI_CHANGER_H_ */ diff --git a/sys/scsi/scsi_debug.h b/sys/scsi/scsi_debug.h new file mode 100644 index 0000000000..480ff146e5 --- /dev/null +++ b/sys/scsi/scsi_debug.h @@ -0,0 +1,53 @@ +/*#define SCSIDEBUG 1*/ +/* + * Written by Julian Elischer (julian@tfs.com) + * + * $Id: scsi_debug.h,v 1.3 93/10/10 09:26:05 julian Exp Locker: julian $ + */ +#ifndef _SCSI_SCSI_DEBUG_H +#define _SCSI_SCSI_DEBUG_H 1 + +/* + * These are the new debug bits. (Sat Oct 2 12:46:46 WST 1993) + * the following DEBUG bits are defined to exist in the flags word of + * the scsi_link structure. + */ +#define SDEV_DB1 0x10 /* scsi commands, errors, data */ +#define SDEV_DB2 0x20 /* routine flow tracking */ +#define SDEV_DB3 0x40 /* internal to routine flows */ +#define SDEV_DB4 0x80 /* level 4 debugging for this dev */ + +/* target and LUN we want to debug */ +#define DEBUGTARG 9 /*9 = dissable*/ +#define DEBUGLUN 0 +#define DEBUGLEVEL (SDEV_DB1|SDEV_DB2) + +/* + * This is the usual debug macro for use with the above bits + */ +#ifdef SCSIDEBUG +#define SC_DEBUG(sc_link,Level,Printstuff) \ + if((sc_link)->flags & (Level)) \ + { \ + printf("%s%d(%s%d:%d:%d): ", \ + sc_link->device->name, \ + sc_link->dev_unit, \ + sc_link->adapter->name, \ + sc_link->adapter_unit, \ + sc_link->target, \ + sc_link->lun); \ + printf Printstuff; \ + } +#define SC_DEBUGN(sc_link,Level,Printstuff) \ + if((sc_link)->flags & (Level)) \ + { \ + printf Printstuff; \ + } +#else +#define SC_DEBUG(A,B,C) /* not included */ +#define SC_DEBUGN(A,B,C) /* not included */ +#endif + +#endif /*_SCSI_SCSI_DEBUG_H*/ +/* END OF FILE */ + diff --git a/sys/scsi/scsi_disk.h b/sys/scsi/scsi_disk.h index e9cb724126..60d0bcc477 100644 --- a/sys/scsi/scsi_disk.h +++ b/sys/scsi/scsi_disk.h @@ -3,7 +3,7 @@ */ /* - * Some lines of this file comes from a file of the name "scsi.h" + * Some lines of this file come from a file of the name "scsi.h" * distributed by OSF as part of mach2.5, * so the following disclaimer has been kept. * @@ -46,16 +46,15 @@ * * Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992 * - * $Id: scsi_disk.h,v 1.4 1993/08/21 20:01:54 rgrimes Exp $ + * $Id: scsi_disk.h,v 1.4 93/08/26 21:09:23 julian Exp Locker: julian $ */ -#ifndef _SCSI_SCSI_DISK_H_ -#define _SCSI_SCSI_DISK_H_ 1 - /* * SCSI command format */ +#ifndef _SCSI_SCSI_DISK_H +#define _SCSI_SCSI_DISK_H 1 struct scsi_reassign_blocks { @@ -214,4 +213,4 @@ union disk_pages /* this is the structure copied from osf */ u_char reserved3; } rigid_geometry; } ; -#endif /* _SCSI_SCSI_DISK_H_ */ +#endif /* _SCSI_SCSI_DISK_H*/ diff --git a/sys/scsi/scsi_ioctl.c b/sys/scsi/scsi_ioctl.c new file mode 100644 index 0000000000..c1b576ded9 --- /dev/null +++ b/sys/scsi/scsi_ioctl.c @@ -0,0 +1,329 @@ +/* + * Contributed by HD Associates (hd@world.std.com). + * Copyright (c) 1992, 1993 HD Associates + * + * Berkeley style copyright. + * + * + */ +#include +#include +#include +#include +#include +#define b_screq b_driver1 /* a patch in buf.h */ +#define b_sc_link b_driver2 /* a patch in buf.h */ +#include + +#include "scbus.h" +#include +#include +#include + + +/* + * We let the user interpret his own sense in the generic scsi world. + * This routine is called at interrupt time if the SCSI_USER bit was set + * in the flags passed to scsi_scsi_cmd(). No other completion processing + * takes place, even if we are running over another device driver. + * The lower level routines that call us here, will free the xs and restart + * the device's queue if such exists. + */ +#ifndef min +#define min(A,B) ((Abp; + if(!bp) { /* ALL user requests must have a buf */ + sc_print_addr(xs->sc_link); + printf("User command with no buf\n"); + return ; + } + screq = bp->b_screq; + if (!screq) { /* Is it one of ours? (the SCSI_USER bit says it is) */ + sc_print_addr(xs->sc_link); + printf("User command with no request\n"); + return ; + } + + SC_DEBUG(xs->sc_link,SDEV_DB2,("user-done\n")); + screq->retsts = 0; + screq->status = xs->status; + switch(xs->error) { + case XS_NOERROR: + SC_DEBUG(xs->sc_link,SDEV_DB3,("no error\n")); + screq->datalen_used = xs->datalen - xs->resid; /* probably rubbish */ + screq->retsts = SCCMD_OK; + break; + + case XS_SENSE: + SC_DEBUG(xs->sc_link,SDEV_DB3,("have sense\n")); + screq->senselen_used = min(sizeof(xs->sense),SENSEBUFLEN); + bcopy(&xs->sense,screq->sense,screq->senselen); + screq->retsts = SCCMD_SENSE; + break; + + case XS_DRIVER_STUFFUP: + sc_print_addr(xs->sc_link); + printf("host adapter code inconsistency\n"); + screq->retsts = SCCMD_UNKNOWN; + break; + + case XS_TIMEOUT: + SC_DEBUG(xs->sc_link,SDEV_DB3,("timeout\n")); + screq->retsts = SCCMD_TIMEOUT; + break; + + case XS_BUSY: + SC_DEBUG(xs->sc_link,SDEV_DB3,("busy\n")); + screq->retsts = SCCMD_BUSY; + break; + + default: + sc_print_addr(xs->sc_link); + printf("unknown error category from host adapter code\n"); + screq->retsts = SCCMD_UNKNOWN; + break; + } + biodone(bp); /* we're waiting on it in scsi_strategy() */ + return; /* it'll free the xs and restart any queue */ +} + + +/* Pseudo strategy function + * Called by scsi_do_ioctl() via physio/physstrat if there is to + * be data transfered, and directly if there is no data transfer. + * + * Should I reorganize this so it returns to physio instead + * of sleeping in scsiio_scsi_cmd? Is there any advantage, other + * than avoiding the probable duplicate wakeup in iodone? [PD] + * + * No, seems ok to me... [JRE] + * (I don't see any duplicate wakeups) + * + * Can't be used with block devices or raw_read/raw_write directly + * from the cdevsw/bdevsw tables because they couldn't have added + * the screq structure. [JRE] + */ +void scsistrategy(struct buf *bp) +{ + errval err; + struct scsi_link *sc_link = bp->b_sc_link; + scsireq_t *screq; + u_int32 flags = 0; + int s; + + + if(!sc_link) { + printf("user_strat: No link pointer\n"); + scsierr(bp,EINVAL); + return; + } + SC_DEBUG(sc_link,SDEV_DB2,("user_strategy\n")); + screq = bp->b_screq; + if(!screq) { + sc_print_addr(sc_link); + printf("No request block\n"); + scsierr(bp,EINVAL); + return; + } + + /* We're in trouble if physio tried to break up the + * transfer: + */ + if (bp->b_bcount != screq->datalen) { + sc_print_addr(sc_link); + printf("physio split the request.. cannot proceed\n"); + scsierr(bp, EIO); + return; + } + + if (screq->timeout == 0) { + scsierr(bp, EINVAL); + return; + } + + if (screq->cmdlen > sizeof(struct scsi_generic)) { + sc_print_addr(sc_link); + printf("cmdlen too big "); + scsierr(bp, EFAULT); + return; + } + + + if (screq->flags & SCCMD_READ) + flags |= SCSI_DATA_IN; + + if (screq->flags & SCCMD_WRITE) + flags |= SCSI_DATA_OUT; + + if (screq->flags & SCCMD_TARGET) + flags |= SCSI_TARGET; + + if (screq->flags & SCCMD_ESCAPE) + flags |= SCSI_ESCAPE; + err = scsi_scsi_cmd(sc_link, + (struct scsi_generic *)screq->cmd, + screq->cmdlen, + (u_char *)bp->b_un.b_addr, + screq->datalen, + 0, /* user must do the retries *//* ignored */ + screq->timeout, + bp, + flags | SCSI_USER); + + + + /*because there is a bp, scsi_scsi_cmd will return immediatly*/ + if (err) + { + scsierr(bp, err); + return; + } + SC_DEBUG(sc_link,SDEV_DB3,("about to sleep\n")); + s = splbio(); + while(!(bp->b_flags & B_DONE)) + { + sleep(bp,PRIBIO); + } + splx(s); + SC_DEBUG(sc_link,SDEV_DB3,("back from sleep\n")); + return; +} + +void scsiminphys(struct buf *bp) +{ + /*XXX*//* call the adapter's minphys */ +} + + +/* + * Something (e.g. another driver) has called us + * with an sc_link for a target/lun/adapter, and a scsi + * specific ioctl to perform, better try. + * If user-level type command, we must still be running + * in the context of the calling process + */ +errval scsi_do_ioctl(struct scsi_link *sc_link, int cmd, caddr_t addr, int f) +{ + errval ret = 0; + int phys; + + SC_DEBUG(sc_link,SDEV_DB2,("scsi_do_ioctl(0x%x)\n",cmd)); + switch(cmd) + { +#ifndef NetBSD + case SCIOCCOMMAND: + { + /* + * You won't believe this, but the arg copied in + * from the user space, is on the kernel stack + * for this process, so we can't write + * to it at interrupt time.. + * we need to copy it in and out! + * Make a static copy using malloc! + */ + scsireq_t *screq2 = (scsireq_t *)addr; + scsireq_t *screq = (scsireq_t *)addr; + int rwflag = (screq->flags & SCCMD_READ) ? B_READ : B_WRITE; + struct buf *bp; + caddr_t d_addr; + int len; + + if((unsigned int)screq < (unsigned int)0xfe000000) + { + screq = malloc(sizeof(scsireq_t),M_TEMP,M_WAITOK); + bcopy(screq2,screq,sizeof(scsireq_t)); + } + bp = malloc(sizeof (struct buf),M_TEMP,M_WAITOK); + bzero(bp,sizeof(struct buf)); + d_addr = screq->databuf; + bp->b_bcount = len = screq->datalen; + bp->b_screq = screq; + bp->b_sc_link = sc_link; + if (len) { + /* have data, translate it. (physio)*/ +#ifdef __NetBSD__ +#error "dev, mincntfn & uio need defining" + ret = physio(scsistrategy, bp, dev, rwflag, + mincntfn, uio); +#else + ret = physio(scsistrategy,0,bp,0,rwflag, + d_addr,&len,curproc); +#endif + } else { + /* if no data, no need to translate it.. */ + bp->b_un.b_addr = 0; + bp->b_dev = -1; /* irrelevant info */ + bp->b_flags = 0; + + scsistrategy(bp); + ret = bp->b_error; + } + free(bp,M_TEMP); + if((unsigned int)screq2 < (unsigned int)0xfe000000) + { + bcopy(screq,screq2,sizeof(scsireq_t)); + free(screq,M_TEMP); + } + break; + } +#endif /* !NetBSD */ + case SCIOCDEBUG: + { + int level = *((int *)addr); + SC_DEBUG(sc_link,SDEV_DB3,("debug set to %d\n",level)); + sc_link->flags &= ~SDEV_DBX; /*clear debug bits */ + if(level & 1) sc_link->flags |= SDEV_DB1; + if(level & 2) sc_link->flags |= SDEV_DB2; + if(level & 4) sc_link->flags |= SDEV_DB3; + if(level & 8) sc_link->flags |= SDEV_DB4; + ret = 0; + break; + } + case SCIOCREPROBE: + { + extern int scsibus; + struct scsi_addr *sca = (struct scsi_addr *) addr; + + ret = scsi_probe_busses(sca->scbus,sca->target,sca->lun); + break; + } + case SCIOCRECONFIG: + case SCIOCDECONFIG: + ret = EINVAL; + break; + case SCIOCIDENTIFY: + { + struct scsi_addr *sca = (struct scsi_addr *) addr; + sca->scbus = sc_link->scsibus; + sca->target = sc_link->target; + sca->lun = sc_link->lun; + break; + } + + default: + ret = ENOTTY; + break; + } + + return ret; +} + +scsierr(bp,err) +struct buf *bp; +int err; +{ + bp->b_flags |= B_ERROR; + bp->b_error = err; + biodone(bp); + return; +} + diff --git a/sys/scsi/scsi_tape.h b/sys/scsi/scsi_tape.h index 103e1165c1..ac417c2680 100644 --- a/sys/scsi/scsi_tape.h +++ b/sys/scsi/scsi_tape.h @@ -21,13 +21,12 @@ /* * Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992 * - * $Id: scsi_tape.h,v 1.6 1993/09/05 15:42:20 rgrimes Exp $ + * $Id: scsi_tape.h,v 1.8 93/08/31 21:40:16 julian Exp Locker: julian $ */ +#ifndef SCSI_SCSI_TAPE_H +#define SCSI_SCSI_TAPE_H 1 -#ifndef _SCSI_SCSI_TAPE_H_ -#define _SCSI_SCSI_TAPE_H_ 1 - /* * SCSI command formats @@ -200,7 +199,6 @@ struct blk_desc_cipher #define QIC_525 0x11 #define QIC_1320 0x12 #define DDS 0x13 -#define DAT-1 0x13 - +#define DAT_1 0x13 -#endif /* _SCSI_SCSI_TAPE_H_ */ +#endif /*SCSI_SCSI_TAPE_H*/ diff --git a/sys/scsi/scsiconf.c b/sys/scsi/scsiconf.c index 70765b062a..708cc7cc17 100644 --- a/sys/scsi/scsiconf.c +++ b/sys/scsi/scsiconf.c @@ -14,768 +14,686 @@ * * Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992 * - * $Id: scsiconf.c,v 1.5 1993/08/28 03:08:53 rgrimes Exp $ + * $Id: scsiconf.c,v 2.6 93/10/24 12:43:51 julian Exp Locker: julian $ */ #include +#include +#include + +#include #include "st.h" #include "sd.h" #include "ch.h" #include "cd.h" -#include "sg.h" +#include "uk.h" +#include "su.h" +#ifndef NSCBUS +#define NSCBUS 8 +#endif /* NSCBUS */ -#ifdef MACH -#include -#endif MACH #include #include -#if !defined(OSF) && !defined(__386BSD__) +#ifdef TFS #include "bll.h" #include "cals.h" #include "kil.h" -#else +#include "scan.h" +#else /* TFS */ #define NBLL 0 #define NCALS 0 #define NKIL 0 -#endif /* !defined(OSF) && !defined(__386BSD__) */ +#define NSCAN 0 +#endif /* TFS */ #if NSD > 0 -extern sdattach(); -#endif NSD +extern sdattach(); +#endif /* NSD */ #if NST > 0 -extern stattach(); -#endif NST +extern stattach(); +#endif /* NST */ #if NCH > 0 -extern chattach(); -#endif NCH +extern chattach(); +#endif /* NCH */ #if NCD > 0 -extern cdattach(); -#endif NCD +extern cdattach(); +#endif /* NCD */ #if NBLL > 0 -extern bllattach(); -#endif NBLL +extern bllattach(); +#endif /* NBLL */ #if NCALS > 0 -extern calsattach(); -#endif NCALS +extern calsattach(); +#endif /* NCALS */ #if NKIL > 0 -extern kil_attach(); -#endif NKIL - -/***************************************************************\ -* The structure of pre-configured devices that might be turned * -* off and therefore may not show up * -\***************************************************************/ -struct predefined -{ - u_char scsibus; - u_char dev; - u_char lu; - int (*attach_rtn)(); - char *devname; - char flags; -} -pd[] = +extern kil_attach(); +#endif /* NKIL */ +#if NUK > 0 +extern ukattach(); +#endif /* NUK */ + +/* + * One of these is allocated and filled in for each scsi bus. + * it holds pointers to allow the scsi bus to get to the driver + * That is running each LUN on the bus + * it also has a template entry which is the prototype struct + * supplied by the adapter driver, this is used to initialise + * the others, before they have the rest of the fields filled in + */ +struct scsibus_data *scbus_data[NSCBUS]; + +/* + * The structure of pre-configured devices that might be turned + * off and therefore may not show up + */ +struct predefined { + u_char scsibus; + u_char dev; + u_char lu; + errval(*attach_rtn) (); + char *devname; + char flags; +} pd[] = + { #ifdef EXAMPLE_PREDEFINE #if NSD > 0 - {0,0,0,sdattach,"sd",0},/* define a disk at scsibus=0 dev=0 lu=0 */ -#endif NSD -#endif EXAMPLE_PREDEFINE - {0,9,9} /*illegal dummy end entry */ + { + 0, 0, 0, sdattach, "sd", 0 + }, /* define a disk at scsibus=0 dev=0 lu=0 */ +#endif /* NSD */ +#endif /* EXAMPLE_PREDEFINE */ + { + 0, 9, 9 + } /*illegal dummy end entry */ }; +/* + * The structure of known drivers for autoconfiguration + */ +struct scsidevs { + u_int32 type; + boolean removable; + char *manufacturer; + char *model; + char *version; + errval(*attach_rtn) (); + char *devname; + char flags; /* 1 show my comparisons during boot(debug) */ +}; -/***************************************************************\ -* The structure of known drivers for autoconfiguration * -\***************************************************************/ -static struct scsidevs -{ - int type; - int removable; - char *manufacturer; - char *model; - char *version; - int (*attach_rtn)(); - char *devname; - char flags; /* 1 show my comparisons during boot(debug) */ -} #define SC_SHOWME 0x01 #define SC_ONE_LU 0x00 #define SC_MORE_LUS 0x02 -knowndevs[] = { +#if NUK > 0 + +static struct scsidevs unknowndev = { + -1, 0, "standard", "any" + ,"any", ukattach, "uk", SC_MORE_LUS +}; +#endif /*NUK*/ +static struct scsidevs knowndevs[] = +{ #if NSD > 0 - { T_DIRECT,T_FIXED,"standard","any" - ,"any",sdattach,"sd",SC_ONE_LU }, - { T_DIRECT,T_FIXED,"MAXTOR ","XT-4170S " - ,"B5A ",sdattach,"mx1",SC_ONE_LU }, -#endif NSD + { + T_DIRECT, T_FIXED, "standard", "any" + ,"any", sdattach, "sd", SC_ONE_LU + }, + { + T_DIRECT, T_FIXED, "MAXTOR ", "XT-4170S " + ,"B5A ", sdattach, "mx1", SC_ONE_LU + }, +#endif /* NSD */ #if NST > 0 - { T_SEQUENTIAL,T_REMOV,"standard","any" - ,"any",stattach,"st",SC_ONE_LU }, -#endif NST + { + T_SEQUENTIAL, T_REMOV, "standard", "any" + ,"any", stattach, "st", SC_ONE_LU + }, +#endif /* NST */ #if NCALS > 0 - { T_PROCESSOR,T_FIXED,"standard","any" - ,"any",calsattach,"cals",SC_MORE_LUS }, -#endif NCALS + { + T_PROCESSOR, T_FIXED, "standard", "any" + ,"any", calsattach, "cals", SC_MORE_LUS + }, +#endif /* NCALS */ #if NCH > 0 - { T_CHANGER,T_REMOV,"standard","any" - ,"any",chattach,"ch",SC_ONE_LU }, -#endif NCH + { + T_CHANGER, T_REMOV, "standard", "any" + ,"any", chattach, "ch", SC_ONE_LU + }, +#endif /* NCH */ #if NCD > 0 - { T_READONLY,T_REMOV,"SONY ","CD-ROM CDU-8012 " - ,"3.1a",cdattach,"cd",SC_ONE_LU }, - { T_READONLY,T_REMOV,"PIONEER ","CD-ROM DRM-600 " - ,"any",cdattach,"cd",SC_MORE_LUS }, -#endif NCD +#ifndef UKTEST /* make cdroms unrecognised to test the uk driver */ + { + T_READONLY, T_REMOV, "SONY ", "CD-ROM CDU-8012 " + ,"3.1a", cdattach, "cd", SC_ONE_LU + }, + { + T_READONLY, T_REMOV, "PIONEER ", "CD-ROM DRM-600 " + ,"any", cdattach, "cd", SC_MORE_LUS + }, +#endif +#endif /* NCD */ #if NBLL > 0 - { T_PROCESSOR,T_FIXED,"AEG ","READER " - ,"V1.0",bllattach,"bll",SC_MORE_LUS }, -#endif NBLL + { + T_PROCESSOR, T_FIXED, "AEG ", "READER " + ,"V1.0", bllattach, "bll", SC_MORE_LUS + }, +#endif /* NBLL */ #if NKIL > 0 - { T_SCANNER,T_FIXED,"KODAK ","IL Scanner 900 " - ,"any",kil_attach,"kil",SC_ONE_LU }, -#endif NKIL + { + T_SCANNER, T_FIXED, "KODAK ", "IL Scanner 900 " + ,"any", kil_attach, "kil", SC_ONE_LU + }, +#endif /* NKIL */ -{0} + { + 0 + } }; -/***************************************************************\ -* Declarations * -\***************************************************************/ -struct predefined *scsi_get_predef(); -struct scsidevs *scsi_probedev(); -struct scsidevs *selectdev(); - -/* controls debug level within the scsi subsystem */ -/* see scsiconf.h for values */ -int scsi_debug = 0x0; -int scsibus = 0x0; /* This is the Nth scsibus */ - -/***************************************************************\ -* The routine called by the adapter boards to get all their * -* devices configured in. * -\***************************************************************/ -scsi_attachdevs( unit, scsi_addr, scsi_switch) -int unit,scsi_addr; -struct scsi_switch *scsi_switch; + +/* + * Declarations + */ +struct predefined *scsi_get_predef(); +struct scsidevs *scsi_probedev(); +struct scsidevs *selectdev(); +errval scsi_probe_bus __P((int bus, int targ, int lun)); + +struct scsi_device probe_switch = { - int targ,lun; - struct scsidevs *bestmatch = (struct scsidevs *)0; - struct predefined *predef; - int maybe_more; + NULL, + NULL, + NULL, + NULL, + "probe", + 0, + { 0, 0 } +}; -#ifdef SCSI_DELAY -#if SCSI_DELAY > 2 +/* + * controls debug level within the scsi subsystem - + * see scsiconf.h for values + */ +int32 scsibus = 0x0; /* This is the Nth scsibus we've seen */ + +/* + * The routine called by the adapter boards to get all their + * devices configured in. + */ +void +scsi_attachdevs(sc_link_proto) + struct scsi_link *sc_link_proto; +{ + + if(scsibus >= NSCBUS) { + printf("too many scsi busses, reconfigure the kernel\n"); + return; + } + sc_link_proto->scsibus = scsibus; + scbus_data[scsibus] = malloc(sizeof(struct scsibus_data), M_TEMP, M_NOWAIT); + if(!scbus_data[scsibus]) { + panic("scsi_attachdevs: malloc\n"); + } + bzero(scbus_data[scsibus], sizeof(struct scsibus_data)); + scbus_data[scsibus]->adapter_link = sc_link_proto; +#if defined(SCSI_DELAY) && SCSI_DELAY > 2 printf("%s%d waiting for scsi devices to settle\n", - scsi_switch->name, unit); -#else SCSI_DELAY > 2 -#define SCSI_DELAY 2 -#endif SCSI_DELAY > 2 -#else + sc_link_proto->adapter->name, sc_link_proto->adapter_unit); +#else /* SCSI_DELAY > 2 */ +#undef SCSI_DELAY #define SCSI_DELAY 2 -#endif SCSI_DELAY - spinwait(1000 * SCSI_DELAY); - targ = 0; - while(targ < 8) - { - maybe_more = 0; /* by default only check 1 lun */ - if (targ == scsi_addr) - { - targ++; +#endif /* SCSI_DELAY */ + DELAY(1000000 * SCSI_DELAY); + scsibus++; + scsi_probe_bus(scsibus - 1,-1,-1); +} + +/* + * Probe the requested scsi bus. It must be already set up. + * -1 requests all set up scsi busses. + * targ and lun optionally narrow the search if not -1 + */ +errval +scsi_probe_busses(int bus, int targ, int lun) +{ + if (bus == -1) { + for(bus = 0; bus < scsibus; bus++) { + scsi_probe_bus(bus, targ, lun); + } + return 0; + } else { + return scsi_probe_bus(bus, targ, lun); + } +} + +/* + * Probe the requested scsi bus. It must be already set up. + * targ and lun optionally narrow the search if not -1 + */ +errval +scsi_probe_bus(int bus, int targ, int lun) +{ + struct scsibus_data *scsi ; + int maxtarg,mintarg,maxlun,minlun; + struct scsi_link *sc_link_proto; + u_int8 scsi_addr ; + struct scsidevs *bestmatch = NULL; + struct predefined *predef = NULL; + struct scsi_link *sc_link = NULL; + boolean maybe_more; + + if ((bus < 0 ) || ( bus >= scsibus)) { + return ENXIO; + } + scsi = scbus_data[bus]; + if(!scsi) return ENXIO; + sc_link_proto = scsi->adapter_link; + scsi_addr = sc_link_proto->adapter_targ; + if(targ == -1){ + maxtarg = 7; + mintarg = 0; + } else { + if((targ < 0 ) || (targ > 7)) return EINVAL; + maxtarg = mintarg = targ; + } + + if(lun == -1){ + maxlun = 7; + minlun = 0; + } else { + if((lun < 0 ) || (lun > 7)) return EINVAL; + maxlun = minlun = lun; + } + + + for ( targ = mintarg;targ <= maxtarg; targ++) { + maybe_more = 0; /* by default only check 1 lun */ + if (targ == scsi_addr) { continue; } - lun = 0; - while(lun < 8) - { - predef = scsi_get_predef(scsibus - ,targ - ,lun - ,scsi_switch - ,&maybe_more); - bestmatch = scsi_probedev(unit - ,targ - ,lun - ,scsi_switch - ,&maybe_more); - if((bestmatch) && (predef)) /* both exist */ - { - if(bestmatch->attach_rtn - != predef->attach_rtn) - { - printf("Clash in found/expected devices\n"); - printf("will link in FOUND\n"); + for ( lun = minlun; lun <= maxlun ;lun++) { + /* + * The spot appears to already have something + * linked in, skip past it. Must be doing a 'reprobe' + */ + if(scsi->sc_link[targ][lun]) + {/* don't do this one, but check other luns */ + maybe_more = 1; + continue; + } + /* + * If we presently don't have a link block + * then allocate one to use while probing + */ + if (!sc_link) { + sc_link = malloc(sizeof(*sc_link), M_TEMP, M_NOWAIT); + *sc_link = *sc_link_proto; /* struct copy */ + sc_link->opennings = 1; + sc_link->device = &probe_switch; + } + sc_link->target = targ; + sc_link->lun = lun; + predef = scsi_get_predef(sc_link, &maybe_more); + bestmatch = scsi_probedev(sc_link, &maybe_more); + if ((bestmatch) && (predef)) { /* both exist */ + if (bestmatch->attach_rtn + != predef->attach_rtn) { + printf("Clash in found/expected devices\n"); +#if NUK > 0 + if(bestmatch == &unknowndev) { + printf("will link in PREDEFINED\n"); + (*(predef->attach_rtn)) (sc_link); + } else +#endif /*NUK*/ + { + printf("will link in FOUND\n"); + (*(bestmatch->attach_rtn)) (sc_link); + } + } else { + (*(bestmatch->attach_rtn)) (sc_link); } - (*(bestmatch->attach_rtn))(unit, - targ, - lun, - scsi_switch); } - if((bestmatch) && (!predef)) /* just FOUND */ - { - (*(bestmatch->attach_rtn))(unit, - targ, - lun, - scsi_switch); + if ((bestmatch) && (!predef)) { /* just FOUND */ + (*(bestmatch->attach_rtn)) (sc_link); } - if((!bestmatch) && (predef)) /* just predef */ - { - (*(predef->attach_rtn))(unit, - targ, - lun, - scsi_switch); + if ((!bestmatch) && (predef)) { /* just predef */ + (*(predef->attach_rtn)) (sc_link); } - if(!(maybe_more)) /* nothing suggests we'll find more */ - { + if ((bestmatch) || (predef)) { /* one exists */ + scsi->sc_link[targ][lun] = sc_link; + sc_link = NULL; /* it's been used */ + } + if (!(maybe_more)) { /* nothing suggests we'll find more */ break; /* nothing here, skip to next targ */ } - /* otherwise something says we should look further*/ - lun++; + /* otherwise something says we should look further */ } - targ++; } -#if NSG > 0 - /***************************************************************\ - * If available hook up the generic scsi driver, letting it * - * know which target is US. (i.e. illegal or at least special) * - \***************************************************************/ - sg_attach(unit,scsi_addr,scsi_switch); -#endif - scsibus++; /* next time we are on the NEXT scsi bus */ + if (sc_link) { + free(sc_link, M_TEMP); + } + return 0; } -/***********************************************\ -* given a target and lu, check if there is a * -* predefined device for that address * -\***********************************************/ -struct predefined *scsi_get_predef(unit,target,lu,scsi_switch,maybe_more) -int unit,target,lu,*maybe_more; -struct scsi_switch *scsi_switch; +/* + * given a target and lu, check if there is a predefined device for + * that address + */ +struct predefined * +scsi_get_predef(sc_link, maybe_more) + struct scsi_link *sc_link; + boolean *maybe_more; { - int upto,numents; + u_int8 unit = sc_link->scsibus; + u_int8 target = sc_link->target; + u_int8 lu = sc_link->lun; + struct scsi_adapter *scsi_adapter = sc_link->adapter; + u_int32 upto, numents; - numents = (sizeof(pd)/sizeof(struct predefined)) - 1; - - for(upto = 0;upto < numents;upto++) - { - if(pd[upto].scsibus != unit) + numents = (sizeof(pd) / sizeof(struct predefined)) - 1; + + for (upto = 0; upto < numents; upto++) { + if (pd[upto].scsibus != unit) continue; - if(pd[upto].dev != target) + if (pd[upto].dev != target) continue; - if(pd[upto].lu != lu) + if (pd[upto].lu != lu) continue; - + printf("%s%d targ %d lun %d: <%s> - PRECONFIGURED -\n" - ,scsi_switch->name - ,unit - ,target - ,lu - ,pd[upto].devname); + ,scsi_adapter->name + ,unit + ,target + ,lu + ,pd[upto].devname); *maybe_more = pd[upto].flags & SC_MORE_LUS; - return(&(pd[upto])); + return (&(pd[upto])); } - return((struct predefined *)0); + return ((struct predefined *) 0); } -/***********************************************\ -* given a target and lu, ask the device what * -* it is, and find the correct driver table * -* entry. * -\***********************************************/ -struct scsidevs *scsi_probedev(unit,target,lu,scsi_switch, maybe_more) - -struct scsi_switch *scsi_switch; -int unit,target,lu; -int *maybe_more; +/* + * given a target and lu, ask the device what + * it is, and find the correct driver table + * entry. + */ +struct scsidevs * +scsi_probedev(sc_link, maybe_more) + boolean *maybe_more; + struct scsi_link *sc_link; { - struct scsidevs *bestmatch = (struct scsidevs *)0; - char *dtype=(char *)0,*desc; - char *qtype; - static struct scsi_inquiry_data inqbuf; - int len,qualifier,type,remov; - char manu[32]; - char model[32]; - char version[32]; - - - bzero(&inqbuf,sizeof(inqbuf)); - /***********************************************\ - * Ask the device what it is * - \***********************************************/ -#ifdef DEBUG - if((target == 0) && (lu == 0)) - scsi_debug = 0xfff; + u_int8 unit = sc_link->adapter_unit; + u_int8 target = sc_link->target; + u_int8 lu = sc_link->lun; + struct scsi_adapter *scsi_adapter = sc_link->adapter; + struct scsidevs *bestmatch = (struct scsidevs *) 0; + char *dtype = (char *) 0, *desc; + char *qtype; + static struct scsi_inquiry_data inqbuf; + u_int32 len, qualifier, type; + boolean remov; + char manu[32]; + char model[32]; + char version[32]; + + bzero(&inqbuf, sizeof(inqbuf)); + /* + * Ask the device what it is + */ +#ifdef SCSIDEBUG + if ((target == DEBUGTARG) && (lu == DEBUGLUN)) + sc_link->flags |= (DEBUGLEVEL); else - scsi_debug = 0; -#endif DEBUG - if(scsi_ready( unit, - target, - lu, - scsi_switch, - SCSI_NOSLEEP | SCSI_NOMASK) != COMPLETE) - { - return(struct scsidevs *)0; - } - if(scsi_inquire(unit, - target, - lu, - scsi_switch, - &inqbuf, - SCSI_NOSLEEP | SCSI_NOMASK) != COMPLETE) - { - return(struct scsidevs *)0; - } + sc_link->flags &= ~(SDEV_DB1 | SDEV_DB2 | SDEV_DB3 | SDEV_DB4); +#endif /* SCSIDEBUG */ + /* catch unit attn */ + scsi_test_unit_ready(sc_link, SCSI_NOSLEEP | SCSI_NOMASK | SCSI_SILENT); +#ifdef DOUBTFULL + switch (scsi_test_unit_ready(sc_link, SCSI_NOSLEEP | SCSI_NOMASK | SCSI_SILENT)) { + case 0: /* said it WAS ready */ + case EBUSY: /* replied 'NOT READY' but WAS present, continue */ + case ENXIO: + break; + case EIO: /* device timed out */ + case EINVAL: /* Lun not supported */ + default: + return (struct scsidevs *) 0; - /***********************************************\ - * note what BASIC type of device it is * - \***********************************************/ - if(scsi_debug & SHOWINQUIRY) - { - desc=(char *)&inqbuf; - printf("inq: %x %x %x %x %x %x %x %x %x %x %x %x %x\n", - desc[0], desc[1], desc[2], desc[3], - desc[4], desc[5], desc[6], desc[7], - desc[8], desc[9], desc[10], desc[11], - desc[12]); + } +#endif /*DOUBTFULL*/ +#ifdef SCSI_2_DEF + /* some devices need to be told to go to SCSI2 */ + /* However some just explode if you tell them this.. leave it out */ + scsi_change_def(sc_link, SCSI_NOSLEEP | SCSI_NOMASK | SCSI_SILENT); +#endif /*SCSI_2_DEF */ + + /* Now go ask the device all about itself */ + if (scsi_inquire(sc_link, &inqbuf, SCSI_NOSLEEP | SCSI_NOMASK) != 0) { + return (struct scsidevs *) 0; } + /* + * note what BASIC type of device it is + */ type = inqbuf.device & SID_TYPE; qualifier = inqbuf.device & SID_QUAL; remov = inqbuf.dev_qual2 & SID_REMOVABLE; - - /* Any device qualifier that has - * the top bit set (qualifier&4 != 0) is vendor specific and - * won't match in this switch. + /* + * Any device qualifier that has the top bit set (qualifier&4 != 0) + * is vendor specific and won't match in this switch. */ - switch(qualifier) - { + switch (qualifier) { case SID_QUAL_LU_OK: - qtype=""; + qtype = ""; break; case SID_QUAL_LU_OFFLINE: - qtype=", Unit not Connected!"; + qtype = ", Unit not Connected!"; break; case SID_QUAL_RSVD: - qtype=", Reserved Peripheral Qualifier!"; + qtype = ", Reserved Peripheral Qualifier!"; *maybe_more = 1; - return (struct scsidevs *)0; + return (struct scsidevs *) 0; break; case SID_QUAL_BAD_LU: /* * Check for a non-existent unit. If the device is returning - * this much, then we must set the flag that has - * the searcher keep looking on other luns. - */ - qtype=", The Target can't support this Unit!"; + * this much, then we must set the flag that has + * the searchers keep looking on other luns. + */ + qtype = ", The Target can't support this Unit!"; *maybe_more = 1; - return (struct scsidevs *)0; + return (struct scsidevs *) 0; default: - dtype="vendor specific"; - qtype=""; + dtype = "vendor specific"; + qtype = ""; *maybe_more = 1; break; } - - if (dtype == 0) - { - switch(type) - { + if (dtype == 0) { + switch (type) { case T_DIRECT: - dtype="direct"; + dtype = "direct"; break; case T_SEQUENTIAL: - dtype="sequential"; + dtype = "sequential"; break; case T_PRINTER: - dtype="printer"; + dtype = "printer"; break; case T_PROCESSOR: - dtype="processor"; + dtype = "processor"; break; case T_READONLY: - dtype="readonly"; + dtype = "readonly"; break; case T_WORM: - dtype="worm"; + dtype = "worm"; break; case T_SCANNER: - dtype="scanner"; + dtype = "scanner"; break; case T_OPTICAL: - dtype="optical"; + dtype = "optical"; break; case T_CHANGER: - dtype="changer"; + dtype = "changer"; break; case T_COMM: - dtype="communication"; + dtype = "communication"; break; case T_NODEVICE: *maybe_more = 1; - return (struct scsidevs *)0; + return (struct scsidevs *) 0; default: - dtype="unknown"; + dtype = "unknown"; break; } - - } - /***********************************************\ - * Then if it's advanced enough, more detailed * - * information * - \***********************************************/ - if((inqbuf.version & SID_ANSII) > 0) - { - if ((len = inqbuf.additional_length - + ( (char *)inqbuf.unused - - (char *)&inqbuf)) - > (sizeof(struct scsi_inquiry_data) - 1)) - len = sizeof(struct scsi_inquiry_data) - 1; - desc=inqbuf.vendor; - desc[len-(desc - (char *)&inqbuf)] = 0; - strncpy(manu,inqbuf.vendor,8);manu[8]=0; - strncpy(model,inqbuf.product,16);model[16]=0; - strncpy(version,inqbuf.revision,4);version[4]=0; } - else - /***********************************************\ - * If not advanced enough, use default values * - \***********************************************/ + /* + * Then if it's advanced enough, more detailed + * information + */ + if ((inqbuf.version & SID_ANSII) > 0) { + if ((len = inqbuf.additional_length + + ((char *) inqbuf.unused + - (char *) &inqbuf)) + > (sizeof(struct scsi_inquiry_data) - 1)) + len = sizeof(struct scsi_inquiry_data) - 1; + desc = inqbuf.vendor; + desc[len - (desc - (char *) &inqbuf)] = 0; + strncpy(manu, inqbuf.vendor, 8); + manu[8] = 0; + strncpy(model, inqbuf.product, 16); + model[16] = 0; + strncpy(version, inqbuf.revision, 4); + version[4] = 0; + } else + /* + * If not advanced enough, use default values + */ { - desc="early protocol device"; - strncpy(manu,"unknown",8); - strncpy(model,"unknown",16); - strncpy(version,"????",4); + desc = "early protocol device"; + strncpy(manu, "unknown", 8); + strncpy(model, "unknown", 16); + strncpy(version, "????", 4); } printf("%s%d targ %d lun %d: type %d(%s) %s SCSI%d\n" - ,scsi_switch->name - ,unit - ,target - ,lu - ,type - ,dtype - ,remov?"removable":"fixed" - ,inqbuf.version & SID_ANSII - ); + ,scsi_adapter->name + ,unit + ,target + ,lu + ,type + ,dtype + ,remov ? "removable" : "fixed" + ,inqbuf.version & SID_ANSII + ); printf("%s%d targ %d lun %d: <%s%s%s>\n" - ,scsi_switch->name - ,unit - ,target - ,lu - ,manu - ,model - ,version - ); - if(qtype[0]) - { + ,scsi_adapter->name + ,unit + ,target + ,lu + ,manu + ,model + ,version + ); + if (qtype[0]) { printf("%s%d targ %d lun %d: qualifier %d(%s)\n" - ,scsi_switch->name - ,unit - ,target - ,lu - ,qualifier - ,qtype - ); + ,scsi_adapter->name + ,unit + ,target + ,lu + ,qualifier + ,qtype + ); } - /***********************************************\ - * Try make as good a match as possible with * - * available sub drivers * - \***********************************************/ - bestmatch = (selectdev(unit,target,lu,&scsi_switch, - qualifier,type,remov?T_REMOV:T_FIXED,manu,model,version)); - if((bestmatch) && (bestmatch->flags & SC_MORE_LUS)) - { + /* + * Try make as good a match as possible with + * available sub drivers + */ + bestmatch = (selectdev( + qualifier, type, remov ? T_REMOV : T_FIXED, manu, model, version)); + if ((bestmatch) && (bestmatch->flags & SC_MORE_LUS)) { *maybe_more = 1; } - return(bestmatch); + return (bestmatch); } - -/***********************************************\ -* Try make as good a match as possible with * -* available sub drivers * -\***********************************************/ -struct scsidevs -*selectdev(unit,target,lu,dvr_switch,qualifier,type,remov,manu,model,rev) -int unit,target,lu; -struct scsi_switch *dvr_switch; -int qualifier,type,remov; -char *manu,*model,*rev; +/* + * Try make as good a match as possible with + * available sub drivers + */ +struct scsidevs * +selectdev(qualifier, type, remov, manu, model, rev) + u_int32 qualifier, type; + boolean remov; + char *manu, *model, *rev; { - int numents = (sizeof(knowndevs)/sizeof(struct scsidevs)) - 1; - int count = 0; - int bestmatches = 0; - struct scsidevs *bestmatch = (struct scsidevs *)0; - struct scsidevs *thisentry = knowndevs; + u_int32 numents = (sizeof(knowndevs) / sizeof(struct scsidevs)) - 1; + u_int32 count = 0; + u_int32 bestmatches = 0; + struct scsidevs *bestmatch = (struct scsidevs *) 0; + struct scsidevs *thisentry = knowndevs; type |= qualifier; /* why? */ thisentry--; - while( count++ < numents) - { + while (count++ < numents) { thisentry++; - if(type != thisentry->type) - { + if (type != thisentry->type) { continue; } - if(bestmatches < 1) - { + if (bestmatches < 1) { bestmatches = 1; bestmatch = thisentry; } - if(remov != thisentry->removable) - { + if (remov != thisentry->removable) { continue; } - if(bestmatches < 2) - { + if (bestmatches < 2) { bestmatches = 2; bestmatch = thisentry; } - if(thisentry->flags & SC_SHOWME) - printf("\n%s-\n%s-",thisentry->manufacturer, manu); - if(strcmp(thisentry->manufacturer, manu)) - { + if (thisentry->flags & SC_SHOWME) + printf("\n%s-\n%s-", thisentry->manufacturer, manu); + if (strcmp(thisentry->manufacturer, manu)) { continue; } - if(bestmatches < 3) - { + if (bestmatches < 3) { bestmatches = 3; bestmatch = thisentry; } - if(thisentry->flags & SC_SHOWME) - printf("\n%s-\n%s-",thisentry->model, model); - if(strcmp(thisentry->model, model)) - { + if (thisentry->flags & SC_SHOWME) + printf("\n%s-\n%s-", thisentry->model, model); + if (strcmp(thisentry->model, model)) { continue; } - if(bestmatches < 4) - { + if (bestmatches < 4) { bestmatches = 4; bestmatch = thisentry; } - if(thisentry->flags & SC_SHOWME) - printf("\n%s-\n%s-",thisentry->version, rev); - if(strcmp(thisentry->version, rev)) - { + if (thisentry->flags & SC_SHOWME) + printf("\n%s-\n%s-", thisentry->version, rev); + if (strcmp(thisentry->version, rev)) { continue; } - if(bestmatches < 5) - { + if (bestmatches < 5) { bestmatches = 5; bestmatch = thisentry; break; } } - - if (bestmatch == (struct scsidevs *)0) - printf(" No explicit device driver match for \"%s %s\".\n", - manu, model); - - return(bestmatch); -} - -static int recurse = 0; -/***********************************************\ -* Do a scsi operation asking a device if it is * -* ready. Use the scsi_cmd routine in the switch * -* table. * -\***********************************************/ -scsi_ready(unit,target,lu,scsi_switch, flags) -struct scsi_switch *scsi_switch; -{ - struct scsi_test_unit_ready scsi_cmd; - struct scsi_xfer scsi_xfer; - volatile int rval; - int key; - - bzero(&scsi_cmd, sizeof(scsi_cmd)); - bzero(&scsi_xfer, sizeof(scsi_xfer)); - scsi_cmd.op_code = TEST_UNIT_READY; - - scsi_xfer.flags=flags | INUSE; - scsi_xfer.adapter=unit; - scsi_xfer.targ=target; - scsi_xfer.lu=lu; - scsi_xfer.cmd=(struct scsi_generic *)&scsi_cmd; - scsi_xfer.retries=8; - scsi_xfer.timeout=10000; - scsi_xfer.cmdlen=sizeof(scsi_cmd); - scsi_xfer.data=0; - scsi_xfer.datalen=0; - scsi_xfer.resid=0; - scsi_xfer.when_done=0; - scsi_xfer.done_arg=0; -retry: scsi_xfer.error=0; - /*******************************************************\ - * do not use interrupts * - \*******************************************************/ - rval = (*(scsi_switch->scsi_cmd))(&scsi_xfer); - if (rval != COMPLETE) - { - if(scsi_debug) - { - printf("scsi error, rval = 0x%x\n",rval); - printf("code from driver: 0x%x\n",scsi_xfer.error); - } - switch(scsi_xfer.error) - { - case XS_SENSE: - /*******************************************************\ - * Any sense value is illegal except UNIT ATTENTION * - * In which case we need to check again to get the * - * correct response. * - *( especially exabytes) * - \*******************************************************/ - if(((scsi_xfer.sense.error_code & SSD_ERRCODE) == 0x70 ) - ||((scsi_xfer.sense.error_code & SSD_ERRCODE) == 0x71 )) - { - key = scsi_xfer.sense.ext.extended.flags & SSD_KEY ; - switch(key) - { - case 2: /* not ready BUT PRESENT! */ - return(COMPLETE); - case 6: - spinwait(1000); - if(scsi_xfer.retries--) - { - scsi_xfer.flags &= ~ITSDONE; - goto retry; - } - return(COMPLETE); - default: - if(scsi_debug) - printf("%d:%d,key=%x.", - target,lu,key); - } - } - return(HAD_ERROR); - case XS_BUSY: - spinwait(1000); - if(scsi_xfer.retries--) - { - scsi_xfer.flags &= ~ITSDONE; - goto retry; - } - return(COMPLETE); /* it's busy so it's there */ - case XS_TIMEOUT: - default: - return(HAD_ERROR); - } - } - return(COMPLETE); -} -/***********************************************\ -* Do a scsi operation asking a device what it is* -* Use the scsi_cmd routine in the switch table. * -\***********************************************/ -scsi_inquire(unit,target,lu,scsi_switch,inqbuf, flags) -struct scsi_switch *scsi_switch; -u_char *inqbuf; -{ - struct scsi_inquiry scsi_cmd; - struct scsi_xfer scsi_xfer; - volatile int rval; - - bzero(&scsi_cmd, sizeof(scsi_cmd)); - bzero(&scsi_xfer, sizeof(scsi_xfer)); - scsi_cmd.op_code = INQUIRY; - scsi_cmd.length = sizeof(struct scsi_inquiry_data); - - scsi_xfer.flags=flags | SCSI_DATA_IN | INUSE; - scsi_xfer.adapter=unit; - scsi_xfer.targ=target; - scsi_xfer.lu=lu; - scsi_xfer.retries=8; - scsi_xfer.timeout=10000; - scsi_xfer.cmd=(struct scsi_generic *)&scsi_cmd; - scsi_xfer.cmdlen= sizeof(struct scsi_inquiry); - scsi_xfer.data=inqbuf; - scsi_xfer.datalen=sizeof(struct scsi_inquiry_data); - scsi_xfer.resid=sizeof(struct scsi_inquiry_data); - scsi_xfer.when_done=0; - scsi_xfer.done_arg=0; -retry: scsi_xfer.error=0; - /*******************************************************\ - * do not use interrupts * - \*******************************************************/ - if ((*(scsi_switch->scsi_cmd))(&scsi_xfer) != COMPLETE) - { - if(scsi_debug) printf("inquiry had error(0x%x) ",scsi_xfer.error); - switch(scsi_xfer.error) - { - case XS_NOERROR: - break; - case XS_SENSE: - /*******************************************************\ - * Any sense value is illegal except UNIT ATTENTION * - * In which case we need to check again to get the * - * correct response. * - *( especially exabytes) * - \*******************************************************/ - if(((scsi_xfer.sense.error_code & SSD_ERRCODE) == 0x70 ) - && ((scsi_xfer.sense.ext.extended.flags & SSD_KEY) == 6)) - { /* it's changed so it's there */ - spinwait(1000); - { - if(scsi_xfer.retries--) - { - scsi_xfer.flags &= ~ITSDONE; - goto retry; - } - } - return( COMPLETE); - } - return(HAD_ERROR); - case XS_BUSY: - spinwait(1000); - if(scsi_xfer.retries--) - { - scsi_xfer.flags &= ~ITSDONE; - goto retry; - } - case XS_TIMEOUT: - default: - return(HAD_ERROR); - } + if (bestmatch == (struct scsidevs *) 0) { +#if NUK > 0 + bestmatch = &unknowndev; +#else + printf("No explicit device driver match.\n"); +#endif } - return(COMPLETE); -} - - - - -/***********************************************\ -* Utility routines often used in SCSI stuff * -\***********************************************/ - -/***********************************************\ -* convert a physical address to 3 bytes, * -* MSB at the lowest address, * -* LSB at the highest. * -\***********************************************/ - -lto3b(val, bytes) -u_char *bytes; -{ - *bytes++ = (val&0xff0000)>>16; - *bytes++ = (val&0xff00)>>8; - *bytes = val&0xff; + return (bestmatch); } - -/***********************************************\ -* The reverse of lto3b * -\***********************************************/ -_3btol(bytes) -u_char *bytes; -{ - int rc; - rc = (*bytes++ << 16); - rc += (*bytes++ << 8); - rc += *bytes; - return(rc); -} - diff --git a/sys/scsi/scsiconf.h b/sys/scsi/scsiconf.h index 5738de5be8..856fe89950 100644 --- a/sys/scsi/scsiconf.h +++ b/sys/scsi/scsiconf.h @@ -14,88 +14,179 @@ * * Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992 * - * $Id: scsiconf.h,v 1.5 1993/08/28 03:08:54 rgrimes Exp $ + * $Id: scsiconf.h,v 2.4 93/10/16 00:59:13 julian Exp Locker: julian $ */ +#ifndef SCSI_SCSICONF_H +#define SCSI_SCSICONF_H 1 +typedef int boolean; +typedef int errval; +typedef long int int32; +typedef short int int16; +typedef char int8; +typedef unsigned long int u_int32; +typedef unsigned short int u_int16; +typedef unsigned char u_int8; -#ifndef _SCSI_SCSICONF_H_ -#define _SCSI_SCSICONF_H_ 1 +#include -/***********************************************\ -* these calls are called by the high-end * -* drivers to get services from whatever low-end * -* drivers they are attached to * -\***********************************************/ -struct scsi_switch +/* + * The following documentation tries to describe the relationship between the + * various structures defined in this file: + * + * each adapter type has a scsi_adapter struct. This describes the adapter and + * identifies routines that can be called to use the adapter. + * each device type has a scsi_device struct. This describes the device and + * identifies routines that can be called to use the device. + * each existing device position (scsibus + target + lun) + * can be described by a scsi_link struct. + * Only scsi positions that actually have devices, have a scsi_link + * structure assigned. so in effect each device has scsi_link struct. + * The scsi_link structure contains information identifying both the + * device driver and the adapter driver for that position on that scsi bus, + * and can be said to 'link' the two. + * each individual scsi bus has an array that points to all the scsi_link + * structs associated with that scsi bus. Slots with no device have + * a NULL pointer. + * each individual device also knows the address of it's own scsi_link + * structure. + * + * ------------- + * + * The key to all this is the scsi_link structure which associates all the + * other structures with each other in the correct configuration. The + * scsi_link is the connecting information that allows each part of the + * scsi system to find the associated other parts. + */ + + +/* + * These entrypoints are called by the high-end drivers to get services from + * whatever low-end drivers they are attached to each adapter type has one of + * these statically allocated. + */ +struct scsi_adapter { - int (*scsi_cmd)(); - void (*scsi_minphys)(); - int (*open_target_lu)(); - int (*close_target_lu)(); - long int (*adapter_info)(); /* see definitions below */ - char *name; /* name of scsi bus controller */ - u_long spare[2]; +/* 04*/ int32 (*scsi_cmd)(); +/* 08*/ void (*scsi_minphys)(); +/* 12*/ int32 (*open_target_lu)(); +/* 16*/ int32 (*close_target_lu)(); +/* 20*/ u_int32 (*adapter_info)(); /* see definitions below */ +/* 24*/ char *name; /* name of scsi bus controller */ +/* 32*/ u_long spare[2]; }; -#define AD_INF_MAX_CMDS 0x000000FF /* maximum number of entries - queuable to a device by - the adapter */ -/* 24 bits of other adapter characteristics go here */ -/***********************************************\ -* The scsi debug control bits * -\***********************************************/ -extern int scsi_debug; -#define PRINTROUTINES 0x01 -#define TRACEOPENS 0x02 -#define TRACEINTERRUPTS 0x04 -#define SHOWREQUESTS 0x08 -#define SHOWSCATGATH 0x10 -#define SHOWINQUIRY 0x20 -#define SHOWCOMMANDS 0x40 - - -/********************************/ -/* return values for scsi_cmd() */ -/********************************/ +/* + * return values for scsi_cmd() + */ #define SUCCESSFULLY_QUEUED 0 #define TRY_AGAIN_LATER 1 #define COMPLETE 2 -#define HAD_ERROR 3 +#define HAD_ERROR 3 /* do not use this, use COMPLETE */ #define ESCAPE_NOT_SUPPORTED 4 +/* + * Format of adapter_info() response data + * e.g. maximum number of entries queuable to a device by the adapter + */ +#define AD_INF_MAX_CMDS 0x000000FF +/* 24 bits of other adapter characteristics go here */ + +/* + * 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. + */ +struct scsi_device +{ +/* 4*/ errval (*err_handler)(); /* returns -1 to say err processing complete */ +/* 8*/ void (*start)(); +/* 12*/ int32 (*async)(); +/* 16*/ int32 (*done)(); /* returns -1 to say done processing complete */ +/* 20*/ char *name; /* name of device type */ +/* 24*/ u_int32 flags; /* device type dependent flags */ +/* 32*/ int32 spare[2]; +}; + +/* + * This structure describes the connection between an adapter driver and + * a device driver, and is used by each to call services provided by + * the other, and to allow generic scsi glue code to call these services + * as well. + */ +struct scsi_link +{ +/* 1*/ u_int8 target; /* targ of this dev */ +/* 2*/ u_int8 lun; /* lun of this dev */ +/* 3*/ u_int8 adapter_targ; /* what are we on the scsi bus */ +/* 4*/ u_int8 adapter_unit; /* e.g. the 0 in aha0 */ +/* 5*/ u_int8 scsibus; /* the Nth scsibus */ +/* 6*/ u_int8 dev_unit; /* e.g. the 0 in sd0 */ +/* 7*/ u_int8 opennings; /* available operations */ +/* 8*/ u_int8 active; /* operations in progress */ +/* 10*/ u_int16 flags; /* flags that all devices have */ +/* 12*/ u_int8 spareb[2]; /* unused */ +/* 16*/ struct scsi_adapter *adapter; /* adapter entry points etc. */ +/* 20*/ struct scsi_device *device; /* device entry points etc. */ +/* 24*/ struct scsi_xfer *active_xs; /* operations under way */ +/* 28*/ void * fordriver; /* for private use by the driver */ +/* 32*/ u_int32 spare; +}; +#define SDEV_MEDIA_LOADED 0x01 /* device figures are still valid */ +#define SDEV_WAITING 0x02 /* a process is waiting for this */ +#define SDEV_OPEN 0x04 /* at least 1 open session */ +#define SDEV_DBX 0xF0 /* debuging flags (scsi_debug.h) */ + +/* + * One of these is allocated and filled in for each scsi bus. + * it holds pointers to allow the scsi bus to get to the driver + * That is running each LUN on the bus + * it also has a template entry which is the prototype struct + * supplied by the adapter driver, this is used to initialise + * the others, before they have the rest of the fields filled in + */ +struct scsibus_data { + struct scsi_link *adapter_link; /* prototype supplied by adapter */ + struct scsi_link *sc_link[8][8]; +}; + +/* + * Each scsi transaction is fully described by one of these structures + * It includes information about the source of the command and also the + * device and adapter for which the command is destined. + * (via the scsi_link structure) * + */ struct scsi_xfer { - struct scsi_xfer *next; /* when free */ - int flags; - u_char adapter; - u_char targ; - u_char lu; - u_char retries; /* the number of times to retry */ - long int timeout; /* in miliseconds */ - struct scsi_generic *cmd; - int cmdlen; - u_char *data; /* either the dma address OR a uio address */ - int datalen; /* data len (blank if uio) */ - int resid; - int (*when_done)(); - int done_arg; - int done_arg2; - int error; - struct buf *bp; - struct scsi_sense_data sense; - - /* Believe it or not, Some targets fall on the ground with +/*04*/ struct scsi_xfer *next; /* when free */ +/*08*/ u_int32 flags; +/*12*/ struct scsi_link *sc_link; /* all about our device and adapter */ +/*13*/ u_int8 retries; /* the number of times to retry */ +/*16*/ u_int8 spare[3]; +/*20*/ int32 timeout; /* in milliseconds */ +/*24*/ struct scsi_generic *cmd; /* The scsi command to execute */ +/*28*/ int32 cmdlen; /* how long it is */ +/*32*/ u_char *data; /* dma address OR a uio address */ +/*36*/ int32 datalen; /* data len (blank if uio) */ +/*40*/ int32 resid; /* how much buffer was not touched */ +/*44*/ int32 error; /* an error value */ +/*48*/ struct buf *bp; /* If we need to associate with a buf */ +/*80*/ struct scsi_sense_data sense; /* 32 bytes*/ + /* + * Believe it or not, Some targets fall on the ground with * anything but a certain sense length. */ - int req_sense_length; /* Explicit request sense length */ - - int status; /* SCSI status */ +/*84*/ int32 req_sense_length; /* Explicit request sense length */ +/*88*/ int32 status; /* SCSI status */ +/*100*/ struct scsi_generic cmdstore; /* stash the command in here */ }; -/********************************/ -/* Flag values */ -/********************************/ + +/* + * Per-request Flag values + */ #define SCSI_NOSLEEP 0x01 /* Not a user... don't sleep */ #define SCSI_NOMASK 0x02 /* dont allow interrupts.. booting */ #define SCSI_NOSTART 0x04 /* left over from ancient history */ +#define SCSI_USER 0x08 /* Is a user cmd, call scsi_user_done */ #define ITSDONE 0x10 /* the transfer is as done as it gets */ #define INUSE 0x20 /* The scsi_xfer block is in use */ #define SCSI_SILENT 0x40 /* Don't report errors to console */ @@ -107,18 +198,18 @@ struct scsi_xfer #define SCSI_TARGET 0x1000 /* This defines a TARGET mode op. */ #define SCSI_ESCAPE 0x2000 /* Escape operation */ -/*************************************************************************/ -/* Escape op codes. This provides an extensible setup for operations */ -/* that are not scsi commands. They are intended for modal operations. */ -/*************************************************************************/ +/* + * Escape op codes. This provides an extensible setup for operations + * that are not scsi commands. They are intended for modal operations. + */ #define SCSI_OP_TARGET 0x0001 #define SCSI_OP_RESET 0x0002 #define SCSI_OP_BDINFO 0x0003 -/********************************/ -/* Error values */ -/********************************/ +/* + * Error values an adapter driver may return + */ #define XS_NOERROR 0x0 /* there is no error, (sense is invalid) */ #define XS_SENSE 0x1 /* Check the returned sense for the error */ #define XS_DRIVER_STUFFUP 0x2 /* Driver failed to perform operation */ @@ -126,4 +217,30 @@ struct scsi_xfer #define XS_SWTIMEOUT 0x04 /* The Timeout reported was caught by SW */ #define XS_BUSY 0x08 /* The device busy, try again later? */ -#endif /* _SCSI_SCSICONF_H_ */ +void scsi_attachdevs __P((struct scsi_link *sc_link_proto)); +struct scsi_xfer *get_xs( struct scsi_link *sc_link, u_int32 flags); +void free_xs(struct scsi_xfer *xs, struct scsi_link *sc_link,u_int32 flags); +u_int32 scsi_size( struct scsi_link *sc_link,u_int32 flags); +errval scsi_test_unit_ready( struct scsi_link *sc_link, u_int32 flags); +errval scsi_change_def( struct scsi_link *sc_link, u_int32 flags); +errval scsi_inquire( struct scsi_link *sc_link, + struct scsi_inquiry_data *inqbuf, u_int32 flags); +errval scsi_prevent( struct scsi_link *sc_link, u_int32 type,u_int32 flags); +errval scsi_start_unit( struct scsi_link *sc_link, u_int32 flags); +void scsi_done(struct scsi_xfer *xs); +errval scsi_scsi_cmd( struct scsi_link *sc_link, struct scsi_generic *scsi_cmd, + u_int32 cmdlen, u_char *data_addr, + u_int32 datalen, u_int32 retries, + u_int32 timeout, struct buf *bp, + u_int32 flags); +errval scsi_do_ioctl __P((struct scsi_link *sc_link, int cmd, caddr_t addr, int f)); + +void show_scsi_xs(struct scsi_xfer *xs); +void show_scsi_cmd(struct scsi_xfer *xs); +void show_mem(unsigned char * , u_int32); + +void lto3b __P((int val, u_char *bytes)); +int _3btol __P((u_char *bytes)); + +#endif /*SCSI_SCSICONF_H*/ +/* END OF FILE */ diff --git a/sys/scsi/sd.c b/sys/scsi/sd.c index 67174495cc..b3320aa399 100644 --- a/sys/scsi/sd.c +++ b/sys/scsi/sd.c @@ -14,7 +14,7 @@ * * Ported to run under 386BSD by Julian Elischer (julian@dialix.oz.au) Sept 1992 * - * $Id: sd.c,v 1.10 1993/09/20 06:28:13 rgrimes Exp $ + * $Id: sd.c,v 2.7 93/10/24 12:44:40 julian Exp Locker: julian $ */ #define SPLSD splbio @@ -37,20 +37,26 @@ #include #include -long int sdstrats,sdqueues; - +u_int32 sdstrats, sdqueues; +#ifdef NetBSD +#ifdef DDB +int Debugger(); +#else /* DDB */ +#define Debugger() +#endif /* DDB */ +#else /* NetBSD */ #include #if NDDB > 0 -int Debugger(); -#else NDDB > 0 +int Debugger(); +#else /* NDDB > 0 */ #define Debugger() -#endif NDDB > 0 - +#endif /* NDDB > 0 */ +#endif #define PAGESIZ 4096 #define SECSIZE 512 -#define PDLOCATION 29 +#define PDLOCATION 29 #define BOOTRECORDSIGNATURE (0x55aa & 0x00ff) #define SDOUTSTANDING 2 #define SDQSIZE 4 @@ -64,838 +70,704 @@ int Debugger(); #define WHOLE_DISK(unit) ( (unit << UNITSHIFT) + RAW_PART ) -struct buf sd_buf_queue[NSD]; -int sd_done(); -int sdstrategy(); +errval sdgetdisklabel __P((unsigned char unit)); +errval sd_get_parms __P((int unit, int flags)); +errval sdstrategy(); +void sdstart(); -#ifdef SDDEBUG -int sd_debug = 0; -#endif /*SDDEBUG*/ - -struct scsi_xfer *sd_free_xfer[NSD]; -int sd_xfer_block_wait[NSD]; - -struct sd_data +struct scsi_device sd_switch = { - int flags; -#define SDVALID 0x02 /* PARAMS LOADED */ -#define SDINIT 0x04 /* device has been init'd */ -#define SDWAIT 0x08 /* device has someone waiting */ -#define SDHAVELABEL 0x10 /* have read the label */ -#define SDDOSPART 0x20 /* Have read the DOS partition table */ -#define SDWRITEPROT 0x40 /* Device in readonly mode (S/W)*/ - struct scsi_switch *sc_sw; /* address of scsi low level switch */ - int ctlr; /* so they know which one we want */ - int targ; /* our scsi target ID */ - int lu; /* out scsi lu */ - long int ad_info; /* info about the adapter */ - int cmdscount; /* cmds allowed outstanding by board*/ - int wlabel; /* label is writable */ - struct disk_parms - { - u_char heads; /* Number of heads */ - u_short cyls; /* Number of cylinders */ - u_char sectors;/*dubious*/ /* Number of sectors/track */ - u_short secsiz; /* Number of bytes/sector */ - u_long disksize; /* total number sectors */ - }params; - struct disklabel disklabel; - struct dos_partition dosparts[NDOSPART]; /* DOS view of disk */ - int partflags[MAXPARTITIONS]; /* per partition flags */ + NULL, /* Use default error handler */ + sdstart, /* have a queue, served by this */ + NULL, /* have no async handler */ + NULL, /* Use default 'done' routine */ + "sd", + 0, + { 0, 0 } +}; + +struct sd_data { + u_int32 flags; +#define SDINIT 0x04 /* device has been init'd */ +#define SDHAVELABEL 0x10 /* have read the label */ +#define SDDOSPART 0x20 /* Have read the DOS partition table */ +#define SDWRITEPROT 0x40 /* Device in readonly mode (S/W) */ + struct scsi_link *sc_link; /* contains our targ, lun etc. */ + u_int32 ad_info; /* info about the adapter */ + u_int32 cmdscount; /* cmds allowed outstanding by board */ + boolean wlabel; /* label is writable */ + struct disk_parms { + u_char heads; /* Number of heads */ + u_int16 cyls; /* Number of cylinders */ + u_char sectors; /*dubious *//* Number of sectors/track */ + u_int16 secsiz; /* Number of bytes/sector */ + u_int32 disksize; /* total number sectors */ + } params; + struct disklabel disklabel; +#ifdef NetBSD + struct cpu_disklabel cpudisklabel; +#else + struct dos_partition dosparts[NDOSPART]; /* DOS view of disk */ +#endif /* NetBSD */ + u_int32 partflags[MAXPARTITIONS]; /* per partition flags */ #define SDOPEN 0x01 - int openparts; /* one bit for each open partition */ - unsigned int sd_start_of_unix; /* unix vs dos partitions */ -}*sd_data[NSD]; + u_int32 openparts; /* one bit for each open partition */ + u_int32 sd_start_of_unix; /* unix vs dos partitions */ + struct buf buf_queue; + u_int32 xfer_block_wait; +} *sd_data[NSD]; +static u_int32 next_sd_unit = 0; -static int next_sd_unit = 0; -/***********************************************************************\ -* The routine called by the low level scsi routine when it discovers * -* A device suitable for this driver * -\***********************************************************************/ - -int sdattach(ctlr,targ,lu,scsi_switch) -struct scsi_switch *scsi_switch; +/* + * The routine called by the low level scsi routine when it discovers + * a device suitable for this driver. + */ +errval +sdattach(sc_link) + struct scsi_link *sc_link; { - int unit,i; - unsigned char *tbl; + u_int32 unit; struct sd_data *sd; struct disk_parms *dp; - long int ad_info; - struct scsi_xfer *sd_scsi_xfer; unit = next_sd_unit++; -#ifdef SDDEBUG - if(scsi_debug & PRINTROUTINES) printf("sdattach: "); -#endif /*SDDEBUG*/ - /*******************************************************\ - * Check we have the resources for another drive * - \*******************************************************/ - if( unit >= NSD) - { - printf("Too many scsi disks..(%d > %d) reconfigure kernel\n",(unit + 1),NSD); - return(0); + SC_DEBUG(sc_link, SDEV_DB2, ("sdattach: ")); + /* + * Check we have the resources for another drive + */ + if (unit >= NSD) { + printf("Too many scsi disks..(%d > %d) reconfigure kernel\n", + (unit + 1), NSD); + return 0; } - if(sd_data[unit]) - { - printf("sd%d: unit already has storage allocated!\n",unit); - return(0); + if (sd_data[unit]) { + printf("sd%d: unit already has storage allocated!\n", unit); + return 0; } - sd = sd_data[unit] = malloc(sizeof(struct sd_data),M_DEVBUF,M_NOWAIT); - if(!sd) - { + sd = sd_data[unit] = malloc(sizeof(struct sd_data), M_DEVBUF, M_NOWAIT); + if (!sd) { printf("malloc failed in sd.c\n"); - return(0); + return (0); } - bzero(sd,sizeof(struct sd_data)); - - dp = &(sd->params); - /*******************************************************\ - * Store information needed to contact our base driver * - \*******************************************************/ - sd->sc_sw = scsi_switch; - sd->ctlr = ctlr; - sd->targ = targ; - sd->lu = lu; - if(sd->sc_sw->adapter_info) - { - sd->ad_info = ( (*(sd->sc_sw->adapter_info))(ctlr)); - sd->cmdscount = sd->ad_info & AD_INF_MAX_CMDS; - if(sd->cmdscount > SDOUTSTANDING) - { + bzero(sd, sizeof(struct sd_data)); + + dp = &(sd->params); + /* + * Store information needed to contact our base driver + */ + sd->sc_link = sc_link; + sc_link->device = &sd_switch; + sc_link->dev_unit = unit; + + if (sd->sc_link->adapter->adapter_info) { + sd->ad_info = ((*(sd->sc_link->adapter->adapter_info)) (sc_link->adapter_unit)); + sd->cmdscount = sd->ad_info & AD_INF_MAX_CMDS; + if (sd->cmdscount > SDOUTSTANDING) { sd->cmdscount = SDOUTSTANDING; } - } - else - { + } else { sd->ad_info = 1; - sd->cmdscount = 1; - } - - i = sd->cmdscount; - sd_scsi_xfer = (struct scsi_xfer *)malloc(sizeof(struct scsi_xfer) * i - ,M_TEMP, M_NOWAIT); - while(i-- ) - { - sd_scsi_xfer->next = sd_free_xfer[unit]; - sd_free_xfer[unit] = sd_scsi_xfer; - sd_scsi_xfer++; - } - /*******************************************************\ - * Use the subdriver to request information regarding * - * the drive. We cannot use interrupts yet, so the * - * request must specify this. * - \*******************************************************/ - sd_get_parms(unit, SCSI_NOSLEEP | SCSI_NOMASK); + sd->cmdscount = 1; + } + sc_link->opennings = sd->cmdscount; + /* + * Use the subdriver to request information regarding + * the drive. We cannot use interrupts yet, so the + * request must specify this. + */ + sd_get_parms(unit, SCSI_NOSLEEP | SCSI_NOMASK); printf("sd%d: %dMB (%d total sec), %d cyl, %d head, %d sec, bytes/sec %d\n", - unit, - dp->disksize / ((1024L * 1024L) / dp->secsiz), - dp->disksize, - dp->cyls, - dp->heads, - dp->sectors, - dp->secsiz); + unit, + dp->disksize / ((1024L * 1024L) / dp->secsiz), + dp->disksize, + dp->cyls, + dp->heads, + dp->sectors, + dp->secsiz); sd->flags |= SDINIT; - return; - + return 0; } - - -/*******************************************************\ -* open the device. Make sure the partition info * -* is a up-to-date as can be. * -\*******************************************************/ +/* + * open the device. Make sure the partition info is a up-to-date as can be. + */ +errval sdopen(dev) + int dev; /* XXX should be dev_t, but avoid promotion problems for now */ { - int errcode = 0; - int unit, part; - struct disk_parms disk_parms; - struct sd_data *sd ; + errval errcode = 0; + u_int32 unit, part; + struct sd_data *sd; + struct scsi_link *sc_link; unit = UNIT(dev); part = PARTITION(dev); sd = sd_data[unit]; -#ifdef SDDEBUG - if(scsi_debug & (PRINTROUTINES | TRACEOPENS)) - printf("sdopen: dev=0x%x (unit %d (of %d),partition %d)\n" - , dev, unit, NSD, part); -#endif /*SDDEBUG*/ - /*******************************************************\ - * Check the unit is legal * - \*******************************************************/ - if ( unit >= NSD ) - { - return(ENXIO); + /* + * Check the unit is legal + */ + if (unit >= NSD) { + return (ENXIO); } - /*******************************************************\ - * Make sure the disk has been initialised * - * At some point in the future, get the scsi driver * - * to look for a new device if we are not initted * - \*******************************************************/ - if (! (sd->flags & SDINIT)) - { - return(ENXIO); + /* + * Make sure the disk has been initialised + * At some point in the future, get the scsi driver + * to look for a new device if we are not initted + */ + if ((!sd) || (!(sd->flags & SDINIT))) { + return (ENXIO); } + sc_link = sd->sc_link; + + SC_DEBUG(sc_link, SDEV_DB1, + ("sdopen: dev=0x%x (unit %d (of %d),partition %d)\n" + ,dev, unit, NSD, part)); + + /* + * "unit attention" errors should occur here if the + * drive has been restarted or the pack changed. + * just ingnore the result, it's a decoy instruction + * The error code will act on the error though + * and invalidate any media information we had. + */ + scsi_test_unit_ready(sc_link, 0); + + /* + * If it's been invalidated, then forget the label + */ + sc_link->flags |= SDEV_OPEN; /* unit attn becomes an err now */ + if (!(sc_link->flags & SDEV_MEDIA_LOADED)) { + sd->flags &= ~SDHAVELABEL; - /*******************************************************\ - * If it's been invalidated, and not everybody has * - * closed it then forbid re-entry. * - \*******************************************************/ - if ((! (sd->flags & SDVALID)) - && ( sd->openparts)) - return(ENXIO); - /*******************************************************\ - * "unit attention" errors should occur here if the * - * drive has been restarted or the pack changed. * - * just ingnore the result, it's a decoy instruction * - * The error code will act on the error though * - * and invalidate any media information we had. * - \*******************************************************/ - sd_test_unit_ready(unit,0); - - /*******************************************************\ - * In case it is a funny one, tell it to start * - * not needed for most hard drives (ignore failure) * - \*******************************************************/ - sd_start_unit(unit,SCSI_ERR_OK|SCSI_SILENT); - - /*******************************************************\ - * Check that it is still responding and ok. * - \*******************************************************/ - if (sd_test_unit_ready(unit,0)) - { -#ifdef SDDEBUG - if(scsi_debug & TRACEOPENS) printf("device not reponding\n"); -#endif /*SDDEBUG*/ - return(ENXIO); + /* + * If somebody still has it open, then forbid re-entry. + */ + if (sd->openparts) { + errcode = ENXIO; + goto bad; + } + } + /* + * In case it is a funny one, tell it to start + * not needed for most hard drives (ignore failure) + */ + scsi_start_unit(sc_link, SCSI_ERR_OK | SCSI_SILENT); + + /* + * Check that it is still responding and ok. + */ + if (scsi_test_unit_ready(sc_link, 0)) { + SC_DEBUG(sc_link, SDEV_DB3, ("device not reponding\n")); + errcode = ENXIO; + goto bad; } -#ifdef SDDEBUG - if(scsi_debug & TRACEOPENS) - printf("device ok\n"); -#endif /*SDDEBUG*/ - - /*******************************************************\ - * Load the physical device parameters * - \*******************************************************/ - sd_get_parms(unit, 0); /* sets SDVALID */ - if (sd->params.secsiz != SECSIZE) /* XXX One day...*/ - { - printf("sd%d: Can't deal with %d bytes logical blocks\n" - ,unit, sd->params.secsiz); + SC_DEBUG(sc_link, SDEV_DB3, ("device ok\n")); + + /* + * Load the physical device parameters + */ + sd_get_parms(unit, 0); /* sets SDEV_MEDIA_LOADED */ + if (sd->params.secsiz != SECSIZE) { /* XXX One day... */ + printf("sd%d: Can't deal with %d bytes logical blocks\n", + unit, sd->params.secsiz); Debugger(); - return(ENXIO); + errcode = ENXIO; + goto bad; } -#ifdef SDDEBUG - if(scsi_debug & TRACEOPENS) - printf("Params loaded "); -#endif /*SDDEBUG*/ - /*******************************************************\ - * Load the partition info if not already loaded * - * Lock the pack in * - \*******************************************************/ - sd_prevent(unit,PR_PREVENT,SCSI_ERR_OK|SCSI_SILENT); - if((errcode = sdgetdisklabel(unit)) && (part != RAW_PART)) - { - sd_prevent(unit,PR_ALLOW,SCSI_ERR_OK|SCSI_SILENT); - return(errcode); + SC_DEBUG(sc_link, SDEV_DB3, ("Params loaded ")); + + /* Lock the pack in. */ + scsi_prevent(sc_link, PR_PREVENT, SCSI_ERR_OK | SCSI_SILENT); + + /* + * Load the partition info if not already loaded. + */ + if ((errcode = sdgetdisklabel(unit)) && (part != RAW_PART)) { + goto bad; } -#ifdef SDDEBUG - if(scsi_debug & TRACEOPENS) - printf("Disklabel loaded "); -#endif /*SDDEBUG*/ - /*******************************************************\ - * Check the partition is legal * - \*******************************************************/ - if ( part >= MAXPARTITIONS ) { - sd_prevent(unit,PR_ALLOW,SCSI_ERR_OK|SCSI_SILENT); /* who cares if it fails? */ - return(ENXIO); + SC_DEBUG(sc_link, SDEV_DB3, ("Disklabel loaded ")); + /* + * Check the partition is legal + */ + if (part >= MAXPARTITIONS) { + errcode = ENXIO; + goto bad; } -#ifdef SDDEBUG - if(scsi_debug & TRACEOPENS) - printf("ok"); -#endif /*SDDEBUG*/ - /*******************************************************\ - * Check that the partition exists * - \*******************************************************/ - if (( sd->disklabel.d_partitions[part].p_size == 0 ) - && (part != RAW_PART)) - { - sd_prevent(unit,PR_ALLOW,SCSI_ERR_OK|SCSI_SILENT); /* who cares if it fails? */ - return(ENXIO); + SC_DEBUG(sc_link, SDEV_DB3, ("partition ok")); + + /* + * Check that the partition exists + */ + if ((sd->disklabel.d_partitions[part].p_size == 0) + && (part != RAW_PART)) { + errcode = ENXIO; + goto bad; } sd->partflags[part] |= SDOPEN; sd->openparts |= (1 << part); -#ifdef SDDEBUG - if(scsi_debug & TRACEOPENS) - printf("open %d %d\n",sdstrats,sdqueues); -#endif /*SDDEBUG*/ - return(0); -} + SC_DEBUG(sc_link, SDEV_DB3, ("open %d %d\n", sdstrats, sdqueues)); + return 0; -/*******************************************************\ -* Get ownership of a scsi_xfer * -* If need be, sleep on it, until it comes free * -\*******************************************************/ -struct scsi_xfer *sd_get_xs(unit,flags) -int flags; -int unit; -{ - struct scsi_xfer *xs; - int s; - - if(flags & (SCSI_NOSLEEP | SCSI_NOMASK)) - { - if (xs = sd_free_xfer[unit]) - { - sd_free_xfer[unit] = xs->next; - xs->flags = 0; - } - } - else - { - s = SPLSD(); - while (!(xs = sd_free_xfer[unit])) - { - sd_xfer_block_wait[unit]++; /* someone waiting! */ - sleep((caddr_t)&sd_free_xfer[unit], PRIBIO+1); - sd_xfer_block_wait[unit]--; - } - sd_free_xfer[unit] = xs->next; - splx(s); - xs->flags = 0; +bad: + if (!(sd->openparts)) { + scsi_prevent(sc_link, PR_ALLOW, SCSI_ERR_OK | SCSI_SILENT); + sc_link->flags &= ~SDEV_OPEN; } - return(xs); + return errcode; } -/*******************************************************\ -* Free a scsi_xfer, wake processes waiting for it * -\*******************************************************/ -sd_free_xs(unit,xs,flags) -struct scsi_xfer *xs; -int unit; -int flags; +/* + * close the device.. only called if we are the LAST occurence of an open + * device. Convenient now but usually a pain. + */ +errval +sdclose(dev) + dev_t dev; { - int s; - - if(flags & SCSI_NOMASK) - { - if (sd_xfer_block_wait[unit]) - { - printf("doing a wakeup from NOMASK mode\n"); - wakeup((caddr_t)&sd_free_xfer[unit]); - } - xs->next = sd_free_xfer[unit]; - sd_free_xfer[unit] = xs; - } - else - { - s = SPLSD(); - if (sd_xfer_block_wait[unit]) - wakeup((caddr_t)&sd_free_xfer[unit]); - xs->next = sd_free_xfer[unit]; - sd_free_xfer[unit] = xs; - splx(s); - } + unsigned char unit, part; + struct sd_data *sd; + + unit = UNIT(dev); + part = PARTITION(dev); + sd = sd_data[unit]; + sd->partflags[part] &= ~SDOPEN; + sd->openparts &= ~(1 << part); + scsi_prevent(sd->sc_link, PR_ALLOW, SCSI_SILENT | SCSI_ERR_OK); + if (!(sd->openparts)) + sd->sc_link->flags &= ~SDEV_OPEN; + return 0; } -/*******************************************************\ -* trim the size of the transfer if needed, * -* called by physio * -* basically the smaller of our max and the scsi driver's* -* minphys (note we have no max) * -\*******************************************************/ -/* Trim buffer length if buffer-size is bigger than page size */ -void sdminphys(bp) -struct buf *bp; +/* + * trim the size of the transfer if needed, called by physio + * basically the smaller of our max and the scsi driver's + * minphys (note we have no max) + * + * Trim buffer length if buffer-size is bigger than page size + */ +void +sdminphys(bp) + struct buf *bp; { - (*(sd_data[UNIT(bp->b_dev)]->sc_sw->scsi_minphys))(bp); + (*(sd_data[UNIT(bp->b_dev)]->sc_link->adapter->scsi_minphys)) (bp); } -/*******************************************************\ -* Actually translate the requested transfer into * -* one the physical driver can understand * -* The transfer is described by a buf and will include * -* only one physical transfer. * -\*******************************************************/ - -int sdstrategy(bp) -struct buf *bp; +/* + * Actually translate the requested transfer into one the physical driver + * can understand. The transfer is described by a buf and will include + * only one physical transfer. + */ +errval +sdstrategy(bp) + struct buf *bp; { - struct buf *dp; - unsigned int opri; - struct sd_data *sd ; - int unit; + struct buf *dp; + u_int32 opri; + struct sd_data *sd; + u_int32 unit; sdstrats++; unit = UNIT((bp->b_dev)); sd = sd_data[unit]; -#ifdef SDDEBUG - if(scsi_debug & PRINTROUTINES) printf("\nsdstrategy "); - if(scsi_debug & SHOWREQUESTS) printf("sd%d: %d bytes @ blk%d\n", - unit,bp->b_bcount,bp->b_blkno); -#endif /*SDDEBUG*/ + SC_DEBUG(sd->sc_link, SDEV_DB2, ("sdstrategy ")); + SC_DEBUG(sd->sc_link, SDEV_DB1, + (" %d bytes @ blk%d\n", bp->b_bcount, bp->b_blkno)); sdminphys(bp); - /*******************************************************\ - * If the device has been made invalid, error out * - \*******************************************************/ - if(!(sd->flags & SDVALID)) - { + /* + * If the device has been made invalid, error out + */ + if (!(sd->sc_link->flags & SDEV_MEDIA_LOADED)) { + sd->flags &= ~SDHAVELABEL; bp->b_error = EIO; goto bad; } - /*******************************************************\ - * "soft" write protect check * - \*******************************************************/ + /* + * "soft" write protect check + */ if ((sd->flags & SDWRITEPROT) && (bp->b_flags & B_READ) == 0) { bp->b_error = EROFS; goto bad; } - /*******************************************************\ - * If it's a null transfer, return immediatly * - \*******************************************************/ - if (bp->b_bcount == 0) - { + /* + * If it's a null transfer, return immediatly + */ + if (bp->b_bcount == 0) { goto done; } - - /*******************************************************\ - * Decide which unit and partition we are talking about * - * only raw is ok if no label * - \*******************************************************/ - if(PARTITION(bp->b_dev) != RAW_PART) - { - if (!(sd->flags & SDHAVELABEL)) - { + /* + * Decide which unit and partition we are talking about + * only raw is ok if no label + */ + if (PARTITION(bp->b_dev) != RAW_PART) { + if (!(sd->flags & SDHAVELABEL)) { bp->b_error = EIO; goto bad; } - /* * do bounds checking, adjust transfer. if error, process. * if end of partition, just return */ - if (bounds_check_with_label(bp,&sd->disklabel,sd->wlabel) <= 0) + if (bounds_check_with_label(bp, &sd->disklabel, sd->wlabel) <= 0) goto done; /* otherwise, process transfer request */ } - opri = SPLSD(); - dp = &sd_buf_queue[unit]; + dp = &sd->buf_queue; - /*******************************************************\ - * Place it in the queue of disk activities for this disk* - \*******************************************************/ + /* + * Place it in the queue of disk activities for this disk + */ disksort(dp, bp); - /*******************************************************\ - * Tell the device to get going on the transfer if it's * - * not doing anything, otherwise just wait for completion* - \*******************************************************/ + /* + * Tell the device to get going on the transfer if it's + * not doing anything, otherwise just wait for completion + */ sdstart(unit); splx(opri); - return; + return 0; bad: bp->b_flags |= B_ERROR; done: - /*******************************************************\ - * Correctly set the buf to indicate a completed xfer * - \*******************************************************/ - bp->b_resid = bp->b_bcount; + /* + * Correctly set the buf to indicate a completed xfer + */ + bp->b_resid = bp->b_bcount; biodone(bp); - return; + return 0; } -/***************************************************************\ -* sdstart looks to see if there is a buf waiting for the device * -* and that the device is not already busy. If both are true, * -* It dequeues the buf and creates a scsi command to perform the * -* transfer in the buf. The transfer request will call sd_done * -* on completion, which will in turn call this routine again * -* so that the next queued transfer is performed. * -* The bufs are queued by the strategy routine (sdstrategy) * -* * -* This routine is also called after other non-queued requests * -* have been made of the scsi driver, to ensure that the queue * -* continues to be drained. * -* * -* must be called at the correct (highish) spl level * -\***************************************************************/ -/* sdstart() is called at SPLSD from sdstrategy and sd_done*/ +/* + * sdstart looks to see if there is a buf waiting for the device + * and that the device is not already busy. If both are true, + * It dequeues the buf and creates a scsi command to perform the + * transfer in the buf. The transfer request will call scsi_done + * on completion, which will in turn call this routine again + * so that the next queued transfer is performed. + * The bufs are queued by the strategy routine (sdstrategy) + * + * This routine is also called after other non-queued requests + * have been made of the scsi driver, to ensure that the queue + * continues to be drained. + * + * must be called at the correct (highish) spl level + * sdstart() is called at SPLSD from sdstrategy and scsi_done + */ +void sdstart(unit) -int unit; + u_int32 unit; { - int drivecount; - register struct buf *bp = 0; - register struct buf *dp; - struct scsi_xfer *xs; - struct scsi_rw_big cmd; - int blkno, nblk; - struct sd_data *sd = sd_data[unit]; - struct partition *p ; - -#ifdef SDDEBUG - if(scsi_debug & PRINTROUTINES) printf("sdstart%d ",unit); -#endif /*SDDEBUG*/ - /*******************************************************\ - * Check if the device is already running full capacity * - \*******************************************************/ - if(!sd_free_xfer[unit]) - { - return; /* none for us, unit already underway */ - } - - /*******************************************************\ - * there is excess capacity, but a special waits * - * It'll need the adapter as soon as we clear out of the * - * way and let it run (user level wait). * - \*******************************************************/ - if(sd_xfer_block_wait[unit]) - { - return; - } + register struct sd_data *sd = sd_data[unit]; + register struct scsi_link *sc_link = sd->sc_link; + struct buf *bp = 0; + struct buf *dp; + struct scsi_rw_big cmd; + u_int32 blkno, nblk; + struct partition *p; + + SC_DEBUG(sc_link, SDEV_DB2, ("sdstart ")); + /* + * Check if the device has room for another command + */ + while (sc_link->opennings) { - /*******************************************************\ - * See if there is a buf with work for us to do.. * - \*******************************************************/ - dp = &sd_buf_queue[unit]; - if ((bp = dp->b_actf) == NULL) /* yes, an assign */ - { - return; - } + /* + * there is excess capacity, but a special waits + * It'll need the adapter as soon as we clear out of the + * way and let it run (user level wait). + */ + if (sc_link->flags & SDEV_WAITING) { + return; + } + /* + * See if there is a buf with work for us to do.. + */ + dp = &sd->buf_queue; + if ((bp = dp->b_actf) == NULL) { /* yes, an assign */ + return; + } + dp->b_actf = bp->av_forw; - dp->b_actf = bp->av_forw; + /* + * If the device has become invalid, abort all the + * reads and writes until all files have been closed and + * re-openned + */ + if (!(sc_link->flags & SDEV_MEDIA_LOADED)) { + sd->flags &= ~SDHAVELABEL; + goto bad; + } + /* + * We have a buf, now we know we are going to go through + * With this thing.. + * + * First, translate the block to absolute + */ + p = sd->disklabel.d_partitions + PARTITION(bp->b_dev); + blkno = bp->b_blkno + p->p_offset; + nblk = (bp->b_bcount + 511) >> 9; - /*******************************************************\ - * If the device has become invalid, abort all the * - * reads and writes until all files have been closed and * - * re-openned * - \*******************************************************/ - if(!(sd->flags & SDVALID)) - { - goto bad; - } - /*******************************************************\ - * We have a buf, now we know we are going to go through * - * With this thing.. * - * * - * First, translate the block to absolute * - \*******************************************************/ - p = sd->disklabel.d_partitions + PARTITION(bp->b_dev); - blkno = bp->b_blkno + p->p_offset; - nblk = (bp->b_bcount + 511) >> 9; - - /*******************************************************\ - * Fill out the scsi command * - \*******************************************************/ - bzero(&cmd, sizeof(cmd)); - cmd.op_code = (bp->b_flags & B_READ) - ? READ_BIG : WRITE_BIG; - cmd.addr_3 = (blkno & 0xff000000) >> 24; - cmd.addr_2 = (blkno & 0xff0000) >> 16; - cmd.addr_1 = (blkno & 0xff00) >> 8; - cmd.addr_0 = blkno & 0xff; - cmd.length2 = (nblk & 0xff00) >> 8; - cmd.length1 = (nblk & 0xff); - /*******************************************************\ - * Call the routine that chats with the adapter * - * Note: we cannot sleep as we may be an interrupt * - \*******************************************************/ - if (sd_scsi_cmd(unit, - &cmd, + /* + * Fill out the scsi command + */ + bzero(&cmd, sizeof(cmd)); + cmd.op_code = (bp->b_flags & B_READ) + ? READ_BIG : WRITE_BIG; + cmd.addr_3 = (blkno & 0xff000000) >> 24; + cmd.addr_2 = (blkno & 0xff0000) >> 16; + cmd.addr_1 = (blkno & 0xff00) >> 8; + cmd.addr_0 = blkno & 0xff; + cmd.length2 = (nblk & 0xff00) >> 8; + cmd.length1 = (nblk & 0xff); + /* + * Call the routine that chats with the adapter. + * Note: we cannot sleep as we may be an interrupt + */ + if (scsi_scsi_cmd(sc_link, + (struct scsi_generic *) &cmd, sizeof(cmd), - (u_char *)bp->b_un.b_addr, + (u_char *) bp->b_un.b_addr, bp->b_bcount, + SD_RETRIES, 10000, bp, - SCSI_NOSLEEP| ((bp->b_flags & B_READ)? - SCSI_DATA_IN : SCSI_DATA_OUT)) - != SUCCESSFULLY_QUEUED) - { + SCSI_NOSLEEP | ((bp->b_flags & B_READ) ? + SCSI_DATA_IN : SCSI_DATA_OUT)) + == SUCCESSFULLY_QUEUED) { + sdqueues++; + } else { bad: - printf("sd%d: oops not queued",unit); - bp->b_error = EIO; - bp->b_flags |= B_ERROR; - biodone(bp); - return ; + printf("sd%d: oops not queued", unit); + bp->b_error = EIO; + bp->b_flags |= B_ERROR; + biodone(bp); + } } - sdqueues++; } -/*******************************************************\ -* Perform special action on behalf of the user * -* Knows about the internals of this device * -\*******************************************************/ +/* + * Perform special action on behalf of the user + * Knows about the internals of this device + */ +errval sdioctl(dev_t dev, int cmd, caddr_t addr, int flag) { - /* struct sd_cmd_buf *args;*/ - int error = 0; - unsigned int opri; + /* struct sd_cmd_buf *args; */ + errval error = 0; unsigned char unit, part; register struct sd_data *sd; - - /*******************************************************\ - * Find the device that the user is talking about * - \*******************************************************/ + /* + * Find the device that the user is talking about + */ unit = UNIT(dev); part = PARTITION(dev); sd = sd_data[unit]; -#ifdef SDDEBUG - if(scsi_debug & PRINTROUTINES) printf("sdioctl%d ",unit); -#endif /*SDDEBUG*/ - - /*******************************************************\ - * If the device is not valid.. abandon ship * - \*******************************************************/ - if (!(sd->flags & SDVALID)) - return(EIO); - switch(cmd) - { + SC_DEBUG(sd->sc_link, SDEV_DB1, ("sdioctl (0x%x)", cmd)); + + /* + * If the device is not valid.. abandon ship + */ + if (!(sd->sc_link->flags & SDEV_MEDIA_LOADED)) + return (EIO); + switch (cmd) { case DIOCSBAD: - error = EINVAL; + error = EINVAL; break; case DIOCGDINFO: - *(struct disklabel *)addr = sd->disklabel; + *(struct disklabel *) addr = sd->disklabel; + break; + + case DIOCGPART: + ((struct partinfo *) addr)->disklab = &sd->disklabel; + ((struct partinfo *) addr)->part = + &sd->disklabel.d_partitions[PARTITION(dev)]; break; - case DIOCGPART: - ((struct partinfo *)addr)->disklab = &sd->disklabel; - ((struct partinfo *)addr)->part = - &sd->disklabel.d_partitions[PARTITION(dev)]; - break; - - case DIOCSDINFO: - if ((flag & FWRITE) == 0) - error = EBADF; - else - error = setdisklabel(&sd->disklabel, - (struct disklabel *)addr, - /*(sd->flags & DKFL_BSDLABEL) ? sd->openparts : */0, - sd->dosparts); - if (error == 0) { + case DIOCSDINFO: + if ((flag & FWRITE) == 0) + error = EBADF; + else + error = setdisklabel(&sd->disklabel, + (struct disklabel *)addr, + /*(sd->flags & DKFL_BSDLABEL) ? sd->openparts : */ 0, +#ifdef NetBSD + &sd->cpudisklabel +#else + sd->dosparts +#endif + ); + if (error == 0) { sd->flags |= SDHAVELABEL; } - break; + break; - case DIOCWLABEL: + case DIOCWLABEL: sd->flags &= ~SDWRITEPROT; - if ((flag & FWRITE) == 0) - error = EBADF; - else - sd->wlabel = *(int *)addr; - break; + if ((flag & FWRITE) == 0) + error = EBADF; + else + sd->wlabel = *(boolean *) addr; + break; - case DIOCWDINFO: + case DIOCWDINFO: sd->flags &= ~SDWRITEPROT; - if ((flag & FWRITE) == 0) - error = EBADF; - else - { - if ((error = setdisklabel(&sd->disklabel - , (struct disklabel *)addr - , /*(sd->flags & SDHAVELABEL) ? sd->openparts :*/ 0 - , sd->dosparts)) == 0) - { - int wlab; - - sd->flags |= SDHAVELABEL; /* ok write will succeed */ - - /* simulate opening partition 0 so write succeeds */ - sd->openparts |= (1 << 0); /* XXX */ - wlab = sd->wlabel; - sd->wlabel = 1; - error = writedisklabel(dev, sdstrategy, - &sd->disklabel, sd->dosparts); - sd->wlabel = wlab; - } - } - break; - + if ((flag & FWRITE) == 0) + error = EBADF; + else { + error = setdisklabel(&sd->disklabel, + (struct disklabel *)addr, + /*(sd->flags & SDHAVELABEL) ? sd->openparts : */ 0, +#ifdef NetBSD + &sd->cpudisklabel +#else + sd->dosparts +#endif + ); + if (!error) { + boolean wlab; + + /* ok - write will succeed */ + sd->flags |= SDHAVELABEL; + + /* simulate opening partition 0 so write succeeds */ + sd->openparts |= (1 << 0); /* XXX */ + wlab = sd->wlabel; + sd->wlabel = 1; + error = writedisklabel(dev, sdstrategy, + &sd->disklabel, +#ifdef NetBSD + &sd->cpudisklabel +#else + sd->dosparts +#endif + ); + sd->wlabel = wlab; + } + } + break; default: - error = ENOTTY; + if (part == RAW_PART) + error = scsi_do_ioctl(sd->sc_link, cmd, addr, flag); + else + error = ENOTTY; break; } - return (error); + return error; } - -/*******************************************************\ -* Load the label information on the named device * -\*******************************************************/ -int sdgetdisklabel(unit) -unsigned char unit; +/* + * Load the label information on the named device + */ +errval +sdgetdisklabel(unsigned char unit) { - /*unsigned int n, m;*/ - char *errstring; - struct dos_partition *dos_partition_p; + char *errstring; struct sd_data *sd = sd_data[unit]; - /*******************************************************\ - * If the inflo is already loaded, use it * - \*******************************************************/ - if(sd->flags & SDHAVELABEL) return(ESUCCESS); - - bzero(&sd->disklabel,sizeof(struct disklabel)); - /*******************************************************\ - * make partition 3 the whole disk in case of failure * - * then get pdinfo * - * for historical reasons, make part a same as raw part * - \*******************************************************/ + /* + * If the inflo is already loaded, use it + */ + if (sd->flags & SDHAVELABEL) + return (ESUCCESS); + + bzero(&sd->disklabel, sizeof(struct disklabel)); + /* + * make partition 3 the whole disk in case of failure then get pdinfo + * for historical reasons, make part a same as raw part + */ sd->disklabel.d_partitions[0].p_offset = 0; sd->disklabel.d_partitions[0].p_size = sd->params.disksize; sd->disklabel.d_partitions[RAW_PART].p_offset = 0; sd->disklabel.d_partitions[RAW_PART].p_size = sd->params.disksize; sd->disklabel.d_npartitions = MAXPARTITIONS; - sd->disklabel.d_secsize = 512; /* as long as it's not 0 */ + sd->disklabel.d_secsize = SECSIZE; /* as long as it's not 0 */ sd->disklabel.d_ntracks = sd->params.heads; sd->disklabel.d_nsectors = sd->params.sectors; sd->disklabel.d_ncylinders = sd->params.cyls; sd->disklabel.d_secpercyl = sd->params.heads * sd->params.sectors; - if (sd->disklabel.d_secpercyl == 0) - { + if (sd->disklabel.d_secpercyl == 0) { sd->disklabel.d_secpercyl = 100; - /* as long as it's not 0 */ - /* readdisklabel divides by it (?)*/ + /* as long as it's not 0 - readdisklabel divides by it (?) */ } - - /*******************************************************\ - * Call the generic disklabel extraction routine * - \*******************************************************/ - if(errstring = readdisklabel(makedev(0 ,(unit<disklabel - , sd->dosparts - , 0 - , 0)) - { - printf("sd%d: %s\n",unit, errstring); - return(ENXIO); + /* + * Call the generic disklabel extraction routine + */ + if (errstring = readdisklabel(makedev(0, (unit << UNITSHIFT) + 3), + sdstrategy, + &sd->disklabel, +#ifdef NetBSD + &sd->cpudisklabel +#else + sd->dosparts, + 0, + 0 +#endif + )) { + printf("sd%d: %s\n", unit, errstring); + return ENXIO; } - - sd->flags |= SDHAVELABEL; /* WE HAVE IT ALL NOW */ - return(ESUCCESS); + sd->flags |= SDHAVELABEL; /* WE HAVE IT ALL NOW */ + return ESUCCESS; } -/*******************************************************\ -* Find out from the device what it's capacity is * -\*******************************************************/ +/* + * Find out from the device what it's capacity is + */ +u_int32 sd_size(unit, flags) + int unit, flags; { struct scsi_read_cap_data rdcap; struct scsi_read_capacity scsi_cmd; - int size; + u_int32 size; - /*******************************************************\ - * make up a scsi command and ask the scsi driver to do * - * it for you. * - \*******************************************************/ + /* + * make up a scsi command and ask the scsi driver to do + * it for you. + */ bzero(&scsi_cmd, sizeof(scsi_cmd)); scsi_cmd.op_code = READ_CAPACITY; - /*******************************************************\ - * If the command works, interpret the result as a 4 byte* - * number of blocks * - \*******************************************************/ - if (sd_scsi_cmd(unit, - &scsi_cmd, - sizeof(scsi_cmd), - &rdcap, - sizeof(rdcap), - 6000, - NULL, - flags | SCSI_DATA_IN) != 0) - { + /* + * If the command works, interpret the result as a 4 byte + * number of blocks + */ + if (scsi_scsi_cmd(sd_data[unit]->sc_link, + (struct scsi_generic *) &scsi_cmd, + sizeof(scsi_cmd), + (u_char *) & rdcap, + sizeof(rdcap), + SD_RETRIES, + 2000, + NULL, + flags | SCSI_DATA_IN) != 0) { printf("sd%d: could not get size\n", unit); - return(0); + return (0); } else { - size = rdcap.addr_0 + 1 ; + size = rdcap.addr_0 + 1; size += rdcap.addr_1 << 8; size += rdcap.addr_2 << 16; size += rdcap.addr_3 << 24; } - return(size); -} - -/*******************************************************\ -* Get scsi driver to send a "are you ready?" command * -\*******************************************************/ -sd_test_unit_ready(unit,flags) -int unit,flags; -{ - struct scsi_test_unit_ready scsi_cmd; - - bzero(&scsi_cmd, sizeof(scsi_cmd)); - scsi_cmd.op_code = TEST_UNIT_READY; - - return (sd_scsi_cmd(unit, - &scsi_cmd, - sizeof(scsi_cmd), - 0, - 0, - 100000, - NULL, - flags)); -} - -/*******************************************************\ -* Prevent or allow the user to remove the tape * -* Don't change this status if any partitions are open * -\*******************************************************/ -sd_prevent(unit,type,flags) -int unit,type,flags; -{ - struct scsi_prevent scsi_cmd; - - if(sd_data[unit]->openparts) return; - - bzero(&scsi_cmd, sizeof(scsi_cmd)); - scsi_cmd.op_code = PREVENT_ALLOW; - scsi_cmd.how=type; - return (sd_scsi_cmd(unit, - &scsi_cmd, - sizeof(scsi_cmd), - 0, - 0, - 5000, - NULL, - flags) ); -} -/*******************************************************\ -* Get scsi driver to send a "start up" command * -\*******************************************************/ -sd_start_unit(unit,flags) -int unit,flags; -{ - struct scsi_start_stop scsi_cmd; - - bzero(&scsi_cmd, sizeof(scsi_cmd)); - scsi_cmd.op_code = START_STOP; - scsi_cmd.how = SSS_START; - - return (sd_scsi_cmd(unit, - &scsi_cmd, - sizeof(scsi_cmd), - 0, - 0, - 6000, - NULL, - flags)); + return (size); } -/*******************************************************\ -* Tell the device to map out a defective block * -\*******************************************************/ -sd_reassign_blocks(unit,block) +/* + * Tell the device to map out a defective block + */ +errval +sd_reassign_blocks(unit, block) + int unit, block; { - struct scsi_reassign_blocks scsi_cmd; - struct scsi_reassign_blocks_data rbdata; - + struct scsi_reassign_blocks scsi_cmd; + struct scsi_reassign_blocks_data rbdata; bzero(&scsi_cmd, sizeof(scsi_cmd)); bzero(&rbdata, sizeof(rbdata)); @@ -905,108 +777,67 @@ sd_reassign_blocks(unit,block) rbdata.length_lsb = sizeof(rbdata.defect_descriptor[0]); rbdata.defect_descriptor[0].dlbaddr_3 = ((block >> 24) & 0xff); rbdata.defect_descriptor[0].dlbaddr_2 = ((block >> 16) & 0xff); - rbdata.defect_descriptor[0].dlbaddr_1 = ((block >> 8) & 0xff); - rbdata.defect_descriptor[0].dlbaddr_0 = ((block ) & 0xff); - - return(sd_scsi_cmd(unit, - &scsi_cmd, - sizeof(scsi_cmd), - &rbdata, - sizeof(rbdata), - 5000, - NULL, - SCSI_DATA_OUT)); + rbdata.defect_descriptor[0].dlbaddr_1 = ((block >> 8) & 0xff); + rbdata.defect_descriptor[0].dlbaddr_0 = ((block) & 0xff); + + return (scsi_scsi_cmd(sd_data[unit]->sc_link, + (struct scsi_generic *) &scsi_cmd, + sizeof(scsi_cmd), + (u_char *) & rbdata, + sizeof(rbdata), + SD_RETRIES, + 5000, + NULL, + SCSI_DATA_OUT)); } - #define b2tol(a) (((unsigned)(a##_1) << 8) + (unsigned)a##_0 ) -/*******************************************************\ -* Get the scsi driver to send a full inquiry to the * -* device and use the results to fill out the disk * -* parameter structure. * -\*******************************************************/ - -int sd_get_parms(unit, flags) +/* + * Get the scsi driver to send a full inquiry to the + * device and use the results to fill out the disk + * parameter structure. + */ +errval +sd_get_parms(unit, flags) + int unit, flags; { struct sd_data *sd = sd_data[unit]; struct disk_parms *disk_parms = &sd->params; - struct scsi_mode_sense scsi_cmd; - struct scsi_mode_sense_data - { - struct scsi_mode_header header; - struct blk_desc blk_desc; - union disk_pages pages; - }scsi_sense; - int sectors; - - /*******************************************************\ - * First check if we have it all loaded * - \*******************************************************/ - if(sd->flags & SDVALID) return(0); - /*******************************************************\ - * First do a mode sense page 3 * - \*******************************************************/ -#ifdef SDDEBUG - if (sd_debug) - { - bzero(&scsi_cmd, sizeof(scsi_cmd)); - scsi_cmd.op_code = MODE_SENSE; - scsi_cmd.page = 3; - scsi_cmd.length = 0x24; - /*******************************************************\ - * do the command, but we don't need the results * - * just print them for our interest's sake * - \*******************************************************/ - if (sd_scsi_cmd(unit, - &scsi_cmd, - sizeof(scsi_cmd), - &scsi_sense, - sizeof(scsi_sense), - 2000, - NULL, - flags | SCSI_DATA_IN) != 0) - { - printf("sd%d: could not mode sense (3)\n", unit); - } - else - { - printf("unit %d: %d trk/zone, %d alt_sec/zone, %d alt_trk/zone, %d alt_trk/lun\n", - unit, - b2tol(scsi_sense.pages.disk_format.trk_z), - b2tol(scsi_sense.pages.disk_format.alt_sec), - b2tol(scsi_sense.pages.disk_format.alt_trk_z), - b2tol(scsi_sense.pages.disk_format.alt_trk_v)); - printf(" %d sec/trk, %d bytes/sec, %d interleave, %d %d bytes/log_blk\n", - b2tol(scsi_sense.pages.disk_format.ph_sec_t), - b2tol(scsi_sense.pages.disk_format.bytes_s), - b2tol(scsi_sense.pages.disk_format.interleave), - sd_size(unit, flags), - _3btol(scsi_sense.blk_desc.blklen)); - } - } -#endif /*SDDEBUG*/ - - - /*******************************************************\ - * do a "mode sense page 4" * - \*******************************************************/ + struct scsi_mode_sense scsi_cmd; + struct scsi_mode_sense_data { + struct scsi_mode_header header; + struct blk_desc blk_desc; + union disk_pages pages; + } scsi_sense; + u_int32 sectors; + + /* + * First check if we have it all loaded + */ + if (sd->flags & SDEV_MEDIA_LOADED) + return 0; + + /* + * do a "mode sense page 4" + */ bzero(&scsi_cmd, sizeof(scsi_cmd)); scsi_cmd.op_code = MODE_SENSE; scsi_cmd.page = 4; scsi_cmd.length = 0x20; - /*******************************************************\ - * If the command worked, use the results to fill out * - * the parameter structure * - \*******************************************************/ - if (sd_scsi_cmd(unit, - &scsi_cmd, - sizeof(scsi_cmd), - &scsi_sense, - sizeof(scsi_sense), - 2000, - NULL, - flags | SCSI_DATA_IN) != 0) - { + /* + * If the command worked, use the results to fill out + * the parameter structure + */ + if (scsi_scsi_cmd(sd->sc_link, + (struct scsi_generic *) &scsi_cmd, + sizeof(scsi_cmd), + (u_char *) & scsi_sense, + sizeof(scsi_sense), + SD_RETRIES, + 2000, + NULL, + flags | SCSI_DATA_IN) != 0) { + printf("sd%d could not mode sense (4).", unit); printf(" Using ficticious geometry\n"); /* @@ -1017,631 +848,212 @@ int sd_get_parms(unit, flags) sectors = sd_size(unit, flags); disk_parms->heads = 64; disk_parms->sectors = 32; - disk_parms->cyls = sectors/(64 * 32); + disk_parms->cyls = sectors / (64 * 32); disk_parms->secsiz = SECSIZE; disk_parms->disksize = sectors; - } - else - { + } else { -#ifdef SDDEBUG - if (sd_debug) - { - printf(" %d cyls, %d heads, %d precomp, %d red_write, %d land_zone\n", + 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_2), scsi_sense.pages.rigid_geometry.nheads, b2tol(scsi_sense.pages.rigid_geometry.st_cyl_wp), b2tol(scsi_sense.pages.rigid_geometry.st_cyl_rwc), - b2tol(scsi_sense.pages.rigid_geometry.land_zone)); - } -#endif /*SDDEBUG*/ - - /*******************************************************\ - * 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 ! * - \*******************************************************/ + b2tol(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 ! + */ disk_parms->heads = scsi_sense.pages.rigid_geometry.nheads; disk_parms->cyls = _3btol(&scsi_sense.pages.rigid_geometry.ncyl_2); - disk_parms->secsiz = _3btol(&scsi_sense.blk_desc.blklen); + disk_parms->secsiz = _3btol(scsi_sense.blk_desc.blklen); sectors = sd_size(unit, flags); disk_parms->disksize = sectors; sectors /= (disk_parms->heads * disk_parms->cyls); - disk_parms->sectors = sectors; /* dubious on SCSI*//*XXX*/ + disk_parms->sectors = sectors; /* dubious on SCSI *//*XXX */ } - - sd->flags |= SDVALID; - return(0); + sd->sc_link->flags |= SDEV_MEDIA_LOADED; + return 0; } -/*******************************************************\ -* close the device.. only called if we are the LAST * -* occurence of an open device * -* convenient now but usually a pain * -\*******************************************************/ -sdclose(dev) -dev_t dev; +int +sdsize(dev_t dev) { - unsigned char unit, part; - unsigned int old_priority; + u_int32 unit = UNIT(dev), part = PARTITION(dev), val; struct sd_data *sd; - unit = UNIT(dev); - part = PARTITION(dev); - sd = sd_data[unit]; - sd->partflags[part] &= ~SDOPEN; - sd->openparts &= ~(1 << part); - sd_prevent(unit,PR_ALLOW,SCSI_SILENT|SCSI_ERR_OK); - return(0); -} - -/*******************************************************\ -* This routine is called by the scsi interrupt when * -* the transfer is complete. -\*******************************************************/ -int sd_done(unit,xs) -int unit; -struct scsi_xfer *xs; -{ - struct buf *bp; - int retval; - int retries = 0; - -#ifdef SDDEBUG - if(scsi_debug & PRINTROUTINES) printf("sd_done%d ",unit); -#endif /*SDDEBUG*/ -#ifdef PARANOID - if (! (xs->flags & INUSE)) - panic("scsi_xfer not in use!"); -#endif - if((bp = xs->bp) == NULL) - { - /***********************************************\ - * if it's a normal user level request, then ask * - * The user level code to handle error checking * - * rather than doing it here at interrupt time * - \***********************************************/ - wakeup(xs); - return; - } - - /***********************************************\ - * If it has a buf, we might be working with * - * a request from the buffer cache or some other * - * piece of code that requires us to process * - * errors right now, despite cost * - \***********************************************/ - switch(xs->error) - { - case XS_NOERROR: - bp->b_error = 0; - bp->b_resid = 0; - break; - - case XS_SENSE: - retval = (sd_interpret_sense(unit,xs)); - if(retval) - { - bp->b_flags |= B_ERROR; - bp->b_error = retval; - } - break; - - case XS_BUSY: - /*should somehow arange for a 1 sec delay here (how?)*/ - case XS_TIMEOUT: - /***********************************************\ - * If we can, resubmit it to the adapter. * - \***********************************************/ - if(xs->retries--) - { - xs->error = XS_NOERROR; - xs->flags &= ~ITSDONE; - if ( (*(sd_data[unit]->sc_sw->scsi_cmd))(xs) - == SUCCESSFULLY_QUEUED) - { /* don't wake the job, ok? */ - return; - } - xs->flags |= ITSDONE; - } /* fall through */ - - case XS_DRIVER_STUFFUP: - bp->b_flags |= B_ERROR; - bp->b_error = EIO; - break; - default: - printf("sd%d: unknown error category from scsi driver\n" - ,unit); - } - /*******************************\ - * tell the owner we're done * - * then free our resources * - * and see if there's more work * - \*******************************/ - biodone(bp); - sd_free_xs(unit,xs,0); - sdstart(unit); /* If there's anything waiting.. do it */ -} - -/*******************************************************\ -* ask the scsi driver to perform a command for us. * -* Call it through the switch table, and tell it which * -* sub-unit we want, and what target and lu we wish to * -* talk to. Also tell it where to find the command * -* and how long it is. * -* Also tell it where to read/write the data, and how * -* long the data is supposed to be. If we have a buf * -* to associate with the transfer, we need that too. * -\*******************************************************/ -int sd_scsi_cmd(unit,scsi_cmd,cmdlen,data_addr,datalen,timeout,bp,flags) - -int unit,flags; -struct scsi_generic *scsi_cmd; -int cmdlen; -int timeout; -u_char *data_addr; -int datalen; -struct buf *bp; -{ - struct scsi_xfer *xs; - int retval; - int s; - struct sd_data *sd = sd_data[unit]; - -#ifdef SDDEBUG - if(scsi_debug & PRINTROUTINES) printf("\nsd_scsi_cmd%d ",unit); -#endif /*SDDEBUG*/ - -#ifdef PARANOID - if(!(sd->sc_sw)) /* If we have a scsi driver */ - {/* How we got here is anyone's guess */ - printf("sd%d: not set up\n",unit); - return(EINVAL); - } -#endif - xs = sd_get_xs(unit,flags); /* should wait unless booting */ -#ifdef PARANOID - if(!xs) - { - printf("sd_scsi_cmd%d: controller busy" - " (this should never happen)\n",unit); - return(EBUSY); - } -#endif - /*******************************************************\ - * Fill out the scsi_xfer structure * - \*******************************************************/ - xs->flags = INUSE | flags; - xs->adapter = sd->ctlr; - xs->targ = sd->targ; - xs->lu = sd->lu; - xs->retries = SD_RETRIES; - xs->timeout = timeout; - xs->cmd = scsi_cmd; - xs->cmdlen = cmdlen; - xs->data = data_addr; - xs->datalen = datalen; - xs->resid = datalen; - xs->when_done = sd_done; - xs->done_arg = unit; - xs->done_arg2 = (int)xs; - xs->bp = bp; -retry: xs->error = XS_NOERROR; - - /*******************************************************\ - * Do the transfer. If we are polling we will return: * - * COMPLETE, Was poll, and sd_done has been called * - * HAD_ERROR, Was poll and an error was encountered * - * TRY_AGAIN_LATER, Adapter short resources, try again * - * * - * if under full steam (interrupts) it will return: * - * SUCCESSFULLY_QUEUED, will do a wakeup when complete * - * HAD_ERROR, had an erro before it could queue * - * TRY_AGAIN_LATER, (as for polling) * - * After the wakeup, we must still check if it succeeded * - * * - * If we have a bp however, all the error proccessing * - * and the buffer code both expect us to return straight * - * to them, so as soon as the command is queued, return * - \*******************************************************/ - retval = (*(sd->sc_sw->scsi_cmd))(xs); - if(bp) return retval; /* will sleep (or not) elsewhere */ - - /*******************************************************\ - * Only here for non I/O cmds. It's cheaper to process * - * the error status here than at interrupt time so * - * sd_done will have done nothing except wake us up. * - \*******************************************************/ - switch(retval) - { - case SUCCESSFULLY_QUEUED: - s = splbio(); - while(!(xs->flags & ITSDONE)) - sleep(xs,PRIBIO+1); - splx(s); - /* fall through to check success of completed command */ - - case HAD_ERROR: - switch(xs->error) - { - case XS_NOERROR: /* nearly always hit this one */ - retval = ESUCCESS; - break; - - case XS_SENSE: - retval = (sd_interpret_sense(unit,xs)); - break; - case XS_BUSY: - /* should sleep 1 sec here */ - case XS_TIMEOUT: - if(xs->retries-- ) - { - xs->flags &= ~ITSDONE; - goto retry; - } - case XS_DRIVER_STUFFUP: - retval = EIO; - break; - default: - retval = EIO; - printf("sd%d: unknown error category from scsi driver\n" - ,unit); - } - break; - case COMPLETE: /* Polling command completed ok */ - retval = ESUCCESS; - break; + if (unit >= NSD) + return -1; - case TRY_AGAIN_LATER: /* adapter resource shortage */ - /* should sleep 1 sec here */ - if(xs->retries-- ) - { - xs->flags &= ~ITSDONE; - goto retry; - } - default: - retval = EIO; + sd = sd_data[unit]; + if (!sd) + return -1; + if ((sd->flags & SDINIT) == 0) + return -1; + if (sd == 0 || (sd->flags & SDHAVELABEL) == 0) { + val = sdopen(MAKESDDEV(major(dev), unit, RAW_PART), FREAD, S_IFBLK, 0); + if (val != 0) + return -1; } - /*******************************************************\ - * we have finished with the xfer stuct, free it and * - * check if anyone else needs to be started up. * - \*******************************************************/ - sd_free_xs(unit,xs,flags); - sdstart(unit); /* check queue */ - return(retval); -} - -/***************************************************************\ -* Look at the returned sense and act on the error and detirmine * -* The unix error number to pass back... (0 = report no error) * -\***************************************************************/ + if (sd->flags & SDWRITEPROT) + return -1; -int sd_interpret_sense(unit,xs) -int unit; -struct scsi_xfer *xs; -{ - struct scsi_sense_data *sense; - int key; - int silent; - long int info; - - /***************************************************************\ - * If the flags say errs are ok, then always return ok. * - \***************************************************************/ - if (xs->flags & SCSI_ERR_OK) return(ESUCCESS); - silent = (xs->flags & SCSI_SILENT); - - sense = &(xs->sense); - info = ((sense->ext.extended.info[0] <<24)| - (sense->ext.extended.info[1] <<16)| - (sense->ext.extended.info[2] <<8)| - (sense->ext.extended.info[3] )); - switch(sense->error_code & SSD_ERRCODE) - { - case 0x70: - { - key=sense->ext.extended.flags & SSD_KEY; - switch(key) - { - case 0x0: - return(ESUCCESS); - case 0x1: - if(!silent) - { - printf("sd%d: soft error(corrected) ", unit); - if(sense->error_code & SSD_ERRCODE_VALID) - { - printf("block no. %d (decimal)",info); - } - printf("\n"); - } - return(ESUCCESS); - case 0x2: - if(!silent)printf("sd%d: not ready\n ", - unit); - return(ENODEV); - case 0x3: - if(!silent) - { - printf("sd%d: medium error ", unit); - if(sense->error_code & SSD_ERRCODE_VALID) - { - printf("block no. %d (decimal)",info); - } - printf("\n"); - } - return(EIO); - case 0x4: - if(!silent)printf("sd%d: non-media hardware failure\n ", - unit); - return(EIO); - case 0x5: - if(!silent)printf("sd%d: illegal request\n ", - unit); - return(EINVAL); - case 0x6: - /***********************************************\ - * If we are not open, then this is not an error * - * as we don't have state yet. Either way, make * - * sure that we don't have any residual state * - \***********************************************/ - if(!silent)printf("sd%d: Unit attention.\n ", unit); - sd_data[unit]->flags &= ~(SDVALID | SDHAVELABEL); - if (sd_data[unit]->openparts) - { - return(EIO); - } - return(ESUCCESS); /* not an error if nothing's open */ - case 0x7: - if(!silent) - { - printf("sd%d: attempted protection violation ", - unit); - if(sense->error_code & SSD_ERRCODE_VALID) - { - printf("block no. %d (decimal)\n",info); - } - printf("\n"); - } - return(EACCES); - case 0x8: - if(!silent) - { - printf("sd%d: block wrong state (format?)\n ", - unit); - if(sense->error_code & SSD_ERRCODE_VALID) - { - printf("block no. %d (decimal)\n",info); - } - printf("\n"); - } - return(EIO); - case 0x9: - if(!silent)printf("sd%d: vendor unique\n", - unit); - return(EIO); - case 0xa: - if(!silent)printf("sd%d: copy aborted\n ", - unit); - return(EIO); - case 0xb: - if(!silent)printf("sd%d: command aborted\n ", - unit); - return(EIO); - case 0xc: - if(!silent) - { - printf("sd%d: search returned\n ", - unit); - if(sense->error_code & SSD_ERRCODE_VALID) - { - printf("block no. %d (decimal)\n",info); - } - printf("\n"); - } - return(ESUCCESS); - case 0xd: - if(!silent)printf("sd%d: volume overflow\n ", - unit); - return(ENOSPC); - case 0xe: - if(!silent) - { - printf("sd%d: verify miscompare\n ", - unit); - if(sense->error_code & SSD_ERRCODE_VALID) - { - printf("block no. %d (decimal)\n",info); - } - printf("\n"); - } - return(EIO); - case 0xf: - if(!silent)printf("sd%d: unknown error key\n ", - unit); - return(EIO); - } - break; - } - default: - { - if(!silent)printf("sd%d: code %d\n", - unit, - sense->error_code & SSD_ERRCODE); - if(sense->error_code & SSD_ERRCODE_VALID) - if(!silent)printf("block no. %d (decimal)\n", - (sense->ext.unextended.blockhi <<16) - + (sense->ext.unextended.blockmed <<8) - + (sense->ext.unextended.blocklow )); - } - return(EIO); - } + return (int)sd->disklabel.d_partitions[part].p_size; } +#define SCSIDUMP 1 +#undef SCSIDUMP +#define NOT_TRUSTED 1 - -int -sdsize(dev_t dev) -{ - int unit = UNIT(dev), part = PARTITION(dev), val; - struct sd_data *sd; - - if (unit >= NSD) - return(-1); - - sd = sd_data[unit]; - if(!sd) return(-1); - if((sd->flags & SDINIT) == 0) return(-1); - if (sd == 0 || (sd->flags & SDHAVELABEL) == 0) - val = sdopen (MAKESDDEV(major(dev), unit, RAW_PART), FREAD, S_IFBLK, 0); - if ( val != 0 || sd->flags & SDWRITEPROT) - return (-1); - - return((int)sd->disklabel.d_partitions[part].p_size); -} -/*#define SCSIDUMP*/ #ifdef SCSIDUMP #include -/***********************************************************************\ -* dump all of physical memory into the partition specified, starting * -* at offset 'dumplo' into the partition. * -\***********************************************************************/ -static struct scsi_xfer sx; -#define MAXTRANSFER 8 /* 1 page at a time */ -int -sddump(dev_t dev) /* dump core after a system crash */ -{ + +static struct scsi_xfer sx; +#define MAXTRANSFER 8 /* 1 page at a time */ + +/* + * dump all of physical memory into the partition specified, starting + * at offset 'dumplo' into the partition. + */ +errval +sddump(dev_t dev) +{ /* dump core after a system crash */ register struct sd_data *sd; /* disk unit to do the IO */ - long num; /* number of sectors to write */ - int unit, part, sdc; - long blkoff, blknum, blkcnt; - long nblocks; + int32 num; /* number of sectors to write */ + u_int32 unit, part; + int32 blkoff, blknum, blkcnt = MAXTRANSFER; + int32 nblocks; char *addr; - struct scsi_rw_big cmd; + struct scsi_rw_big cmd; extern int Maxmem; - static sddoingadump = 0 ; - extern caddr_t CADDR1; /* map the page we are about to write, here*/ - struct scsi_xfer *xs = &sx; - int retval; + static int sddoingadump = 0; +#define MAPTO CADDR1 + extern caddr_t MAPTO; /* map the page we are about to write, here */ + struct scsi_xfer *xs = &sx; + errval retval; + int c; - addr = (char *) 0; /* starting address */ + addr = (char *) 0; /* starting address */ /* toss any characters present prior to dump */ - while (sgetc(1)) - ; + while ((c = sgetc(1)) && (c != 0x100)); /*syscons and pccons differ */ /* size of memory to dump */ num = Maxmem; - unit = UNIT(dev); /* eventually support floppies? */ - part = PARTITION(dev); /* file system */ + unit = UNIT(dev); /* eventually support floppies? */ + part = PARTITION(dev); /* file system */ /* check for acceptable drive number */ - if (unit >= NSD) return(ENXIO); /* 31 Jul 92*/ + if (unit >= NSD) + return (ENXIO); /* 31 Jul 92 */ sd = sd_data[unit]; - if(!sd) return (ENXIO); + if (!sd) + return (ENXIO); /* was it ever initialized etc. ? */ - if (!(sd->flags & SDINIT)) return (ENXIO); - if (sd->flags & SDVALID != SDVALID) return (ENXIO) ; - if (sd->flags & SDWRITEPROT) return (ENXIO); + if (!(sd->flags & SDINIT)) + return (ENXIO); + if (sd->sc_link->flags & SDEV_MEDIA_LOADED != SDEV_MEDIA_LOADED) + return (ENXIO); + if (sd->flags & SDWRITEPROT) + return (ENXIO); /* Convert to disk sectors */ - num = (u_long) num * NBPG / sd->disklabel.d_secsize; + num = (u_int32) num * NBPG / sd->disklabel.d_secsize; /* check if controller active */ - if (sddoingadump) return(EFAULT); + if (sddoingadump) + return (EFAULT); nblocks = sd->disklabel.d_partitions[part].p_size; blkoff = sd->disklabel.d_partitions[part].p_offset; /* check transfer bounds against partition size */ if ((dumplo < 0) || ((dumplo + num) > nblocks)) - return(EINVAL); + return (EINVAL); - sddoingadump = 1 ; + sddoingadump = 1; blknum = dumplo + blkoff; - while (num > 0) - { - if (blkcnt > MAXTRANSFER) blkcnt = MAXTRANSFER; - pmap_enter( kernel_pmap, - CADDR1, - trunc_page(addr), - VM_PROT_READ, - TRUE); + /* blkcnt = initialise_me; */ + while (num > 0) { + pmap_enter(kernel_pmap, + MAPTO, + trunc_page(addr), + VM_PROT_READ, + TRUE); #ifndef NOT_TRUSTED - /*******************************************************\ - * Fill out the scsi command * - \*******************************************************/ + /* + * Fill out the scsi command + */ bzero(&cmd, sizeof(cmd)); - cmd.op_code = WRITE_BIG; - cmd.addr_3 = (blknum & 0xff000000) >> 24; - cmd.addr_2 = (blknum & 0xff0000) >> 16; - cmd.addr_1 = (blknum & 0xff00) >> 8; - cmd.addr_0 = blknum & 0xff; - cmd.length2 = (blkcnt & 0xff00) >> 8; - cmd.length1 = (blkcnt & 0xff); - /*******************************************************\ - * Fill out the scsi_xfer structure * - * Note: we cannot sleep as we may be an interrupt * - \*******************************************************/ + cmd.op_code = WRITE_BIG; + cmd.addr_3 = (blknum & 0xff000000) >> 24; + cmd.addr_2 = (blknum & 0xff0000) >> 16; + cmd.addr_1 = (blknum & 0xff00) >> 8; + cmd.addr_0 = blknum & 0xff; + cmd.length2 = (blkcnt & 0xff00) >> 8; + cmd.length1 = (blkcnt & 0xff); + /* + * Fill out the scsi_xfer structure + * Note: we cannot sleep as we may be an interrupt + * don't use scsi_scsi_cmd() as it may want + * to wait for an xs. + */ bzero(xs, sizeof(sx)); - xs->flags |= SCSI_NOMASK|SCSI_NOSLEEP|INUSE; - xs->adapter = sd->ctlr; - xs->targ = sd->targ; - xs->lu = sd->lu; - xs->retries = SD_RETRIES; - xs->timeout = 10000;/* 10000 millisecs for a disk !*/ - xs->cmd = (struct scsi_generic *)&cmd; - xs->cmdlen = sizeof(cmd); - xs->resid = blkcnt * 512; - xs->when_done = 0; - xs->done_arg = unit; - xs->done_arg2 = (int)xs; - xs->error = XS_NOERROR; - xs->bp = 0; - xs->data = (u_char *)CADDR1; - xs->datalen = blkcnt * 512; - - /*******************************************************\ - * Pass all this info to the scsi driver. * - \*******************************************************/ - retval = (*(sd->sc_sw->scsi_cmd))(xs); - switch(retval) - { - case SUCCESSFULLY_QUEUED: - case HAD_ERROR: - return(ENXIO); /* we said not to sleep! */ - case COMPLETE: + xs->flags |= SCSI_NOMASK | SCSI_NOSLEEP | INUSE; + xs->sc_link = sd->sc_link; + xs->retries = SD_RETRIES; + xs->timeout = 10000; /* 10000 millisecs for a disk ! */ + xs->cmd = (struct scsi_generic *) &cmd; + xs->cmdlen = sizeof(cmd); + xs->resid = blkcnt * 512; + xs->error = XS_NOERROR; + xs->bp = 0; + xs->data = (u_char *) MAPTO; + xs->datalen = blkcnt * 512; + + /* + * Pass all this info to the scsi driver. + */ + retval = (*(sd->sc_link->adapter->scsi_cmd)) (xs); + switch (retval) { + case SUCCESSFULLY_QUEUED: + case HAD_ERROR: + return (ENXIO); /* we said not to sleep! */ + case COMPLETE: break; default: - return(ENXIO); /* we said not to sleep! */ + return (ENXIO); /* we said not to sleep! */ } -#else NOT_TRUSTED - /* lets just talk about this first...*/ - printf ("sd%d: dump addr 0x%x, blk %d\n",unit,addr,blknum); -#endif NOT_TRUSTED - - if ((unsigned)addr % (1024*1024) == 0) printf("%d ", num/2048) ; +#else /* NOT_TRUSTED */ + /* lets just talk about this first... */ + printf("sd%d: dump addr 0x%x, blk %d\n", unit, addr, blknum); +#endif /* NOT_TRUSTED */ + + if ((unsigned) addr % (1024 * 1024) == 0) + printf("%d ", num / 2048); /* update block count */ - num -= MAXTRANSFER; - blknum += MAXTRANSFER ; - (int) addr += 512 * MAXTRANSFER; + num -= blkcnt; + blknum += blkcnt; + (int) addr += 512 * blkcnt; /* operator aborting dump? */ - if (sgetc(1)) - return(EINTR); + if ((c = sgetc(1)) && (c != 0x100)) + return (EINTR); } - return(0); + return (0); } -#else SCSIDUMP +#else /* SCSIDUMP */ +errval sddump() { printf("\nsddump() -- not implemented\n"); - DELAY(20000000); /* 20 seconds */ - return(-1); + DELAY(60000000); /* 60 seconds */ + return -1; } -#endif SCSIDUMP - +#endif /* SCSIDUMP */ diff --git a/sys/scsi/st.c b/sys/scsi/st.c index e367389144..08c8d4679d 100644 --- a/sys/scsi/st.c +++ b/sys/scsi/st.c @@ -12,13 +12,24 @@ * on the understanding that TFS is not responsible for the correct * functioning of this software in any circumstances. * + * + * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE + * -------------------- ----- ---------------------- + * CURRENT PATCH LEVEL: 1 00098 + * -------------------- ----- ---------------------- + * + * 16 Feb 93 Julian Elischer ADDED for SCSI system + * 1.15 is the last version to support MACH and OSF/1 + */ +/* $Revision: 2.6 $ */ + +/* * Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992 * major changes by Julian Elischer (julian@jules.dialix.oz.au) May 1993 * - * $Id: st.c,v 1.11 1993/10/16 17:21:10 rgrimes Exp $ + * $Id: st.c,v 2.6 93/10/21 03:24:38 julian Exp Locker: julian $ */ - /* * To do: * work out some better way of guessing what a good timeout is going @@ -41,886 +52,882 @@ #include #include - #include #include #include - -long int ststrats,stqueues; +u_int32 ststrats, stqueues; /* Defines for device specific stuff */ #define PAGE_0_SENSE_DATA_SIZE 12 #define PAGESIZ 4096 #define DEF_FIXED_BSIZE 512 -#define STQSIZE 4 -#define ST_RETRIES 4 - +#define ST_RETRIES 4 /* only on non IO commands */ #define MODE(z) ( (minor(z) & 0x03) ) #define DSTY(z) ( ((minor(z) >> 2) & 0x03) ) #define UNIT(z) ( (minor(z) >> 4) ) - -#define DSTY3 3 -#define DSTY2 2 -#define DSTY1 1 +#define CTLMODE 3 #define SCSI_2_MAX_DENSITY_CODE 0x17 /* maximum density code specified - in SCSI II spec. */ -/***************************************************************\ -* Define various devices that we know mis-behave in some way, * -* and note how they are bad, so we can correct for them * -\***************************************************************/ -struct modes -{ - int quirks; /* same definitions as in rogues */ - char density; - char spare[3]; + * in SCSI II spec. */ +/* + * Define various devices that we know mis-behave in some way, + * and note how they are bad, so we can correct for them + */ +struct modes { + u_int32 blksiz; + u_int32 quirks; /* same definitions as in rogues */ + char density; + char spare[3]; }; -struct rogues -{ - char *name; - char *manu; - char *model; - char *version; - int quirks; /* valid for all modes */ - struct modes modes[4]; + +struct rogues { + char *name; + char *manu; + char *model; + char *version; + u_int32 quirks; /* valid for all modes */ + struct modes modes[4]; }; /* define behaviour codes (quirks) */ #define ST_Q_NEEDS_PAGE_0 0x00001 #define ST_Q_FORCE_FIXED_MODE 0x00002 #define ST_Q_FORCE_VAR_MODE 0x00004 -#define ST_Q_SNS_HLP 0x00008 /* must do READ for good MODE SENSE */ +#define ST_Q_SNS_HLP 0x00008 /* must do READ for good MODE SENSE */ #define ST_Q_IGNORE_LOADS 0x00010 -#define ST_Q_BLKSIZ 0x00020 /* variable-block media_blksiz > 0 */ +#define ST_Q_BLKSIZ 0x00020 /* variable-block media_blksiz > 0 */ -static struct rogues gallery[] = /* ends with an all null entry */ +static struct rogues gallery[] = /* ends with an all-null entry */ { - { "Such an old device ", "pre-scsi", " unknown model ","????", - 0, - { {ST_Q_FORCE_FIXED_MODE,0}, /* minor 0,1,2,3 */ - {ST_Q_FORCE_FIXED_MODE,QIC_24}, /* minor 4,5,6,7 */ - {ST_Q_FORCE_VAR_MODE,HALFINCH_1600}, /* minor 8,9,10,11*/ - {ST_Q_FORCE_VAR_MODE,HALFINCH_6250} /* minor 12,13,14,15*/ - } - }, - { "Tandberg tdc3600", "TANDBERG", " TDC 3600","????", - ST_Q_NEEDS_PAGE_0, - { {0,0}, /* minor 0,1,2,3*/ - {ST_Q_FORCE_VAR_MODE,QIC_525}, /* minor 4,5,6,7*/ - {0,QIC_150}, /* minor 8,9,10,11*/ - {0,QIC_120} /* minor 12,13,14,15*/ - } - }, - { "Rev 5 of the Archive 2525", "ARCHIVE ", "VIPER 2525 25462","-005", - 0, - { {ST_Q_SNS_HLP,0}, /* minor 0,1,2,3*/ - {ST_Q_SNS_HLP,QIC_525}, /* minor 4,5,6,7*/ - {0,QIC_150}, /* minor 8,9,10,11*/ - {0,QIC_120} /* minor 12,13,14,15*/ - } - }, - { "Archive Viper 150", "ARCHIVE ", "VIPER 150","????", - ST_Q_NEEDS_PAGE_0, - { {0,0}, /* minor 0,1,2,3*/ - {0,QIC_150}, /* minor 4,5,6,7*/ - {0,QIC_120}, /* minor 8,9,10,11*/ - {0,QIC_24} /* minor 12,13,14,15*/ - } - }, - { "Wangtek 5525ES", "WANGTEK ", "5525ES SCSI REV7", "????", - 0, - { {0,0}, /* minor 0,1,2,3*/ - {ST_Q_BLKSIZ,QIC_525}, /* minor 4,5,6,7*/ - {0,QIC_150}, /* minor 8,9,10,11*/ - {0,QIC_120} /* minor 12,13,14,15*/ - } - }, - {(char *)0} + {"Such an old device ", "pre-scsi", " unknown model ", "????", + 0, + { + {512, ST_Q_FORCE_FIXED_MODE, 0}, /* minor 0,1,2,3 */ + {512, ST_Q_FORCE_FIXED_MODE, QIC_24}, /* minor 4,5,6,7 */ + {0, ST_Q_FORCE_VAR_MODE, HALFINCH_1600}, /* minor 8,9,10,11 */ + {0, ST_Q_FORCE_VAR_MODE, HALFINCH_6250} /* minor 12,13,14,15 */ + } + }, + {"Tandberg tdc3600", "TANDBERG", " TDC 3600", "????", + ST_Q_NEEDS_PAGE_0, + { + {0, 0, 0}, /* minor 0,1,2,3 */ + {0, ST_Q_FORCE_VAR_MODE, QIC_525}, /* minor 4,5,6,7 */ + {0, 0, QIC_150}, /* minor 8,9,10,11 */ + {0, 0, QIC_120} /* minor 12,13,14,15 */ + } + }, + {"Rev 5 of the Archive 2525", "ARCHIVE ", "VIPER 2525 25462", "-005", + 0, + { + {0, ST_Q_SNS_HLP, 0}, /* minor 0,1,2,3 */ + {0, ST_Q_SNS_HLP, QIC_525}, /* minor 4,5,6,7 */ + {0, 0, QIC_150}, /* minor 8,9,10,11 */ + {0, 0, QIC_120} /* minor 12,13,14,15 */ + } + }, + {"Archive Viper 150", "ARCHIVE ", "VIPER 150", "????", + ST_Q_NEEDS_PAGE_0, + { + {0, 0, 0}, /* minor 0,1,2,3 */ + {0, 0, QIC_150}, /* minor 4,5,6,7 */ + {0, 0, QIC_120}, /* minor 8,9,10,11 */ + {0, 0, QIC_24} /* minor 12,13,14,15 */ + } + }, + {"Wangtek 5525ES", "WANGTEK ", "5525ES SCSI REV7", "????", + 0, + { + {0, 0, 0}, /* minor 0,1,2,3 */ + {0, ST_Q_BLKSIZ, QIC_525}, /* minor 4,5,6,7 */ + {0, 0, QIC_150}, /* minor 8,9,10,11 */ + {0, 0, QIC_120} /* minor 12,13,14,15 */ + } + }, + {"WangDAT model 1300", "WangDAT ", "Model 1300", "????", + 0, + { + {0, 0, 0}, /* minor 0,1,2,3 */ + {512, ST_Q_FORCE_FIXED_MODE, 0x13}, /* minor 4,5,6,7 */ + {1024, ST_Q_FORCE_FIXED_MODE, 0x13}, /* minor 8,9,10,11 */ + {0, ST_Q_FORCE_VAR_MODE, 0x13} /* minor 12,13,14,15 */ + } + }, + {(char *) 0} }; - -int ststrategy(); -void stminphys(); +errval st_space __P((u_int32 unit, int32 number, u_int32 what, u_int32 flags)); +errval st_rewind __P((u_int32 unit, boolean immed, u_int32 flags)); +errval st_mode_sense __P((u_int32 unit, u_int32 flags)); +errval st_decide_mode __P((u_int32 unit, boolean first_read)); +errval st_rd_blk_lim __P((u_int32 unit, u_int32 flags)); +errval st_touch_tape __P((u_int32 unit)); +errval st_write_filemarks __P((u_int32 unit, int32 number, u_int32 flags)); +errval st_load __P((u_int32 unit, u_int32 type, u_int32 flags)); +errval st_mode_select __P((u_int32 unit, u_int32 flags)); +void ststrategy(); +void stminphys(); +int32 st_chkeod(); +errval stattach(); +void ststart(); +void st_unmount(); +errval st_mount_tape(); +void st_loadquirks(); +void st_identify_drive(); +errval st_interpret_sense(); #define ESUCCESS 0 +#define NOEJECT 0 +#define EJECT 1 -#ifdef STDEBUG -int st_debug = 1; -#endif /*STDEBUG*/ - -int stattach(); -int st_done(); - -struct st_data +struct scsi_device st_switch = { + st_interpret_sense, /* check errors with us first */ + ststart, /* we have a queue, and this is how we service it */ + NULL, + NULL, /* use the default 'done' routine */ + "st", + 0, + { 0, 0 } +}; + +struct st_data { /*--------------------present operating parameters, flags etc.----------------*/ - int flags; /* see below */ - int blksiz; /* blksiz we are using */ - int density; /* present density */ - int quirks; /* quirks for the open mode */ - int last_dsty; /* last density used */ + u_int32 flags; /* see below */ + u_int32 blksiz; /* blksiz we are using */ + u_int32 density; /* present density */ + u_int32 quirks; /* quirks for the open mode */ + u_int32 last_dsty; /* last density openned */ /*--------------------device/scsi parameters----------------------------------*/ - struct scsi_switch *sc_sw; /* address of scsi low level switch */ - int ctlr; /* so they know which one we want */ - int targ; /* our scsi target ID */ - int lu; /* our scsi lu */ + struct scsi_link *sc_link; /* our link to the adpter etc. */ /*--------------------parameters reported by the device ----------------------*/ - int blkmin; /* min blk size */ - int blkmax; /* max blk size */ + u_int32 blkmin; /* min blk size */ + u_int32 blkmax; /* max blk size */ + struct rogues *rogues; /* if we have a rogue entry */ /*--------------------parameters reported by the device for this media--------*/ - int numblks; /* nominal blocks capacity */ - int media_blksiz; /* 0 if not ST_FIXEDBLOCKS */ - int media_density; /* this is what it said when asked */ + u_int32 numblks; /* nominal blocks capacity */ + u_int32 media_blksiz; /* 0 if not ST_FIXEDBLOCKS */ + u_int32 media_density; /* this is what it said when asked */ /*--------------------quirks for the whole drive------------------------------*/ - int drive_quirks; /* quirks of this drive */ + u_int32 drive_quirks; /* quirks of this drive */ /*--------------------How we should set up when openning each minor device----*/ - struct modes modes[4]; /* plus more for each mode */ + struct modes modes[4]; /* plus more for each mode */ + u_int8 modeflags[4]; /* flags for the modes */ +#define DENSITY_SET_BY_USER 0x01 +#define DENSITY_SET_BY_QUIRK 0x02 +#define BLKSIZE_SET_BY_USER 0x04 +#define BLKSIZE_SET_BY_QUIRK 0x08 /*--------------------storage for sense data returned by the drive------------*/ - unsigned char sense_data[12]; /* additional sense data needed */ - /* for mode sense/select. */ - struct buf *buf_queue; /* the queue of pending IO operations */ - struct scsi_xfer scsi_xfer; /* The scsi xfer struct for this drive*/ - int xfer_block_wait; /* whether there is a process waiting */ -}*st_data[NST]; + unsigned char sense_data[12]; /* + * additional sense data needed + * for mode sense/select. + */ + struct buf *buf_queue; /* the queue of pending IO operations */ + struct scsi_xfer scsi_xfer; /* scsi xfer struct for this drive */ + u_int32 xfer_block_wait; /* is a process waiting? */ +} *st_data[NST]; + #define ST_INITIALIZED 0x01 #define ST_INFO_VALID 0x02 #define ST_OPEN 0x04 -#define ST_BLOCK_SET 0x08 /* block size, mode set by ioctl */ -#define ST_WRITTEN 0x10 /* data have been written, EOD needed */ +#define ST_BLOCK_SET 0x08 /* block size, mode set by ioctl */ +#define ST_WRITTEN 0x10 /* data have been written, EOD needed */ #define ST_FIXEDBLOCKS 0x20 #define ST_AT_FILEMARK 0x40 -#define ST_EIO_PENDING 0x80 /* we couldn't report it then (had data)*/ -#define ST_AT_BOM 0x100 /* ops history suggests Beg of Medium */ -#define ST_READONLY 0x200 /* st_mode_sense says write protected */ -#define ST_FM_WRITTEN 0x400 /* EOF file mark written -- */ - /* used with ~ST_WRITTEN to indicate */ - /* that multiple file marks have been */ - /* written */ -#define ST_BLANK_READ 0x800 /* BLANK CHECK encountered already */ -#define ST_2FM_AT_EOD 0x1000 /* write 2 file marks at EOD */ +#define ST_EIO_PENDING 0x80 /* we couldn't report it then (had data) */ +#define ST_NEW_MOUNT 0x100 /* still need to decide mode */ +#define ST_READONLY 0x200 /* st_mode_sense says write protected */ +#define ST_FM_WRITTEN 0x400 /* + * EOF file mark written -- used with + * ~ST_WRITTEN to indicate that multiple file + * marks have been written + */ +#define ST_BLANK_READ 0x800 /* BLANK CHECK encountered already */ +#define ST_2FM_AT_EOD 0x1000 /* write 2 file marks at EOD */ +#define ST_MOUNTED 0x2000 /* Device is presently mounted */ #define ST_PER_ACTION (ST_AT_FILEMARK | ST_EIO_PENDING | ST_BLANK_READ) -#define ST_PER_OPEN ST_OPEN -#define ST_PER_MEDIA (ST_INFO_VALID | ST_BLOCK_SET | ST_WRITTEN | \ - ST_FIXEDBLOCKS | ST_AT_BOM | ST_READONLY | \ +#define ST_PER_MOUNT (ST_INFO_VALID | ST_BLOCK_SET | ST_WRITTEN | \ + ST_FIXEDBLOCKS | ST_READONLY | \ ST_FM_WRITTEN | ST_2FM_AT_EOD | ST_PER_ACTION) -static int next_st_unit = 0; -/***********************************************************************\ -* The routine called by the low level scsi routine when it discovers * -* A device suitable for this driver * -\***********************************************************************/ +static u_int32 next_st_unit = 0; -int stattach(ctlr,targ,lu,scsi_switch) -struct scsi_switch *scsi_switch; +/* + * The routine called by the low level scsi routine when it discovers + * A device suitable for this driver + */ + +errval +stattach(sc_link) + struct scsi_link *sc_link; { - int unit,i; + u_int32 unit; struct st_data *st; -#ifdef STDEBUG - if(scsi_debug & PRINTROUTINES) printf("stattach: "); -#endif /*STDEBUG*/ - /*******************************************************\ - * Check we have the resources for another drive * - \*******************************************************/ + SC_DEBUG(sc_link, SDEV_DB2, ("stattach: ")); + /* + * Check we have the resources for another drive + */ unit = next_st_unit++; - if( unit >= NST) - { + + if (unit >= NST) { printf("Too many scsi tapes..(%d > %d) reconfigure kernel\n", - (unit + 1),NST); - return(0); + (unit + 1), NST); + return 0; } - if(st_data[unit]) - { - printf("st%d: Already has storage!\n",unit); - return(0); + if (st_data[unit]) { + printf("st%d: Already has storage!\n", unit); + return 0; } - st = st_data[unit] = malloc(sizeof(struct st_data),M_DEVBUF,M_NOWAIT); - if(!st) - { - printf("st%d: malloc failed in st.c\n",unit); - return(0); + sc_link->device = &st_switch; + sc_link->dev_unit = unit; + st = st_data[unit] = malloc(sizeof(struct st_data), M_DEVBUF, M_NOWAIT); + if (!st) { + printf("st%d: malloc failed in st.c\n", unit); + return 0; } - bzero(st,sizeof(struct st_data)); - - /*******************************************************\ - * Store information needed to contact our base driver * - \*******************************************************/ - st->sc_sw = scsi_switch; - st->ctlr = ctlr; - st->targ = targ; - st->lu = lu; - - /*******************************************************\ - * Store information about default densities * - \*******************************************************/ - st->modes[DSTY1].density = QIC_525; - st->modes[DSTY2].density = QIC_150; - st->modes[DSTY3].density = QIC_120; - - /*******************************************************\ - * Check if the drive is a known criminal and take * - * Any steps needed to bring it into line * - \*******************************************************/ + bzero(st, sizeof(struct st_data)); + + /* + * Store information needed to contact our base driver + */ + st->sc_link = sc_link; + + /* + * Check if the drive is a known criminal and take + * Any steps needed to bring it into line + */ st_identify_drive(unit); - /*******************************************************\ - * Use the subdriver to request information regarding * - * the drive. We cannot use interrupts yet, so the * - * request must specify this. * - \*******************************************************/ - if(st_mode_sense(unit, SCSI_NOSLEEP | SCSI_NOMASK | SCSI_SILENT)) - { + /* + * Use the subdriver to request information regarding + * the drive. We cannot use interrupts yet, so the + * request must specify this. + */ + if (st_mode_sense(unit, SCSI_NOSLEEP | SCSI_NOMASK | SCSI_SILENT)) { printf("st%d: drive offline\n", unit); - } - else - { - if(!st_test_ready(unit,SCSI_NOSLEEP | SCSI_NOMASK | SCSI_SILENT)) - { - printf("st%d: density code 0x%x, ", - unit, st->media_density); - if (st->media_blksiz) - { + } else { + printf("st%d: density code 0x%x, ", unit, st->media_density); + if (!scsi_test_unit_ready(sc_link, SCSI_NOSLEEP | SCSI_NOMASK | SCSI_SILENT)) { + if (st->media_blksiz) { printf("%d-byte", st->media_blksiz); - } - else - { + } else { printf("variable"); } printf(" blocks, write-%s\n", - st->flags & ST_READONLY ? "protected" : "enabled"); - } - else - { - printf("st%d: drive empty\n", unit); + (st->flags & ST_READONLY) ? "protected" : "enabled"); + } else { + printf(" drive empty\n"); } } - /*******************************************************\ - * Set up the bufs for this device * - \*******************************************************/ - st->buf_queue = 0; - - + /* + * Set up the buf queue for this device + */ + st->buf_queue = 0; st->flags |= ST_INITIALIZED; - return; - + return 0; } -/***********************************************************************\ -* Use the identify routine in 'scsiconf' to get drive info so we can * -* Further tailor our behaviour. * -\***********************************************************************/ - +/* + * Use the inquiry routine in 'scsi_base' to get drive info so we can + * Further tailor our behaviour. + */ +void st_identify_drive(unit) -int unit; + u_int32 unit; { - - struct st_data *st = st_data[unit]; - struct scsi_inquiry_data inqbuf; - struct rogues *finger; - char manu[32]; - char model[32]; - char model2[32]; - char version[32]; - int model_len; - - - /*******************************************************\ - * Get the device type information * - \*******************************************************/ - if (scsi_inquire(st->ctlr, st->targ, st->lu, st->sc_sw, &inqbuf, - SCSI_NOSLEEP | SCSI_NOMASK | SCSI_SILENT) != COMPLETE) - { + struct st_data *st = st_data[unit]; + struct scsi_inquiry_data inqbuf; + struct rogues *finger; + char manu[32]; + char model[32]; + char model2[32]; + char version[32]; + u_int32 model_len; + + /* + * Get the device type information + */ + if (scsi_inquire(st->sc_link, &inqbuf, + SCSI_NOSLEEP | SCSI_NOMASK | SCSI_SILENT) != 0) { printf("st%d: couldn't get device type, using default\n", unit); return; } - if((inqbuf.version & SID_ANSII) == 0) - { - /***********************************************\ - * If not advanced enough, use default values * - \***********************************************/ - strncpy(manu,"pre-scsi",8);manu[8]=0; - strncpy(model," unknown model ",16);model[16]=0; - strncpy(version,"????",4);version[4]=0; - } - else - { - strncpy(manu,inqbuf.vendor,8);manu[8]=0; - strncpy(model,inqbuf.product,16);model[16]=0; - strncpy(version,inqbuf.revision,4);version[4]=0; + if ((inqbuf.version & SID_ANSII) == 0) { + /* + * If not advanced enough, use default values + */ + strncpy(manu, "pre-scsi", 8); + manu[8] = 0; + strncpy(model, " unknown model ", 16); + model[16] = 0; + strncpy(version, "????", 4); + version[4] = 0; + } else { + strncpy(manu, inqbuf.vendor, 8); + manu[8] = 0; + strncpy(model, inqbuf.product, 16); + model[16] = 0; + strncpy(version, inqbuf.revision, 4); + version[4] = 0; } - - /*******************************************************\ - * Load the parameters for this kind of device, so we * - * treat it as appropriate for each operating mode * - * Only check the number of characters in the array's * - * model entry, not the entire model string returned. * - \*******************************************************/ + + /* + * Load the parameters for this kind of device, so we + * treat it as appropriate for each operating mode. + * Only check the number of characters in the array's + * model entry, not the entire model string returned. + */ finger = gallery; - while(finger->name) - { + while (finger->name) { model_len = 0; - while(finger->model[model_len] && (model_len < 32)) - { + while (finger->model[model_len] && (model_len < 32)) { model2[model_len] = model[model_len]; model_len++; } model2[model_len] = 0; - if ((strcmp(manu, finger->manu) == 0 ) - && (strcmp(model2, finger->model) == 0 || - strcmp("????????????????", finger->model) == 0) - && (strcmp(version, finger->version) == 0 || - strcmp("????", finger->version) == 0)) - { - printf("st%d: %s is a known rogue\n", unit,finger->name); - st->modes[0] = finger->modes[0]; - st->modes[1] = finger->modes[1]; - st->modes[2] = finger->modes[2]; - st->modes[3] = finger->modes[3]; - st->drive_quirks= finger->quirks; - st->quirks = finger->quirks; /*start value*/ + if ((strcmp(manu, finger->manu) == 0) + && (strcmp(model2, finger->model) == 0 || + strcmp("????????????????", finger->model) == 0) + && (strcmp(version, finger->version) == 0 || + strcmp("????", finger->version) == 0)) { + printf("st%d: %s is a known rogue\n", unit, finger->name); + st->rogues = finger; + st->drive_quirks = finger->quirks; + st->quirks = finger->quirks; /*start value */ + st_loadquirks(st); break; - } - else - { + } else { finger++; /* go to next suspect */ } } } -/*******************************************************\ -* open the device. * -\*******************************************************/ +/* + * initialise the subdevices to the default (QUIRK) state. + * this will remove any setting made by the system operator or previous + * operations. + */ +void +st_loadquirks(st) + struct st_data *st; +{ + int i; + struct modes *mode; + struct modes *mode2; + + if (!st->rogues) + return; + mode = st->rogues->modes; + mode2 = st->modes; + for (i = 0; i < 4; i++) { + bzero(mode2, sizeof(struct modes)); + st->modeflags[i] &= ~(BLKSIZE_SET_BY_QUIRK + | DENSITY_SET_BY_QUIRK + | BLKSIZE_SET_BY_USER + | DENSITY_SET_BY_USER); + if (mode->blksiz && ((mode->quirks | st->drive_quirks) + & (ST_Q_FORCE_FIXED_MODE))) { + mode2->blksiz = mode->blksiz; + st->modeflags[i] |= BLKSIZE_SET_BY_QUIRK; + } else { + if ((mode->quirks | st->drive_quirks) + & ST_Q_FORCE_VAR_MODE) { + mode2->blksiz = 0; + st->modeflags[i] |= BLKSIZE_SET_BY_QUIRK; + } + } + if (mode->density) { + mode2->density = mode->density; + st->modeflags[i] |= DENSITY_SET_BY_QUIRK; + } + mode++; + mode2++; + } +} + +/* + * open the device. + */ +errval stopen(dev, flags) -int dev, flags; + dev_t dev; + u_int32 flags; { - int unit,mode,dsty; - int errno = 0; + u_int32 unit, mode, dsty; + errval errno = 0; struct st_data *st; + struct scsi_link *sc_link; unit = UNIT(dev); mode = MODE(dev); dsty = DSTY(dev); - /*******************************************************\ - * Check the unit is legal * - \*******************************************************/ - if ( unit >= NST ) - { - return(ENXIO); + /* + * Check the unit is legal + */ + if (unit >= NST) { + return (ENXIO); } st = st_data[unit]; - /*******************************************************\ - * Make sure the device has been initialised * - \*******************************************************/ + /* + * Make sure the device has been initialised + */ if ((st == NULL) || (!(st->flags & ST_INITIALIZED))) - return(ENXIO); - - /*******************************************************\ - * Only allow one at a time * - \*******************************************************/ - if(st->flags & ST_OPEN) - { - return(ENXIO); - } - - /*******************************************************\ - * Throw out a dummy instruction to catch 'Unit attention* - * errors (the error handling will invalidate all our * - * device info if we get one, but otherwise, ignore it * - \*******************************************************/ - st_test_ready(unit, SCSI_SILENT); - - /***************************************************************\ - * Check that the device is ready to use (media loaded?) * - * This time take notice of the return result * - \***************************************************************/ - if(errno = (st_test_ready(unit,0))) - { - printf("st%d: not ready\n",unit); - return(errno); - } - - /*******************************************************\ - * Set up the mode flags according to the minor number * - * ensure all open flags are in a known state * - * if it's a different mode, dump all cached parameters * - \*******************************************************/ - if(st->last_dsty != dsty || !(st->flags & ST_INFO_VALID)) - { - st->flags &= ~ST_INFO_VALID; - st->last_dsty = dsty; - st->quirks = st->drive_quirks | st->modes[dsty].quirks; - st->density = st->modes[dsty].density; - } - st->flags &= ~ST_PER_OPEN; - -#ifdef STDEBUG - if(scsi_debug & (PRINTROUTINES | TRACEOPENS)) - printf("stopen: dev=0x%x (unit %d (of %d))\n" - , dev, unit, NST); -#endif /*STDEBUG*/ - /***************************************************************\ - * If the media is new, then make sure we give it a chance to * - * to do a 'load' instruction. * - \***************************************************************/ - if(!(st->flags & ST_INFO_VALID)) /* is media new? */ - { - if(errno = st_load(unit,LD_LOAD,0)) - { - return(errno); - } - st_test_ready(unit,0); - if(st->quirks & ST_Q_SNS_HLP) - { - /***********************************************\ - * The quirk here is that the drive returns some * - * value to st_mode_sense incorrectly until the * - * tape has actually passed by the head. * - * * - * The method is to set the drive to large * - * fixed-block state (user-specified density and * - * 1024-byte blocks), then read and rewind to * - * get it to sense the tape. If that doesn't * - * work, try 512-byte fixed blocks. If that * - * doesn't work, as a last resort, try variable- * - * length blocks. The result will be the * - * ability to do an accurate st_mode_sense. * - * * - * We pretend not to be at beginning of medium * - * to keep st_read from calling st_decide_mode. * - * * - * We know we can do a rewind because we just * - * did a load, which implies rewind. Rewind * - * seems preferable to space backward if we have * - * a virgin tape. * - * * - * The rest of the code for this quirk is in ILI * - * processing and BLANK CHECK error processing, * - * both part of st_interpret_sense. * - \***********************************************/ - char *buf; - int readsiz; - - buf = malloc(1024,M_TEMP,M_NOWAIT); - if(!buf) return(ENOMEM); - - if (errno = st_mode_sense(unit, 0)) - { - goto bad; - } - st->blksiz = 1024; - do { - switch (st->blksiz) - { - case 512: - case 1024: - readsiz = st->blksiz; - st->flags |= ST_FIXEDBLOCKS; - break; - default: - readsiz = 1; - st->flags &= ~ST_FIXEDBLOCKS; - } - if (errno = st_mode_select(unit, 0)) - { - goto bad; - } - st->flags &= ~ST_AT_BOM; - st_read(unit, buf, readsiz, SCSI_SILENT); - if (errno = st_rewind(unit, FALSE, 0)) - { -bad: free(buf,M_TEMP); - return(errno); - } - } while (readsiz != 1 && readsiz > st->blksiz); - free(buf,M_TEMP); - } + return (ENXIO); + + sc_link = st->sc_link; + SC_DEBUG(sc_link, SDEV_DB1, ("open: dev=0x%x (unit %d (of %d))\n" + ,dev, unit, NST)); + /* + * Only allow one at a time + */ + if (st->flags & ST_OPEN) { + return (ENXIO); } - - /*******************************************************\ - * Load the physical device parameters * - * loads: blkmin, blkmax * - \*******************************************************/ - if(errno = st_rd_blk_lim(unit,0)) - { - return(errno); - } - - /*******************************************************\ - * Load the media dependent parameters * - * includes: media_blksiz,media_density,numblks * - \*******************************************************/ - if(errno = st_mode_sense(unit,0)) - { - return(errno); + /* + * Throw out a dummy instruction to catch 'Unit attention + * errors (the error handling will invalidate all our + * device info if we get one, but otherwise, ignore it) + */ + scsi_test_unit_ready(sc_link, SCSI_SILENT); + + sc_link->flags |= SDEV_OPEN; /* unit attn are now errors */ + /* + * If the mode is 3 (e.g. minor = 3,7,11,15) + * then the device has been openned to set defaults + * This mode does NOT ALLOW I/O, only ioctls + */ + if (mode == CTLMODE) + return 0; + + /* + * Check that the device is ready to use (media loaded?) + * This time take notice of the return result + */ + if (errno = (scsi_test_unit_ready(sc_link, 0))) { + printf("st%d: not ready\n", unit); + st_unmount(unit, NOEJECT); + return (errno); } - - if (!(st->flags & ST_INFO_VALID) && dsty == 0) - { - /*******************************************************\ - * If the user defaulted the density, use the drive's * - * opinion of it. * - \*******************************************************/ - st->quirks = st->drive_quirks; - st->density = st->media_density; - do { - if (st->density == st->modes[dsty].density) - { - st->quirks |= st->modes[dsty].quirks; -#ifdef STDEBUG - if(st_debug) printf("selected density %d\n", dsty); -#endif /*STDEBUG*/ - break; /* only out of the loop*/ - } - } while (++dsty < 4); - /*******************************************************\ - * If dsty got to 4, the drive must have reported a * - * density which isn't in our density list (e.g. QIC-24 * - * for a default drive). We can handle that, except * - * there'd better be no density-specific quirks in the * - * drive's behavior. * - \*******************************************************/ + /* + * if it's a different mode, or if the media has been + * invalidated, unmount the tape from the previous + * session but continue with open processing + */ + if ((st->last_dsty != dsty) + || (!(sc_link->flags & SDEV_MEDIA_LOADED))) { + st_unmount(unit, NOEJECT); } - - /***************************************************************\ - * Decide whether or not to write two file marks to signify end- * - * of-data. Make the decision as a function of density. If * - * the decision is not to use a second file mark, the SCSI BLANK * - * CHECK condition code will be recognized as end-of-data when * - * first read. * - \***************************************************************/ - switch (st->density) - { -/* case 8 mm: What is the SCSI density code for 8 mm, anyway? */ - case QIC_11: - case QIC_24: - case QIC_120: - case QIC_150: - case QIC_525: - case QIC_1320: - st->flags &= ~ST_2FM_AT_EOD; - break; - default: - st->flags |= ST_2FM_AT_EOD; + /* + * If we are not mounted, then we should start a new + * mount session. + */ + if (!(st->flags & ST_MOUNTED)) { + st_mount_tape(dev, flags); + st->last_dsty = dsty; } - - /***************************************************************\ - * Make sure that a tape opened in write-only mode will have * - * file marks written on it. This is the only way to write a * - * zero-length file on tape. * - \***************************************************************/ + /* + * Make sure that a tape opened in write-only mode will have + * file marks written on it when closed, even if not written to. + * This is for SUN compatibility + */ if ((flags & O_ACCMODE) == FWRITE) st->flags |= ST_WRITTEN; - st->flags |= ST_INFO_VALID; - - st_prevent(unit,PR_PREVENT,0); /* who cares if it fails? */ - -#ifdef STDEBUG - if(scsi_debug & TRACEOPENS) - printf("Params loaded "); -#endif /*STDEBUG*/ + SC_DEBUG(sc_link, SDEV_DB2, ("Open complete\n")); st->flags |= ST_OPEN; - return(0); + return (0); } -/*******************************************************\ -* close the device.. only called if we are the LAST * -* occurence of an open device * -\*******************************************************/ +/* + * close the device.. only called if we are the LAST + * occurence of an open device + */ +errval stclose(dev) + dev_t dev; { - unsigned char unit,mode; - struct st_data *st; + unsigned char unit, mode; + struct st_data *st; + struct scsi_link *sc_link; unit = UNIT(dev); mode = MODE(dev); st = st_data[unit]; - -#ifdef STDEBUG - if(scsi_debug & TRACEOPENS) - printf("Closing device"); -#endif /*STDEBUG*/ - switch(mode) - { - case 0: - st_rewind(unit,FALSE,SCSI_SILENT); - st_prevent(unit,PR_ALLOW,SCSI_SILENT); - st->flags &= ~ST_PER_MEDIA; + sc_link = st->sc_link; + + SC_DEBUG(sc_link, SDEV_DB1, ("closing\n")); + if ((st->flags & (ST_WRITTEN | ST_FM_WRITTEN)) == ST_WRITTEN) + st_write_filemarks(unit, 1, 0); + switch (mode & 0x3) { + case 0: + case 3: /* for now */ + st_unmount(unit, NOEJECT); break; - case 1: /*non rewind*/ - if((st->flags & (ST_WRITTEN | ST_FM_WRITTEN)) == ST_WRITTEN) - st_write_filemarks(unit, 1, 0); - break; - case 2: - st_rewind(unit,FALSE,SCSI_SILENT); - st_prevent(unit,PR_ALLOW,SCSI_SILENT); - st_load(unit,LD_UNLOAD,SCSI_SILENT); - st->flags &= ~ST_PER_MEDIA; + case 1: /*leave mounted unless media seems to have been removed */ + if (!(sc_link->flags & SDEV_MEDIA_LOADED)) { + st_unmount(unit, NOEJECT); + } break; - case 3:/* a bit silly really */ - st_prevent(unit,PR_ALLOW,SCSI_SILENT); - st_load(unit,LD_UNLOAD,SCSI_SILENT); - st->flags &= ~ST_PER_MEDIA; + case 2: + st_unmount(unit, EJECT); break; - default: - printf("st%d: close: Bad mode (minor number)%d how's it open?\n" - ,unit,mode); - return(EINVAL); } - st->flags &= ~ST_PER_OPEN; - return(0); + sc_link->flags &= ~SDEV_OPEN; + st->flags &= ~ST_OPEN; + return (0); } -/***************************************************************\ -* Given all we know about the device, media, mode, 'quirks' and * -* initial operation, make a decision as to how we should be set * -* up. First, choose the density, then variable/fixed blocks. * -\***************************************************************/ -st_decide_mode(unit, first_read) -int unit, first_read; +/* + * Start a new mount session. + * Copy in all the default parameters from the selected device mode. + * and try guess any that seem to be defaulted. + */ +errval +st_mount_tape(dev, flags) + dev_t dev; + u_int32 flags; { - int dsty, error; - struct st_data *st = st_data[unit]; + u_int32 unit, mode, dsty; + struct st_data *st; + struct scsi_link *sc_link; + errval errno = 0; - /***************************************************************\ - * First, if our information about the tape is out of date, get * - * new information. * - \***************************************************************/ - if (!(st->flags & ST_INFO_VALID)) - { - if (error = st_mode_sense(unit, 0)) - return (error); - st->flags |= ST_INFO_VALID; + unit = UNIT(dev); + mode = MODE(dev); + dsty = DSTY(dev); + st = st_data[unit]; + sc_link = st->sc_link; + + if (st->flags & ST_MOUNTED) + return 0; + + SC_DEBUG(sc_link, SDEV_DB1, ("mounting\n ")); + st->flags |= ST_NEW_MOUNT; + st->quirks = st->drive_quirks | st->modes[dsty].quirks; + /* + * If the media is new, then make sure we give it a chance to + * to do a 'load' instruction. ( We assume it is new) + */ + if (errno = st_load(unit, LD_LOAD, 0)) { + return (errno); } -#ifdef STDEBUG - if(st_debug) printf("starting mode decision\n"); -#endif /*STDEBUG*/ - - /***************************************************************\ - * If the user has already specified fixed or variable-length * - * blocks using an ioctl, just believe him. OVERRIDE ALL * - \***************************************************************/ - if (st->flags & ST_BLOCK_SET) - { -#ifdef STDEBUG - if(st_debug) printf("user has specified %s mode\n", - st->flags & ST_FIXEDBLOCKS ? "fixed" : "variable"); -#endif /*STDEBUG*/ - goto done; + /* + * Throw another dummy instruction to catch + * 'Unit attention' errors. Some drives appear to give + * these after doing a Load instruction. + * (noteably some DAT drives) + */ + scsi_test_unit_ready(sc_link, SCSI_SILENT); + + /* + * Some devices can't tell you much until they have been + * asked to look at the media. This quirk does this. + */ + if (st->quirks & ST_Q_SNS_HLP) { + if (errno = st_touch_tape(unit)) + return errno; + } + /* + * Load the physical device parameters + * loads: blkmin, blkmax + */ + if (errno = st_rd_blk_lim(unit, 0)) { + return errno; + } + /* + * Load the media dependent parameters + * includes: media_blksiz,media_density,numblks + * As we have a tape in, it should be reflected here. + * If not you may need the "quirk" above. + */ + if (errno = st_mode_sense(unit, 0)) { + return errno; + } + /* + * If we have gained a permanent density from somewhere, + * then use it in preference to the one supplied by + * default by the driver. + */ + if (st->modeflags[dsty] & (DENSITY_SET_BY_QUIRK | DENSITY_SET_BY_USER)) { + st->density = st->modes[dsty].density; + } else { + st->density = st->media_density; + } + /* + * If we have gained a permanent blocksize + * then use it in preference to the one supplied by + * default by the driver. + */ + st->flags &= ~ST_FIXEDBLOCKS; + if (st->modeflags[dsty] & (BLKSIZE_SET_BY_QUIRK | BLKSIZE_SET_BY_USER)) { + st->blksiz = st->modes[dsty].blksiz; + if (st->blksiz) { + st->flags |= ST_FIXEDBLOCKS; + } + } else { + if (errno = st_decide_mode(unit, FALSE)) { + return errno; + } } + if (errno = st_mode_select(unit, 0)) { + printf("st%d: Cannot set selected mode", unit); + return errno; + } + scsi_prevent(sc_link, PR_PREVENT, 0); /* who cares if it fails? */ + st->flags &= ~ST_NEW_MOUNT; + st->flags |= ST_MOUNTED; + sc_link->flags |= SDEV_MEDIA_LOADED; /* move earlier? */ - /***************************************************************\ - * If the user hasn't already specified fixed or variable-length * - * blocks and the block size (zero if variable-length), we'll * - * have to try to figure them out ourselves. * - * * - * Our first shot at a method is, "The quirks made me do it!" * - \***************************************************************/ - switch (st->quirks & (ST_Q_FORCE_FIXED_MODE | ST_Q_FORCE_VAR_MODE)) - { - case (ST_Q_FORCE_FIXED_MODE | ST_Q_FORCE_VAR_MODE): - printf("st%d: bad quirks\n",unit); + return 0; +} + +/* + * End the present mount session. + * Rewind, and optionally eject the tape. + * Reset various flags to indicate that all new + * operations require another mount operation + */ +void +st_unmount(int unit, boolean eject) +{ + struct st_data *st = st_data[unit]; + struct scsi_link *sc_link = st->sc_link; + int32 nmarks; + + if (!(st->flags & ST_MOUNTED)) + return; + SC_DEBUG(sc_link, SDEV_DB1, ("unmounting\n")); + st_chkeod(unit, FALSE, &nmarks, SCSI_SILENT); + st_rewind(unit, FALSE, SCSI_SILENT); + scsi_prevent(sc_link, PR_ALLOW, SCSI_SILENT); + if (eject) { + st_load(unit, LD_UNLOAD, SCSI_SILENT); + } + st->flags &= ~(ST_MOUNTED | ST_NEW_MOUNT); + sc_link->flags &= ~SDEV_MEDIA_LOADED; +} + +/* + * Given all we know about the device, media, mode, 'quirks' and + * initial operation, make a decision as to how we should be set + * to run (regarding blocking and EOD marks) + */ +errval +st_decide_mode(unit, first_read) + u_int32 unit; + boolean first_read; +{ + struct st_data *st = st_data[unit]; +#ifdef SCSIDEBUG + struct scsi_link *sc_link = st->sc_link; +#endif + + SC_DEBUG(sc_link, SDEV_DB2, ("starting block mode decision\n")); + + /* + * If the user hasn't already specified fixed or variable-length + * blocks and the block size (zero if variable-length), we'll + * have to try to figure them out ourselves. + * + * Our first shot at a method is, "The quirks made me do it!" + */ + switch (st->quirks & (ST_Q_FORCE_FIXED_MODE | ST_Q_FORCE_VAR_MODE)) { + case (ST_Q_FORCE_FIXED_MODE | ST_Q_FORCE_VAR_MODE): + printf("st%d: bad quirks\n", unit); return (EINVAL); - case ST_Q_FORCE_FIXED_MODE: + case ST_Q_FORCE_FIXED_MODE: /*specified fixed, but not what size */ st->flags |= ST_FIXEDBLOCKS; if (st->blkmin && (st->blkmin == st->blkmax)) st->blksiz = st->blkmin; - else if(st->media_blksiz > 0) + else if (st->media_blksiz > 0) st->blksiz = st->media_blksiz; else st->blksiz = DEF_FIXED_BSIZE; -#ifdef STDEBUG - if(st_debug) printf("Quirks force fixed mode\n"); -#endif /*STDEBUG*/ + SC_DEBUG(sc_link, SDEV_DB3, ("Quirks force fixed mode(%d)\n", + st->blksiz)); goto done; - case ST_Q_FORCE_VAR_MODE: + case ST_Q_FORCE_VAR_MODE: st->flags &= ~ST_FIXEDBLOCKS; st->blksiz = 0; -#ifdef STDEBUG - if(st_debug) printf("Quirks force variable mode\n"); -#endif /*STDEBUG*/ + SC_DEBUG(sc_link, SDEV_DB3, ("Quirks force variable mode\n")); goto done; } - - /***************************************************************\ - * If the drive can only handle fixed-length blocks and only at * - * one size, perhaps we should just do that. * - \***************************************************************/ - if (st->blkmin && (st->blkmin == st->blkmax)) - { + /* + * If the drive can only handle fixed-length blocks and only at + * one size, perhaps we should just do that. + */ + if (st->blkmin && (st->blkmin == st->blkmax)) { st->flags |= ST_FIXEDBLOCKS; st->blksiz = st->blkmin; -#ifdef STDEBUG - if(st_debug) printf("blkmin == blkmax of %d\n",st->blkmin); -#endif /*STDEBUG*/ + SC_DEBUG(sc_link, SDEV_DB3, + ("blkmin == blkmax of %d\n", st->blkmin)); goto done; } - - /***************************************************************\ - * If the tape density mandates use of fixed or variable-length * - * blocks, comply. * - \***************************************************************/ - switch (st->density) - { - case HALFINCH_800: - case HALFINCH_1600: - case HALFINCH_6250: - case DDS: + /* + * If the tape density mandates (or even suggests) use of fixed + * or variable-length blocks, comply. + */ + switch (st->density) { + case HALFINCH_800: + case HALFINCH_1600: + case HALFINCH_6250: + case DDS: st->flags &= ~ST_FIXEDBLOCKS; st->blksiz = 0; -#ifdef STDEBUG - if(st_debug) printf("density specified variable\n"); -#endif /*STDEBUG*/ + SC_DEBUG(sc_link, SDEV_DB3, ("density specified variable\n")); goto done; - case QIC_11: - case QIC_24: - case QIC_120: - case QIC_150: + case QIC_11: + case QIC_24: + case QIC_120: + case QIC_150: + case QIC_525: + case QIC_1320: st->flags |= ST_FIXEDBLOCKS; - if (st->media_blksiz > 0) + if (st->media_blksiz > 0) { st->blksiz = st->media_blksiz; - else + } else { st->blksiz = DEF_FIXED_BSIZE; -#ifdef STDEBUG - if(st_debug) printf("density specified fixed\n"); -#endif /*STDEBUG*/ + } + SC_DEBUG(sc_link, SDEV_DB3, ("density specified fixed\n")); goto done; } - - /***************************************************************\ - * If we're about to read the tape, perhaps we should choose * - * fixed or variable-length blocks and block size according to * - * what the drive found on the tape. * - \***************************************************************/ - if (first_read && (!(st->quirks & ST_Q_BLKSIZ) || st->media_blksiz == 0 - || st->media_blksiz == DEF_FIXED_BSIZE || st->media_blksiz == 1024)) - { - if (st->media_blksiz == 0) + /* + * If we're about to read the tape, perhaps we should choose + * fixed or variable-length blocks and block size according to + * what the drive found on the tape. + */ + if (first_read + && (!(st->quirks & ST_Q_BLKSIZ) + || (st->media_blksiz == 0) + || (st->media_blksiz == DEF_FIXED_BSIZE) + || (st->media_blksiz == 1024))) { + if (st->media_blksiz == 0) { st->flags &= ~ST_FIXEDBLOCKS; - else + } else { st->flags |= ST_FIXEDBLOCKS; + } st->blksiz = st->media_blksiz; -#ifdef STDEBUG - if(st_debug) printf("Used media_blksiz of %d\n",st->media_blksiz); -#endif /*STDEBUG*/ + SC_DEBUG(sc_link, SDEV_DB3, + ("Used media_blksiz of %d\n", st->media_blksiz)); goto done; } - - /***************************************************************\ - * We're getting no hints from any direction. Choose variable- * - * length blocks arbitrarily. * - \***************************************************************/ + /* + * We're getting no hints from any direction. Choose variable- + * length blocks arbitrarily. + */ st->flags &= ~ST_FIXEDBLOCKS; st->blksiz = 0; -#ifdef STDEBUG - if(st_debug) printf("Give up and default to variable mode\n"); -#endif /*STDEBUG*/ + SC_DEBUG(sc_link, SDEV_DB3, ("Give up and default to variable mode\n")); done: - st->flags &= ~ST_AT_BOM; - return (st_mode_select(unit, 0)); + + /* + * Decide whether or not to write two file marks to signify end- + * of-data. Make the decision as a function of density. If + * the decision is not to use a second file mark, the SCSI BLANK + * CHECK condition code will be recognized as end-of-data when + * first read. + * (I think this should be a by-product of fixed/variable..julian) + */ + switch (st->density) { +/* case 8 mm: What is the SCSI density code for 8 mm, anyway? */ + case QIC_11: + case QIC_24: + case QIC_120: + case QIC_150: + case QIC_525: + case QIC_1320: + st->flags &= ~ST_2FM_AT_EOD; + break; + default: + st->flags |= ST_2FM_AT_EOD; + } + return 0; } -/*******************************************************\ -* trim the size of the transfer if needed, * -* called by physio * -* basically the smaller of our min and the scsi driver's* -* minphys * -\*******************************************************/ -void stminphys(bp) -struct buf *bp; +/* + * trim the size of the transfer if needed, + * called by physio + * basically the smaller of our min and the scsi driver's + * minphys + */ +void +stminphys(bp) + struct buf *bp; { - (*(st_data[UNIT(bp->b_dev)]->sc_sw->scsi_minphys))(bp); + (*(st_data[UNIT(bp->b_dev)]->sc_link->adapter->scsi_minphys)) (bp); } -/*******************************************************\ -* Actually translate the requested transfer into * -* one the physical driver can understand * -* The transfer is described by a buf and will include * -* only one physical transfer. * -\*******************************************************/ - -int ststrategy(bp) -struct buf *bp; +/* + * Actually translate the requested transfer into + * one the physical driver can understand + * The transfer is described by a buf and will include + * only one physical transfer. + */ +void +ststrategy(bp) + struct buf *bp; { - struct buf **dp; + struct buf **dp; unsigned char unit; - unsigned int opri; + u_int32 opri; struct st_data *st; ststrats++; unit = UNIT((bp->b_dev)); st = st_data[unit]; -#ifdef STDEBUG - if(scsi_debug & PRINTROUTINES) printf("\nststrategy "); - if(scsi_debug & SHOWREQUESTS) printf("st%d: %d bytes @ blk%d\n", - unit,bp->b_bcount,bp->b_blkno); -#endif /*STDEBUG*/ - /*******************************************************\ - * If it's a null transfer, return immediatly * - \*******************************************************/ - if (bp->b_bcount == 0) - { + SC_DEBUG(st->sc_link, SDEV_DB1, + (" strategy: %d bytes @ blk%d\n", bp->b_bcount, bp->b_blkno)); + /* + * If it's a null transfer, return immediatly + */ + if (bp->b_bcount == 0) { goto done; } - - /*******************************************************\ - * If we're at beginning of medium, now is the time to * - * set medium access density, fixed or variable-blocks * - * and, if fixed, the block size. * - \*******************************************************/ - if (st->flags & ST_AT_BOM && - (bp->b_error = st_decide_mode(unit, (bp->b_flags & B_READ) != 0))) - goto bad; - - /*******************************************************\ - * Odd sized request on fixed drives are verboten * - \*******************************************************/ - if(st->flags & ST_FIXEDBLOCKS) - { - if(bp->b_bcount % st->blksiz) - { + /* + * Odd sized request on fixed drives are verboten + */ + if (st->flags & ST_FIXEDBLOCKS) { + if (bp->b_bcount % st->blksiz) { printf("st%d: bad request, must be multiple of %d\n", - unit, st->blksiz); + unit, st->blksiz); bp->b_error = EIO; goto bad; } } - /*******************************************************\ - * as are out-of-range requests on variable drives. * - \*******************************************************/ - else if(bp->b_bcount < st->blkmin || bp->b_bcount > st->blkmax) - { + /* + * as are out-of-range requests on variable drives. + */ + else if (bp->b_bcount < st->blkmin || bp->b_bcount > st->blkmax) { printf("st%d: bad request, must be between %d and %d\n", - unit, st->blkmin, st->blkmax); + unit, st->blkmin, st->blkmax); bp->b_error = EIO; goto bad; } - stminphys(bp); opri = splbio(); - /*******************************************************\ - * Place it in the queue of activities for this tape * - * at the end (a bit silly because we only have on user..* - * (but it could fork() )) * - \*******************************************************/ + /* + * Place it in the queue of activities for this tape + * at the end (a bit silly because we only have on user.. + * (but it could fork() )) + */ dp = &(st->buf_queue); - while (*dp) - { + while (*dp) { dp = &((*dp)->b_actf); - } + } *dp = bp; bp->b_actf = NULL; - /*******************************************************\ - * Tell the device to get going on the transfer if it's * - * not doing anything, otherwise just wait for completion* - * (All a bit silly if we're only allowing 1 open but..) * - \*******************************************************/ + /* + * Tell the device to get going on the transfer if it's + * not doing anything, otherwise just wait for completion + * (All a bit silly if we're only allowing 1 open but..) + */ ststart(unit); splx(opri); @@ -928,1443 +935,993 @@ struct buf *bp; bad: bp->b_flags |= B_ERROR; done: - /*******************************************************\ - * Correctly set the buf to indicate a completed xfer * - \*******************************************************/ + /* + * Correctly set the buf to indicate a completed xfer + */ iodone(bp); return; } +/* + * ststart looks to see if there is a buf waiting for the device + * and that the device is not already busy. If both are true, + * It dequeues the buf and creates a scsi command to perform the + * transfer required. The transfer request will call scsi_done + * on completion, which will in turn call this routine again + * so that the next queued transfer is performed. + * The bufs are queued by the strategy routine (ststrategy) + * + * This routine is also called after other non-queued requests + * have been made of the scsi driver, to ensure that the queue + * continues to be drained. + * ststart() is called at splbio + */ +void +ststart(unit) + u_int32 unit; +{ + struct st_data *st = st_data[unit]; + struct scsi_link *sc_link = st->sc_link; + register struct buf *bp = 0; + struct scsi_rw_tape cmd; + u_int32 flags; + + SC_DEBUG(sc_link, SDEV_DB2, ("ststart ")); + /* + * See if there is a buf to do and we are not already + * doing one + */ + while (sc_link->opennings != 0) { + + /* if a special awaits, let it proceed first */ + if (sc_link->flags & SDEV_WAITING) { + wakeup((caddr_t)sc_link); + return; + } + if ((bp = st->buf_queue) == NULL) { + return; /* no work to bother with */ + } + st->buf_queue = bp->b_actf; + + /* + * if the device has been unmounted byt the user + * then throw away all requests until done + */ + if ((!(st->flags & ST_MOUNTED)) + || (!(sc_link->flags & SDEV_MEDIA_LOADED))) { + /* make sure that one implies the other.. */ + sc_link->flags &= ~SDEV_MEDIA_LOADED; + goto badnews; + } + /* + * only FIXEDBLOCK devices have pending operations + */ + if (st->flags & ST_FIXEDBLOCKS) { + /* + * If we are at a filemark but have not reported it yet + * then we should report it now + */ + if (st->flags & ST_AT_FILEMARK) { + if ((bp->b_flags & B_READ) == B_WRITE) { + /* + * Handling of ST_AT_FILEMARK in + * st_space will fill in the right file + * mark count. + * Back up over filemark + */ + if (st_space(unit, 0, SP_FILEMARKS, 0) != + ESUCCESS) + goto badnews; + } else { + bp->b_resid = bp->b_bcount; + bp->b_error = 0; + bp->b_flags &= ~B_ERROR; + st->flags &= ~ST_AT_FILEMARK; + biodone(bp); + continue; /* seek more work */ + } + } + /* + * If we are at EIO (e.g. EOM) but have not reported it + * yet then we should report it now + */ + if (st->flags & ST_EIO_PENDING) { + bp->b_resid = bp->b_bcount; + bp->b_error = EIO; + bp->b_flags |= B_ERROR; + st->flags &= ~ST_EIO_PENDING; + biodone(bp); + continue; /* seek more work */ + } + } + /* + * Fill out the scsi command + */ + bzero(&cmd, sizeof(cmd)); + if ((bp->b_flags & B_READ) == B_WRITE) { + cmd.op_code = WRITE_COMMAND_TAPE; + st->flags &= ~ST_FM_WRITTEN; + st->flags |= ST_WRITTEN; + flags = SCSI_DATA_OUT; + } else { + cmd.op_code = READ_COMMAND_TAPE; + flags = SCSI_DATA_IN; + } + /* + * Handle "fixed-block-mode" tape drives by using the + * block count instead of the length. + */ + if (st->flags & ST_FIXEDBLOCKS) { + cmd.byte2 |= SRWT_FIXED; + lto3b(bp->b_bcount / st->blksiz, cmd.len); + } else { + lto3b(bp->b_bcount, cmd.len); + } + /* + * go ask the adapter to do all this for us + */ + if (scsi_scsi_cmd(sc_link, + (struct scsi_generic *) &cmd, + sizeof(cmd), + (u_char *) bp->b_un.b_addr, + bp->b_bcount, + 0, /* can't retry a read on a tape really */ + 100000, + bp, + flags | SCSI_NOSLEEP) == SUCCESSFULLY_QUEUED) { + stqueues++; + } else { +badnews: + printf("st%d: oops not queued\n", unit); + bp->b_flags |= B_ERROR; + bp->b_error = EIO; + biodone(bp); + } + } /* go back and see if we can cram more work in.. */ +} - -/*******************************************************\ -* Perform special action on behalf of the user * -* Knows about the internals of this device * -\*******************************************************/ -stioctl(dev, cmd, arg, mode) -dev_t dev; -int cmd; -caddr_t arg; +/* + * Perform special action on behalf of the user; + * knows about the internals of this device + */ +errval +stioctl(dev, cmd, arg, flag) + dev_t dev; + int cmd; + caddr_t arg; + int flag; { - int errcode = 0; + errval errcode = 0; unsigned char unit; - int number,flags,dsty; - struct st_data *st; - - - /*******************************************************\ - * Find the device that the user is talking about * - \*******************************************************/ - flags = 0; /* give error messages, act on errors etc. */ + u_int32 number, flags, dsty; + struct st_data *st; + u_int32 hold_blksiz; + u_int32 hold_density; + int32 nmarks; + struct mtop *mt = (struct mtop *) arg; + + /* + * Find the device that the user is talking about + */ + flags = 0; /* give error messages, act on errors etc. */ unit = UNIT(dev); dsty = DSTY(dev); - st = st_data[unit]; + st = st_data[unit]; + hold_blksiz = st->blksiz; + hold_density = st->density; - switch(cmd) - { + switch (cmd) { case MTIOCGET: - { - struct mtget *g = (struct mtget *) arg; - - bzero(g, sizeof(struct mtget)); - g->mt_type = 0x7; /* Ultrix compat */ /*?*/ - if (st->flags & ST_FIXEDBLOCKS) { - g->mt_bsiz = st->blksiz; - } else { - g->mt_bsiz = 0; - } - g->mt_dns_dflt = st->modes[0].density; - g->mt_dns_dsty1 = st->modes[DSTY1].density; - g->mt_dns_dsty2 = st->modes[DSTY2].density; - g->mt_dns_dsty3 = st->modes[DSTY3].density; - break; - } - - + { + struct mtget *g = (struct mtget *) arg; + + SC_DEBUG(st->sc_link, SDEV_DB1, ("[ioctl: get status]\n")); + bzero(g, sizeof(struct mtget)); + g->mt_type = 0x7; /* Ultrix compat *//*? */ + g->mt_density = st->density; + g->mt_blksiz = st->blksiz; + g->mt_density0 = st->modes[0].density; + g->mt_density1 = st->modes[1].density; + g->mt_density2 = st->modes[2].density; + g->mt_density3 = st->modes[3].density; + g->mt_blksiz0 = st->modes[0].blksiz; + g->mt_blksiz1 = st->modes[1].blksiz; + g->mt_blksiz2 = st->modes[2].blksiz; + g->mt_blksiz3 = st->modes[3].blksiz; + break; + } case MTIOCTOP: - { - int nmarks; - struct mtop *mt = (struct mtop *) arg; - -#ifdef STDEBUG - if (st_debug) - printf("[sctape_sstatus: %x %x]\n", - mt->mt_op, mt->mt_count); -#endif /*STDEBUG*/ - + { + SC_DEBUG(st->sc_link, SDEV_DB1, ("[ioctl: op=0x%x count=0x%x]\n", + mt->mt_op, mt->mt_count)); - /* compat: in U*x it is a short */ - number = mt->mt_count; - switch ((short)(mt->mt_op)) - { - case MTWEOF: /* write an end-of-file record */ - errcode = st_write_filemarks(unit,number,flags); - break; - case MTBSF: /* backward space file */ - number = -number; - case MTFSF: /* forward space file */ - errcode = st_chkeod(unit, FALSE, &nmarks, flags); - if (errcode == ESUCCESS) - errcode = st_space(unit, number - nmarks, - SP_FILEMARKS, flags); - break; - case MTBSR: /* backward space record */ - number = -number; - case MTFSR: /* forward space record */ - errcode = st_chkeod(unit, TRUE, &nmarks, flags); - if (errcode == ESUCCESS) - errcode = st_space(unit,number,SP_BLKS,flags); - break; - case MTREW: /* rewind */ - errcode = st_rewind(unit,FALSE,flags); - break; - case MTOFFL: /* rewind and put the drive offline */ - if(st_rewind(unit,FALSE,flags)) - { - printf("st%d: rewind failed, unit still loaded\n", - unit); - } - else - { - st_prevent(unit,PR_ALLOW,0); - st_load(unit,LD_UNLOAD,flags); - } - break; - case MTNOP: /* no operation, sets status only */ - case MTCACHE: /* enable controller cache */ - case MTNOCACHE: /* disable controller cache */ - break; - case MTSETBSIZ: /* Set block size for device */ - if (!(st->flags & ST_AT_BOM)) - { - errcode = EINVAL; + /* compat: in U*x it is a short */ + number = mt->mt_count; + switch ((short) (mt->mt_op)) { + case MTWEOF: /* write an end-of-file record */ + errcode = st_write_filemarks(unit, number, flags); break; - } - if (number == 0) - { - st->flags &= ~ST_FIXEDBLOCKS; - } - else - { - if ((st->blkmin || st->blkmax) /* they exist */ - && ((number < st->blkmin - || number > st->blkmax))) - { + case MTBSF: /* backward space file */ + number = -number; + case MTFSF: /* forward space file */ + errcode = st_chkeod(unit, FALSE, &nmarks, flags); + if (errcode == ESUCCESS) + errcode = st_space(unit, number - nmarks, + SP_FILEMARKS, flags); + break; + case MTBSR: /* backward space record */ + number = -number; + case MTFSR: /* forward space record */ + errcode = st_chkeod(unit, TRUE, &nmarks, flags); + if (errcode == ESUCCESS) + errcode = st_space(unit, number, SP_BLKS, flags); + break; + case MTREW: /* rewind */ + errcode = st_rewind(unit, FALSE, flags); + break; + case MTOFFL: /* rewind and put the drive offline */ + st_unmount(unit, EJECT); + break; + case MTNOP: /* no operation, sets status only */ + case MTCACHE: /* enable controller cache */ + case MTNOCACHE: /* disable controller cache */ + break; + case MTSETBSIZ: /* Set block size for device */ +#ifdef NOTYET + if (!(st->flags & ST_NEW_MOUNT)) { + uprintf("re-mount tape before changing blocksize"); errcode = EINVAL; break; } - st->flags |= ST_FIXEDBLOCKS; - } - st->blksiz = number; - st->flags |= ST_BLOCK_SET; - break; +#endif + if (number == 0) { + st->flags &= ~ST_FIXEDBLOCKS; + } else { + if ((st->blkmin || st->blkmax) /* they exist */ + &&((number < st->blkmin + || number > st->blkmax))) { + errcode = EINVAL; + break; + } + st->flags |= ST_FIXEDBLOCKS; + } + st->blksiz = number; + st->flags |= ST_BLOCK_SET; /*XXX */ + goto try_new_value; - /* How do we check that the drive can handle - the requested density ? */ + case MTSETDNSTY: /* Set density for device and mode */ + if (number > SCSI_2_MAX_DENSITY_CODE) { + errcode = EINVAL; + } else { + st->density = number; + } + goto try_new_value; - case MTSETDNSTY: /* Set density for device and mode */ - if (number < 0 || number > SCSI_2_MAX_DENSITY_CODE) - { + default: errcode = EINVAL; } - else - { - st->modes[dsty].density = number; - } break; - - default: - errcode = EINVAL; } - break; - } case MTIOCIEOT: case MTIOCEEOT: break; default: - errcode = EINVAL; + if(MODE(dev) == CTLMODE) + errcode = scsi_do_ioctl(st->sc_link,cmd,arg,flag); + else + errcode = ENOTTY; + break; } - return errcode; +/*-----------------------------*/ +try_new_value: + /* + * Check that the mode being asked for is aggreeable to the + * drive. If not, put it back the way it was. + */ + if (errcode = st_mode_select(unit, 0)) { /* put it back as it was */ + printf("st%d: Cannot set selected mode", unit); + st->density = hold_density; + st->blksiz = hold_blksiz; + if (st->blksiz) { + st->flags |= ST_FIXEDBLOCKS; + } else { + st->flags &= ~ST_FIXEDBLOCKS; + } + return (errcode); + } + /* + * As the drive liked it, if we are setting a new default, + * set it into the structures as such. + * + * The means for deciding this are not finalised yet + */ + if (MODE(dev) == 0x03) { + /* special mode */ + /* XXX */ + switch ((short) (mt->mt_op)) { + case MTSETBSIZ: + st->modes[dsty].blksiz = st->blksiz; + st->modeflags[dsty] |= BLKSIZE_SET_BY_USER; + break; + case MTSETDNSTY: + st->modes[dsty].density = st->density; + st->modeflags[dsty] |= DENSITY_SET_BY_USER; + break; + } + } + return 0; } -/*******************************************************\ -* Do a synchronous read. * -\*******************************************************/ -int st_read(unit, buf, size, flags) -int unit, size, flags; -char *buf; +/* + * Do a synchronous read. + */ +errval +st_read(unit, buf, size, flags) + u_int32 unit, size, flags; + char *buf; { - int error; struct scsi_rw_tape scsi_cmd; struct st_data *st = st_data[unit]; - /*******************************************************\ - * If it's a null transfer, return immediatly * - \*******************************************************/ - if (size == 0) - { - return(ESUCCESS); + /* + * If it's a null transfer, return immediatly + */ + if (size == 0) { + return (ESUCCESS); } - - /*******************************************************\ - * If we're at beginning of medium, now is the time to * - * set medium access density, fixed or variable-blocks * - * and, if fixed, the block size. * - \*******************************************************/ - if (st->flags & ST_AT_BOM && (error = st_decide_mode(unit, TRUE))) - return (error); - bzero(&scsi_cmd, sizeof(scsi_cmd)); scsi_cmd.op_code = READ_COMMAND_TAPE; - scsi_cmd.byte2 |= st->flags & ST_FIXEDBLOCKS ? SRWT_FIXED : 0; - lto3b(scsi_cmd.byte2 & SRWT_FIXED ? - size / (st->blksiz ? st->blksiz : DEF_FIXED_BSIZE) : size, - scsi_cmd.len); - return (st_scsi_cmd(unit, - &scsi_cmd, - sizeof(scsi_cmd), - buf, - size, - 100000, - NULL, - flags | SCSI_DATA_IN)); -} - -/*******************************************************\ -* Get scsi driver to send a "are you ready" command * -\*******************************************************/ -st_test_ready(unit,flags) -int unit,flags; -{ - struct scsi_test_unit_ready scsi_cmd; - - bzero(&scsi_cmd, sizeof(scsi_cmd)); - scsi_cmd.op_code = TEST_UNIT_READY; - - return (st_scsi_cmd(unit, - &scsi_cmd, - sizeof(scsi_cmd), - 0, - 0, - 100000, - NULL, - flags)); + if (st->flags & ST_FIXEDBLOCKS) { + scsi_cmd.byte2 |= SRWT_FIXED; + lto3b(size / (st->blksiz ? st->blksiz : DEF_FIXED_BSIZE), + scsi_cmd.len); + } else { + lto3b(size, scsi_cmd.len); + } + return (scsi_scsi_cmd(st->sc_link, + (struct scsi_generic *) &scsi_cmd, + sizeof(scsi_cmd), + (u_char *) buf, + size, + 0, /* not on io commands */ + 100000, + NULL, + flags | SCSI_DATA_IN)); } - - #ifdef __STDC__ #define b2tol(a) (((unsigned)(a##_1) << 8) + (unsigned)a##_0 ) #else #define b2tol(a) (((unsigned)(a/**/_1) << 8) + (unsigned)a/**/_0 ) #endif -/*******************************************************\ -* Ask the drive what it's min and max blk sizes are. * -\*******************************************************/ +/* + * Ask the drive what it's min and max blk sizes are. + */ +errval st_rd_blk_lim(unit, flags) -int unit,flags; + u_int32 unit, flags; { - struct scsi_blk_limits scsi_cmd; + struct scsi_blk_limits scsi_cmd; struct scsi_blk_limits_data scsi_blkl; struct st_data *st = st_data[unit]; - int errno; - - /*******************************************************\ - * First check if we have it all loaded * - \*******************************************************/ - if ((st->flags & ST_INFO_VALID)) return 0; - - /*******************************************************\ - * do a 'Read Block Limits' * - \*******************************************************/ + errval errno; + struct scsi_link *sc_link = st->sc_link; + + /* + * First check if we have it all loaded + */ + if ((sc_link->flags & SDEV_MEDIA_LOADED)) + return 0; + + /* + * do a 'Read Block Limits' + */ bzero(&scsi_cmd, sizeof(scsi_cmd)); scsi_cmd.op_code = READ_BLK_LIMITS; - /*******************************************************\ - * do the command, update the global values * - \*******************************************************/ - if ( errno = st_scsi_cmd(unit, - &scsi_cmd, - sizeof(scsi_cmd), - &scsi_blkl, - sizeof(scsi_blkl), - 5000, - NULL, - flags | SCSI_DATA_IN)) - { + /* + * do the command, update the global values + */ + if (errno = scsi_scsi_cmd(sc_link, + (struct scsi_generic *) &scsi_cmd, + sizeof(scsi_cmd), + (u_char *) & scsi_blkl, + sizeof(scsi_blkl), + ST_RETRIES, + 5000, + NULL, + flags | SCSI_DATA_IN)) { return errno; - } + } st->blkmin = b2tol(scsi_blkl.min_length); st->blkmax = _3btol(&scsi_blkl.max_length_2); -#ifdef STDEBUG - if (st_debug) - { - printf("(%d <= blksiz <= %d)\n", st->blkmin, st->blkmax); - } -#endif /*STDEBUG*/ + SC_DEBUG(sc_link, SDEV_DB3, + ("(%d <= blksiz <= %d)\n", st->blkmin, st->blkmax)); return 0; } -/*******************************************************\ -* Get the scsi driver to send a full inquiry to the * -* device and use the results to fill out the global * -* parameter structure. * -* * -* called from: * -* attach * -* open * -* ioctl (to reset original blksize) * -\*******************************************************/ +/* + * Get the scsi driver to send a full inquiry to the + * device and use the results to fill out the global + * parameter structure. + * + * called from: + * attach + * open + * ioctl (to reset original blksize) + */ +errval st_mode_sense(unit, flags) -int unit,flags; + u_int32 unit, flags; { - int scsi_sense_len; - int errno; - char *scsi_sense_ptr; - struct scsi_mode_sense scsi_cmd; - struct scsi_sense - { - struct scsi_mode_header header; - struct blk_desc blk_desc; - }scsi_sense; + u_int32 scsi_sense_len; + errval errno; + char *scsi_sense_ptr; + struct scsi_mode_sense scsi_cmd; + struct scsi_sense { + struct scsi_mode_header header; + struct blk_desc blk_desc; + } scsi_sense; + + struct scsi_sense_page_0 { + struct scsi_mode_header header; + struct blk_desc blk_desc; + unsigned char sense_data[PAGE_0_SENSE_DATA_SIZE]; + /* Tandberg tape drives returns page 00 + * with the sense data, whether or not + * you want it( ie the don't like you + * saying you want anything less!!!!! + * They also expect page 00 + * back when you issue a mode select + */ + } scsi_sense_page_0; + struct st_data *st = st_data[unit]; + struct scsi_link *sc_link = st->sc_link; - struct scsi_sense_page_0 - { - struct scsi_mode_header header; - struct blk_desc blk_desc; - unsigned char sense_data[PAGE_0_SENSE_DATA_SIZE]; - /* Tandberg tape drives returns page 00 */ - /* with the sense data, whether or not */ - /* you want it( ie the don't like you */ - /* saying you want anything less!!!!! */ - /* They also expect page 00 */ - /* back when you issue a mode select */ - }scsi_sense_page_0; - struct st_data *st = st_data[unit]; - - /*******************************************************\ - * First check if we have it all loaded * - \*******************************************************/ - if ((st->flags & ST_INFO_VALID)) return 0; - - /*******************************************************\ - * Define what sort of structure we're working with * - \*******************************************************/ - if (st->quirks & ST_Q_NEEDS_PAGE_0) - { + /* + * Define what sort of structure we're working with + */ + if (st->quirks & ST_Q_NEEDS_PAGE_0) { scsi_sense_len = sizeof(scsi_sense_page_0); scsi_sense_ptr = (char *) &scsi_sense_page_0; - } - else - { + } else { scsi_sense_len = sizeof(scsi_sense); scsi_sense_ptr = (char *) &scsi_sense; } - - /*******************************************************\ - * Set up a mode sense * - \*******************************************************/ + /* + * Set up a mode sense + */ bzero(&scsi_cmd, sizeof(scsi_cmd)); scsi_cmd.op_code = MODE_SENSE; scsi_cmd.length = scsi_sense_len; - /*******************************************************\ - * do the command, but we don't need the results * - * just print them for our interest's sake, if asked, * - * or if we need it as a template for the mode select * - * store it away. * - \*******************************************************/ - if (errno = st_scsi_cmd(unit, - &scsi_cmd, - sizeof(scsi_cmd), - scsi_sense_ptr, - scsi_sense_len, - 5000, - NULL, - flags | SCSI_DATA_IN) ) - { + /* + * do the command, but we don't need the results + * just print them for our interest's sake, if asked, + * or if we need it as a template for the mode select + * store it away. + */ + if (errno = scsi_scsi_cmd(sc_link, + (struct scsi_generic *) &scsi_cmd, + sizeof(scsi_cmd), + (u_char *) scsi_sense_ptr, + scsi_sense_len, + ST_RETRIES, + 5000, + NULL, + flags | SCSI_DATA_IN)) { return errno; - } - st->numblks = _3btol(&(((struct scsi_sense *)scsi_sense_ptr)->blk_desc.nblocks)); - st->media_blksiz = _3btol(&(((struct scsi_sense *)scsi_sense_ptr)->blk_desc.blklen)); - st->media_density = ((struct scsi_sense *)scsi_sense_ptr)->blk_desc.density; - if (((struct scsi_sense *)scsi_sense_ptr)->header.dev_spec & - SMH_DSP_WRITE_PROT) + } + st->numblks = _3btol(((struct scsi_sense *)scsi_sense_ptr)->blk_desc.nblocks); + st->media_blksiz = _3btol(((struct scsi_sense *)scsi_sense_ptr)->blk_desc.blklen); + st->media_density = ((struct scsi_sense *) scsi_sense_ptr)->blk_desc.density; + if (((struct scsi_sense *) scsi_sense_ptr)->header.dev_spec & + SMH_DSP_WRITE_PROT) { st->flags |= ST_READONLY; -#ifdef STDEBUG - if (st_debug) - { - printf("st%d: density code 0x%x, %d-byte blocks, write-%s, ", - unit, st->media_density, st->media_blksiz, - st->flags & ST_READONLY ? "protected" : "enabled"); - printf("%sbuffered\n", - ((struct scsi_sense *)scsi_sense_ptr)->header.dev_spec - & SMH_DSP_BUFF_MODE ? "" : "un"); } -#endif /*STDEBUG*/ - if (st->quirks & ST_Q_NEEDS_PAGE_0) - { - bcopy(((struct scsi_sense_page_0 *)scsi_sense_ptr)->sense_data, - st->sense_data, - sizeof(((struct scsi_sense_page_0 *)scsi_sense_ptr)->sense_data)); + SC_DEBUG(sc_link, SDEV_DB3, + ("density code 0x%x, %d-byte blocks, write-%s, ", + st->media_density, st->media_blksiz, + st->flags & ST_READONLY ? "protected" : "enabled")); + SC_DEBUG(sc_link, SDEV_DB3, + ("%sbuffered\n", + ((struct scsi_sense *) scsi_sense_ptr)->header.dev_spec + & SMH_DSP_BUFF_MODE ? "" : "un")); + if (st->quirks & ST_Q_NEEDS_PAGE_0) { + bcopy(((struct scsi_sense_page_0 *) scsi_sense_ptr)->sense_data, + st->sense_data, + sizeof(((struct scsi_sense_page_0 *) scsi_sense_ptr)->sense_data)); } + sc_link->flags |= SDEV_MEDIA_LOADED; return 0; } -/*******************************************************\ -* Send a filled out parameter structure to the drive to * -* set it into the desire modes etc. * -\*******************************************************/ +/* + * Send a filled out parameter structure to the drive to + * set it into the desire modes etc. + */ +errval st_mode_select(unit, flags) -int unit, flags; + u_int32 unit, flags; { - int dat_len; - char *dat_ptr; + u_int32 dat_len; + char *dat_ptr; struct scsi_mode_select scsi_cmd; - struct dat - { - struct scsi_mode_header header; - struct blk_desc blk_desc; - }dat; - struct dat_page_0 - { - struct scsi_mode_header header; - struct blk_desc blk_desc; - unsigned char sense_data[PAGE_0_SENSE_DATA_SIZE]; - }dat_page_0; - struct st_data *st = st_data[unit]; - - /*******************************************************\ - * Define what sort of structure we're working with * - \*******************************************************/ - if (st->quirks & ST_Q_NEEDS_PAGE_0) - { + struct dat { + struct scsi_mode_header header; + struct blk_desc blk_desc; + } dat; + struct dat_page_0 { + struct scsi_mode_header header; + struct blk_desc blk_desc; + unsigned char sense_data[PAGE_0_SENSE_DATA_SIZE]; + } dat_page_0; + struct st_data *st = st_data[unit]; + + /* + * Define what sort of structure we're working with + */ + if (st->quirks & ST_Q_NEEDS_PAGE_0) { dat_len = sizeof(dat_page_0); dat_ptr = (char *) &dat_page_0; - } - else - { + } else { dat_len = sizeof(dat); dat_ptr = (char *) &dat; } - - /*******************************************************\ - * Set up for a mode select * - \*******************************************************/ + /* + * Set up for a mode select + */ bzero(dat_ptr, dat_len); bzero(&scsi_cmd, sizeof(scsi_cmd)); scsi_cmd.op_code = MODE_SELECT; scsi_cmd.length = dat_len; - ((struct dat *)dat_ptr)->header.blk_desc_len = sizeof(struct blk_desc); - ((struct dat *)dat_ptr)->header.dev_spec |= SMH_DSP_BUFF_MODE_ON; - ((struct dat *)dat_ptr)->blk_desc.density = st->density; - if(st->flags & ST_FIXEDBLOCKS) - { - lto3b( st->blksiz , ((struct dat *)dat_ptr)->blk_desc.blklen); + ((struct dat *) dat_ptr)->header.blk_desc_len = sizeof(struct blk_desc); + ((struct dat *) dat_ptr)->header.dev_spec |= SMH_DSP_BUFF_MODE_ON; + ((struct dat *) dat_ptr)->blk_desc.density = st->density; + if (st->flags & ST_FIXEDBLOCKS) { + lto3b(st->blksiz, ((struct dat *) dat_ptr)->blk_desc.blklen); } - if (st->quirks & ST_Q_NEEDS_PAGE_0) - { - bcopy(st->sense_data, ((struct dat_page_0 *)dat_ptr)->sense_data, - sizeof(((struct dat_page_0 *)dat_ptr)->sense_data)); - /* the Tandberg tapes need the block size to */ - /* be set on each mode sense/select. */ + if (st->quirks & ST_Q_NEEDS_PAGE_0) { + bcopy(st->sense_data, ((struct dat_page_0 *) dat_ptr)->sense_data, + sizeof(((struct dat_page_0 *) dat_ptr)->sense_data)); + /* the Tandberg tapes need the block size to */ + /* be set on each mode sense/select. */ } - /*******************************************************\ - * do the command * - \*******************************************************/ - return (st_scsi_cmd(unit, - &scsi_cmd, - sizeof(scsi_cmd), - dat_ptr, - dat_len, - 5000, - NULL, - flags | SCSI_DATA_OUT) ); + /* + * do the command + */ + return (scsi_scsi_cmd(st->sc_link, + (struct scsi_generic *) &scsi_cmd, + sizeof(scsi_cmd), + (u_char *) dat_ptr, + dat_len, + ST_RETRIES, + 5000, + NULL, + flags | SCSI_DATA_OUT)); } -/*******************************************************\ -* skip N blocks/filemarks/seq filemarks/eom * -\*******************************************************/ -st_space(unit,number,what,flags) -int unit,number,what,flags; +/* + * skip N blocks/filemarks/seq filemarks/eom + */ +errval +st_space(unit, number, what, flags) + u_int32 unit, what, flags; + int32 number; { - int error; + errval error; struct scsi_space scsi_cmd; - struct st_data *st = st_data[unit]; - - /*******************************************************\ - * If we're at beginning of medium, now is the time to * - * set medium access density, fixed or variable-blocks * - * and, if fixed, the block size. * - \*******************************************************/ - if (st->flags & ST_AT_BOM && - (error = st_decide_mode(unit, TRUE))) - return (error); + struct st_data *st = st_data[unit]; - switch (what) - { - case SP_BLKS: - if (st->flags & ST_PER_ACTION) - { - if (number > 0) - { + switch (what) { + case SP_BLKS: + if (st->flags & ST_PER_ACTION) { + if (number > 0) { st->flags &= ~ST_PER_ACTION; - return(EIO); - } - else if (number < 0) - { - if (st->flags & ST_AT_FILEMARK) - { - /*******************************\ - * Handling of ST_AT_FILEMARK * - * in st_space will fill in the * - * right file mark count. * - \*******************************/ + return (EIO); + } else if (number < 0) { + if (st->flags & ST_AT_FILEMARK) { + /* + * Handling of ST_AT_FILEMARK + * in st_space will fill in the + * right file mark count. + */ error = st_space(unit, 0, SP_FILEMARKS, flags); - if (error) return(error); + if (error) + return (error); } - if (st->flags & ST_BLANK_READ) - { + if (st->flags & ST_BLANK_READ) { st->flags &= ~ST_BLANK_READ; - return(EIO); + return (EIO); } st->flags &= ~ST_EIO_PENDING; } } break; - case SP_FILEMARKS: - if (st->flags & ST_EIO_PENDING) - { - if (number > 0) - { + case SP_FILEMARKS: + if (st->flags & ST_EIO_PENDING) { + if (number > 0) { /* pretend we just discover the error */ st->flags &= ~ST_EIO_PENDING; - return(EIO); - } - else if (number < 0) + return (EIO); + } else if (number < 0) { /* back away from the error */ st->flags &= ~ST_EIO_PENDING; + } } - if (st->flags & ST_AT_FILEMARK) - { + if (st->flags & ST_AT_FILEMARK) { st->flags &= ~ST_AT_FILEMARK; number--; } - if (st->flags & ST_BLANK_READ && number < 0) - { + if ((st->flags & ST_BLANK_READ) && (number < 0)) { /* back away from unwritten tape */ st->flags &= ~ST_BLANK_READ; - number++; + number++; /* dubious */ } } - if (number == 0) - return(ESUCCESS); + if (number == 0) { + return (ESUCCESS); + } bzero(&scsi_cmd, sizeof(scsi_cmd)); scsi_cmd.op_code = SPACE; scsi_cmd.byte2 = what & SS_CODE; - lto3b(number,scsi_cmd.number); - return (st_scsi_cmd(unit, - &scsi_cmd, - sizeof(scsi_cmd), - 0, - 0, - 600000, /* 10 mins enough? */ - NULL, - flags)); + lto3b(number, scsi_cmd.number); + return (scsi_scsi_cmd(st->sc_link, + (struct scsi_generic *) &scsi_cmd, + sizeof(scsi_cmd), + 0, + 0, + 0, /* no retries please , just fail */ + 600000, /* 10 mins enough? */ + NULL, + flags)); } -/*******************************************************\ -* write N filemarks * -\*******************************************************/ -st_write_filemarks(unit,number,flags) -int unit,number,flags; + +/* + * write N filemarks + */ +errval +st_write_filemarks(unit, number, flags) + u_int32 unit, flags; + int32 number; { - int error; struct scsi_write_filemarks scsi_cmd; - struct st_data *st = st_data[unit]; - - /*******************************************************\ - * It's hard to write a negative number of file marks. * - * Don't try. * - \*******************************************************/ - if (number < 0) - return (EINVAL); - - /*******************************************************\ - * If we're at beginning of medium, now is the time to * - * set medium access density, fixed or variable-blocks * - * and, if fixed, the block size. * - \*******************************************************/ - if (st->flags & ST_AT_BOM && number > 0 && - (error = st_decide_mode(unit, FALSE))) - return (error); + struct st_data *st = st_data[unit]; - switch (number) - { - case 0: /* really a command to sync the drive's buffers */ + /* + * It's hard to write a negative number of file marks. + * Don't try. + */ + if (number < 0) { + return EINVAL; + } + switch (number) { + case 0: /* really a command to sync the drive's buffers */ break; - case 1: - if (st->flags & ST_FM_WRITTEN) + case 1: + if (st->flags & ST_FM_WRITTEN) { /* already have one down */ st->flags &= ~ST_WRITTEN; - else + } else { st->flags |= ST_FM_WRITTEN; + } st->flags &= ~ST_PER_ACTION; break; default: st->flags &= ~(ST_PER_ACTION | ST_WRITTEN); } - bzero(&scsi_cmd, sizeof(scsi_cmd)); scsi_cmd.op_code = WRITE_FILEMARKS; - lto3b(number,scsi_cmd.number); - return (st_scsi_cmd(unit, - &scsi_cmd, - sizeof(scsi_cmd), - 0, - 0, - 100000, /* 10 secs.. (may need to repos head )*/ - NULL, - flags) ); + lto3b(number, scsi_cmd.number); + return scsi_scsi_cmd(st->sc_link, + (struct scsi_generic *) &scsi_cmd, + sizeof(scsi_cmd), + 0, + 0, + 0, /* no retries, just fail */ + 100000, /* 10 secs.. (may need to repos head ) */ + NULL, + flags); } -/***************************************************************\ -* Make sure the right number of file marks is on tape if the * -* tape has been written. If the position argument is true, * -* leave the tape positioned where it was originally. * -* * -* nmarks returns the number of marks to skip (or, if position * -* true, which were skipped) to get back original position. * -\***************************************************************/ +/* + * Make sure the right number of file marks is on tape if the + * tape has been written. If the position argument is true, + * leave the tape positioned where it was originally. + * + * nmarks returns the number of marks to skip (or, if position + * true, which were skipped) to get back original position. + */ +int32 st_chkeod(unit, position, nmarks, flags) -int unit; -int position; -int *nmarks; -int flags; + u_int32 unit; + boolean position; + int32 *nmarks; + u_int32 flags; { - int error; - struct st_data *st = st_data[unit]; + errval error; + struct st_data *st = st_data[unit]; - switch (st->flags & (ST_WRITTEN | ST_FM_WRITTEN | ST_2FM_AT_EOD)) - { + switch (st->flags & (ST_WRITTEN | ST_FM_WRITTEN | ST_2FM_AT_EOD)) { default: *nmarks = 0; - return(ESUCCESS); - case ST_WRITTEN: - case ST_WRITTEN | ST_FM_WRITTEN | ST_2FM_AT_EOD: + return (ESUCCESS); + case ST_WRITTEN: + case ST_WRITTEN | ST_FM_WRITTEN | ST_2FM_AT_EOD: *nmarks = 1; break; - case ST_WRITTEN | ST_2FM_AT_EOD: + case ST_WRITTEN | ST_2FM_AT_EOD: *nmarks = 2; } error = st_write_filemarks(unit, *nmarks, flags); - if (position && error == ESUCCESS) + if (position && (error == ESUCCESS)) error = st_space(unit, -*nmarks, SP_FILEMARKS, flags); return (error); } -/*******************************************************\ -* load/unload (with retension if true) * -\*******************************************************/ -st_load(unit,type,flags) -int unit,type,flags; +/* + * load/unload (with retension if true) + */ +errval +st_load(unit, type, flags) + u_int32 unit, type, flags; { - struct scsi_load scsi_cmd; - struct st_data *st = st_data[unit]; + struct scsi_load scsi_cmd; + struct st_data *st = st_data[unit]; + struct scsi_link *sc_link = st->sc_link; - st->flags &= ~ST_PER_MEDIA; bzero(&scsi_cmd, sizeof(scsi_cmd)); - if (type == LD_LOAD) - { - /*scsi_cmd.how |= LD_RETEN;*/ - st->flags |= ST_AT_BOM; - } - else - { - int error, nmarks; + if (type != LD_LOAD) { + errval error; + int32 nmarks; error = st_chkeod(unit, FALSE, &nmarks, flags); - if (error != ESUCCESS) return(error); - st->flags &= ~ST_INFO_VALID; + if (error != ESUCCESS) + return (error); + sc_link->flags &= ~SDEV_MEDIA_LOADED; } - if(st->quirks & ST_Q_IGNORE_LOADS) return(0); + if (st->quirks & ST_Q_IGNORE_LOADS) + return (0); scsi_cmd.op_code = LOAD_UNLOAD; scsi_cmd.how |= type; - return (st_scsi_cmd(unit, - &scsi_cmd, - sizeof(scsi_cmd), - 0, - 0, - 300000, /* 5 min */ - NULL, - flags)); + return (scsi_scsi_cmd(st->sc_link, + (struct scsi_generic *) &scsi_cmd, + sizeof(scsi_cmd), + 0, + 0, + ST_RETRIES, + 300000, /* 5 min */ + NULL, + flags)); } -/*******************************************************\ -* Prevent or allow the user to remove the tape * -\*******************************************************/ -st_prevent(unit,type,flags) -int unit,type,flags; -{ - struct scsi_prevent scsi_cmd; - - if (type == PR_ALLOW) - { - int error, nmarks; - error = st_chkeod(unit, TRUE, &nmarks, flags); - if (error != ESUCCESS) return(error); - st_data[unit]->flags &= ~ST_INFO_VALID; - } - bzero(&scsi_cmd, sizeof(scsi_cmd)); - scsi_cmd.op_code = PREVENT_ALLOW; - scsi_cmd.how=type; - return (st_scsi_cmd(unit, - &scsi_cmd, - sizeof(scsi_cmd), - 0, - 0, - 5000, - NULL, - flags)); -} -/*******************************************************\ -* Rewind the device * -\*******************************************************/ -st_rewind(unit,immed,flags) -int unit,immed,flags; +/* + * Rewind the device + */ +errval +st_rewind(unit, immed, flags) + u_int32 unit, flags; + boolean immed; { - struct scsi_rewind scsi_cmd; - struct st_data *st = st_data[unit]; - int error, nmarks; + struct scsi_rewind scsi_cmd; + struct st_data *st = st_data[unit]; + errval error; + int32 nmarks; error = st_chkeod(unit, FALSE, &nmarks, flags); - if (error != ESUCCESS) return(error); + if (error != ESUCCESS) + return (error); st->flags &= ~ST_PER_ACTION; - st->flags |= ST_AT_BOM; bzero(&scsi_cmd, sizeof(scsi_cmd)); scsi_cmd.op_code = REWIND; scsi_cmd.byte2 = immed ? SR_IMMED : 0; - return (st_scsi_cmd(unit, - &scsi_cmd, - sizeof(scsi_cmd), - 0, - 0, - immed?5000:300000, /* 5 sec or 5 min */ - NULL, - flags)); -} - -/***************************************************************\ -* ststart looks to see if there is a buf waiting for the device * -* and that the device is not already busy. If both are true, * -* It deques the buf and creates a scsi command to perform the * -* transfer in the buf. The transfer request will call st_done * -* on completion, which will in turn call this routine again * -* so that the next queued transfer is performed. * -* The bufs are queued by the strategy routine (ststrategy) * -* * -* This routine is also called after other non-queued requests * -* have been made of the scsi driver, to ensure that the queue * -* continues to be drained. * -\***************************************************************/ -/* ststart() is called at splbio */ -ststart(unit) -{ - int drivecount; - register struct buf *bp = 0; - register struct buf *dp; - struct scsi_rw_tape cmd; - int blkno, nblk; - struct st_data *st = st_data[unit]; - int flags; - - - -#ifdef STDEBUG - if(scsi_debug & PRINTROUTINES) printf("ststart%d ",unit); -#endif /*STDEBUG*/ - /*******************************************************\ - * See if there is a buf to do and we are not already * - * doing one * - \*******************************************************/ - if(st->scsi_xfer.flags & INUSE) - { - return; /* unit already underway */ - } -trynext: - if(st->xfer_block_wait) /* a special awaits, let it proceed first */ - { - wakeup(&(st->xfer_block_wait)); - return; - } - - if ((bp = st->buf_queue) == NULL) - { - return; /* no work to bother with */ - } - st->buf_queue = bp->b_actf; - - - - /*******************************************************\ - * only FIXEDBLOCK devices have pending operations * - \*******************************************************/ - if(st->flags & ST_FIXEDBLOCKS) - { - /*******************************************************\ - * If we are at a filemark but have not reported it yet * - * then we should report it now * - \*******************************************************/ - if(st->flags & ST_AT_FILEMARK) - { - if ((bp->b_flags & B_READ) == B_WRITE) - { - /***************************************\ - * Handling of ST_AT_FILEMARK in * - * st_space will fill in the right file * - * mark count. * - \***************************************/ - if (st_space(unit, 0, SP_FILEMARKS, 0) != - ESUCCESS) goto badnews; - } - else - { - bp->b_resid = bp->b_bcount; - bp->b_error = 0; - bp->b_flags &= ~B_ERROR; - st->flags &= ~ST_AT_FILEMARK; - biodone(bp); - goto trynext; - } - } - /*******************************************************\ - * If we are at EIO (e.g. EOM) but have not reported it * - * yet then we should report it now * - \*******************************************************/ - if(st->flags & ST_EIO_PENDING) - { - bp->b_resid = bp->b_bcount; - bp->b_error = EIO; - bp->b_flags |= B_ERROR; - st->flags &= ~ST_EIO_PENDING; - biodone(bp); - goto trynext; - } - } - /*******************************************************\ - * Fill out the scsi command * - \*******************************************************/ - bzero(&cmd, sizeof(cmd)); - if((bp->b_flags & B_READ) == B_WRITE) - { - cmd.op_code = WRITE_COMMAND_TAPE; - st->flags &= ~ST_FM_WRITTEN; - st->flags |= ST_WRITTEN; - flags = SCSI_DATA_OUT; - } - else - { - cmd.op_code = READ_COMMAND_TAPE; - flags = SCSI_DATA_IN; - } - - /*******************************************************\ - * Handle "fixed-block-mode" tape drives by using the * - * block count instead of the length. * - \*******************************************************/ - if(st->flags & ST_FIXEDBLOCKS) - { - cmd.byte2 |= SRWT_FIXED; - lto3b(bp->b_bcount/st->blksiz,cmd.len); - } - else - { - lto3b(bp->b_bcount,cmd.len); - } - - /*******************************************************\ - * go ask the adapter to do all this for us * - \*******************************************************/ - if (st_scsi_cmd(unit, - &cmd, - sizeof(cmd), - (u_char *)bp->b_un.b_addr, - bp->b_bcount, - 100000, - bp, - flags | SCSI_NOSLEEP ) != SUCCESSFULLY_QUEUED) - - { -badnews: - printf("st%d: oops not queued\n",unit); - bp->b_flags |= B_ERROR; - bp->b_error = EIO; - biodone(bp); - return; - } - stqueues++; + return (scsi_scsi_cmd(st->sc_link, + (struct scsi_generic *) &scsi_cmd, + sizeof(scsi_cmd), + 0, + 0, + ST_RETRIES, + immed ? 5000 : 300000, /* 5 sec or 5 min */ + NULL, + flags)); } -/*******************************************************\ -* This routine is called by the scsi interrupt when * -* the transfer is complete. -\*******************************************************/ -int st_done(unit,xs) -int unit; -struct scsi_xfer *xs; -{ - struct buf *bp; - int retval; - struct st_data *st = st_data[unit]; - -#ifdef STDEBUG - if(scsi_debug & PRINTROUTINES) printf("st_done%d ",unit); -#endif /*STDEBUG*/ -#ifdef PARANOID - if (! (xs->flags & INUSE)) - panic("scsi_xfer not in use!"); -#endif /*PARANOID*/ - if((bp = xs->bp)== NULL) - { - wakeup(xs); - return; - } - switch(xs->error) - { - case XS_NOERROR: - bp->b_flags &= ~B_ERROR; - bp->b_error = 0; - bp->b_resid = 0; - break; - case XS_SENSE: - retval = (st_interpret_sense(unit,xs)); - bp->b_resid = xs->resid; /* already multiplied by blksiz */ - if(retval) - { - /***************************************\ - * We have a real error, the bit should * - * be set to indicate this. The return * - * value will contain the unix error code* - * that the error interpretation routine * - * thought was suitable, so pass this * - * value back in the buf structure. * - * Furthermore we return information * - * saying that no data was transferred * - * All status is now suspect * - \***************************************/ - bp->b_flags |= B_ERROR; - bp->b_error = retval; - bp->b_resid = bp->b_bcount; - st->flags &= ~ST_PER_ACTION; - } - else - { - /***********************************************\ - * The error interpretation code has declared * - * that it wasn't a real error, or at least that * - * we should be ignoring it if it was. * - \***********************************************/ - if(xs->resid == 0) - { - /***************************************\ - * we apparently had a corrected error * - * or something. * - * pretend the error never happenned * - \***************************************/ - bp->b_flags &= ~B_ERROR; - bp->b_error = 0; - break; - } - if ( xs->resid != xs->datalen ) - { - /***************************************\ - * Here we have the tricky part.. * - * We successfully read less data than * - * we requested. (but not 0) * - *------for variable blocksize tapes:----* - * UNDER 386BSD: * - * We should legitimatly have the error * - * bit set, with the error value set to * - * zero.. This is to indicate to the * - * physio code that while we didn't get * - * as much information as was requested, * - * we did reach the end of the record * - * and so physio should not call us * - * again for more data... we have it all * - * SO SET THE ERROR BIT! * - * * - * UNDER NetBSD: * - * To indicate the same as above, we * - * need only have a non 0 resid that is * - * less than the b_bcount, but the * - * ERROR BIT MUST BE CLEAR! (sigh) * - * * - *-------for fixed blocksize device------* - * We read some successful records * - * before hitting the EOF or EOT. These * - * must be passed to the user, before we * - * report the EOx. We will report the * - * EOx NEXT time. * - \***************************************/ -#ifdef NETBSD - bp->b_flags &= ~B_ERROR; +#ifdef NETBSD +#define SIGNAL_SHORT_READ #else - bp->b_flags |= B_ERROR; -#endif - bp->b_error = 0; - xs->error = XS_NOERROR; - break; - } - else - { - /***************************************\ - * We have come out of the error handler * - * with no error code. We have also not * - * transferred any data (would have gone * - * to the previous clause). * - * This must be an EOF * - * Any caller request to read no * - * data would have been short-circuited * - * at st_read or ststrategy. * - * * - * At least all o/s agree that: * - * 0 bytes read with no error is EOF * - \***************************************/ - - bp->b_error = 0; - bp->b_flags &= ~B_ERROR; - st->flags &= ~ST_AT_FILEMARK; - break; - } - } - break; - - case XS_TIMEOUT: - printf("st%d: timeout\n",unit); - - case XS_BUSY: /* should retry */ /* how? */ - /************************************************/ - /* SHOULD put buf back at head of queue */ - /* and decrement retry count in (*xs) */ - /* HOWEVER, this should work as a kludge */ - /************************************************/ - if(xs->retries--) - { - xs->flags &= ~ITSDONE; - xs->error = XS_NOERROR; - if ( (*(st->sc_sw->scsi_cmd))(xs) - == SUCCESSFULLY_QUEUED) - { /* don't wake the job, ok? */ - return; - } - printf("st%d: device busy\n",unit); - xs->flags |= ITSDONE; - } - - case XS_DRIVER_STUFFUP: - bp->b_flags |= B_ERROR; - bp->b_error = EIO; - break; - default: - printf("st%d: unknown error category from scsi driver\n" - ,unit); - } - biodone(bp); - xs->flags = 0; /* no longer in use */ - ststart(unit); /* If there's another waiting.. do it */ -} - - +#define SIGNAL_SHORT_READ bp->b_flags |= B_ERROR; +#endif -/*******************************************************\ -* ask the scsi driver to perform a command for us. * -* Call it through the switch table, and tell it which * -* sub-unit we want, and what target and lu we wish to * -* talk to. Also tell it where to find the command * -* how long int is. * -* Also tell it where to read/write the data, and how * -* long the data is supposed to be * -\*******************************************************/ -int st_scsi_cmd(unit,scsi_cmd,cmdlen,data_addr,datalen,timeout,bp,flags) - -int unit,flags; -struct scsi_generic *scsi_cmd; -int cmdlen; -int timeout; -u_char *data_addr; -struct buf *bp; -int datalen; +/* + * Look at the returned sense and act on the error and detirmine + * The unix error number to pass back... (0 = report no error) + * (-1 = continue processing) + */ +errval +st_interpret_sense(xs) + struct scsi_xfer *xs; { - struct scsi_xfer *xs; - int retval; - int s; - struct st_data *st = st_data[unit]; - -#ifdef STDEBUG - if(scsi_debug & PRINTROUTINES) printf("\nst_scsi_cmd%d ",unit); -#endif /*STDEBUG*/ -#ifdef PARANOID - if(st->sc_sw == NULL) /* If we have no scsi driver */ - { - printf("st%d: not set up\n",unit); - return(EINVAL); + struct scsi_link *sc_link = xs->sc_link; + struct scsi_sense_data *sense = &(xs->sense); + boolean silent = xs->flags & SCSI_SILENT; + struct buf *bp = xs->bp; + u_int32 unit = sc_link->dev_unit; + struct st_data *st = st_data[unit]; + u_int32 key; + int32 info; + + /* + * Get the sense fields and work out what code + */ + if (sense->error_code & SSD_ERRCODE_VALID) { + info = ntohl(*((int32 *) sense->ext.extended.info)); + } else { + info = xs->datalen; /* bad choice if fixed blocks */ } -#endif /*PARANOID*/ - - xs = &(st->scsi_xfer); - if(!(flags & SCSI_NOMASK)) - s = splbio(); - st->xfer_block_wait++; /* there is someone waiting */ - while (xs->flags & INUSE) - { - if(flags & SCSI_NOSLEEP) - return EBUSY; - sleep(&(st->xfer_block_wait),PRIBIO+1); + if ((sense->error_code & SSD_ERRCODE) != 0x70) { + return (-1); /* let the generic code handle it */ } - st->xfer_block_wait--; - xs->flags = INUSE; - if(!(flags & SCSI_NOMASK)) - splx(s); - - /*******************************************************\ - * Fill out the scsi_xfer structure * - \*******************************************************/ - xs->flags |= flags; - xs->adapter = st->ctlr; - xs->targ = st->targ; - xs->lu = st->lu; - xs->retries = bp?0:ST_RETRIES;/*can't retry on IO*/ - xs->timeout = timeout; - xs->cmd = scsi_cmd; - xs->cmdlen = cmdlen; - xs->data = data_addr; - xs->datalen = datalen; - xs->resid = datalen; - xs->when_done = st_done; - xs->done_arg = unit; - xs->done_arg2 = (int)xs; - xs->bp = bp; -retry: xs->error = XS_NOERROR; - - /***********************************************\ - * Ask the adapter to do the command for us * - \***********************************************/ - retval = (*(st->sc_sw->scsi_cmd))(xs); - - /***********************************************\ - * IO operations are handled differently.. * - * Physio does the sleep, and error handling is * - * Done in st_done at interrupt time * - \***********************************************/ - if(bp) return retval; - - /***********************************************\ - * Wait for the result if queued, or handle the * - * error if it was rejected.. * - \***********************************************/ - switch(retval) - { - case SUCCESSFULLY_QUEUED: - s = splbio(); - while(!(xs->flags & ITSDONE)) - sleep(xs,PRIBIO+1); - splx(s); - /*******************************\ - * finished.. check for failure * - * Fall through...... * - \*******************************/ - case HAD_ERROR: - case COMPLETE: - switch(xs->error) - { - case XS_NOERROR: - retval = ESUCCESS; - break; - case XS_SENSE: - retval = (st_interpret_sense(unit,xs)); - /* only useful for reads *//* why did I say that?*/ - if (retval) - { /* error... don't care about filemarks */ - st->flags &= ~ST_PER_ACTION; - } - else - { - xs->error = XS_NOERROR; - retval = ESUCCESS; + if (st->flags & ST_FIXEDBLOCKS) { + xs->resid = info * st->blksiz; + if (sense->ext.extended.flags & SSD_EOM) { + st->flags |= ST_EIO_PENDING; + if (bp) { + bp->b_resid = xs->resid; + SIGNAL_SHORT_READ } - break; - case XS_DRIVER_STUFFUP: - retval = EIO; - break; - case XS_BUSY: - /* should sleep 1 sec here */ - case XS_TIMEOUT: - if(xs->retries-- ) - { - xs->flags &= ~ITSDONE; - goto retry; - } - retval = EIO; - break; - default: - retval = EIO; - printf("st%d: unknown error category from scsi driver\n" - ,unit); - break; - } - break; - case TRY_AGAIN_LATER: - if(xs->retries-- ) - { - xs->flags &= ~ITSDONE; - /* should delay here */ - goto retry; } - retval = EIO; - break; - default: - retval = EIO; - } - xs->flags = 0; /* it's free! */ - ststart(unit); - return(retval); -} -/***************************************************************\ -* Look at the returned sense and act on the error and detirmine * -* The unix error number to pass back... (0 = report no error) * -\***************************************************************/ - -int st_interpret_sense(unit,xs) -int unit; -struct scsi_xfer *xs; -{ - struct scsi_sense_data *sense; - int key; - int silent = xs->flags & SCSI_SILENT; - struct st_data *st = st_data[unit]; - int info; - static char *error_mes[] = { "soft error (corrected)", - "not ready", "medium error", - "non-media hardware failure", "illegal request", - "unit attention", "tape is write-protected", - "no data found", "vendor unique", - "copy aborted", "command aborted", - "search returned equal", "volume overflow", - "verify miscompare", "unknown error key" - }; - - /***************************************************************\ - * If errors are ok, report a success * - \***************************************************************/ - if(xs->flags & SCSI_ERR_OK) return(ESUCCESS); - - /***************************************************************\ - * Get the sense fields and work out what code * - \***************************************************************/ - sense = &(xs->sense); -#ifdef STDEBUG - if(st_debug) - { - int count = 0; - printf("code%x valid%x\n" - ,sense->error_code & SSD_ERRCODE - ,sense->error_code & SSD_ERRCODE_VALID ? 1 : 0); - printf("seg%x key%x ili%x eom%x fmark%x\n" - ,sense->ext.extended.segment - ,sense->ext.extended.flags & SSD_KEY - ,sense->ext.extended.flags & SSD_ILI ? 1 : 0 - ,sense->ext.extended.flags & SSD_EOM ? 1 : 0 - ,sense->ext.extended.flags & SSD_FILEMARK ? 1 : 0); - printf("info: %x %x %x %x followed by %d extra bytes\n" - ,sense->ext.extended.info[0] - ,sense->ext.extended.info[1] - ,sense->ext.extended.info[2] - ,sense->ext.extended.info[3] - ,sense->ext.extended.extra_len); - printf("extra: "); - while(count < sense->ext.extended.extra_len) - { - printf ("%x ",sense->ext.extended.extra_bytes[count++]); + if (sense->ext.extended.flags & SSD_FILEMARK) { + st->flags |= ST_AT_FILEMARK; + if (bp) { + bp->b_resid = xs->resid; + SIGNAL_SHORT_READ + } } - printf("\n"); - } -#endif /*STDEBUG*/ - if(sense->error_code & SSD_ERRCODE_VALID) - { - info = ntohl(*((long *)sense->ext.extended.info)); - } - else - { - info = xs->datalen; /* bad choice if fixed blocks */ - } - - - switch(sense->error_code & SSD_ERRCODE) - { - /***************************************************************\ - * If it's code 70, use the extended stuff and interpret the key * - \***************************************************************/ - case 0x70: - if(st->flags & ST_FIXEDBLOCKS) - { - xs->resid = info * st->blksiz; - if(sense->ext.extended.flags & SSD_EOM) - { - st->flags |= ST_EIO_PENDING; + if (sense->ext.extended.flags & SSD_ILI) { + st->flags |= ST_EIO_PENDING; + if (bp) { + bp->b_resid = xs->resid; + SIGNAL_SHORT_READ } - if(sense->ext.extended.flags & SSD_FILEMARK) - { - st->flags |= ST_AT_FILEMARK; + if (sense->error_code & SSD_ERRCODE_VALID && + !silent) + printf("st%d: block wrong size" + ", %d blocks residual\n", unit + ,info); + + /* + * This quirk code helps the drive read + * the first tape block, regardless of + * format. That is required for these + * drives to return proper MODE SENSE + * information. + */ + if ((st->quirks & ST_Q_SNS_HLP) && + !(sc_link->flags & SDEV_MEDIA_LOADED)) { + st->blksiz -= 512; } - if(sense->ext.extended.flags & SSD_ILI) - { - st->flags |= ST_EIO_PENDING; - if (sense->error_code & SSD_ERRCODE_VALID && - !silent) - printf("st%d: %d-byte block wrong size" - "\n", unit, xs->datalen - info); - - /***************************************\ - * This quirk code helps the drive read * - * the first tape block, regardless of * - * format. That is required for these * - * drives to return proper MODE SENSE * - * information. * - \***************************************/ - if ((st->quirks & ST_Q_SNS_HLP) && - !(st->flags & ST_INFO_VALID)) - { - st->blksiz -= 512; - } + } + /* + * If no data was tranfered, do it immediatly + */ + if (xs->resid >= xs->datalen) { + if (st->flags & ST_EIO_PENDING) { + return EIO; } - /***********************************************\ - * If no data was tranfered, do it immediatly * - \***********************************************/ - if(xs->resid >= xs->datalen) - { - if(st->flags & ST_EIO_PENDING) - { - return EIO; - } - if(st->flags & ST_AT_FILEMARK) - { - return 0; + if (st->flags & ST_AT_FILEMARK) { + if (bp) { + bp->b_resid = xs->resid; + SIGNAL_SHORT_READ } + return 0; } } - else - { - xs->resid = xs->datalen; /* to be sure */ - if(sense->ext.extended.flags & SSD_EOM) - { - return(EIO); + } else { /* must be variable mode */ + xs->resid = xs->datalen; /* to be sure */ + if (sense->ext.extended.flags & SSD_EOM) { + return (EIO); + } + if (sense->ext.extended.flags & SSD_FILEMARK) { + if (bp) + bp->b_resid = bp->b_bcount; + return 0; + } + if (sense->ext.extended.flags & SSD_ILI) { + if (info < 0) { + /* + * the record was bigger than the read + */ + if (!silent) + printf("st%d: %d-byte record " + "too big\n", unit, + xs->datalen - info); + return (EIO); } - if(sense->ext.extended.flags & SSD_FILEMARK) - { - return 0; + xs->resid = info; + if (bp) { + bp->b_resid = info; + SIGNAL_SHORT_READ } - if(sense->ext.extended.flags & SSD_ILI) - { - if(info < 0) - /***************************************\ - * the record was bigger than the read * - \***************************************/ - { - if (!silent) - printf("st%d: %d-byte record " - "too big\n", unit, - xs->datalen - info); - return(EIO); - } - xs->resid = info; + } + } + key = sense->ext.extended.flags & SSD_KEY; + + if (key == 0x8) { + /* + * This quirk code helps the drive read the + * first tape block, regardless of format. That + * is required for these drives to return proper + * MODE SENSE information. + */ + if ((st->quirks & ST_Q_SNS_HLP) && + !(sc_link->flags & SDEV_MEDIA_LOADED)) { /* still starting */ + st->blksiz -= 512; + } else if (!(st->flags & (ST_2FM_AT_EOD | ST_BLANK_READ))) { + st->flags |= ST_BLANK_READ; + xs->resid = xs->datalen; + if (bp) { + bp->b_resid = xs->resid; + /*return an EOF */ } - }/* there may be some other error. check the rest */ + return (ESUCCESS); + } + } + return (-1); /* let the default/generic handler handle it */ +} - key=sense->ext.extended.flags & SSD_KEY; +/* + * The quirk here is that the drive returns some value to st_mode_sense + * incorrectly until the tape has actually passed by the head. + * + * The method is to set the drive to large fixed-block state (user-specified + * density and 1024-byte blocks), then read and rewind to get it to sense the + * tape. If that doesn't work, try 512-byte fixed blocks. If that doesn't + * work, as a last resort, try variable- length blocks. The result will be + * the ability to do an accurate st_mode_sense. + * + * We know we can do a rewind because we just did a load, which implies rewind. + * Rewind seems preferable to space backward if we have a virgin tape. + * + * The rest of the code for this quirk is in ILI processing and BLANK CHECK + * error processing, both part of st_interpret_sense. + */ +errval +st_touch_tape(unit) + u_int32 unit; +{ + struct st_data *st = st_data[unit]; + char *buf; + u_int32 readsiz; + errval errno; - if (!silent && key > 0 && (key != 0x8 || - st->flags & (ST_2FM_AT_EOD | ST_BLANK_READ))) - { - printf("st%d: %s", unit, error_mes[key - 1]); - if(sense->error_code & SSD_ERRCODE_VALID) - { - switch (key) - { - case 0x2: /* NOT READY */ - case 0x5: /* ILLEGAL REQUEST */ - case 0x6: /* UNIT ATTENTION */ - case 0x7: /* DATA PROTECT */ - break; - case 0x8: /* BLANK CHECK */ - printf(", requested size: %d (decimal)", - info); - break; - default: - printf(", info = %d (decimal)", info); - } - } - printf("\n"); - } + buf = malloc(1024, M_TEMP, M_NOWAIT); + if (!buf) + return (ENOMEM); - switch (key) - { - case 0x0: /* NO SENSE */ - case 0x1: /* RECOVERED ERROR */ - if(xs->resid == xs->datalen) xs->resid = 0; - case 0xc: /* EQUAL */ - return(ESUCCESS); - case 0x2: /* NOT READY */ - return(ENODEV); - case 0x5: /* ILLEGAL REQUEST */ - return(EINVAL); - case 0x6: /* UNIT ATTENTION */ - st->flags &= ~ST_PER_MEDIA; - if (st->flags & ST_OPEN) /* TEMP!!!! */ - return(EIO); - else - return(ESUCCESS); - case 0x7: /* DATA PROTECT */ - return(EACCES); - case 0xd: /* VOLUME OVERFLOW */ - return(ENOSPC); - case 0x8: /* BLANK CHECK */ - /***********************************************\ - * This quirk code helps the drive read the * - * first tape block, regardless of format. That * - * is required for these drives to return proper * - * MODE SENSE information. * - \***********************************************/ - if ((st->quirks & ST_Q_SNS_HLP) && - !(st->flags & ST_INFO_VALID)) - { - st->blksiz -= 512; - } - else if (!(st->flags & (ST_2FM_AT_EOD | ST_BLANK_READ))) - { - st->flags |= ST_BLANK_READ; - xs->resid = xs->datalen; - return(ESUCCESS); - } + if (errno = st_mode_sense(unit, 0)) { + goto bad; + } + st->blksiz = 1024; + do { + switch (st->blksiz) { + case 512: + case 1024: + readsiz = st->blksiz; + st->flags |= ST_FIXEDBLOCKS; + break; default: - return(EIO); + readsiz = 1; + st->flags &= ~ST_FIXEDBLOCKS; + } if (errno = st_mode_select(unit, 0)) { + goto bad; } - /***************************************************************\ - * If it's NOT code 70, just report it. * - \***************************************************************/ - default: - if (!silent) - { - printf("st%d: error code %d", unit, - sense->error_code & SSD_ERRCODE); - if(sense->error_code & SSD_ERRCODE_VALID) - { - printf(" at block no. %d (decimal)", - (sense->ext.unextended.blockhi << 16) + - (sense->ext.unextended.blockmed << 8) + - sense->ext.unextended.blocklow); - } - printf("\n"); + st_read(unit, buf, readsiz, SCSI_SILENT); + if (errno = st_rewind(unit, FALSE, 0)) { +bad: free(buf, M_TEMP); + return (errno); } - return(EIO); - } + } while (readsiz != 1 && readsiz > st->blksiz); + free(buf, M_TEMP); + return 0; } diff --git a/sys/scsi/su.c b/sys/scsi/su.c new file mode 100644 index 0000000000..de4f0172da --- /dev/null +++ b/sys/scsi/su.c @@ -0,0 +1,4 @@ + +/* this will be a special user scsi device */ +/* not written yet */ + diff --git a/sys/scsi/uk.c b/sys/scsi/uk.c new file mode 100644 index 0000000000..5c48d0149a --- /dev/null +++ b/sys/scsi/uk.c @@ -0,0 +1,156 @@ +/* + * Dummy driver for a device we can't identify. + * by Julian Elischer (julian@tfs.com) + * + * $Id: uk.c,v 1.2 93/10/11 11:53:28 julian Exp Locker: julian $ + */ + + +#include +#include +#include +#include +#include +#include +#define NUK 16 + +/* + * This driver is so simple it uses all the default services + */ +struct scsi_device uk_switch = +{ + NULL, + NULL, + NULL, + NULL, + "uk", + 0, + 0, 0 +}; + +struct uk_data { + u_int32 flags; + struct scsi_link *sc_link; /* all the inter level info */ +} uk_data[NUK]; + +#define UK_KNOWN 0x02 + +static u_int32 next_uk_unit = 0; + +/* + * The routine called by the low level scsi routine when it discovers + * a device suitable for this driver. + */ +errval +ukattach(sc_link) + struct scsi_link *sc_link; +{ + u_int32 unit, i, stat; + unsigned char *tbl; + + SC_DEBUG(sc_link, SDEV_DB2, ("ukattach: ")); + /* + * Check we have the resources for another drive + */ + unit = next_uk_unit++; + if (unit >= NUK) { + printf("Too many unknown devices..(%d > %d) reconfigure kernel\n", + (unit + 1), NUK); + return (0); + } + /* + * Store information needed to contact our base driver + */ + uk_data[unit].sc_link = sc_link; + sc_link->device = &uk_switch; + sc_link->dev_unit = unit; + + printf("uk%d: unknown device\n", unit); + uk_data[unit].flags = UK_KNOWN; + + return; + +} + +/* + * open the device. + */ +errval +ukopen(dev) +{ + errval errcode = 0; + u_int32 unit, mode; + struct scsi_link *sc_link; + unit = minor(dev); + + /* + * Check the unit is legal + */ + if (unit >= NUK) { + printf("uk%d: uk %d > %d\n", unit, unit, NUK); + return ENXIO; + } + + /* + * Make sure the device has been initialised + */ + if((uk_data[unit].flags & UK_KNOWN) == 0) { + printf("uk%d: not set up\n", unit); + return ENXIO; + } + + /* + * Only allow one at a time + */ + sc_link = uk_data[unit].sc_link; + if (sc_link->flags & SDEV_OPEN) { + printf("uk%d: already open\n", unit); + return ENXIO; + } + sc_link->flags |= SDEV_OPEN; + SC_DEBUG(sc_link, SDEV_DB1, ("ukopen: dev=0x%x (unit %d (of %d))\n" + ,dev, unit, NUK)); + /* + * Catch any unit attention errors. + */ + return 0; +} + +/* + * close the device.. only called if we are the LAST + * occurence of an open device + */ +errval +ukclose(dev) +{ + unsigned char unit, mode; + struct scsi_link *sc_link; + + sc_link = uk_data[unit].sc_link; + + SC_DEBUG(sc_link, SDEV_DB1, ("Closing device")); + sc_link->flags &= ~SDEV_OPEN; + return (0); +} + +/* + * Perform special action on behalf of the user + * Only does generic scsi ioctls. + */ +errval +ukioctl(dev, cmd, arg, mode) + dev_t dev; + u_int32 cmd; + caddr_t arg; +{ + unsigned char unit; + struct scsi_link *sc_link; + + /* + * Find the device that the user is talking about + */ + unit = minor(dev); + sc_link = uk_data[unit].sc_link; + return(scsi_do_ioctl(sc_link,cmd,arg,mode)); +} + diff --git a/sys/sys/buf.h b/sys/sys/buf.h index 0f8685e500..60316832e0 100644 --- a/sys/sys/buf.h +++ b/sys/sys/buf.h @@ -31,7 +31,7 @@ * SUCH DAMAGE. * * from: @(#)buf.h 7.11 (Berkeley) 5/9/90 - * $Id: buf.h,v 1.2 1993/10/16 17:16:21 rgrimes Exp $ + * $Id: buf.h,v 1.3 1993/11/07 17:52:21 wollman Exp $ */ #ifndef _SYS_BUF_H_ @@ -102,6 +102,8 @@ struct buf int b_dirtyoff; /* offset in buffer of dirty region */ int b_dirtyend; /* offset of end of dirty region */ caddr_t b_saveaddr; /* original b_addr for PHYSIO */ + void * b_driver1; /* for private use by the driver */ + void * b_driver2; /* for private use by the driver */ }; #define BQUEUES 4 /* number of free buffer queues */ @@ -178,6 +180,11 @@ void allocbuf(struct buf *, int); #define B_CALL 0x200000 /* call b_iodone from iodone */ #define B_RAW 0x400000 /* set by physio for raw transfers */ #define B_NOCACHE 0x800000 /* do not cache block after use */ +#define B_DRIVER 0xF000000 /* Four bits for the driver to use */ +#define B_DRIVER1 0x1000000 /* bits for the driver to use */ +#define B_DRIVER2 0x2000000 /* bits for the driver to use */ +#define B_DRIVER4 0x3000000 /* bits for the driver to use */ +#define B_DRIVER8 0x4000000 /* bits for the driver to use */ /* * Insq/Remq for the buffer hash lists. diff --git a/sys/sys/chio.h b/sys/sys/chio.h index 1106e2f321..10fa51d351 100644 --- a/sys/sys/chio.h +++ b/sys/sys/chio.h @@ -1,7 +1,7 @@ /* * 16 Feb 93 Julian Elischer ADDED for SCSI system * - * $Id$ + * $Id: chio.h,v 1.3 1993/10/16 17:16:27 rgrimes Exp $ */ /* This is a "convertet" mtio.h from 386BSD @@ -11,8 +11,8 @@ /* * Structures and definitions for changer io control commands */ -#ifndef _CHIO_H_ -#define _CHIO_H_ +#ifndef _SYS_CHIO_H_ +#define _SYS_CHIO_H_ #define CH_INVERT 0x10000 #define CH_ADDR_MASK 0xffff @@ -88,4 +88,5 @@ struct chop { /* Changer IO control command */ #define CHIOOP _IOWR('c', 1, struct chop) /* do a mag tape op */ -#endif + +#endif /*_SYS_CHIO_H*/ diff --git a/sys/sys/mtio.h b/sys/sys/mtio.h index d9dafd7a32..969c30f23f 100644 --- a/sys/sys/mtio.h +++ b/sys/sys/mtio.h @@ -31,7 +31,7 @@ * SUCH DAMAGE. * * from: @(#)mtio.h 7.6 (Berkeley) 2/5/91 - * $Id: mtio.h,v 1.4 1993/10/16 17:17:16 rgrimes Exp $ + * $Id: mtio.h,v 1.5 1993/11/07 17:52:52 wollman Exp $ */ #ifndef _SYS_MTIO_H_ @@ -64,8 +64,7 @@ struct mtop { /* a non zero parameter will change the device to a fixed block size */ /* device with block size set to that of the parameter passed in. */ /* Resetting the block size to 0 will restore the device to a variable */ -/* block size device. At this time this command works across all modes */ -/* unlike the density command below.. this may change */ +/* block size device. */ #define MTSETBSIZ 10 @@ -85,11 +84,16 @@ struct mtget { /* end device-dependent registers */ short mt_resid; /* residual count */ #if defined (__386BSD__) - daddr_t mt_bsiz; /* block size, 0 is variable */ - short mt_dns_dflt; /* density setting for default density */ - short mt_dns_dsty1; /* density setting for high density */ - short mt_dns_dsty2; /* density setting for medium density */ - short mt_dns_dsty3; /* density setting for low density */ + daddr_t mt_blksiz; /* presently operatin blocksize */ + daddr_t mt_density; /* presently operatin density */ + daddr_t mt_blksiz0; /* blocksize for mode 0 */ + daddr_t mt_blksiz1; /* blocksize for mode 1 */ + daddr_t mt_blksiz2; /* blocksize for mode 2 */ + daddr_t mt_blksiz3; /* blocksize for mode 3 */ + daddr_t mt_density0; /* density for mode 0 */ + daddr_t mt_density1; /* density for mode 1 */ + daddr_t mt_density2; /* density for mode 2 */ + daddr_t mt_density3; /* density for mode 3 */ #endif /* the following two are not yet implemented */ daddr_t mt_fileno; /* file number of current position */ @@ -126,7 +130,7 @@ struct mtget { #define MTIOCEEOT _IO('m', 4) /* enable EOT error */ #ifndef KERNEL -#define DEFTAPE "/dev/rst0" +#define DEFTAPE "/dev/nrst0" #endif #ifdef KERNEL diff --git a/sys/sys/scsiio.h b/sys/sys/scsiio.h new file mode 100644 index 0000000000..05753e41e9 --- /dev/null +++ b/sys/sys/scsiio.h @@ -0,0 +1,63 @@ + +#ifndef _SYS_SCSIIO_H_ +#define _SYS_SCSIIO_H_ + + +#include +#include + +#define SENSEBUFLEN 48 + +typedef struct scsireq { + u_long flags; /* info about the request status and type */ + u_long timeout; + u_char cmd[16]; /* 12 is actually the max */ + u_char cmdlen; + caddr_t databuf; /* address in user space of buffer */ + u_long datalen; /* size of user buffer (request) */ + u_long datalen_used; /* size of user buffer (used)*/ + u_char sense[SENSEBUFLEN]; /* returned sense will be in here */ + u_char senselen; /* sensedata request size (MAX of SENSEBUFLEN)*/ + u_char senselen_used; /* return value only */ + u_char status; /* what the scsi status was from the adapter */ + u_char retsts; /* the return status for the command */ + int error; /* error bits */ +} scsireq_t; + +/* bit defintions for flags */ +#define SCCMD_READ 0x00000001 +#define SCCMD_WRITE 0x00000002 +#define SCCMD_IOV 0x00000004 +#define SCCMD_ESCAPE 0x00000010 +#define SCCMD_TARGET 0x00000020 + + +/* definitions for the return status (retsts) */ +#define SCCMD_OK 0x00 +#define SCCMD_TIMEOUT 0x01 +#define SCCMD_BUSY 0x02 +#define SCCMD_SENSE 0x03 +#define SCCMD_UNKNOWN 0x04 + +#define SCIOCCOMMAND _IOWR('Q', 1, scsireq_t) + +#define SC_DB_CMDS 0x00000001 /* show all scsi cmds and errors */ +#define SC_DB_FLOW 0x00000002 /* show routines entered */ +#define SC_DB_FLOW2 0x00000004 /* show path INSIDE routines */ +#define SC_DB_DMA 0x00000008 /* show DMA segments etc */ +#define SCIOCDEBUG _IOW('Q', 2, int) /* from 0 to 15 */ + +struct scsi_addr { + int scbus; /* -1 if wildcard */ + int target; /* -1 if wildcard */ + int lun; /* -1 if wildcard */ +} ; + +#define SCIOCREPROBE _IOW('Q', 3, struct scsi_addr) /* look for new devs */ +#define SCIOCIDENTIFY _IOR('Q', 4, struct scsi_addr) /* where are you? */ +#define SCIOCDECONFIG _IO('Q', 5) /* please dissappear */ +#define SCIOCRECONFIG _IO('Q', 6) /* please check again */ +#define SCIOCRESET _IO('Q', 7) /* reset the device */ + + +#endif /* _SYS_SCSIIO_H_ */ -- 2.20.1