New version of scsi code from Julian

This commit is contained in:
Rodney W. Grimes 1993-11-18 05:03:27 +00:00
parent 0def918bed
commit 57bb0ee45f
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=785
30 changed files with 10078 additions and 11171 deletions

View file

@ -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
#

View file

@ -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
#

View file

@ -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
#

File diff suppressed because it is too large Load diff

View file

@ -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'.

View file

@ -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_ */

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -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;

View file

@ -1,46 +1,55 @@
This release consists of the following files
(relative to the base of the kernel tree)
(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
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
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.

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -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*/

852
sys/scsi/scsi_base.c Normal file
View file

@ -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 <sys/types.h>
#include <sys/param.h>
#include <sys/buf.h>
#include <sys/uio.h>
#include <sys/malloc.h>
#include <sys/errno.h>
#include <scsi/scsi_all.h>
#include <scsi/scsi_disk.h>
#include <scsi/scsiconf.h>
#ifdef NetBSD
#ifdef DDB
int Debugger();
#else /* DDB */
#define Debugger()
#endif /* DDB */
#else /* NetBSD */
#include <ddb.h>
#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 */

View file

@ -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_ */

View file

@ -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_ */

53
sys/scsi/scsi_debug.h Normal file
View file

@ -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 */

View file

@ -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*/

329
sys/scsi/scsi_ioctl.c Normal file
View file

@ -0,0 +1,329 @@
/*
* Contributed by HD Associates (hd@world.std.com).
* Copyright (c) 1992, 1993 HD Associates
*
* Berkeley style copyright.
*
*
*/
#include <sys/types.h>
#include <sys/errno.h>
#include <sys/param.h>
#include <sys/malloc.h>
#include <sys/buf.h>
#define b_screq b_driver1 /* a patch in buf.h */
#define b_sc_link b_driver2 /* a patch in buf.h */
#include <sys/proc.h>
#include "scbus.h"
#include <scsi/scsi_all.h>
#include <scsi/scsiconf.h>
#include <sys/scsiio.h>
/*
* 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) ((A<B) ? A : B )
#endif
void scsi_user_done(xs)
struct scsi_xfer *xs;
{
struct buf *bp;
scsireq_t *screq;
bp = xs->bp;
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;
}

View file

@ -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*/

File diff suppressed because it is too large Load diff

View file

@ -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;
#include <scsi/scsi_debug.h>
/*
* 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.
*/
#ifndef _SCSI_SCSICONF_H_
#define _SCSI_SCSICONF_H_ 1
/***********************************************\
* these calls are called by the high-end *
* drivers to get services from whatever low-end *
* drivers they are attached to *
\***********************************************/
struct scsi_switch
/*
* 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 */

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

4
sys/scsi/su.c Normal file
View file

@ -0,0 +1,4 @@
/* this will be a special user scsi device */
/* not written yet */

156
sys/scsi/uk.c Normal file
View file

@ -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 <sys/types.h>
#include <sys/param.h>
#include <sys/errno.h>
#include <sys/ioctl.h>
#include <scsi/scsi_all.h>
#include <scsi/scsiconf.h>
#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));
}

View file

@ -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*/

63
sys/sys/scsiio.h Normal file
View file

@ -0,0 +1,63 @@
#ifndef _SYS_SCSIIO_H_
#define _SYS_SCSIIO_H_
#include <sys/types.h>
#include <sys/ioctl.h>
#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_ */