Obsoleted by CAM.
This commit is contained in:
parent
d13e6580b9
commit
bd9d336e40
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=39266
File diff suppressed because it is too large
Load Diff
@ -1,181 +0,0 @@
|
||||
/*
|
||||
* Interface for the 93C66/56/46/26/06 serial eeprom parts.
|
||||
*
|
||||
* Copyright (c) 1995, 1996 Daniel M. Eischen
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice immediately at the beginning of the file, without modification,
|
||||
* this list of conditions, and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Absolutely no warranty of function or purpose is made by the author
|
||||
* Daniel M. Eischen.
|
||||
* 4. Modifications may be freely made to this file if the above conditions
|
||||
* are met.
|
||||
*
|
||||
* $Id: 93cx6.c,v 1.10 1997/02/22 09:38:36 peter Exp $
|
||||
*/
|
||||
|
||||
/*
|
||||
* The instruction set of the 93C66/56/46/26/06 chips are as follows:
|
||||
*
|
||||
* Start OP *
|
||||
* Function Bit Code Address** Data Description
|
||||
* -------------------------------------------------------------------
|
||||
* READ 1 10 A5 - A0 Reads data stored in memory,
|
||||
* starting at specified address
|
||||
* EWEN 1 00 11XXXX Write enable must preceed
|
||||
* all programming modes
|
||||
* ERASE 1 11 A5 - A0 Erase register A5A4A3A2A1A0
|
||||
* WRITE 1 01 A5 - A0 D15 - D0 Writes register
|
||||
* ERAL 1 00 10XXXX Erase all registers
|
||||
* WRAL 1 00 01XXXX D15 - D0 Writes to all registers
|
||||
* EWDS 1 00 00XXXX Disables all programming
|
||||
* instructions
|
||||
* *Note: A value of X for address is a don't care condition.
|
||||
* **Note: There are 8 address bits for the 93C56/66 chips unlike
|
||||
* the 93C46/26/06 chips which have 6 address bits.
|
||||
*
|
||||
* The 93C46 has a four wire interface: clock, chip select, data in, and
|
||||
* data out. In order to perform one of the above functions, you need
|
||||
* to enable the chip select for a clock period (typically a minimum of
|
||||
* 1 usec, with the clock high and low a minimum of 750 and 250 nsec
|
||||
* respectively). While the chip select remains high, you can clock in
|
||||
* the instructions (above) starting with the start bit, followed by the
|
||||
* OP code, Address, and Data (if needed). For the READ instruction, the
|
||||
* requested 16-bit register contents is read from the data out line but
|
||||
* is preceded by an initial zero (leading 0, followed by 16-bits, MSB
|
||||
* first). The clock cycling from low to high initiates the next data
|
||||
* bit to be sent from the chip.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#if defined(__FreeBSD__)
|
||||
#include <i386/scsi/93cx6.h>
|
||||
#elif defined(__NetBSD__)
|
||||
#include <machine/bus.h>
|
||||
#include <dev/ic/smc93cx6var.h>
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Right now, we only have to read the SEEPROM. But we make it easier to
|
||||
* add other 93Cx6 functions.
|
||||
*/
|
||||
static struct seeprom_cmd {
|
||||
unsigned char len;
|
||||
unsigned char bits[3];
|
||||
} seeprom_read = {3, {1, 1, 0}};
|
||||
|
||||
/*
|
||||
* Wait for the SEERDY to go high; about 800 ns.
|
||||
*/
|
||||
#define CLOCK_PULSE(sd, rdy) \
|
||||
while ((SEEPROM_INB(sd) & rdy) == 0) { \
|
||||
; /* Do nothing */ \
|
||||
}
|
||||
|
||||
/*
|
||||
* Read the serial EEPROM and returns 1 if successful and 0 if
|
||||
* not successful.
|
||||
*/
|
||||
int
|
||||
read_seeprom(sd, buf, start_addr, count)
|
||||
struct seeprom_descriptor *sd;
|
||||
u_int16_t *buf;
|
||||
#if defined(__FreeBSD__)
|
||||
u_int start_addr;
|
||||
u_int count;
|
||||
#elif defined(__NetBSD__)
|
||||
bus_io_size_t start_addr;
|
||||
bus_io_size_t count;
|
||||
#endif
|
||||
{
|
||||
int i = 0;
|
||||
u_int k = 0;
|
||||
u_int16_t v;
|
||||
u_int8_t temp;
|
||||
|
||||
/*
|
||||
* Read the requested registers of the seeprom. The loop
|
||||
* will range from 0 to count-1.
|
||||
*/
|
||||
for (k = start_addr; k < count + start_addr; k++) {
|
||||
/* Send chip select for one clock cycle. */
|
||||
temp = sd->sd_MS ^ sd->sd_CS;
|
||||
SEEPROM_OUTB(sd, temp ^ sd->sd_CK);
|
||||
CLOCK_PULSE(sd, sd->sd_RDY);
|
||||
|
||||
/*
|
||||
* Now we're ready to send the read command followed by the
|
||||
* address of the 16-bit register we want to read.
|
||||
*/
|
||||
for (i = 0; i < seeprom_read.len; i++) {
|
||||
if (seeprom_read.bits[i] != 0)
|
||||
temp ^= sd->sd_DO;
|
||||
SEEPROM_OUTB(sd, temp);
|
||||
CLOCK_PULSE(sd, sd->sd_RDY);
|
||||
SEEPROM_OUTB(sd, temp ^ sd->sd_CK);
|
||||
CLOCK_PULSE(sd, sd->sd_RDY);
|
||||
if (seeprom_read.bits[i] != 0)
|
||||
temp ^= sd->sd_DO;
|
||||
}
|
||||
/* Send the 6 or 8 bit address (MSB first, LSB last). */
|
||||
for (i = (sd->sd_chip - 1); i >= 0; i--) {
|
||||
if ((k & (1 << i)) != 0)
|
||||
temp ^= sd->sd_DO;
|
||||
SEEPROM_OUTB(sd, temp);
|
||||
CLOCK_PULSE(sd, sd->sd_RDY);
|
||||
SEEPROM_OUTB(sd, temp ^ sd->sd_CK);
|
||||
CLOCK_PULSE(sd, sd->sd_RDY);
|
||||
if ((k & (1 << i)) != 0)
|
||||
temp ^= sd->sd_DO;
|
||||
}
|
||||
|
||||
/*
|
||||
* Now read the 16 bit register. An initial 0 precedes the
|
||||
* register contents which begins with bit 15 (MSB) and ends
|
||||
* with bit 0 (LSB). The initial 0 will be shifted off the
|
||||
* top of our word as we let the loop run from 0 to 16.
|
||||
*/
|
||||
v = 0;
|
||||
for (i = 16; i >= 0; i--) {
|
||||
SEEPROM_OUTB(sd, temp);
|
||||
CLOCK_PULSE(sd, sd->sd_RDY);
|
||||
v <<= 1;
|
||||
if (SEEPROM_INB(sd) & sd->sd_DI)
|
||||
v |= 1;
|
||||
SEEPROM_OUTB(sd, temp ^ sd->sd_CK);
|
||||
CLOCK_PULSE(sd, sd->sd_RDY);
|
||||
}
|
||||
|
||||
buf[k - start_addr] = v;
|
||||
|
||||
/* Reset the chip select for the next command cycle. */
|
||||
temp = sd->sd_MS;
|
||||
SEEPROM_OUTB(sd, temp);
|
||||
CLOCK_PULSE(sd, sd->sd_RDY);
|
||||
SEEPROM_OUTB(sd, temp ^ sd->sd_CK);
|
||||
CLOCK_PULSE(sd, sd->sd_RDY);
|
||||
SEEPROM_OUTB(sd, temp);
|
||||
CLOCK_PULSE(sd, sd->sd_RDY);
|
||||
}
|
||||
#if 0
|
||||
printf ("Serial EEPROM:");
|
||||
for (k = 0; k < count; k = k + 1) {
|
||||
if (((k % 8) == 0) && (k != 0))
|
||||
{
|
||||
printf ("\n ");
|
||||
}
|
||||
printf (" 0x%x", buf[k]);
|
||||
}
|
||||
printf ("\n");
|
||||
#endif
|
||||
return (1);
|
||||
}
|
@ -1,93 +0,0 @@
|
||||
/*
|
||||
* Interface to the 93C46 serial EEPROM that is used to store BIOS
|
||||
* settings for the aic7xxx based adaptec SCSI controllers. It can
|
||||
* also be used for 93C26 and 93C06 serial EEPROMS.
|
||||
*
|
||||
* Copyright (c) 1994, 1995 Justin T. Gibbs.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice immediately at the beginning of the file, without modification,
|
||||
* this list of conditions, and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Absolutely no warranty of function or purpose is made by the author
|
||||
* Justin T. Gibbs.
|
||||
* 4. Modifications may be freely made to this file if the above conditions
|
||||
* are met.
|
||||
*
|
||||
* $Id: 93cx6.h,v 1.7 1997/02/22 09:38:37 peter Exp $
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#if !defined(__NetBSD__)
|
||||
#include <sys/systm.h>
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
C46 = 6,
|
||||
C56_66 = 8
|
||||
} seeprom_chip_t;
|
||||
|
||||
struct seeprom_descriptor {
|
||||
#if defined(__FreeBSD__)
|
||||
u_int32_t sd_iobase;
|
||||
volatile u_int8_t *sd_maddr;
|
||||
#elif defined(__NetBSD__)
|
||||
bus_chipset_tag_t sd_bc;
|
||||
bus_io_handle_t sd_ioh;
|
||||
bus_io_size_t sd_offset;
|
||||
#endif
|
||||
seeprom_chip_t sd_chip;
|
||||
u_int16_t sd_MS;
|
||||
u_int16_t sd_RDY;
|
||||
u_int16_t sd_CS;
|
||||
u_int16_t sd_CK;
|
||||
u_int16_t sd_DO;
|
||||
u_int16_t sd_DI;
|
||||
};
|
||||
|
||||
/*
|
||||
* This function will read count 16-bit words from the serial EEPROM and
|
||||
* return their value in buf. The port address of the aic7xxx serial EEPROM
|
||||
* control register is passed in as offset. The following parameters are
|
||||
* also passed in:
|
||||
*
|
||||
* CS - Chip select
|
||||
* CK - Clock
|
||||
* DO - Data out
|
||||
* DI - Data in
|
||||
* RDY - SEEPROM ready
|
||||
* MS - Memory port mode select
|
||||
*
|
||||
* A failed read attempt returns 0, and a successful read returns 1.
|
||||
*/
|
||||
|
||||
#if defined(__FreeBSD__)
|
||||
#define SEEPROM_INB(sd) \
|
||||
(((sd)->sd_maddr != NULL) ? \
|
||||
*((sd)->sd_maddr) : \
|
||||
inb((sd)->sd_iobase))
|
||||
#define SEEPROM_OUTB(sd, value) \
|
||||
(((sd)->sd_maddr != NULL) ? \
|
||||
(void)(*((sd)->sd_maddr) = (value)) : \
|
||||
outb((sd)->sd_iobase, (value)))
|
||||
|
||||
#elif defined(__NetBSD__)
|
||||
#define SEEPROM_INB(sd) \
|
||||
bus_io_read_1(sd->sd_bc, sd->sd_ioh, sd->sd_offset)
|
||||
#define SEEPROM_OUTB(sd, value) \
|
||||
bus_io_write_1(sd->sd_bc, sd->sd_ioh, sd->sd_offset, value)
|
||||
#endif
|
||||
|
||||
#if defined(__FreeBSD__)
|
||||
int read_seeprom __P((struct seeprom_descriptor *sd,
|
||||
u_int16_t *buf, u_int start_addr, u_int count));
|
||||
#elif defined(__NetBSD__)
|
||||
int read_seeprom __P((struct seeprom_descriptor *sd,
|
||||
u_int16_t *buf, bus_io_size_t start_addr, bus_io_size_t count));
|
||||
#endif
|
@ -1,783 +0,0 @@
|
||||
/*
|
||||
* Generic driver for the Advanced Systems Inc. SCSI controllers
|
||||
* Product specific probe and attach routines can be found in:
|
||||
*
|
||||
* i386/isa/adv_isa.c ABP5140, ABP542, ABP5150, ABP842, ABP852
|
||||
*
|
||||
* Copyright (c) 1996 Justin T. Gibbs.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice immediately at the beginning of the file, without modification,
|
||||
* this list of conditions, and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
/*
|
||||
* Ported from:
|
||||
* advansys.c - Linux Host Driver for AdvanSys SCSI Adapters
|
||||
*
|
||||
* Copyright (c) 1995-1996 Advanced System Products, Inc.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that redistributions of source
|
||||
* code retain the above copyright notice and this comment without
|
||||
* modification.
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/buf.h>
|
||||
|
||||
#include <machine/clock.h>
|
||||
|
||||
#include <scsi/scsi_all.h>
|
||||
#include <scsi/scsi_message.h>
|
||||
#include <scsi/scsiconf.h>
|
||||
|
||||
#include <vm/vm.h>
|
||||
#include <vm/vm_param.h>
|
||||
#include <vm/pmap.h>
|
||||
|
||||
#include <i386/scsi/advansys.h>
|
||||
|
||||
static void adv_scsi_cmd __P((struct scsi_xfer *xs));
|
||||
static void advminphys __P((struct buf *bp));
|
||||
static timeout_t
|
||||
adv_timeout;
|
||||
static int adv_qdone __P((struct adv_softc *adv));
|
||||
static void adv_done __P((struct adv_softc *adv,
|
||||
struct adv_q_done_info *qdonep));
|
||||
static int adv_poll __P((struct adv_softc *ahc, struct scsi_xfer *xs));
|
||||
|
||||
struct adv_softc *advsoftcs[NADV]; /* XXX Config should handle this */
|
||||
|
||||
static struct scsi_adapter adv_switch =
|
||||
{
|
||||
adv_scsi_cmd,
|
||||
advminphys,
|
||||
NULL,
|
||||
NULL,
|
||||
"adv"
|
||||
};
|
||||
|
||||
static void
|
||||
adv_scsi_cmd(xs)
|
||||
struct scsi_xfer *xs;
|
||||
{
|
||||
struct adv_softc *adv;
|
||||
struct adv_scsi_q scsiq;
|
||||
struct adv_sg_head sghead;
|
||||
|
||||
SC_DEBUG(xs->sc_link, SDEV_DB2, ("adv_scsi_cmd\n"));
|
||||
|
||||
adv = (struct adv_softc *)xs->sc_link->scsibus->adpt_link.adpt_softc;
|
||||
|
||||
/*
|
||||
* Build up the request
|
||||
*/
|
||||
scsiq.q1.cntl = 0;
|
||||
scsiq.q1.sg_queue_cnt = 0;
|
||||
scsiq.q1.status = 0;
|
||||
scsiq.q1.q_no = 0;
|
||||
scsiq.q1.target_id = ADV_TID_TO_TARGET_ID(xs->sc_link->target);
|
||||
scsiq.q1.target_lun = xs->sc_link->lun;
|
||||
scsiq.q1.sense_addr = (u_int32_t)vtophys(&xs->sense);
|
||||
scsiq.q1.sense_len = sizeof(xs->sense);
|
||||
scsiq.q1.data_cnt = 0;
|
||||
scsiq.q1.data_addr = 0;
|
||||
scsiq.q1.user_def = 0;
|
||||
scsiq.q2.xs_ptr = (u_int32_t)xs;
|
||||
scsiq.q2.target_ix = ADV_TIDLUN_TO_IX(xs->sc_link->target, xs->sc_link->lun);
|
||||
scsiq.q2.flag = 0;
|
||||
scsiq.q2.cdb_len = xs->cmdlen;
|
||||
scsiq.q2.tag_code = xs->tag_type;
|
||||
scsiq.q2.vm_id = 0;
|
||||
scsiq.sg_head = NULL;
|
||||
scsiq.cdbptr = &xs->cmd;
|
||||
|
||||
if (xs->datalen) {
|
||||
/*
|
||||
* Determin the number of segments needed for this
|
||||
* transfer. We should only use SG if we need more
|
||||
* than one.
|
||||
*/
|
||||
int seg;
|
||||
u_int32_t datalen;
|
||||
vm_offset_t vaddr;
|
||||
u_int32_t paddr;
|
||||
u_int32_t nextpaddr;
|
||||
struct adv_sg_entry *sg;
|
||||
|
||||
seg = 0;
|
||||
datalen = xs->datalen;
|
||||
vaddr = (vm_offset_t)xs->data;
|
||||
paddr = vtophys(vaddr);
|
||||
sg = &sghead.sg_list[0];
|
||||
|
||||
while ((datalen > 0) && (seg < ADV_MAX_SG_LIST)) {
|
||||
/* put in the base address and length */
|
||||
sg->addr = paddr;
|
||||
sg->bytes = 0;
|
||||
|
||||
/* do it at least once */
|
||||
nextpaddr = paddr;
|
||||
|
||||
while ((datalen > 0) && (paddr == nextpaddr)) {
|
||||
u_int32_t size;
|
||||
/*
|
||||
* This page is contiguous (physically)
|
||||
* with the the last, just extend the
|
||||
* length
|
||||
*/
|
||||
/* how far to the end of the page */
|
||||
nextpaddr = (paddr & (~PAGE_MASK)) + PAGE_SIZE;
|
||||
|
||||
/*
|
||||
* Compute the maximum size
|
||||
*/
|
||||
size = nextpaddr - paddr;
|
||||
if (size > datalen)
|
||||
size = datalen;
|
||||
|
||||
sg->bytes += size;
|
||||
vaddr += size;
|
||||
datalen -= size;
|
||||
if (datalen > 0)
|
||||
paddr = vtophys(vaddr);
|
||||
}
|
||||
/*
|
||||
* next page isn't contiguous, finish the seg
|
||||
*/
|
||||
seg++;
|
||||
sg++;
|
||||
}
|
||||
if (seg > 1) {
|
||||
scsiq.q1.cntl |= QC_SG_HEAD;
|
||||
scsiq.sg_head = &sghead;
|
||||
sghead.entry_cnt = sghead.entry_to_copy = seg;
|
||||
sghead.res = 0;
|
||||
}
|
||||
scsiq.q1.data_addr = sghead.sg_list[0].addr;
|
||||
scsiq.q1.data_cnt = sghead.sg_list[0].bytes;
|
||||
}
|
||||
|
||||
if (adv_execute_scsi_queue(adv, &scsiq) != 0) {
|
||||
xs->error = XS_QUEUE_RESOURCE_SHORTAGE;
|
||||
scsi_done(xs);
|
||||
} else if ((xs->flags & SCSI_POLL) != 0) {
|
||||
/*
|
||||
* If we can't use interrupts, poll for completion
|
||||
*/
|
||||
int s;
|
||||
|
||||
s = splbio();
|
||||
if (adv_poll(adv, xs)) {
|
||||
if (!(xs->flags & SCSI_SILENT))
|
||||
printf("cmd fail\n");
|
||||
adv_timeout(xs);
|
||||
}
|
||||
splx(s);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
advminphys(bp)
|
||||
struct buf *bp;
|
||||
{
|
||||
if (bp->b_bcount > ((ADV_MAX_SG_LIST - 1) * PAGE_SIZE))
|
||||
bp->b_bcount = ((ADV_MAX_SG_LIST - 1) * PAGE_SIZE);
|
||||
}
|
||||
|
||||
static void
|
||||
adv_timeout(arg)
|
||||
void *arg;
|
||||
{
|
||||
printf("adv: Ooops. Had a timeout\n");
|
||||
}
|
||||
|
||||
struct adv_softc *
|
||||
adv_alloc(unit, iobase)
|
||||
int unit;
|
||||
u_long iobase;
|
||||
{
|
||||
struct adv_softc *adv;
|
||||
int i;
|
||||
|
||||
if (unit >= NADV) {
|
||||
printf("adv: unit number (%d) too high\n", unit);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate a storage area for us
|
||||
*/
|
||||
if (advsoftcs[unit]) {
|
||||
printf("adv%d: memory already allocated\n", unit);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
adv = malloc(sizeof(struct adv_softc), M_DEVBUF, M_NOWAIT);
|
||||
if (!adv) {
|
||||
printf("adv%d: cannot malloc!\n", unit);
|
||||
return NULL;
|
||||
}
|
||||
bzero(adv, sizeof(struct adv_softc));
|
||||
advsoftcs[unit] = adv;
|
||||
adv->unit = unit;
|
||||
adv->iobase = iobase;
|
||||
|
||||
/* Set reasonable defaults incase we can't read the EEPROM */
|
||||
adv->max_openings = ADV_DEF_MAX_TOTAL_QNG;
|
||||
adv->start_motor = TARGET_BIT_VECTOR_SET;
|
||||
adv->disc_enable = TARGET_BIT_VECTOR_SET;
|
||||
adv->cmd_qng_enabled = TARGET_BIT_VECTOR_SET;
|
||||
adv->scsi_id = 7;
|
||||
|
||||
for (i = 0; i <= ADV_MAX_TID; i++)
|
||||
adv->sdtr_data[i] = ADV_DEF_SDTR_OFFSET | (ADV_DEF_SDTR_INDEX << 4);
|
||||
|
||||
return(adv);
|
||||
}
|
||||
|
||||
void
|
||||
adv_free(adv)
|
||||
struct adv_softc *adv;
|
||||
{
|
||||
if (adv->sense_buffers != NULL)
|
||||
free(adv->sense_buffers, M_DEVBUF);
|
||||
free(adv, M_DEVBUF);
|
||||
}
|
||||
|
||||
int
|
||||
adv_init(adv)
|
||||
struct adv_softc *adv;
|
||||
{
|
||||
struct adv_eeprom_config eeprom_config;
|
||||
int checksum, i;
|
||||
u_int16_t config_lsw;
|
||||
u_int16_t config_msw;
|
||||
|
||||
adv_get_board_type(adv);
|
||||
|
||||
/*
|
||||
* Stop script execution.
|
||||
*/
|
||||
adv_write_lram_16(adv, ADV_HALTCODE_W, 0x00FE);
|
||||
adv_stop_execution(adv);
|
||||
adv_reset_chip_and_scsi_bus(adv);
|
||||
/*
|
||||
* The generic SCSI code does a minimum delay for us
|
||||
* already.
|
||||
*/
|
||||
/* DELAY(3 * 1000 * 1000);*/ /* 3 Second Delay */
|
||||
if (adv_is_chip_halted(adv) == 0) {
|
||||
printf("adv%d: Unable to halt adapter. Initialization"
|
||||
"failed\n", adv->unit);
|
||||
return (1);
|
||||
}
|
||||
ADV_OUTW(adv, ADV_REG_PROG_COUNTER, ADV_MCODE_START_ADDR);
|
||||
if (ADV_INW(adv, ADV_REG_PROG_COUNTER) != ADV_MCODE_START_ADDR) {
|
||||
printf("adv%d: Unable to set program counter. Initialization"
|
||||
"failed\n", adv->unit);
|
||||
return (1);
|
||||
}
|
||||
|
||||
config_lsw = ADV_INW(adv, ADV_CONFIG_LSW);
|
||||
config_msw = ADV_INW(adv, ADV_CONFIG_MSW);
|
||||
|
||||
#if 0
|
||||
/* XXX Move to PCI probe code */
|
||||
if (adv->type & ADV_PCI) {
|
||||
#if CC_DISABLE_PCI_PARITY_INT
|
||||
config_msw &= 0xFFC0;
|
||||
ADV_OUTW(adv, ADV_CONFIG_MSW, config_msw);
|
||||
#endif
|
||||
|
||||
if (asc_dvc->cfg->pci_device_id == ASC_PCI_DEVICE_ID_REV_A) {
|
||||
asc_dvc->bug_fix_cntl |= ASC_BUG_FIX_ADD_ONE_BYTE;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if ((config_msw & ADV_CFG_MSW_CLR_MASK) != 0) {
|
||||
config_msw &= (~(ADV_CFG_MSW_CLR_MASK));
|
||||
/*
|
||||
* XXX The Linux code flags this as an error,
|
||||
* but what should we report to the user???
|
||||
* It seems that clearing the config register
|
||||
* makes this error recoverable.
|
||||
*/
|
||||
ADV_OUTW(adv, ADV_CONFIG_MSW, config_msw);
|
||||
}
|
||||
|
||||
/* Suck in the configuration from the EEProm */
|
||||
checksum = adv_get_eeprom_config(adv, &eeprom_config);
|
||||
|
||||
eeprom_config.cfg_msw &= (~(ADV_CFG_MSW_CLR_MASK));
|
||||
|
||||
if (ADV_INW(adv, ADV_CHIP_STATUS) & ADV_CSW_AUTO_CONFIG) {
|
||||
/*
|
||||
* XXX The Linux code sets a warning level for this
|
||||
* condition, yet nothing of meaning is printed to
|
||||
* the user. What does this mean???
|
||||
*/
|
||||
if (adv->chip_version == 3) {
|
||||
if (eeprom_config.cfg_lsw != config_lsw) {
|
||||
/* XXX Yet another supposed Warning */
|
||||
eeprom_config.cfg_lsw =
|
||||
ADV_INW(adv, ADV_CONFIG_LSW);
|
||||
}
|
||||
if (eeprom_config.cfg_msw != config_msw) {
|
||||
/* XXX Yet another supposed Warning */
|
||||
eeprom_config.cfg_msw =
|
||||
ADV_INW(adv, ADV_CONFIG_MSW);
|
||||
}
|
||||
}
|
||||
}
|
||||
eeprom_config.cfg_lsw |= ADV_CFG_LSW_HOST_INT_ON;
|
||||
if (checksum == eeprom_config.chksum) {
|
||||
if (adv_test_external_lram(adv) == 0) {
|
||||
if (adv->type & ADV_PCI) {
|
||||
eeprom_config.cfg_msw |= 0x0800;
|
||||
config_msw |= 0x0800;
|
||||
ADV_OUTW(adv, ADV_CONFIG_MSW, config_msw);
|
||||
eeprom_config.max_total_qng = ADV_MAX_PCI_INRAM_TOTAL_QNG;
|
||||
eeprom_config.max_tag_qng = ADV_MAX_INRAM_TAG_QNG;
|
||||
}
|
||||
}
|
||||
/* XXX What about wide bussed cards?? */
|
||||
for (i = 0; i <= 7; i++)
|
||||
adv->sdtr_data[i] = eeprom_config.sdtr_data[i];
|
||||
|
||||
/* Range/Sanity checking */
|
||||
if (eeprom_config.max_total_qng < ADV_MIN_TOTAL_QNG) {
|
||||
eeprom_config.max_total_qng = ADV_MIN_TOTAL_QNG;
|
||||
}
|
||||
if (eeprom_config.max_total_qng > ADV_MAX_TOTAL_QNG) {
|
||||
eeprom_config.max_total_qng = ADV_MAX_TOTAL_QNG;
|
||||
}
|
||||
if (eeprom_config.max_tag_qng > eeprom_config.max_total_qng) {
|
||||
eeprom_config.max_tag_qng = eeprom_config.max_total_qng;
|
||||
}
|
||||
if (eeprom_config.max_tag_qng < ADV_MIN_TAG_Q_PER_DVC) {
|
||||
eeprom_config.max_tag_qng = ADV_MIN_TAG_Q_PER_DVC;
|
||||
}
|
||||
adv->max_openings = eeprom_config.max_total_qng;
|
||||
|
||||
if ((eeprom_config.use_cmd_qng & eeprom_config.disc_enable) !=
|
||||
eeprom_config.use_cmd_qng) {
|
||||
eeprom_config.disc_enable |= eeprom_config.use_cmd_qng;
|
||||
printf("adv:%d: WARNING! One or more targets with tagged "
|
||||
"queuing enabled have the disconnection priveledge "
|
||||
"disabled.\n"
|
||||
"adv:%d: Overriding disconnection settings to "
|
||||
"allow tagged queueing devices to disconnect.\n ",
|
||||
adv->unit, adv->unit);
|
||||
}
|
||||
#if 0
|
||||
/*
|
||||
* XXX We should range check our target ID
|
||||
* based on the width of our bus
|
||||
*/
|
||||
EEPROM_SET_SCSIID(eeprom_config,
|
||||
EEPROM_SCSIID(eeprom_config) & ADV_MAX_TID);
|
||||
#endif
|
||||
adv->initiate_sdtr = eeprom_config.init_sdtr;
|
||||
adv->disc_enable = eeprom_config.disc_enable;
|
||||
adv->cmd_qng_enabled = eeprom_config.use_cmd_qng;
|
||||
adv->isa_dma_speed = EEPROM_DMA_SPEED(eeprom_config);
|
||||
adv->scsi_id = EEPROM_SCSIID(eeprom_config);
|
||||
adv->start_motor = eeprom_config.start_motor;
|
||||
adv->control = eeprom_config.cntl;
|
||||
adv->no_scam = eeprom_config.no_scam;
|
||||
} else {
|
||||
/*
|
||||
* Use the defaults that adv was initialized with.
|
||||
*/
|
||||
/*
|
||||
* XXX Fixup EEPROM with default values???
|
||||
*/
|
||||
printf("adv%d: Warning EEPROM Checksum mismatch. "
|
||||
"Using default device parameters\n", adv->unit);
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* XXX Do this in the PCI probe */
|
||||
if ((adv->btype & ADV_PCI) &&
|
||||
!(asc_dvc->dvc_cntl & ASC_CNTL_NO_PCI_FIX_ASYN_XFER)) {
|
||||
if ((asc_dvc->cfg->pci_device_id == ASC_PCI_DEVICE_ID_REV_A) ||
|
||||
(asc_dvc->cfg->pci_device_id == ASC_PCI_DEVICE_ID_REV_B)) {
|
||||
asc_dvc->pci_fix_asyn_xfer = ASC_ALL_DEVICE_BIT_SET;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (adv_set_eeprom_config(adv, &eeprom_config) != 0)
|
||||
printf("adv:%d: WARNING! Failure writing to EEPROM.\n");
|
||||
|
||||
/* Allocate space for our sense buffers */
|
||||
/* XXX this should really be done by the generic SCSI layer by ensuring
|
||||
* that all scsi_xfer structs are allocated below 16M if any controller
|
||||
* needs to bounce.
|
||||
*/
|
||||
if (adv->type & ADV_ISA) {
|
||||
adv->sense_buffers = (struct scsi_sense_data *)contigmalloc(sizeof(struct scsi_sense_data) * adv->max_openings,
|
||||
M_DEVBUF, M_NOWAIT, 0ul, 0xfffffful, 1ul,
|
||||
0x10000ul);
|
||||
if (adv->sense_buffers == NULL) {
|
||||
printf("adv%d: Unable to allocate sense buffer space.\n");
|
||||
return (1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (adv_init_lram_and_mcode(adv))
|
||||
return (1);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
adv_intr(arg)
|
||||
void *arg;
|
||||
{
|
||||
struct adv_softc *adv;
|
||||
u_int16_t chipstat;
|
||||
u_int16_t saved_ram_addr;
|
||||
u_int8_t ctrl_reg;
|
||||
u_int8_t saved_ctrl_reg;
|
||||
int status;
|
||||
u_int8_t host_flag;
|
||||
|
||||
adv = (struct adv_softc *)arg;
|
||||
|
||||
ctrl_reg = ADV_INB(adv, ADV_CHIP_CTRL);
|
||||
saved_ctrl_reg = ctrl_reg & (~(ADV_CC_SCSI_RESET | ADV_CC_CHIP_RESET |
|
||||
ADV_CC_SINGLE_STEP | ADV_CC_DIAG | ADV_CC_TEST));
|
||||
|
||||
|
||||
if ((chipstat = ADV_INW(adv, ADV_CHIP_STATUS)) & ADV_CSW_INT_PENDING) {
|
||||
|
||||
adv_ack_interrupt(adv);
|
||||
|
||||
host_flag = adv_read_lram_8(adv, ADVV_HOST_FLAG_B);
|
||||
adv_write_lram_8(adv, ADVV_HOST_FLAG_B,
|
||||
host_flag | ADV_HOST_FLAG_IN_ISR);
|
||||
saved_ram_addr = ADV_INW(adv, ADV_LRAM_ADDR);
|
||||
|
||||
if ((chipstat & ADV_CSW_HALTED)
|
||||
&& (ctrl_reg & ADV_CC_SINGLE_STEP)) {
|
||||
adv_isr_chip_halted(adv);
|
||||
saved_ctrl_reg &= ~ADV_CC_HALT;
|
||||
} else {
|
||||
if ((adv->control & ADV_CNTL_INT_MULTI_Q) != 0) {
|
||||
while (((status = adv_qdone(adv)) & 0x01) != 0)
|
||||
;
|
||||
} else {
|
||||
do {
|
||||
status = adv_qdone(adv);
|
||||
} while (status == 0x11);
|
||||
}
|
||||
}
|
||||
ADV_OUTW(adv, ADV_LRAM_ADDR, saved_ram_addr);
|
||||
#ifdef DIAGNOSTIC
|
||||
if (ADV_INW(adv, ADV_LRAM_ADDR) != saved_ram_addr)
|
||||
panic("adv_intr: Unable to set LRAM addr");
|
||||
#endif
|
||||
adv_write_lram_8(adv, ADVV_HOST_FLAG_B, host_flag);
|
||||
}
|
||||
|
||||
ADV_OUTB(adv, ADV_CHIP_CTRL, saved_ctrl_reg);
|
||||
}
|
||||
|
||||
int
|
||||
adv_qdone(adv)
|
||||
struct adv_softc *adv;
|
||||
{
|
||||
u_int8_t next_qp;
|
||||
u_int8_t i;
|
||||
u_int8_t n_q_used;
|
||||
u_int8_t sg_list_qp;
|
||||
u_int8_t sg_queue_cnt;
|
||||
u_int8_t done_q_tail;
|
||||
u_int8_t tid_no;
|
||||
target_bit_vector target_id;
|
||||
u_int16_t q_addr;
|
||||
u_int16_t sg_q_addr;
|
||||
struct adv_q_done_info scsiq_buf;
|
||||
struct adv_q_done_info *scsiq;
|
||||
int false_overrun;
|
||||
u_int8_t tag_code;
|
||||
|
||||
n_q_used = 1;
|
||||
scsiq = &scsiq_buf;
|
||||
done_q_tail = adv_read_lram_16(adv, ADVV_DONE_Q_TAIL_W) & 0xFF;
|
||||
q_addr = ADV_QNO_TO_QADDR(done_q_tail);
|
||||
next_qp = adv_read_lram_8(adv, q_addr + ADV_SCSIQ_B_FWD);
|
||||
if (next_qp != ADV_QLINK_END) {
|
||||
adv_write_lram_16(adv, ADVV_DONE_Q_TAIL_W, next_qp);
|
||||
q_addr = ADV_QNO_TO_QADDR(next_qp);
|
||||
|
||||
sg_queue_cnt = adv_copy_lram_doneq(adv, q_addr, scsiq, adv->max_dma_count);
|
||||
|
||||
adv_write_lram_8(adv, q_addr + ADV_SCSIQ_B_STATUS,
|
||||
scsiq->q_status & ~(QS_READY | QS_ABORTED));
|
||||
tid_no = ADV_TIX_TO_TID(scsiq->d2.target_ix);
|
||||
target_id = ADV_TIX_TO_TARGET_ID(scsiq->d2.target_ix);
|
||||
if ((scsiq->cntl & QC_SG_HEAD) != 0) {
|
||||
sg_q_addr = q_addr;
|
||||
sg_list_qp = next_qp;
|
||||
for (i = 0; i < sg_queue_cnt; i++) {
|
||||
sg_list_qp = adv_read_lram_8(adv,
|
||||
sg_q_addr + ADV_SCSIQ_B_FWD);
|
||||
sg_q_addr = ADV_QNO_TO_QADDR(sg_list_qp);
|
||||
#ifdef DIAGNOSTIC
|
||||
if (sg_list_qp == ASC_QLINK_END) {
|
||||
panic("adv_qdone: Corrupted SG list encountered");
|
||||
}
|
||||
#endif
|
||||
adv_write_lram_8(adv, sg_q_addr + ADV_SCSIQ_B_STATUS,
|
||||
QS_FREE);
|
||||
}
|
||||
|
||||
n_q_used = sg_queue_cnt + 1;
|
||||
adv_write_lram_16(adv, ADVV_DONE_Q_TAIL_W, sg_list_qp);
|
||||
}
|
||||
#if 0
|
||||
/* XXX Fix later */
|
||||
if (adv->queue_full_or_busy & target_id) {
|
||||
cur_target_qng = adv_read_lram_8(adv,
|
||||
ADV_QADR_BEG + scsiq->d2.target_ix);
|
||||
if (cur_target_qng < adv->max_dvc_qng[tid_no]) {
|
||||
scsi_busy = adv_read_lram_8(adv, ADVV_SCSIBUSY_B);
|
||||
scsi_busy &= ~target_id;
|
||||
adv_write_lram_8(adv, ADVV_SCSIBUSY_B, scsi_busy);
|
||||
adv->queue_full_or_busy &= ~target_id;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#ifdef DIAGNOSTIC
|
||||
if (adv->cur_total_qng < n_q_used)
|
||||
panic("adv_qdone: Attempting to free more queues than are active");
|
||||
#endif
|
||||
adv->cur_active -= n_q_used;
|
||||
|
||||
if ((scsiq->d2.xs_ptr == 0) ||
|
||||
((scsiq->q_status & QS_ABORTED) != 0))
|
||||
return (0x11);
|
||||
else if (scsiq->q_status == QS_DONE) {
|
||||
|
||||
false_overrun = FALSE;
|
||||
|
||||
if (adv->bug_fix_control & ADV_BUG_FIX_ADD_ONE_BYTE) {
|
||||
tag_code = adv_read_lram_8(adv, q_addr + ADV_SCSIQ_B_TAG_CODE);
|
||||
if (tag_code & ADV_TAG_FLAG_ADD_ONE_BYTE) {
|
||||
if (scsiq->remain_bytes != 0) {
|
||||
scsiq->remain_bytes--;
|
||||
if (scsiq->remain_bytes == 0)
|
||||
false_overrun = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((scsiq->d3.done_stat == QD_WITH_ERROR) &&
|
||||
(scsiq->d3.host_stat == QHSTA_M_DATA_OVER_RUN)) {
|
||||
if ((scsiq->cntl & (QC_DATA_IN | QC_DATA_OUT)) == 0) {
|
||||
scsiq->d3.done_stat = QD_NO_ERROR;
|
||||
scsiq->d3.host_stat = QHSTA_NO_ERROR;
|
||||
} else if (false_overrun) {
|
||||
scsiq->d3.done_stat = QD_NO_ERROR;
|
||||
scsiq->d3.host_stat = QHSTA_NO_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
if ((scsiq->cntl & QC_NO_CALLBACK) == 0)
|
||||
adv_done(adv, scsiq);
|
||||
else {
|
||||
if ((adv_read_lram_8(adv, q_addr + ADV_SCSIQ_CDB_BEG) ==
|
||||
START_STOP)) {
|
||||
adv->unit_not_ready &= ~target_id;
|
||||
if (scsiq->d3.done_stat != QD_NO_ERROR)
|
||||
adv->start_motor &= ~target_id;
|
||||
}
|
||||
}
|
||||
return (1);
|
||||
} else {
|
||||
panic("adv_qdone: completed scsiq with unknown status");
|
||||
#if 0
|
||||
/*
|
||||
* XXX Doesn't this simply indicate a software bug?
|
||||
* What does setting the lram error code do for
|
||||
* you. Would we even recover?
|
||||
*/
|
||||
AscSetLibErrorCode(asc_dvc, ASCQ_ERR_Q_STATUS);
|
||||
|
||||
FATAL_ERR_QDONE:
|
||||
if ((scsiq->cntl & QC_NO_CALLBACK) == 0) {
|
||||
(*asc_isr_callback) (asc_dvc, scsiq);
|
||||
}
|
||||
return (0x80);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
adv_done(adv, qdonep)
|
||||
struct adv_softc *adv;
|
||||
struct adv_q_done_info *qdonep;
|
||||
{
|
||||
struct scsi_xfer *xs;
|
||||
|
||||
xs = (struct scsi_xfer *)qdonep->d2.xs_ptr;
|
||||
|
||||
xs->status = qdonep->d3.scsi_stat;
|
||||
/*
|
||||
* 'qdonep' contains the command's ending status.
|
||||
*/
|
||||
switch (qdonep->d3.done_stat) {
|
||||
case QD_NO_ERROR:
|
||||
switch (qdonep->d3.host_stat) {
|
||||
case QHSTA_NO_ERROR:
|
||||
break;
|
||||
case QHSTA_M_SEL_TIMEOUT:
|
||||
xs->error = XS_SELTIMEOUT;
|
||||
break;
|
||||
default:
|
||||
/* QHSTA error occurred */
|
||||
#if 0
|
||||
/* XXX Can I get more explicit information here? */
|
||||
xs->error = XS_DRIVER_STUFFUP;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case QD_WITH_ERROR:
|
||||
switch (qdonep->d3.host_stat) {
|
||||
case QHSTA_NO_ERROR:
|
||||
if ((qdonep->d3.scsi_stat == STATUS_CHECK_CONDITION)
|
||||
|| (qdonep->d3.scsi_stat == STATUS_COMMAND_TERMINATED)) {
|
||||
/* We have valid sense information to return */
|
||||
xs->error = XS_SENSE;
|
||||
if (adv->sense_buffers != NULL)
|
||||
/* Structure copy */
|
||||
xs->sense = adv->sense_buffers[qdonep->q_no];
|
||||
}
|
||||
break;
|
||||
case QHSTA_M_SEL_TIMEOUT:
|
||||
xs->error = XS_SELTIMEOUT;
|
||||
break;
|
||||
default:
|
||||
#if 0
|
||||
/* XXX Can I get more explicit information here? */
|
||||
xs->error = XS_DRIVER_STUFFUP;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case QD_ABORTED_BY_HOST:
|
||||
/* XXX Should have an explicit ABORTED error code */
|
||||
xs->error = XS_ABORTED;
|
||||
break;
|
||||
|
||||
default:
|
||||
#if 0
|
||||
printf("adv_done: Unknown done status 0x%x\n",
|
||||
qdonep->d3.done_stat);
|
||||
xs->error = XS_DRIVER_STUFFUP;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
xs->flags |= SCSI_ITSDONE;
|
||||
scsi_done(xs);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Function to poll for command completion when
|
||||
* interrupts are disabled (crash dumps)
|
||||
*/
|
||||
static int
|
||||
adv_poll(adv, xs)
|
||||
struct adv_softc *adv;
|
||||
struct scsi_xfer *xs;
|
||||
{
|
||||
int wait;
|
||||
|
||||
wait = xs->timeout;
|
||||
do {
|
||||
DELAY(1000);
|
||||
adv_intr((void *)adv);
|
||||
} while (--wait && ((xs->flags & SCSI_ITSDONE) == 0));
|
||||
if (wait == 0) {
|
||||
printf("adv%d: board is not responding\n", adv->unit);
|
||||
return (EIO);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Attach all the sub-devices we can find
|
||||
*/
|
||||
int
|
||||
adv_attach(adv)
|
||||
struct adv_softc *adv;
|
||||
{
|
||||
struct scsi_bus *scbus;
|
||||
struct scsi_queue *scsiq;
|
||||
|
||||
scsiq = scsi_alloc_queue(adv->max_openings);
|
||||
if (scsiq == NULL)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Prepare the scsi_bus area for the upperlevel scsi code.
|
||||
*/
|
||||
scbus = scsi_alloc_bus(&adv_switch, adv, adv->unit, scsiq);
|
||||
if (scbus == NULL) {
|
||||
scsi_free_queue(scsiq);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Override defaults */
|
||||
if ((adv->type & ADV_ISA) != 0)
|
||||
scbus->adpt_link.adpt_flags |= SADPT_BOUNCE;
|
||||
scbus->adpt_link.adpt_target = adv->scsi_id;
|
||||
scbus->adpt_link.adpt_openings = 2; /* XXX Is this correct for these cards? */
|
||||
scbus->adpt_link.adpt_tagged_openings = adv->max_openings;
|
||||
|
||||
/*
|
||||
* ask the adapter what subunits are present
|
||||
*/
|
||||
if(bootverbose)
|
||||
printf("adv%d: Probing SCSI bus\n", adv->unit);
|
||||
|
||||
scsi_attachdevs(scbus);
|
||||
|
||||
return 1;
|
||||
}
|
@ -1,50 +0,0 @@
|
||||
/*
|
||||
* Generic driver for the Advanced Systems Inc. SCSI controllers
|
||||
* Product specific probe and attach routines can be found in:
|
||||
*
|
||||
* XXX Fill this in.
|
||||
*
|
||||
* Copyright (c) 1996 Justin T. Gibbs.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice immediately at the beginning of the file, without modification,
|
||||
* this list of conditions, and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#ifndef _ADVANSYS_H_
|
||||
#define _ADVANSYS_H_
|
||||
|
||||
#include "adv.h"
|
||||
#include <dev/advansys/advlib.h>
|
||||
|
||||
struct adv_softc * adv_alloc __P((int unit, u_long iobase));
|
||||
void adv_free __P((struct adv_softc *adv));
|
||||
int adv_init __P((struct adv_softc *adv));
|
||||
void adv_intr __P((void *arg));
|
||||
int adv_attach __P((struct adv_softc *adv));
|
||||
|
||||
extern struct adv_softc *advsoftcs[NADV]; /* XXX Config should handle this */
|
||||
#endif /* _ADVANSYS_H_ */
|
File diff suppressed because it is too large
Load Diff
@ -1,403 +0,0 @@
|
||||
/*
|
||||
* Interface to the generic driver for the aic7xxx based adaptec
|
||||
* SCSI controllers. This is used to implement product specific
|
||||
* probe and attach routines.
|
||||
*
|
||||
* Copyright (c) 1994-1997 Justin Gibbs.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions, and the following disclaimer,
|
||||
* without modification, immediately at the beginning of the file.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* Where this Software is combined with software released under the terms of
|
||||
* the GNU Public License ("GPL") and the terms of the GPL would require the
|
||||
* combined work to also be released under the terms of the GPL, the terms
|
||||
* and conditions of this License will apply in addition to those of the
|
||||
* GPL with the exception of any terms or conditions of this License that
|
||||
* conflict with, or are expressly prohibited by, the GPL.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id: aic7xxx.h,v 1.42 1997/08/13 17:02:47 gibbs Exp $
|
||||
*/
|
||||
|
||||
#ifndef _AIC7XXX_H_
|
||||
#define _AIC7XXX_H_
|
||||
|
||||
#if defined(__FreeBSD__)
|
||||
#include "ahc.h" /* for NAHC from config */
|
||||
#include "opt_aic7xxx.h" /* for config options */
|
||||
#endif
|
||||
|
||||
#if defined(__NetBSD__)
|
||||
/*
|
||||
* convert FreeBSD's <sys/queue.h> symbols to NetBSD's
|
||||
*/
|
||||
#define STAILQ_ENTRY SIMPLEQ_ENTRY
|
||||
#define STAILQ_HEAD SIMPLEQ_HEAD
|
||||
#define STAILQ_INIT SIMPLEQ_INIT
|
||||
#define STAILQ_INSERT_HEAD SIMPLEQ_INSERT_HEAD
|
||||
#define STAILQ_INSERT_TAIL SIMPLEQ_INSERT_TAIL
|
||||
#define STAILQ_REMOVE_HEAD(head, field) \
|
||||
SIMPLEQ_REMOVE_HEAD(head, (head)->sqh_first, field)
|
||||
#define stqh_first sqh_first
|
||||
#define stqe_next sqe_next
|
||||
#endif
|
||||
|
||||
#define AHC_NSEG 32 /* The number of dma segments supported.
|
||||
* AHC_NSEG can be maxed out at 256 entries,
|
||||
* but the kernel will never need to transfer
|
||||
* such a large (1MB) request. To reduce the
|
||||
* driver's memory consumption, we reduce the
|
||||
* max to 32. 16 would work if all transfers
|
||||
* are paged alined since the kernel will only
|
||||
* generate at most a 64k transfer, but to
|
||||
* handle non-page aligned transfers, you need
|
||||
* 17, so we round to the next power of two
|
||||
* to make allocating SG space easy and
|
||||
* efficient.
|
||||
*/
|
||||
|
||||
#define AHC_SCB_MAX 255 /*
|
||||
* Up to 255 SCBs on some types of aic7xxx
|
||||
* based boards. The aic7870 have 16 internal
|
||||
* SCBs, but external SRAM bumps this to 255.
|
||||
* The aic7770 family have only 4, and the
|
||||
* aic7850 has only 3.
|
||||
*/
|
||||
|
||||
|
||||
typedef u_int32_t physaddr;
|
||||
#if defined(__FreeBSD__)
|
||||
extern u_long ahc_unit;
|
||||
#endif
|
||||
|
||||
struct ahc_dma_seg {
|
||||
physaddr addr;
|
||||
u_int32_t len;
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
AHC_NONE = 0x0000,
|
||||
AHC_ULTRA = 0x0001, /* Supports 20MHz Transfers */
|
||||
AHC_WIDE = 0x0002, /* Wide Channel */
|
||||
AHC_TWIN = 0x0008, /* Twin Channel */
|
||||
AHC_AIC7770 = 0x0010,
|
||||
AHC_AIC7850 = 0x0020,
|
||||
AHC_AIC7860 = 0x0021, /* ULTRA version of the aic7850 */
|
||||
AHC_AIC7870 = 0x0040,
|
||||
AHC_AIC7880 = 0x0041,
|
||||
AHC_AIC78X0 = 0x0060, /* PCI Based Controller */
|
||||
AHC_274 = 0x0110, /* EISA Based Controller */
|
||||
AHC_284 = 0x0210, /* VL/ISA Based Controller */
|
||||
AHC_294AU = 0x0421, /* aic7860 based '2940' */
|
||||
AHC_294 = 0x0440, /* PCI Based Controller */
|
||||
AHC_294U = 0x0441, /* ULTRA PCI Based Controller */
|
||||
AHC_394 = 0x0840, /* Twin Channel PCI Controller */
|
||||
AHC_394U = 0x0841, /* ULTRA, Twin Channel PCI Controller */
|
||||
AHC_398 = 0x1040, /* Multi Channel PCI RAID Controller */
|
||||
AHC_398U = 0x1041, /* ULTRA, Multi Channel PCI
|
||||
* RAID Controller
|
||||
*/
|
||||
AHC_39X = 0x1800 /* Multi Channel PCI Adapter */
|
||||
}ahc_type;
|
||||
|
||||
typedef enum {
|
||||
AHC_FNONE = 0x00,
|
||||
AHC_INIT = 0x01,
|
||||
AHC_RUNNING = 0x02,
|
||||
AHC_PAGESCBS = 0x04, /* Enable SCB paging */
|
||||
AHC_CHANNEL_B_PRIMARY = 0x08, /*
|
||||
* On twin channel adapters, probe
|
||||
* channel B first since it is the
|
||||
* primary bus.
|
||||
*/
|
||||
AHC_USEDEFAULTS = 0x10, /*
|
||||
* For cards without an seeprom
|
||||
* or a BIOS to initialize the chip's
|
||||
* SRAM, we use the default target
|
||||
* settings.
|
||||
*/
|
||||
AHC_CHNLB = 0x20, /*
|
||||
* Second controller on 3940/398X
|
||||
* Also encodes the offset in the
|
||||
* SEEPROM for CHNLB info (32)
|
||||
*/
|
||||
AHC_CHNLC = 0x40 /*
|
||||
* Third controller on 3985
|
||||
* Also encodes the offset in the
|
||||
* SEEPROM for CHNLC info (64)
|
||||
*/
|
||||
} ahc_flag;
|
||||
|
||||
typedef enum {
|
||||
SCB_FREE = 0x0000,
|
||||
SCB_ACTIVE = 0x0001,
|
||||
SCB_ABORTED = 0x0002,
|
||||
SCB_DEVICE_RESET = 0x0004,
|
||||
SCB_SENSE = 0x0008,
|
||||
SCB_TIMEDOUT = 0x0010,
|
||||
SCB_QUEUED_FOR_DONE = 0x0020,
|
||||
SCB_RECOVERY_SCB = 0x0040,
|
||||
SCB_WAITINGQ = 0x0080,
|
||||
SCB_ASSIGNEDQ = 0x0100,
|
||||
SCB_SENTORDEREDTAG = 0x0200,
|
||||
SCB_MSGOUT_SDTR = 0x0400,
|
||||
SCB_MSGOUT_WDTR = 0x0800,
|
||||
SCB_ABORT = 0x1000,
|
||||
SCB_QUEUED_ABORT = 0x2000
|
||||
} scb_flag;
|
||||
|
||||
/*
|
||||
* The driver keeps up to MAX_SCB scb structures per card in memory. The SCB
|
||||
* consists of a "hardware SCB" mirroring the fields availible on the card
|
||||
* and additional information the kernel stores for each transaction.
|
||||
*/
|
||||
struct hardware_scb {
|
||||
/*0*/ u_int8_t control;
|
||||
/*1*/ u_int8_t tcl; /* 4/1/3 bits */
|
||||
/*2*/ u_int8_t status;
|
||||
/*3*/ u_int8_t SG_segment_count;
|
||||
/*4*/ physaddr SG_list_pointer;
|
||||
/*8*/ u_int8_t residual_SG_segment_count;
|
||||
/*9*/ u_int8_t residual_data_count[3];
|
||||
/*12*/ physaddr data;
|
||||
/*16*/ u_int32_t datalen; /* Really only three bits, but its
|
||||
* faster to treat it as a long on
|
||||
* a quad boundary.
|
||||
*/
|
||||
/*20*/ physaddr cmdpointer;
|
||||
/*24*/ u_int8_t cmdlen;
|
||||
/*25*/ u_int8_t tag; /* Index into our kernel SCB array.
|
||||
* Also used as the tag for tagged I/O
|
||||
*/
|
||||
#define SCB_PIO_TRANSFER_SIZE 26 /* amount we need to upload/download
|
||||
* via PIO to initialize a transaction.
|
||||
*/
|
||||
/*26*/ u_int8_t next; /* Used for threading SCBs in the
|
||||
* "Waiting for Selection" and
|
||||
* "Disconnected SCB" lists down
|
||||
* in the sequencer.
|
||||
*/
|
||||
/*27*/ u_int8_t prev;
|
||||
|
||||
/*28*/ u_int32_t pad; /*
|
||||
* Unused by the kernel, but we require
|
||||
* the padding so that the array of
|
||||
* hardware SCBs is alligned on 32 byte
|
||||
* boundaries so the sequencer can
|
||||
* index them easily.
|
||||
*/
|
||||
};
|
||||
|
||||
struct scb {
|
||||
struct hardware_scb *hscb;
|
||||
STAILQ_ENTRY(scb) links; /* for chaining */
|
||||
struct scsi_xfer *xs; /* the scsi_xfer for this cmd */
|
||||
scb_flag flags;
|
||||
struct ahc_dma_seg *ahc_dma;/* Pointer to SG segments */
|
||||
struct scsi_sense sense_cmd;
|
||||
u_int8_t sg_count;/* How full ahc_dma_seg is */
|
||||
u_int8_t position;/* Position in card's scbarray */
|
||||
};
|
||||
|
||||
struct scb_data {
|
||||
struct hardware_scb *hscbs; /* Array of hardware SCBs */
|
||||
struct scb *scbarray[AHC_SCB_MAX]; /* Array of kernel SCBs */
|
||||
STAILQ_HEAD(, scb) free_scbs; /*
|
||||
* Pool of SCBs ready to be assigned
|
||||
* commands to execute.
|
||||
*/
|
||||
u_int8_t numscbs;
|
||||
u_int8_t maxhscbs; /* Number of SCBs on the card */
|
||||
u_int8_t maxscbs; /*
|
||||
* Max SCBs we allocate total including
|
||||
* any that will force us to page SCBs
|
||||
*/
|
||||
};
|
||||
|
||||
struct ahc_busreset_args {
|
||||
struct ahc_softc *ahc;
|
||||
char bus;
|
||||
};
|
||||
|
||||
struct ahc_softc {
|
||||
#if defined(__FreeBSD__)
|
||||
int unit;
|
||||
#elif defined(__NetBSD__)
|
||||
struct device sc_dev;
|
||||
void *sc_ih;
|
||||
bus_chipset_tag_t sc_bc;
|
||||
bus_io_handle_t sc_ioh;
|
||||
#endif
|
||||
ahc_type type;
|
||||
ahc_flag flags;
|
||||
#if defined(__FreeBSD__)
|
||||
u_int32_t baseport;
|
||||
#endif
|
||||
volatile u_int8_t *maddr;
|
||||
struct scb_data *scb_data;
|
||||
struct scsi_link sc_link;
|
||||
struct scsi_link sc_link_b; /* Second bus for Twin channel cards */
|
||||
STAILQ_HEAD(, scb) waiting_scbs;/*
|
||||
* SCBs waiting ready to go but
|
||||
* waiting for space in the QINFIFO.
|
||||
*/
|
||||
STAILQ_HEAD(, scb) cmplete_scbs;/*
|
||||
* SCBs out of the QOUTFIFO, waiting
|
||||
* to be ahc_done'd.
|
||||
*/
|
||||
u_int8_t activescbs;
|
||||
u_int8_t cmdoutcnt;
|
||||
u_int16_t needsdtr_orig; /* Targets we initiate sync neg with */
|
||||
u_int16_t needwdtr_orig; /* Targets we initiate wide neg with */
|
||||
u_int16_t needsdtr; /* Current list of negotiated targets */
|
||||
u_int16_t needwdtr; /* Current list of negotiated targets */
|
||||
u_int16_t sdtrpending; /* Pending SDTR to these targets */
|
||||
u_int16_t wdtrpending; /* Pending WDTR to these targets */
|
||||
u_int16_t tagenable; /* Targets that can handle tags */
|
||||
u_int16_t orderedtag; /* Targets to use ordered tag on */
|
||||
u_int16_t discenable; /* Targets allowed to disconnect */
|
||||
u_int8_t our_id; /* our scsi id */
|
||||
u_int8_t our_id_b; /* B channel scsi id */
|
||||
u_int8_t qcntmask; /*
|
||||
* Mask of valid registers in the
|
||||
* Q*CNT registers.
|
||||
*/
|
||||
u_int8_t qfullcount; /*
|
||||
* The maximum number of entries
|
||||
* storable in the Q*FIFOs.
|
||||
*/
|
||||
u_int8_t curqincnt; /*
|
||||
* The current value we "think" the
|
||||
* QINCNT has. The reason it is
|
||||
* "think" is that this is a cached
|
||||
* value that is only updated when
|
||||
* curqincount == qfullcount to reduce
|
||||
* the amount of accesses made to the
|
||||
* card.
|
||||
*/
|
||||
u_int8_t unpause;
|
||||
u_int8_t pause;
|
||||
u_int8_t in_timeout;
|
||||
};
|
||||
|
||||
struct full_ahc_softc {
|
||||
struct ahc_softc softc;
|
||||
struct scb_data scb_data_storage;
|
||||
};
|
||||
|
||||
/* #define AHC_DEBUG */
|
||||
#ifdef AHC_DEBUG
|
||||
/* Different debugging levels used when AHC_DEBUG is defined */
|
||||
#define AHC_SHOWMISC 0x0001
|
||||
#define AHC_SHOWCMDS 0x0002
|
||||
#define AHC_SHOWSCBS 0x0004
|
||||
#define AHC_SHOWABORTS 0x0008
|
||||
#define AHC_SHOWSENSE 0x0010
|
||||
#define AHC_SHOWSCBCNT 0x0020
|
||||
|
||||
extern int ahc_debug; /* Initialized in i386/scsi/aic7xxx.c */
|
||||
#endif
|
||||
|
||||
#if defined(__FreeBSD__)
|
||||
char *ahc_name __P((struct ahc_softc *ahc));
|
||||
|
||||
struct ahc_softc *ahc_alloc __P((int unit, u_int32_t io_base,
|
||||
vm_offset_t maddr, ahc_type type,
|
||||
ahc_flag flags, struct scb_data *scb_data));
|
||||
#elif defined(__NetBSD__)
|
||||
|
||||
#define ahc_name(ahc) (ahc)->sc_dev.dv_xname
|
||||
|
||||
void ahc_construct __P((struct ahc_softc *ahc, bus_chipset_tag_t bc, bus_io_handle_t ioh, ahc_type type, ahc_flag flags));
|
||||
#endif
|
||||
void ahc_reset __P((struct ahc_softc *ahc));
|
||||
void ahc_free __P((struct ahc_softc *));
|
||||
int ahc_init __P((struct ahc_softc *));
|
||||
int ahc_attach __P((struct ahc_softc *));
|
||||
#if defined(__FreeBSD__)
|
||||
void ahc_intr __P((void *arg));
|
||||
#elif defined(__NetBSD__)
|
||||
int ahc_intr __P((void *arg));
|
||||
#endif
|
||||
|
||||
#if defined(__FreeBSD__)
|
||||
static __inline u_int8_t ahc_inb __P((struct ahc_softc *ahc, u_int32_t port));
|
||||
static __inline void ahc_outb __P((struct ahc_softc *ahc, u_int32_t port,
|
||||
u_int8_t val));
|
||||
static __inline void ahc_outsb __P((struct ahc_softc *ahc, u_int32_t port,
|
||||
u_int8_t *valp, size_t size));
|
||||
|
||||
static __inline u_int8_t
|
||||
ahc_inb(ahc, port)
|
||||
struct ahc_softc *ahc;
|
||||
u_int32_t port;
|
||||
{
|
||||
if (ahc->maddr != NULL)
|
||||
return ahc->maddr[port];
|
||||
else
|
||||
return inb(ahc->baseport + port);
|
||||
}
|
||||
|
||||
static __inline void
|
||||
ahc_outb(ahc, port, val)
|
||||
struct ahc_softc *ahc;
|
||||
u_int32_t port;
|
||||
u_int8_t val;
|
||||
{
|
||||
if (ahc->maddr != NULL)
|
||||
ahc->maddr[port] = val;
|
||||
else
|
||||
outb(ahc->baseport + port, val);
|
||||
}
|
||||
|
||||
static __inline void
|
||||
ahc_outsb(ahc, port, valp, size)
|
||||
struct ahc_softc *ahc;
|
||||
u_int32_t port;
|
||||
u_int8_t *valp;
|
||||
size_t size;
|
||||
{
|
||||
if (ahc->maddr != NULL) {
|
||||
__asm __volatile("
|
||||
cld;
|
||||
1: lodsb;
|
||||
movb %%al,(%0);
|
||||
loop 1b" :
|
||||
:
|
||||
"r" ((ahc)->maddr + (port)),
|
||||
"S" ((valp)), "c" ((size)) :
|
||||
"%esi", "%ecx", "%eax");
|
||||
} else
|
||||
outsb(ahc->baseport + port, valp, size);
|
||||
}
|
||||
#elif defined(__NetBSD__)
|
||||
#define ahc_inb(ahc, port) \
|
||||
bus_io_read_1((ahc)->sc_bc, (ahc)->sc_ioh, port)
|
||||
#define ahc_outb(ahc, port, val) \
|
||||
bus_io_write_1((ahc)->sc_bc, (ahc)->sc_ioh, port, val)
|
||||
#define ahc_outsb(ahc, port, valp, size) \
|
||||
bus_io_write_multi_1((ahc)->sc_bc, (ahc)->sc_ioh, port, valp, size)
|
||||
#endif
|
||||
|
||||
#endif /* _AIC7XXX_H_ */
|
1583
sys/i386/scsi/bt.c
1583
sys/i386/scsi/bt.c
File diff suppressed because it is too large
Load Diff
@ -1,149 +0,0 @@
|
||||
/*
|
||||
* Written by Julian Elischer (julian@tfs.com)
|
||||
* for TRW Financial Systems for use under the MACH(2.5) operating system.
|
||||
*
|
||||
* TRW Financial Systems, in accordance with their agreement with Carnegie
|
||||
* Mellon University, makes this software available to CMU to distribute
|
||||
* or use in any manner that they see fit as long as this message is kept with
|
||||
* the software. For this reason TFS also grants any other persons or
|
||||
* organizations permission to use or modify this software.
|
||||
*
|
||||
* TFS supplies this software to be publicly redistributed
|
||||
* on the understanding that TFS is not responsible for the correct
|
||||
* functioning of this software in any circumstances.
|
||||
*
|
||||
* $Id: btreg.h,v 1.6 1997/02/22 09:38:43 peter Exp $
|
||||
*/
|
||||
|
||||
#ifndef _BTREG_H_
|
||||
#define _BTREG_H_
|
||||
|
||||
#include "bt.h"
|
||||
|
||||
/*
|
||||
* Mail box defs etc.
|
||||
* these could be bigger but we need the bt_data to fit on a single page..
|
||||
*/
|
||||
|
||||
#define BT_MBX_SIZE 32 /* 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 BT_NSEG 33 /*
|
||||
* Number of SG segments per command
|
||||
* Max of 2048???
|
||||
*/
|
||||
|
||||
typedef unsigned long int physaddr;
|
||||
|
||||
struct bt_scat_gath {
|
||||
unsigned long seg_len;
|
||||
physaddr seg_addr;
|
||||
};
|
||||
|
||||
typedef struct bt_mbx_out {
|
||||
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;
|
||||
} BT_MBI;
|
||||
|
||||
struct bt_mbx {
|
||||
BT_MBO mbo[BT_MBX_SIZE];
|
||||
#define BT_MBO_FREE 0x0 /* MBO intry is free */
|
||||
#define BT_MBO_START 0x1 /* MBO activate entry */
|
||||
#define BT_MBO_ABORT 0x2 /* MBO abort entry */
|
||||
BT_MBI mbi[BT_MBX_SIZE];
|
||||
#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 */
|
||||
BT_MBO *tmbo; /* Target Mail Box out */
|
||||
BT_MBI *tmbi; /* Target Mail Box in */
|
||||
};
|
||||
|
||||
|
||||
struct bt_ccb {
|
||||
unsigned char opcode;
|
||||
#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 w/sg */
|
||||
#define BT_RESET_CCB 0x81 /* SCSI Bus reset */
|
||||
unsigned :3, data_in:1, data_out:1,:3;
|
||||
unsigned char scsi_cmd_length;
|
||||
unsigned char req_sense_length;
|
||||
unsigned long data_length;
|
||||
physaddr data_addr;
|
||||
unsigned char dummy[2];
|
||||
unsigned char host_stat;
|
||||
#define BT_OK 0x00 /* cmd ok */
|
||||
#define BT_LINK_OK 0x0a /* Link cmd ok */
|
||||
#define BT_LINK_IT 0x0b /* Link cmd ok + int */
|
||||
#define BT_SEL_TIMEOUT 0x11 /* Selection time out */
|
||||
#define BT_OVER_UNDER 0x12 /* Data over/under run */
|
||||
#define BT_BUS_FREE 0x13 /* Bus dropped at unexpected time */
|
||||
#define BT_INV_BUS 0x14 /* Invalid bus phase/sequence */
|
||||
#define BT_BAD_MBO 0x15 /* Incorrect MBO cmd */
|
||||
#define BT_BAD_CCB 0x16 /* Incorrect ccb opcode */
|
||||
#define BT_BAD_LINK 0x17 /* Not same values of LUN for links */
|
||||
#define BT_INV_TARGET 0x18 /* Invalid target direction */
|
||||
#define BT_CCB_DUP 0x19 /* Duplicate CCB received */
|
||||
#define BT_INV_CCB 0x1a /* Invalid CCB or segment list */
|
||||
#define BT_ABORTED 42 /* pseudo value from driver */
|
||||
unsigned char target_stat;
|
||||
unsigned char target;
|
||||
unsigned char lun;
|
||||
unsigned char scsi_cmd[12]; /* 12 bytes (bytes only) */
|
||||
unsigned char dummy2[1];
|
||||
unsigned char link_id;
|
||||
physaddr link_addr;
|
||||
physaddr sense_ptr;
|
||||
struct scsi_sense_data scsi_sense;
|
||||
struct bt_scat_gath scat_gath[BT_NSEG];
|
||||
struct bt_ccb *next;
|
||||
struct scsi_xfer *xfer; /* the scsi_xfer for this cmd */
|
||||
struct bt_mbx_out *mbx; /* pointer to mail box */
|
||||
int flags;
|
||||
#define CCB_FREE 0
|
||||
#define CCB_ACTIVE 1
|
||||
#define CCB_ABORTED 2
|
||||
struct bt_ccb *nexthash; /* if two hash the same */
|
||||
physaddr hashkey; /*physaddr of this ccb */
|
||||
};
|
||||
|
||||
struct bt_data {
|
||||
int 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 */
|
||||
int bt_bounce; /* should we bounce? */
|
||||
int unit; /* The zero in bt0 */
|
||||
struct scsi_link sc_link; /* prototype for devs */
|
||||
};
|
||||
|
||||
extern struct bt_data *btdata[NBT];
|
||||
|
||||
extern u_long bt_unit;
|
||||
|
||||
struct bt_data *bt_alloc __P((int unit, u_long iobase));
|
||||
void bt_free __P((struct bt_data *bt));
|
||||
void bt_intr __P((void *arg));
|
||||
int bt_init __P((struct bt_data *bt));
|
||||
int bt_attach __P((struct bt_data *bt));
|
||||
|
||||
#endif /* _BT_H_ */
|
@ -1,997 +0,0 @@
|
||||
/*
|
||||
* Product specific probe and attach routines for:
|
||||
* 3940, 2940, aic7880, aic7870, aic7860 and aic7850 SCSI controllers
|
||||
*
|
||||
* Copyright (c) 1995-1997 Justin Gibbs.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions, and the following disclaimer,
|
||||
* without modification, immediately at the beginning of the file.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* Where this Software is combined with software released under the terms of
|
||||
* the GNU Public License ("GPL") and the terms of the GPL would require the
|
||||
* combined work to also be released under the terms of the GPL, the terms
|
||||
* and conditions of this License will apply in addition to those of the
|
||||
* GPL with the exception of any terms or conditions of this License that
|
||||
* conflict with, or are expressly prohibited by, the GPL.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id: aic7870.c,v 1.55 1998/07/06 18:38:57 gibbs Exp $
|
||||
*/
|
||||
|
||||
#if defined(__FreeBSD__)
|
||||
#include "pci.h"
|
||||
#endif
|
||||
#if NPCI > 0 || defined(__NetBSD__)
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/queue.h>
|
||||
#if defined(__NetBSD__)
|
||||
#include <sys/device.h>
|
||||
#include <machine/bus.h>
|
||||
#include <machine/intr.h>
|
||||
#endif /* defined(__NetBSD__) */
|
||||
|
||||
#include <scsi/scsiconf.h>
|
||||
|
||||
#if defined(__FreeBSD__)
|
||||
|
||||
#include <pci/pcireg.h>
|
||||
#include <pci/pcivar.h>
|
||||
|
||||
#include <machine/clock.h>
|
||||
|
||||
#include <i386/scsi/aic7xxx.h>
|
||||
#include <i386/scsi/93cx6.h>
|
||||
|
||||
#include "aic7xxx_reg.h"
|
||||
|
||||
#define PCI_BASEADR0 PCI_MAP_REG_START /* I/O Address */
|
||||
#define PCI_BASEADR1 PCI_MAP_REG_START + 4 /* Mem I/O Address */
|
||||
|
||||
#elif defined(__NetBSD__)
|
||||
|
||||
#include <dev/pci/pcireg.h>
|
||||
#include <dev/pci/pcivar.h>
|
||||
|
||||
#include <dev/ic/aic7xxxreg.h>
|
||||
#include <dev/ic/aic7xxxvar.h>
|
||||
#include <dev/ic/smc93cx6var.h>
|
||||
|
||||
#define bootverbose 1
|
||||
#define PCI_BASEADR0 PCI_MAPREG_START /* I/O Address */
|
||||
#define PCI_BASEADR1 PCI_MAPREG_START + 4 /* Mem I/O Address */
|
||||
|
||||
#endif /* defined(__NetBSD__) */
|
||||
|
||||
#define PCI_DEVICE_ID_ADAPTEC_398XU 0x83789004ul
|
||||
#define PCI_DEVICE_ID_ADAPTEC_3940U 0x82789004ul
|
||||
#define PCI_DEVICE_ID_ADAPTEC_2944U 0x84789004ul
|
||||
#define PCI_DEVICE_ID_ADAPTEC_2940U 0x81789004ul
|
||||
#define PCI_DEVICE_ID_ADAPTEC_2940AU 0x61789004ul
|
||||
#define PCI_DEVICE_ID_ADAPTEC_398X 0x73789004ul
|
||||
#define PCI_DEVICE_ID_ADAPTEC_3940 0x72789004ul
|
||||
#define PCI_DEVICE_ID_ADAPTEC_2944 0x74789004ul
|
||||
#define PCI_DEVICE_ID_ADAPTEC_2940 0x71789004ul
|
||||
#define PCI_DEVICE_ID_ADAPTEC_AIC7880 0x80789004ul
|
||||
#define PCI_DEVICE_ID_ADAPTEC_AIC7870 0x70789004ul
|
||||
#define PCI_DEVICE_ID_ADAPTEC_AIC7860 0x60789004ul
|
||||
#define PCI_DEVICE_ID_ADAPTEC_AIC7855 0x55789004ul
|
||||
#define PCI_DEVICE_ID_ADAPTEC_AIC7850 0x50789004ul
|
||||
#define PCI_DEVICE_ID_ADAPTEC_AIC7810 0x10789004ul
|
||||
|
||||
#define DEVCONFIG 0x40
|
||||
#define MPORTMODE 0x00000400ul /* aic7870 only */
|
||||
#define RAMPSM 0x00000200ul /* aic7870 only */
|
||||
#define VOLSENSE 0x00000100ul
|
||||
#define SCBRAMSEL 0x00000080ul
|
||||
#define MRDCEN 0x00000040ul
|
||||
#define EXTSCBTIME 0x00000020ul /* aic7870 only */
|
||||
#define EXTSCBPEN 0x00000010ul /* aic7870 only */
|
||||
#define BERREN 0x00000008ul
|
||||
#define DACEN 0x00000004ul
|
||||
#define STPWLEVEL 0x00000002ul
|
||||
#define DIFACTNEGEN 0x00000001ul /* aic7870 only */
|
||||
|
||||
#define CSIZE_LATTIME 0x0c
|
||||
#define CACHESIZE 0x0000003ful /* only 5 bits */
|
||||
#define LATTIME 0x0000ff00ul
|
||||
|
||||
/*
|
||||
* Define the format of the aic78X0 SEEPROM registers (16 bits).
|
||||
*/
|
||||
|
||||
struct seeprom_config {
|
||||
|
||||
/*
|
||||
* SCSI ID Configuration Flags
|
||||
*/
|
||||
#define CFXFER 0x0007 /* synchronous transfer rate */
|
||||
#define CFSYNCH 0x0008 /* enable synchronous transfer */
|
||||
#define CFDISC 0x0010 /* enable disconnection */
|
||||
#define CFWIDEB 0x0020 /* wide bus device */
|
||||
/* UNUSED 0x00C0 */
|
||||
#define CFSTART 0x0100 /* send start unit SCSI command */
|
||||
#define CFINCBIOS 0x0200 /* include in BIOS scan */
|
||||
#define CFRNFOUND 0x0400 /* report even if not found */
|
||||
/* UNUSED 0xf800 */
|
||||
u_int16_t device_flags[16]; /* words 0-15 */
|
||||
|
||||
/*
|
||||
* BIOS Control Bits
|
||||
*/
|
||||
#define CFSUPREM 0x0001 /* support all removeable drives */
|
||||
#define CFSUPREMB 0x0002 /* support removeable drives for boot only */
|
||||
#define CFBIOSEN 0x0004 /* BIOS enabled */
|
||||
/* UNUSED 0x0008 */
|
||||
#define CFSM2DRV 0x0010 /* support more than two drives */
|
||||
/* UNUSED 0x0060 */
|
||||
#define CFEXTEND 0x0080 /* extended translation enabled */
|
||||
/* UNUSED 0xff00 */
|
||||
u_int16_t bios_control; /* word 16 */
|
||||
|
||||
/*
|
||||
* Host Adapter Control Bits
|
||||
*/
|
||||
#define CFAUTOTERM 0x0001 /* Perform Auto termination */
|
||||
#define CFULTRAEN 0x0002 /* Ultra SCSI speed enable */
|
||||
#define CFSTERM 0x0004 /* SCSI low byte termination */
|
||||
#define CFWSTERM 0x0008 /* SCSI high byte termination */
|
||||
#define CFSPARITY 0x0010 /* SCSI parity */
|
||||
/* UNUSED 0x0020 */
|
||||
#define CFRESETB 0x0040 /* reset SCSI bus at boot */
|
||||
/* UNUSED 0xff80 */
|
||||
u_int16_t adapter_control; /* word 17 */
|
||||
|
||||
/*
|
||||
* Bus Release, Host Adapter ID
|
||||
*/
|
||||
#define CFSCSIID 0x000f /* host adapter SCSI ID */
|
||||
/* UNUSED 0x00f0 */
|
||||
#define CFBRTIME 0xff00 /* bus release time */
|
||||
u_int16_t brtime_id; /* word 18 */
|
||||
|
||||
/*
|
||||
* Maximum targets
|
||||
*/
|
||||
#define CFMAXTARG 0x00ff /* maximum targets */
|
||||
/* UNUSED 0xff00 */
|
||||
u_int16_t max_targets; /* word 19 */
|
||||
|
||||
u_int16_t res_1[11]; /* words 20-30 */
|
||||
u_int16_t checksum; /* word 31 */
|
||||
};
|
||||
|
||||
static void load_seeprom __P((struct ahc_softc *ahc, u_int8_t *sxfrctl1));
|
||||
static int acquire_seeprom __P((struct seeprom_descriptor *sd));
|
||||
static void release_seeprom __P((struct seeprom_descriptor *sd));
|
||||
static void write_brdctl __P((struct ahc_softc *ahc, u_int8_t value));
|
||||
static u_int8_t read_brdctl __P((struct ahc_softc *ahc));
|
||||
|
||||
static int aic3940_count;
|
||||
static int aic398X_count;
|
||||
static struct ahc_softc *first_398X;
|
||||
|
||||
#if defined(__FreeBSD__)
|
||||
|
||||
static char* aic7870_probe __P((pcici_t tag, pcidi_t type));
|
||||
static void aic7870_attach __P((pcici_t config_id, int unit));
|
||||
|
||||
static struct pci_device ahc_pci_driver = {
|
||||
"ahc",
|
||||
aic7870_probe,
|
||||
aic7870_attach,
|
||||
&ahc_unit,
|
||||
NULL
|
||||
};
|
||||
|
||||
DATA_SET (pcidevice_set, ahc_pci_driver);
|
||||
|
||||
static char*
|
||||
aic7870_probe (pcici_t tag, pcidi_t type)
|
||||
{
|
||||
switch (type) {
|
||||
case PCI_DEVICE_ID_ADAPTEC_398XU:
|
||||
return ("Adaptec 398X Ultra SCSI RAID adapter");
|
||||
break;
|
||||
case PCI_DEVICE_ID_ADAPTEC_3940U:
|
||||
return ("Adaptec 3940 Ultra SCSI host adapter");
|
||||
break;
|
||||
case PCI_DEVICE_ID_ADAPTEC_398X:
|
||||
return ("Adaptec 398X SCSI RAID adapter");
|
||||
break;
|
||||
case PCI_DEVICE_ID_ADAPTEC_3940:
|
||||
return ("Adaptec 3940 SCSI host adapter");
|
||||
break;
|
||||
case PCI_DEVICE_ID_ADAPTEC_2944U:
|
||||
return ("Adaptec 2944 Ultra SCSI host adapter");
|
||||
break;
|
||||
case PCI_DEVICE_ID_ADAPTEC_2940U:
|
||||
return ("Adaptec 2940 Ultra SCSI host adapter");
|
||||
break;
|
||||
case PCI_DEVICE_ID_ADAPTEC_2944:
|
||||
return ("Adaptec 2944 SCSI host adapter");
|
||||
break;
|
||||
case PCI_DEVICE_ID_ADAPTEC_2940:
|
||||
return ("Adaptec 2940 SCSI host adapter");
|
||||
break;
|
||||
case PCI_DEVICE_ID_ADAPTEC_2940AU:
|
||||
return ("Adaptec 2940A Ultra SCSI host adapter");
|
||||
break;
|
||||
case PCI_DEVICE_ID_ADAPTEC_AIC7880:
|
||||
return ("Adaptec aic7880 Ultra SCSI host adapter");
|
||||
break;
|
||||
case PCI_DEVICE_ID_ADAPTEC_AIC7870:
|
||||
return ("Adaptec aic7870 SCSI host adapter");
|
||||
break;
|
||||
case PCI_DEVICE_ID_ADAPTEC_AIC7860:
|
||||
return ("Adaptec aic7860 SCSI host adapter");
|
||||
break;
|
||||
case PCI_DEVICE_ID_ADAPTEC_AIC7855:
|
||||
return ("Adaptec aic7855 SCSI host adapter");
|
||||
break;
|
||||
case PCI_DEVICE_ID_ADAPTEC_AIC7850:
|
||||
return ("Adaptec aic7850 SCSI host adapter");
|
||||
break;
|
||||
case PCI_DEVICE_ID_ADAPTEC_AIC7810:
|
||||
return ("Adaptec aic7810 RAID memory controller");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return (0);
|
||||
|
||||
}
|
||||
|
||||
#elif defined(__NetBSD__)
|
||||
|
||||
int ahc_pci_probe __P((struct device *, void *, void *));
|
||||
void ahc_pci_attach __P((struct device *, struct device *, void *));
|
||||
|
||||
struct cfattach ahc_pci_ca = {
|
||||
sizeof(struct ahc_softc), ahc_pci_probe, ahc_pci_attach
|
||||
};
|
||||
|
||||
int
|
||||
ahc_pci_probe(parent, match, aux)
|
||||
struct device *parent;
|
||||
void *match, *aux;
|
||||
{
|
||||
struct pci_attach_args *pa = aux;
|
||||
|
||||
switch (pa->pa_id) {
|
||||
case PCI_DEVICE_ID_ADAPTEC_398XU:
|
||||
case PCI_DEVICE_ID_ADAPTEC_3940U:
|
||||
case PCI_DEVICE_ID_ADAPTEC_2944U:
|
||||
case PCI_DEVICE_ID_ADAPTEC_2940U:
|
||||
case PCI_DEVICE_ID_ADAPTEC_2940AU:
|
||||
case PCI_DEVICE_ID_ADAPTEC_398X:
|
||||
case PCI_DEVICE_ID_ADAPTEC_3940:
|
||||
case PCI_DEVICE_ID_ADAPTEC_2944:
|
||||
case PCI_DEVICE_ID_ADAPTEC_2940:
|
||||
case PCI_DEVICE_ID_ADAPTEC_AIC7880:
|
||||
case PCI_DEVICE_ID_ADAPTEC_AIC7870:
|
||||
case PCI_DEVICE_ID_ADAPTEC_AIC7860:
|
||||
case PCI_DEVICE_ID_ADAPTEC_AIC7855:
|
||||
case PCI_DEVICE_ID_ADAPTEC_AIC7850:
|
||||
case PCI_DEVICE_ID_ADAPTEC_AIC7810:
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif /* defined(__NetBSD__) */
|
||||
|
||||
#if defined(__FreeBSD__)
|
||||
static void
|
||||
aic7870_attach(config_id, unit)
|
||||
pcici_t config_id;
|
||||
int unit;
|
||||
#elif defined(__NetBSD__)
|
||||
void
|
||||
ahc_pci_attach(parent, self, aux)
|
||||
struct device *parent, *self;
|
||||
void *aux;
|
||||
#endif
|
||||
{
|
||||
#if defined(__FreeBSD__)
|
||||
u_int16_t io_port;
|
||||
struct ahc_softc *ahc;
|
||||
#elif defined(__NetBSD__)
|
||||
struct pci_attach_args *pa = aux;
|
||||
struct ahc_softc *ahc = (void *)self;
|
||||
int unit = ahc->sc_dev.dv_unit;
|
||||
bus_io_addr_t iobase;
|
||||
bus_io_size_t iosize;
|
||||
bus_io_handle_t ioh;
|
||||
pci_intr_handle_t ih;
|
||||
const char *intrstr;
|
||||
#endif
|
||||
u_int32_t id;
|
||||
u_int32_t command;
|
||||
struct scb_data *shared_scb_data;
|
||||
int opri;
|
||||
ahc_type ahc_t = AHC_NONE;
|
||||
ahc_flag ahc_f = AHC_FNONE;
|
||||
vm_offset_t vaddr;
|
||||
vm_offset_t paddr;
|
||||
u_int8_t ultra_enb = 0;
|
||||
u_int8_t our_id = 0;
|
||||
u_int8_t sxfrctl1;
|
||||
|
||||
shared_scb_data = NULL;
|
||||
vaddr = NULL;
|
||||
paddr = NULL;
|
||||
#if defined(__FreeBSD__)
|
||||
io_port = 0;
|
||||
command = pci_conf_read(config_id, PCI_COMMAND_STATUS_REG);
|
||||
#ifdef AHC_ALLOW_MEMIO
|
||||
if ((command & PCI_COMMAND_MEM_ENABLE) == 0
|
||||
|| (pci_map_mem(config_id, PCI_BASEADR1, &vaddr, &paddr)) == 0)
|
||||
#endif
|
||||
if ((command & PCI_COMMAND_IO_ENABLE) == 0
|
||||
|| (pci_map_port(config_id, PCI_BASEADR0, &io_port)) == 0)
|
||||
return;
|
||||
#elif defined(__NetBSD__)
|
||||
/* XXX Memory mapped I/O?? */
|
||||
if (bus_io_map(pa->pa_bc, iobase, iosize, &ioh))
|
||||
if (pci_io_find(pa->pa_pc, pa->pa_tag, PCI_BASEADR0, &iobase,
|
||||
&iosize))
|
||||
return;
|
||||
#endif
|
||||
|
||||
#if defined(__FreeBSD__)
|
||||
switch ((id = pci_conf_read(config_id, PCI_ID_REG))) {
|
||||
#elif defined(__NetBSD__)
|
||||
switch (id = pa->pa_id) {
|
||||
#endif
|
||||
case PCI_DEVICE_ID_ADAPTEC_398XU:
|
||||
case PCI_DEVICE_ID_ADAPTEC_398X:
|
||||
if (id == PCI_DEVICE_ID_ADAPTEC_398XU)
|
||||
ahc_t = AHC_398U;
|
||||
else
|
||||
ahc_t = AHC_398;
|
||||
switch (aic398X_count) {
|
||||
case 0:
|
||||
break;
|
||||
case 1:
|
||||
ahc_f |= AHC_CHNLB;
|
||||
break;
|
||||
case 2:
|
||||
ahc_f |= AHC_CHNLC;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
aic398X_count++;
|
||||
if (first_398X != NULL)
|
||||
#ifdef AHC_SHARE_SCBS
|
||||
shared_scb_data = first_398X->scb_data;
|
||||
#endif
|
||||
if (aic398X_count == 3) {
|
||||
/*
|
||||
* This is the last device on this RAID
|
||||
* controller, so reset our counts.
|
||||
* XXX This won't work for the multiple 3980
|
||||
* controllers since they have only 2 channels,
|
||||
* but I'm not even sure if Adaptec actually
|
||||
* went through with their plans to produce
|
||||
* this controller.
|
||||
*/
|
||||
aic398X_count = 0;
|
||||
first_398X = NULL;
|
||||
}
|
||||
break;
|
||||
case PCI_DEVICE_ID_ADAPTEC_3940U:
|
||||
case PCI_DEVICE_ID_ADAPTEC_3940:
|
||||
if (id == PCI_DEVICE_ID_ADAPTEC_3940U)
|
||||
ahc_t = AHC_394U;
|
||||
else
|
||||
ahc_t = AHC_394;
|
||||
if ((aic3940_count & 0x01) != 0)
|
||||
/* Odd count implies second channel */
|
||||
ahc_f |= AHC_CHNLB;
|
||||
aic3940_count++;
|
||||
break;
|
||||
case PCI_DEVICE_ID_ADAPTEC_2944U:
|
||||
case PCI_DEVICE_ID_ADAPTEC_2940U:
|
||||
ahc_t = AHC_294U;
|
||||
break;
|
||||
case PCI_DEVICE_ID_ADAPTEC_2944:
|
||||
case PCI_DEVICE_ID_ADAPTEC_2940:
|
||||
ahc_t = AHC_294;
|
||||
break;
|
||||
case PCI_DEVICE_ID_ADAPTEC_2940AU:
|
||||
ahc_t = AHC_294AU;
|
||||
break;
|
||||
case PCI_DEVICE_ID_ADAPTEC_AIC7880:
|
||||
ahc_t = AHC_AIC7880;
|
||||
break;
|
||||
case PCI_DEVICE_ID_ADAPTEC_AIC7870:
|
||||
ahc_t = AHC_AIC7870;
|
||||
break;
|
||||
case PCI_DEVICE_ID_ADAPTEC_AIC7860:
|
||||
ahc_t = AHC_AIC7860;
|
||||
break;
|
||||
case PCI_DEVICE_ID_ADAPTEC_AIC7855:
|
||||
case PCI_DEVICE_ID_ADAPTEC_AIC7850:
|
||||
ahc_t = AHC_AIC7850;
|
||||
break;
|
||||
case PCI_DEVICE_ID_ADAPTEC_AIC7810:
|
||||
printf("RAID functionality unsupported\n");
|
||||
return;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* On all PCI adapters, we allow SCB paging */
|
||||
ahc_f |= AHC_PAGESCBS;
|
||||
#if defined(__FreeBSD__)
|
||||
if ((ahc = ahc_alloc(unit, io_port, vaddr, ahc_t, ahc_f,
|
||||
shared_scb_data)) == NULL)
|
||||
return; /* XXX PCI code should take return status */
|
||||
#else
|
||||
ahc_construct(ahc, pa->pa_bc, ioh, ahc_t, ahc_f);
|
||||
#endif
|
||||
|
||||
/* Remeber how the card was setup in case there is no SEEPROM */
|
||||
our_id = ahc_inb(ahc, SCSIID) & OID;
|
||||
if (ahc_t & AHC_ULTRA)
|
||||
ultra_enb = ahc_inb(ahc, SXFRCTL0) & FAST20;
|
||||
sxfrctl1 = ahc_inb(ahc, SXFRCTL1) & STPWEN;
|
||||
|
||||
#if defined(__NetBSD__)
|
||||
printf("\n");
|
||||
#endif
|
||||
ahc_reset(ahc);
|
||||
|
||||
#ifdef AHC_SHARE_SCBS
|
||||
if (ahc_t & AHC_AIC7870) {
|
||||
#if defined(__FreeBSD__)
|
||||
u_int32_t devconfig = pci_conf_read(config_id, DEVCONFIG);
|
||||
#elif defined(__NetBSD__)
|
||||
u_int32_t devconfig =
|
||||
pci_conf_read(pa->pa_pc, pa->pa_tag, DEVCONFIG);
|
||||
#endif
|
||||
if (devconfig & (RAMPSM)) {
|
||||
/* XXX Assume 9bit SRAM and enable parity checking */
|
||||
devconfig |= EXTSCBPEN;
|
||||
|
||||
/* XXX Assume fast SRAM and only enable 2 cycle
|
||||
* access if we are sharing the SRAM across mutiple
|
||||
* adapters (398X adapter).
|
||||
*/
|
||||
if ((devconfig & MPORTMODE) == 0)
|
||||
/* Multi-user mode */
|
||||
devconfig |= EXTSCBTIME;
|
||||
|
||||
devconfig &= ~SCBRAMSEL;
|
||||
#if defined(__FreeBSD__)
|
||||
pci_conf_write(config_id, DEVCONFIG, devconfig);
|
||||
#elif defined(__NetBSD__)
|
||||
pci_conf_write(pa->pa_pc, pa->pa_tag,
|
||||
DEVCONFIG, devconfig);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(__FreeBSD__)
|
||||
if (!(pci_map_int(config_id, ahc_intr, (void *)ahc, &bio_imask))) {
|
||||
ahc_free(ahc);
|
||||
return;
|
||||
}
|
||||
#elif defined(__NetBSD__)
|
||||
|
||||
if (pci_intr_map(pa->pa_pc, pa->pa_intrtag, pa->pa_intrpin,
|
||||
pa->pa_intrline, &ih)) {
|
||||
printf("%s: couldn't map interrupt\n", ahc->sc_dev.dv_xname);
|
||||
ahc_free(ahc);
|
||||
return;
|
||||
}
|
||||
intrstr = pci_intr_string(pa->pa_pc, ih);
|
||||
#ifdef __OpenBSD__
|
||||
ahc->sc_ih = pci_intr_establish(pa->pa_pc, ih, IPL_BIO, ahc_intr, ahc,
|
||||
ahc->sc_dev.dv_xname);
|
||||
#else
|
||||
ahc->sc_ih = pci_intr_establish(pa->pa_pc, ih, IPL_BIO, ahc_intr, ahc);
|
||||
#endif
|
||||
if (ahc->sc_ih == NULL) {
|
||||
printf("%s: couldn't establish interrupt",
|
||||
ahc->sc_dev.dv_xname);
|
||||
if (intrstr != NULL)
|
||||
printf(" at %s", intrstr);
|
||||
printf("\n");
|
||||
ahc_free(ahc);
|
||||
return;
|
||||
}
|
||||
if (intrstr != NULL)
|
||||
printf("%s: interrupting at %s\n", ahc->sc_dev.dv_xname,
|
||||
intrstr);
|
||||
#endif
|
||||
/*
|
||||
* Protect ourself from spurrious interrupts during
|
||||
* intialization.
|
||||
*/
|
||||
opri = splbio();
|
||||
|
||||
/*
|
||||
* Do aic7880/aic7870/aic7860/aic7850 specific initialization
|
||||
*/
|
||||
{
|
||||
u_int8_t sblkctl;
|
||||
char *id_string;
|
||||
|
||||
switch(ahc->type) {
|
||||
case AHC_398U:
|
||||
case AHC_394U:
|
||||
case AHC_294U:
|
||||
case AHC_AIC7880:
|
||||
id_string = "aic7880 ";
|
||||
load_seeprom(ahc, &sxfrctl1);
|
||||
break;
|
||||
case AHC_398:
|
||||
case AHC_394:
|
||||
case AHC_294:
|
||||
case AHC_AIC7870:
|
||||
id_string = "aic7870 ";
|
||||
load_seeprom(ahc, &sxfrctl1);
|
||||
break;
|
||||
case AHC_294AU:
|
||||
case AHC_AIC7860:
|
||||
id_string = "aic7860 ";
|
||||
load_seeprom(ahc, &sxfrctl1);
|
||||
break;
|
||||
case AHC_AIC7850:
|
||||
id_string = "aic7850 ";
|
||||
/*
|
||||
* Use defaults, if the chip wasn't initialized by
|
||||
* a BIOS.
|
||||
*/
|
||||
ahc->flags |= AHC_USEDEFAULTS;
|
||||
break;
|
||||
default:
|
||||
printf("ahc: Unknown controller type. Ignoring.\n");
|
||||
ahc_free(ahc);
|
||||
splx(opri);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Take the LED out of diagnostic mode
|
||||
*/
|
||||
sblkctl = ahc_inb(ahc, SBLKCTL);
|
||||
ahc_outb(ahc, SBLKCTL, (sblkctl & ~(DIAGLEDEN|DIAGLEDON)));
|
||||
|
||||
/*
|
||||
* I don't know where this is set in the SEEPROM or by the
|
||||
* BIOS, so we default to 100%.
|
||||
*/
|
||||
ahc_outb(ahc, DSPCISTATUS, DFTHRSH_100);
|
||||
|
||||
if (ahc->flags & AHC_USEDEFAULTS) {
|
||||
/*
|
||||
* PCI Adapter default setup
|
||||
* Should only be used if the adapter does not have
|
||||
* an SEEPROM.
|
||||
*/
|
||||
/* See if someone else set us up already */
|
||||
u_int32_t i;
|
||||
for (i = TARG_SCRATCH; i < 0x60; i++) {
|
||||
if (ahc_inb(ahc, i) != 0x00)
|
||||
break;
|
||||
}
|
||||
if (i == TARG_SCRATCH) {
|
||||
/*
|
||||
* Try looking for all ones. You can get
|
||||
* either.
|
||||
*/
|
||||
for (i = TARG_SCRATCH; i < 0x60; i++) {
|
||||
if (ahc_inb(ahc, i) != 0xff)
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ((i != 0x60) && (our_id != 0)) {
|
||||
printf("%s: Using left over BIOS settings\n",
|
||||
ahc_name(ahc));
|
||||
ahc->flags &= ~AHC_USEDEFAULTS;
|
||||
} else {
|
||||
/*
|
||||
* Assume only one connector and always turn
|
||||
* on termination.
|
||||
*/
|
||||
our_id = 0x07;
|
||||
sxfrctl1 = STPWEN;
|
||||
}
|
||||
ahc_outb(ahc, SCSICONF,
|
||||
(our_id & 0x07)|ENSPCHK|RESET_SCSI);
|
||||
/* In case we are a wide card */
|
||||
ahc_outb(ahc, SCSICONF + 1, our_id);
|
||||
|
||||
if (ultra_enb == 0
|
||||
&& (ahc->flags & AHC_USEDEFAULTS) == 0) {
|
||||
/*
|
||||
* If there wasn't a BIOS or the board
|
||||
* wasn't in this mode to begin with,
|
||||
* turn off ultra.
|
||||
*/
|
||||
ahc->type &= ~AHC_ULTRA;
|
||||
}
|
||||
}
|
||||
|
||||
printf("%s: %s", ahc_name(ahc), id_string);
|
||||
}
|
||||
|
||||
/*
|
||||
* Put our termination setting into sxfrctl1 now so that the
|
||||
* generic initialization can see it.
|
||||
*/
|
||||
sxfrctl1 |= ahc_inb(ahc, SXFRCTL1);
|
||||
ahc_outb(ahc, SXFRCTL1, sxfrctl1);
|
||||
|
||||
if (ahc_init(ahc)){
|
||||
ahc_free(ahc);
|
||||
splx(opri);
|
||||
return; /* XXX PCI code should take return status */
|
||||
}
|
||||
|
||||
if ((ahc->type & AHC_398) == AHC_398) {
|
||||
/* Only set this once we've successfully probed */
|
||||
if (shared_scb_data == NULL)
|
||||
first_398X = ahc;
|
||||
}
|
||||
splx(opri);
|
||||
|
||||
ahc_attach(ahc);
|
||||
}
|
||||
|
||||
/*
|
||||
* Read the SEEPROM. Return 0 on failure
|
||||
*/
|
||||
void
|
||||
load_seeprom(ahc, sxfrctl1)
|
||||
struct ahc_softc *ahc;
|
||||
u_int8_t *sxfrctl1;
|
||||
{
|
||||
struct seeprom_descriptor sd;
|
||||
struct seeprom_config sc;
|
||||
u_int16_t *scarray = (u_int16_t *)≻
|
||||
u_int8_t scsi_conf;
|
||||
u_int8_t host_id;
|
||||
int have_seeprom;
|
||||
|
||||
#if defined(__FreeBSD__)
|
||||
sd.sd_maddr = ahc->maddr;
|
||||
if (sd.sd_maddr != NULL)
|
||||
sd.sd_maddr += SEECTL;
|
||||
sd.sd_iobase = ahc->baseport;
|
||||
if (sd.sd_iobase != 0)
|
||||
sd.sd_iobase += SEECTL;
|
||||
#elif defined(__NetBSD__)
|
||||
sd.sd_bc = ahc->sc_bc;
|
||||
sd.sd_ioh = ahc->sc_ioh;
|
||||
sd.sd_offset = SEECTL;
|
||||
#endif
|
||||
/*
|
||||
* For some multi-channel devices, the c46 is simply too
|
||||
* small to work. For the other controller types, we can
|
||||
* get our information from either SEEPROM type. Set the
|
||||
* type to start our probe with accordingly.
|
||||
*/
|
||||
if ((ahc->type & AHC_398) == AHC_398)
|
||||
sd.sd_chip = C56_66;
|
||||
else
|
||||
sd.sd_chip = C46;
|
||||
sd.sd_MS = SEEMS;
|
||||
sd.sd_RDY = SEERDY;
|
||||
sd.sd_CS = SEECS;
|
||||
sd.sd_CK = SEECK;
|
||||
sd.sd_DO = SEEDO;
|
||||
sd.sd_DI = SEEDI;
|
||||
|
||||
have_seeprom = acquire_seeprom(&sd);
|
||||
if (have_seeprom) {
|
||||
if (bootverbose)
|
||||
printf("%s: Reading SEEPROM...", ahc_name(ahc));
|
||||
|
||||
for (;;) {
|
||||
u_int start_addr;
|
||||
|
||||
start_addr = ahc->flags & (AHC_CHNLB|AHC_CHNLC);
|
||||
|
||||
have_seeprom = read_seeprom(&sd, (u_int16_t *)&sc,
|
||||
start_addr, sizeof(sc)/2);
|
||||
|
||||
if (have_seeprom) {
|
||||
/* Check checksum */
|
||||
int i;
|
||||
int maxaddr;
|
||||
u_int16_t *scarray;
|
||||
u_int16_t checksum;
|
||||
|
||||
maxaddr = (sizeof(sc)/2) - 1;
|
||||
checksum = 0;
|
||||
scarray = (u_int16_t *)≻
|
||||
|
||||
for (i = 0; i < maxaddr; i++)
|
||||
checksum = checksum + scarray[i];
|
||||
if (checksum == 0 || checksum != sc.checksum) {
|
||||
if (bootverbose && sd.sd_chip == C56_66)
|
||||
printf ("checksum error\n");
|
||||
have_seeprom = 0;
|
||||
} else {
|
||||
if (bootverbose)
|
||||
printf("done.\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (sd.sd_chip == C56_66)
|
||||
break;
|
||||
sd.sd_chip = C56_66;
|
||||
}
|
||||
}
|
||||
release_seeprom(&sd);
|
||||
if (!have_seeprom) {
|
||||
if (bootverbose)
|
||||
printf("\n%s: No SEEPROM available\n", ahc_name(ahc));
|
||||
ahc->flags |= AHC_USEDEFAULTS;
|
||||
} else {
|
||||
/*
|
||||
* Put the data we've collected down into SRAM
|
||||
* where ahc_init will find it.
|
||||
*/
|
||||
int i;
|
||||
int max_targ = sc.max_targets & CFMAXTARG;
|
||||
|
||||
for (i = 0; i < max_targ; i++){
|
||||
u_char target_settings;
|
||||
target_settings = (sc.device_flags[i] & CFXFER) << 4;
|
||||
if (sc.device_flags[i] & CFSYNCH)
|
||||
target_settings |= SOFS;
|
||||
if (sc.device_flags[i] & CFWIDEB)
|
||||
target_settings |= WIDEXFER;
|
||||
if (sc.device_flags[i] & CFDISC)
|
||||
ahc->discenable |= (0x01 << i);
|
||||
ahc_outb(ahc, TARG_SCRATCH+i, target_settings);
|
||||
}
|
||||
ahc_outb(ahc, DISC_DSB, ~(ahc->discenable & 0xff));
|
||||
ahc_outb(ahc, DISC_DSB + 1, ~((ahc->discenable >> 8) & 0xff));
|
||||
|
||||
host_id = sc.brtime_id & CFSCSIID;
|
||||
|
||||
scsi_conf = (host_id & 0x7);
|
||||
if (sc.adapter_control & CFSPARITY)
|
||||
scsi_conf |= ENSPCHK;
|
||||
if (sc.adapter_control & CFRESETB)
|
||||
scsi_conf |= RESET_SCSI;
|
||||
|
||||
/*
|
||||
* Update the settings in sxfrctl1 to match the
|
||||
*termination settings
|
||||
*/
|
||||
*sxfrctl1 = 0;
|
||||
if (sc.adapter_control & CFAUTOTERM) {
|
||||
/* Play around with the memory port */
|
||||
have_seeprom = acquire_seeprom(&sd);
|
||||
if (have_seeprom) {
|
||||
u_int8_t brdctl;
|
||||
u_int8_t seectl;
|
||||
int internal50_present;
|
||||
int internal68_present;
|
||||
int external68_present;
|
||||
int eprom_present;
|
||||
int high_on;
|
||||
int low_on;
|
||||
|
||||
seectl = sd.sd_CS|sd.sd_MS;
|
||||
SEEPROM_OUTB(&sd, seectl);
|
||||
/*
|
||||
* First read the status of our cables.
|
||||
* Set the rom bank to 0 since the
|
||||
* bank setting serves as a multiplexor
|
||||
* for the cable detection logic.
|
||||
* BRDDAT5 controls the bank switch.
|
||||
*/
|
||||
write_brdctl(ahc, 0);
|
||||
|
||||
/*
|
||||
* Now read the state of the internal
|
||||
* connectors. BRDDAT6 is INT50 and
|
||||
* BRDDAT7 is INT68.
|
||||
*/
|
||||
brdctl = read_brdctl(ahc);
|
||||
internal50_present = !(brdctl & BRDDAT6);
|
||||
internal68_present = !(brdctl & BRDDAT7)
|
||||
&& (max_targ > 8);
|
||||
if (bootverbose) {
|
||||
printf("internal50 cable %s present\n"
|
||||
"internal68 cable %s present\n"
|
||||
"brdctl == 0x%x\n",
|
||||
internal50_present ? "is":"not",
|
||||
internal68_present ? "is":"not",
|
||||
brdctl);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the rom bank to 1 and determine
|
||||
* the other signals.
|
||||
*/
|
||||
write_brdctl(ahc, BRDDAT5);
|
||||
|
||||
/*
|
||||
* Now read the state of the external
|
||||
* connectors. BRDDAT6 is EXT68 and
|
||||
* BRDDAT7 is EPROMPS.
|
||||
*/
|
||||
brdctl = read_brdctl(ahc);
|
||||
external68_present = !(brdctl & BRDDAT6);
|
||||
eprom_present = brdctl & BRDDAT7;
|
||||
if (bootverbose) {
|
||||
printf("external cable %s present\n"
|
||||
"eprom %s present\n"
|
||||
"brdctl == 0x%x\n",
|
||||
external68_present ? "is":"not",
|
||||
eprom_present ? "is" : "not",
|
||||
brdctl);
|
||||
}
|
||||
|
||||
/*
|
||||
* Now set the termination based on what
|
||||
* we found. BRDDAT6 controls wide
|
||||
* termination enable.
|
||||
*/
|
||||
high_on = FALSE;
|
||||
low_on = FALSE;
|
||||
if ((max_targ > 8)
|
||||
&& ((external68_present == 0)
|
||||
|| (internal68_present == 0)))
|
||||
high_on = TRUE;
|
||||
|
||||
if (((internal50_present ? 1 : 0)
|
||||
+ (internal68_present ? 1 : 0)
|
||||
+ (external68_present ? 1 : 0)) <= 1)
|
||||
low_on = TRUE;
|
||||
|
||||
if ((internal50_present != 0)
|
||||
&& (internal68_present != 0)
|
||||
&& (external68_present != 0)) {
|
||||
printf("Illegal cable configuration!!. "
|
||||
"Only two connectors on the "
|
||||
"adapter may be used at a "
|
||||
"time!");
|
||||
}
|
||||
|
||||
if (high_on == TRUE)
|
||||
write_brdctl(ahc, BRDDAT6);
|
||||
else
|
||||
write_brdctl(ahc, 0);
|
||||
|
||||
if (low_on == TRUE)
|
||||
*sxfrctl1 |= STPWEN;
|
||||
|
||||
if (bootverbose) {
|
||||
printf("low byte termination %s, "
|
||||
"high byte termination %s\n",
|
||||
low_on ? "enabled":"disabled",
|
||||
high_on ? "enabled":"disabled");
|
||||
}
|
||||
}
|
||||
release_seeprom(&sd);
|
||||
} else {
|
||||
if (sc.adapter_control & CFSTERM)
|
||||
*sxfrctl1 |= STPWEN;
|
||||
have_seeprom = acquire_seeprom(&sd);
|
||||
if (have_seeprom) {
|
||||
SEEPROM_OUTB(&sd, sd.sd_CS|sd.sd_MS);
|
||||
if (sc.adapter_control & CFWSTERM)
|
||||
write_brdctl(ahc, BRDDAT6);
|
||||
else
|
||||
write_brdctl(ahc, 0);
|
||||
release_seeprom(&sd);
|
||||
} else
|
||||
printf("Unabled to configure high byte "
|
||||
"termination!\n");
|
||||
|
||||
if (bootverbose) {
|
||||
printf("low byte termination %s, "
|
||||
"high byte termination %s\n",
|
||||
sc.adapter_control & CFSTERM ?
|
||||
"enabled":"disabled",
|
||||
sc.adapter_control & CFWSTERM ?
|
||||
"enabled":"disabled");
|
||||
}
|
||||
}
|
||||
|
||||
if (ahc->type & AHC_ULTRA) {
|
||||
/* Should we enable Ultra mode? */
|
||||
if (!(sc.adapter_control & CFULTRAEN))
|
||||
/* Treat us as a non-ultra card */
|
||||
ahc->type &= ~AHC_ULTRA;
|
||||
}
|
||||
/* Set the host ID */
|
||||
ahc_outb(ahc, SCSICONF, scsi_conf);
|
||||
/* In case we are a wide card */
|
||||
ahc_outb(ahc, SCSICONF + 1, host_id);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
acquire_seeprom(sd)
|
||||
struct seeprom_descriptor *sd;
|
||||
{
|
||||
int wait;
|
||||
|
||||
/*
|
||||
* Request access of the memory port. When access is
|
||||
* granted, SEERDY will go high. We use a 1 second
|
||||
* timeout which should be near 1 second more than
|
||||
* is needed. Reason: after the chip reset, there
|
||||
* should be no contention.
|
||||
*/
|
||||
SEEPROM_OUTB(sd, sd->sd_MS);
|
||||
wait = 1000; /* 1 second timeout in msec */
|
||||
while (--wait && ((SEEPROM_INB(sd) & sd->sd_RDY) == 0)) {
|
||||
DELAY (1000); /* delay 1 msec */
|
||||
}
|
||||
if ((SEEPROM_INB(sd) & sd->sd_RDY) == 0) {
|
||||
SEEPROM_OUTB(sd, 0);
|
||||
return (0);
|
||||
}
|
||||
return(1);
|
||||
}
|
||||
|
||||
static void
|
||||
release_seeprom(sd)
|
||||
struct seeprom_descriptor *sd;
|
||||
{
|
||||
/* Release access to the memory port and the serial EEPROM. */
|
||||
SEEPROM_OUTB(sd, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
write_brdctl(ahc, value)
|
||||
struct ahc_softc *ahc;
|
||||
u_int8_t value;
|
||||
{
|
||||
u_int8_t brdctl;
|
||||
|
||||
brdctl = BRDCS|BRDSTB;
|
||||
ahc_outb(ahc, BRDCTL, brdctl);
|
||||
brdctl |= value;
|
||||
ahc_outb(ahc, BRDCTL, brdctl);
|
||||
brdctl &= ~BRDSTB;
|
||||
ahc_outb(ahc, BRDCTL, brdctl);
|
||||
brdctl &= ~BRDCS;
|
||||
ahc_outb(ahc, BRDCTL, brdctl);
|
||||
}
|
||||
|
||||
static u_int8_t
|
||||
read_brdctl(ahc)
|
||||
struct ahc_softc *ahc;
|
||||
{
|
||||
ahc_outb(ahc, BRDCTL, BRDRW|BRDCS);
|
||||
return ahc_inb(ahc, BRDCTL);
|
||||
}
|
||||
|
||||
#endif /* NPCI > 0 */
|
117
sys/pci/bt9xx.c
117
sys/pci/bt9xx.c
@ -1,117 +0,0 @@
|
||||
/*
|
||||
* Product specific probe and attach routines for:
|
||||
* Buslogic BT946 and BT956 SCSI controllers
|
||||
*
|
||||
* Copyright (c) 1995 Justin T. Gibbs
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice immediately at the beginning of the file, without modification,
|
||||
* this list of conditions, and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Absolutely no warranty of function or purpose is made by the author
|
||||
* Justin T. Gibbs.
|
||||
* 4. Modifications may be freely made to this file if the above conditions
|
||||
* are met.
|
||||
*
|
||||
* $Id: bt9xx.c,v 1.10 1997/02/22 09:44:00 peter Exp $
|
||||
*/
|
||||
|
||||
#include "pci.h"
|
||||
#if NPCI > 0
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <scsi/scsiconf.h>
|
||||
#include <pci/pcireg.h>
|
||||
#include <pci/pcivar.h>
|
||||
#include <i386/scsi/btreg.h>
|
||||
|
||||
/* XXX Need more device IDs */
|
||||
#define PCI_DEVICE_ID_BUSLOGIC_946 0x1040104Bul
|
||||
#define PCI_DEVICE_ID_BUSLOGIC_946_OLD 0x0140104Bul
|
||||
|
||||
static char* bt_pci_probe __P((pcici_t tag, pcidi_t type));
|
||||
static void bt_pci_attach __P((pcici_t config_id, int unit));
|
||||
|
||||
static struct pci_device bt_pci_driver = {
|
||||
"bt",
|
||||
bt_pci_probe,
|
||||
bt_pci_attach,
|
||||
&bt_unit,
|
||||
NULL
|
||||
};
|
||||
|
||||
DATA_SET (pcidevice_set, bt_pci_driver);
|
||||
|
||||
static char*
|
||||
bt_pci_probe (pcici_t tag, pcidi_t type)
|
||||
{
|
||||
switch(type) {
|
||||
case PCI_DEVICE_ID_BUSLOGIC_946_OLD:
|
||||
case PCI_DEVICE_ID_BUSLOGIC_946:
|
||||
return ("Buslogic 946 SCSI host adapter");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return (0);
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
bt_pci_attach(config_id, unit)
|
||||
pcici_t config_id;
|
||||
int unit;
|
||||
{
|
||||
u_char reg;
|
||||
u_long io_port;
|
||||
unsigned opri = 0;
|
||||
struct bt_data *bt;
|
||||
|
||||
for(reg = PCI_MAP_REG_START; reg < PCI_MAP_REG_END; reg+=4) {
|
||||
io_port = pci_conf_read(config_id, reg);
|
||||
if ((io_port&~7)==0) continue;
|
||||
if(io_port & PCI_MAP_IO) {
|
||||
io_port &= ~PCI_MAP_IO;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(reg == PCI_MAP_REG_END)
|
||||
return;
|
||||
|
||||
if(!(bt = bt_alloc(unit, io_port)))
|
||||
return; /* XXX PCI code should take return status */
|
||||
|
||||
if(!(pci_map_int(config_id, bt_intr, (void *)bt, &bio_imask))) {
|
||||
bt_free(bt);
|
||||
return;
|
||||
}
|
||||
/*
|
||||
* Protect ourself from spurrious interrupts during
|
||||
* intialization and attach. We should really rely
|
||||
* on interrupts during attach, but we don't have
|
||||
* access to our interrupts during ISA probes, so until
|
||||
* that changes, we mask our interrupts during attach
|
||||
* too.
|
||||
*/
|
||||
opri = splbio();
|
||||
|
||||
if(bt_init(bt)){
|
||||
bt_free(bt);
|
||||
splx(opri);
|
||||
return; /* XXX PCI code should take return status */
|
||||
}
|
||||
|
||||
bt_attach(bt);
|
||||
|
||||
splx(opri);
|
||||
return;
|
||||
}
|
||||
|
||||
#endif /* NPCI > 0 */
|
203
sys/scsi/README
203
sys/scsi/README
@ -1,203 +0,0 @@
|
||||
WARNING: This file was not fully updated by dufault@hda.com when
|
||||
changing the configuration. See the end for new notes.
|
||||
|
||||
This release consists of the following files
|
||||
(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
|
||||
|
||||
|
||||
----------------------------------------------------------------
|
||||
This scsi system is designed to allow the re-use of top end drivers
|
||||
such as disk and tape drivers, with different scsi adapters.
|
||||
|
||||
As of writing this document, There are top end drivers working for:
|
||||
----------------------------------------------------------------
|
||||
generic scsi disk
|
||||
generic scsi tape
|
||||
cd-rom (plays music under the xcplayer (?) program)
|
||||
AEG Character recognition devices *
|
||||
Calera Character recognition devices *
|
||||
Generic scsi-II scanners *
|
||||
Exabyte tape changer device.
|
||||
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 (445S?))(and 747?)
|
||||
adaptec 174x (note NOT 27xx)
|
||||
Ultrastore 14f (works for 34f (VESA version))
|
||||
Ultrastore 24f RSN (Beta version included here)
|
||||
----------------------------------------------------------------
|
||||
|
||||
|
||||
################## Using the scsi system ##################
|
||||
------------minor numbers---------------
|
||||
This scsi system does not allocate minor numbers to devices depending
|
||||
on their SCSI IDs is any way. A devices minor number is dependant
|
||||
on the order in which it was found.
|
||||
e.g. the first tape found will become st0 (minor number 0)
|
||||
the second found will become st1 (minor number 16)
|
||||
the third will become st2 (minor 32)
|
||||
etc.
|
||||
|
||||
These devices could be on the same scsi bus or different scsi busses.
|
||||
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 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.
|
||||
|
||||
|
||||
--------------making devices------------
|
||||
A changed version of /dev/MAKEDEV is supplied that
|
||||
can be used to make devices sd[01234] and st[01234]
|
||||
|
||||
e.g.
|
||||
cd /dev
|
||||
sh MAKEDEV sd0 sd1 sd2 st0 st1 cd0
|
||||
|
||||
see st(1) and st(4) for info on tape devices.
|
||||
|
||||
--------------file layout-------------------
|
||||
Originally I had all scsi definitions in one file: scsi.h
|
||||
I have since moved definitions of commands so that all
|
||||
definitions needed for a particular type of device are
|
||||
found together in the include file of that name.
|
||||
This approximatly follows the layout of their definition
|
||||
in the SCSI-2 spec.
|
||||
As such they are:
|
||||
|
||||
scsi_all.h general commands for all devices --- CHAPTER 7
|
||||
scsi-disk.h commands relevant to disk --- CHAPTER 8
|
||||
scsi-tape.h commands for scsi tapes --- CHAPTER 9
|
||||
scsi-cd.h commands for cd-roms (and audio) --- CHAPTER 13
|
||||
scsi-changer.h commands medium changer devices --- CHAPTER 16
|
||||
|
||||
---------ioctl definitions-------------
|
||||
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@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@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
|
||||
and program.
|
||||
|
||||
WARNING: This has not been tested for a LONG TIME!
|
||||
|
||||
|
||||
---------recent changes-----------
|
||||
Removed all bitfields from machine independent sections to make
|
||||
it possible for them to be used on big-endian architectures.
|
||||
|
||||
Removed scsi specific timeouts in favour of system timeout handling.
|
||||
|
||||
Many structures (getting more all the time) now dynamically allocated.
|
||||
|
||||
Addition of code in the tape driver to recognise models of drive that
|
||||
have particular problems so they can be handled specially.
|
||||
|
||||
many bug-fixes and cleanups.
|
||||
|
||||
---------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.
|
||||
|
||||
------Tue Feb 28 07:43:17 EST 1995-----
|
||||
dufault@hda.com: Redid configuration to support wired devices.
|
||||
All driver entries now get bounced directly into the routines in
|
||||
"scsi_driver" via a set of functions generated by the SCSI_ENTRIES macro
|
||||
in scsi_conf.h. This lets us put the common code in a single place.
|
1419
sys/scsi/cd.c
1419
sys/scsi/cd.c
File diff suppressed because it is too large
Load Diff
750
sys/scsi/ch.c
750
sys/scsi/ch.c
@ -1,750 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 1996 Jason R. Thorpe <thorpej@and.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Partially based on an autochanger driver written by Stefan Grefen
|
||||
* and on an autochanger driver written by the Systems Programming Group
|
||||
* at the University of Utah Computer Science Department.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgements:
|
||||
* This product includes software developed by Jason R. Thorpe
|
||||
* for And Communications, http://www.and.com/
|
||||
* 4. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id: ch.c,v 1.47 1998/06/17 14:13:13 bde Exp $
|
||||
*/
|
||||
|
||||
#include "opt_devfs.h"
|
||||
#include "opt_bounce.h"
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/chio.h>
|
||||
#include <sys/conf.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/malloc.h>
|
||||
#ifdef DEVFS
|
||||
#include <sys/devfsext.h>
|
||||
#endif /*DEVFS*/
|
||||
#ifdef BOUNCE_BUFFERS
|
||||
#include <sys/buf.h>
|
||||
#endif
|
||||
|
||||
#include <scsi/scsi_changer.h>
|
||||
#include <scsi/scsiconf.h>
|
||||
#include <scsi/scsi_driver.h>
|
||||
|
||||
#include "ioconf.h"
|
||||
|
||||
#define CHRETRIES 2
|
||||
#define CHUNIT(x) (minor((x)))
|
||||
#define CHSETUNIT(x, y) makedev(major(x), y)
|
||||
|
||||
struct ch_softc {
|
||||
/*
|
||||
* Human-readable external name. FreeBSD doesn't have a
|
||||
* generic hook for this, so we make it look NetBSD-like. See
|
||||
* comment in chattach().
|
||||
*/
|
||||
struct {
|
||||
char dv_xname[16];
|
||||
} sc_dev;
|
||||
|
||||
/*
|
||||
* Pointer back to the scsi_link. See comment in chattach().
|
||||
*/
|
||||
struct scsi_link *sc_link;
|
||||
|
||||
int sc_picker; /* current picker */
|
||||
|
||||
/*
|
||||
* The following information is obtained from the
|
||||
* element address assignment page.
|
||||
*/
|
||||
int sc_firsts[4]; /* firsts, indexed by CHET_* */
|
||||
int sc_counts[4]; /* counts, indexed by CHET_* */
|
||||
|
||||
/*
|
||||
* The following mask defines the legal combinations
|
||||
* of elements for the MOVE MEDIUM command.
|
||||
*/
|
||||
u_int8_t sc_movemask[4];
|
||||
|
||||
/*
|
||||
* As above, but for EXCHANGE MEDIUM.
|
||||
*/
|
||||
u_int8_t sc_exchangemask[4];
|
||||
|
||||
int flags; /* misc. info */
|
||||
#ifdef DEVFS
|
||||
void *c_devfs_token;
|
||||
void *ctl_devfs_token;
|
||||
#endif
|
||||
};
|
||||
|
||||
/* sc_flags */
|
||||
#define CHF_ROTATE 0x01 /* picker can rotate */
|
||||
|
||||
static d_open_t chopen;
|
||||
static d_close_t chclose;
|
||||
static d_ioctl_t chioctl;
|
||||
|
||||
#define CDEV_MAJOR 17
|
||||
static struct cdevsw ch_cdevsw =
|
||||
{ chopen, chclose, noread, nowrite, /*17*/
|
||||
chioctl, nostop, nullreset, nodevtotty,/* ch */
|
||||
seltrue, nommap, nostrat, "ch", NULL, -1 };
|
||||
|
||||
/*
|
||||
* SCSI glue.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Under FreeBSD, this macro sets up a bunch of trampoline
|
||||
* functions that indirect through the SCSI subsystem.
|
||||
*/
|
||||
SCSI_DEVICE_ENTRIES(ch)
|
||||
|
||||
static int chunit __P((dev_t));
|
||||
static dev_t chsetunit __P((dev_t, int));
|
||||
|
||||
/* So, like, why not "int"? */
|
||||
static errval ch_devopen __P((dev_t, int, int, struct proc *,
|
||||
struct scsi_link *));
|
||||
static errval ch_devioctl __P((dev_t, u_long, caddr_t, int, struct proc *,
|
||||
struct scsi_link *));
|
||||
static errval ch_devclose __P((dev_t, int, int, struct proc *,
|
||||
struct scsi_link *));
|
||||
|
||||
static struct scsi_device ch_switch = {
|
||||
NULL, /* (*err_handler) */
|
||||
NULL, /* (*start) */
|
||||
NULL, /* (*async) */
|
||||
NULL, /* (*done) */
|
||||
"ch", /* name */
|
||||
0, /* flags */
|
||||
{ 0, 0 }, /* spare[2] */
|
||||
0, /* link_flags */
|
||||
chattach, /* (*attach) */
|
||||
"Medium-Changer", /* desc */
|
||||
chopen, /* (*open) */
|
||||
sizeof(struct ch_softc), /* sizeof_scsi_data */
|
||||
T_CHANGER, /* type */
|
||||
chunit, /* (*getunit) */
|
||||
chsetunit, /* (*setunit) */
|
||||
ch_devopen, /* (*dev_open) */
|
||||
ch_devioctl, /* (*dev_ioctl) */
|
||||
ch_devclose, /* (*dev_close) */
|
||||
};
|
||||
|
||||
static int ch_move __P((struct ch_softc *, struct changer_move *));
|
||||
static int ch_exchange __P((struct ch_softc *, struct changer_exchange *));
|
||||
static int ch_position __P((struct ch_softc *, struct changer_position *));
|
||||
static int ch_usergetelemstatus __P((struct ch_softc *, int, u_int8_t *));
|
||||
static int ch_getelemstatus __P((struct ch_softc *, int, int, caddr_t, size_t));
|
||||
static int ch_get_params __P((struct ch_softc *, int));
|
||||
|
||||
static errval
|
||||
chattach(link)
|
||||
struct scsi_link *link;
|
||||
{
|
||||
struct ch_softc *sc = (struct ch_softc *)(link->sd);
|
||||
u_int32_t unit = link->dev_unit;
|
||||
|
||||
/*
|
||||
* FreeBSD doesn't have any common way of carrying
|
||||
* around a device's external name (i.e. <name><unit>),
|
||||
* so emulate the structure used by NetBSD to keep the
|
||||
* diffs lower.
|
||||
*/
|
||||
bzero(sc->sc_dev.dv_xname, sizeof(sc->sc_dev.dv_xname));
|
||||
sprintf(sc->sc_dev.dv_xname, "%s%d", ch_switch.name, unit);
|
||||
|
||||
/*
|
||||
* FreeBSD gets "softc" info for a device from the
|
||||
* scsi_link argument passed to indirect entry point functions.
|
||||
* NetBSD get scsi_link info from softcs that are
|
||||
* obtained from indexes passed to direct entry point functions.
|
||||
* We emulate the NetBSD behavior here to keep the diffs
|
||||
* lower.
|
||||
*/
|
||||
sc->sc_link = link;
|
||||
|
||||
/*
|
||||
* Get information about the device. Note we can't use
|
||||
* interrupts yet.
|
||||
*/
|
||||
if (ch_get_params(sc, SCSI_NOSLEEP|SCSI_NOMASK))
|
||||
printf("offline");
|
||||
else {
|
||||
printf("%d slot%s, %d drive%s, %d picker%s",
|
||||
sc->sc_counts[CHET_ST], (sc->sc_counts[CHET_ST] > 1) ?
|
||||
"s" : "",
|
||||
sc->sc_counts[CHET_DT], (sc->sc_counts[CHET_DT] > 1) ?
|
||||
"s" : "",
|
||||
sc->sc_counts[CHET_MT], (sc->sc_counts[CHET_MT] > 1) ?
|
||||
"s" : "");
|
||||
if (sc->sc_counts[CHET_IE])
|
||||
printf(", %d portal%s", sc->sc_counts[CHET_IE],
|
||||
(sc->sc_counts[CHET_IE] > 1) ? "s" : "");
|
||||
if (bootverbose) {
|
||||
printf("\n"); /* This will probably look ugly ... bummer. */
|
||||
printf("%s: move mask: 0x%x 0x%x 0x%x 0x%x\n",
|
||||
sc->sc_dev.dv_xname,
|
||||
sc->sc_movemask[CHET_MT], sc->sc_movemask[CHET_ST],
|
||||
sc->sc_movemask[CHET_IE], sc->sc_movemask[CHET_DT]);
|
||||
printf("%s: exchange mask: 0x%x 0x%x 0x%x 0x%x\n",
|
||||
sc->sc_dev.dv_xname,
|
||||
sc->sc_exchangemask[CHET_MT], sc->sc_exchangemask[CHET_ST],
|
||||
sc->sc_exchangemask[CHET_IE], sc->sc_exchangemask[CHET_DT]);
|
||||
}
|
||||
}
|
||||
|
||||
/* Default the current picker. */
|
||||
sc->sc_picker = sc->sc_firsts[CHET_MT];
|
||||
|
||||
#ifdef DEVFS
|
||||
sc->c_devfs_token = devfs_add_devswf(&ch_cdevsw, unit << 4, DV_CHR,
|
||||
UID_ROOT, GID_OPERATOR, 0600,
|
||||
"ch%d", unit);
|
||||
sc->ctl_devfs_token = devfs_add_devswf(&ch_cdevsw,
|
||||
(unit << 4) | SCSI_CONTROL_MASK,
|
||||
DV_CHR,
|
||||
UID_ROOT, GID_OPERATOR, 0600,
|
||||
"ch%d.ctl", unit);
|
||||
#endif
|
||||
return (0);
|
||||
}
|
||||
|
||||
static errval
|
||||
ch_devopen(dev, flags, fmt, p, link)
|
||||
dev_t dev;
|
||||
int flags, fmt;
|
||||
struct proc *p;
|
||||
struct scsi_link *link;
|
||||
{
|
||||
struct ch_softc *sc = (struct ch_softc *)(link->sd);
|
||||
errval error = 0;
|
||||
int unit;
|
||||
|
||||
unit = CHUNIT(dev);
|
||||
|
||||
/*
|
||||
* Only allow one open at a time.
|
||||
*/
|
||||
if (link->flags & SDEV_OPEN)
|
||||
return (EBUSY);
|
||||
|
||||
link->flags |= SDEV_OPEN;
|
||||
|
||||
/*
|
||||
* Absorb any unit attention errors. Ignore "not ready"
|
||||
* since this might occur if e.g. a tape isn't actually
|
||||
* loaded in the drive.
|
||||
*/
|
||||
(void)scsi_test_unit_ready(link, SCSI_SILENT);
|
||||
|
||||
/*
|
||||
* Make sure our parameters are up to date.
|
||||
*/
|
||||
if (error = ch_get_params(sc, 0))
|
||||
goto bad;
|
||||
|
||||
return (0);
|
||||
|
||||
bad:
|
||||
link->flags &= ~SDEV_OPEN;
|
||||
return (error);
|
||||
}
|
||||
|
||||
static errval
|
||||
ch_devclose(dev, flags, fmt, p, link)
|
||||
dev_t dev;
|
||||
int flags, fmt;
|
||||
struct proc *p;
|
||||
struct scsi_link *link;
|
||||
{
|
||||
|
||||
link->flags &= ~SDEV_OPEN;
|
||||
return (0);
|
||||
}
|
||||
|
||||
static errval
|
||||
ch_devioctl(dev, cmd, data, flags, p, link)
|
||||
dev_t dev;
|
||||
u_long cmd;
|
||||
caddr_t data;
|
||||
int flags;
|
||||
struct proc *p;
|
||||
struct scsi_link *link;
|
||||
{
|
||||
struct ch_softc *sc = (struct ch_softc *)(link->sd);
|
||||
caddr_t elemdata;
|
||||
int error = 0;
|
||||
|
||||
switch (cmd) {
|
||||
case CHIOMOVE:
|
||||
error = ch_move(sc, (struct changer_move *)data);
|
||||
break;
|
||||
|
||||
case CHIOEXCHANGE:
|
||||
error = ch_exchange(sc, (struct changer_exchange *)data);
|
||||
break;
|
||||
|
||||
case CHIOPOSITION:
|
||||
error = ch_position(sc, (struct changer_position *)data);
|
||||
break;
|
||||
|
||||
case CHIOGPICKER:
|
||||
*(int *)data = sc->sc_picker - sc->sc_firsts[CHET_MT];
|
||||
break;
|
||||
|
||||
case CHIOSPICKER: {
|
||||
int new_picker = *(int *)data;
|
||||
|
||||
if (new_picker > (sc->sc_counts[CHET_MT] - 1))
|
||||
return (EINVAL);
|
||||
sc->sc_picker = sc->sc_firsts[CHET_MT] + new_picker;
|
||||
break; }
|
||||
|
||||
case CHIOGPARAMS: {
|
||||
struct changer_params *cp = (struct changer_params *)data;
|
||||
|
||||
cp->cp_curpicker = sc->sc_picker - sc->sc_firsts[CHET_MT];
|
||||
cp->cp_npickers = sc->sc_counts[CHET_MT];
|
||||
cp->cp_nslots = sc->sc_counts[CHET_ST];
|
||||
cp->cp_nportals = sc->sc_counts[CHET_IE];
|
||||
cp->cp_ndrives = sc->sc_counts[CHET_DT];
|
||||
break; }
|
||||
|
||||
case CHIOGSTATUS: {
|
||||
struct changer_element_status *ces =
|
||||
(struct changer_element_status *)data;
|
||||
|
||||
error = ch_usergetelemstatus(sc, ces->ces_type, ces->ces_data);
|
||||
break; }
|
||||
|
||||
/* Implement prevent/allow? */
|
||||
|
||||
default:
|
||||
error = scsi_do_ioctl(dev, cmd, data, flags, p, link);
|
||||
break;
|
||||
}
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
static int
|
||||
ch_move(sc, cm)
|
||||
struct ch_softc *sc;
|
||||
struct changer_move *cm;
|
||||
{
|
||||
struct scsi_move_medium cmd;
|
||||
u_int16_t fromelem, toelem;
|
||||
|
||||
/*
|
||||
* Check arguments.
|
||||
*/
|
||||
if ((cm->cm_fromtype > CHET_DT) || (cm->cm_totype > CHET_DT))
|
||||
return (EINVAL);
|
||||
if ((cm->cm_fromunit > (sc->sc_counts[cm->cm_fromtype] - 1)) ||
|
||||
(cm->cm_tounit > (sc->sc_counts[cm->cm_totype] - 1)))
|
||||
return (ENODEV);
|
||||
|
||||
/*
|
||||
* Check the request against the changer's capabilities.
|
||||
*/
|
||||
if ((sc->sc_movemask[cm->cm_fromtype] & (1 << cm->cm_totype)) == 0)
|
||||
return (EINVAL);
|
||||
|
||||
/*
|
||||
* Calculate the source and destination elements.
|
||||
*/
|
||||
fromelem = sc->sc_firsts[cm->cm_fromtype] + cm->cm_fromunit;
|
||||
toelem = sc->sc_firsts[cm->cm_totype] + cm->cm_tounit;
|
||||
|
||||
/*
|
||||
* Build the SCSI command.
|
||||
*/
|
||||
bzero(&cmd, sizeof(cmd));
|
||||
cmd.opcode = MOVE_MEDIUM;
|
||||
scsi_uto2b(sc->sc_picker, cmd.tea);
|
||||
scsi_uto2b(fromelem, cmd.src);
|
||||
scsi_uto2b(toelem, cmd.dst);
|
||||
if (cm->cm_flags & CM_INVERT)
|
||||
cmd.flags |= MOVE_MEDIUM_INVERT;
|
||||
|
||||
/*
|
||||
* Send command to changer.
|
||||
*/
|
||||
return (scsi_scsi_cmd(sc->sc_link, (struct scsi_generic *)&cmd,
|
||||
sizeof(cmd), NULL, 0, CHRETRIES, 100000, NULL, 0));
|
||||
}
|
||||
|
||||
static int
|
||||
ch_exchange(sc, ce)
|
||||
struct ch_softc *sc;
|
||||
struct changer_exchange *ce;
|
||||
{
|
||||
struct scsi_exchange_medium cmd;
|
||||
u_int16_t src, dst1, dst2;
|
||||
|
||||
/*
|
||||
* Check arguments.
|
||||
*/
|
||||
if ((ce->ce_srctype > CHET_DT) || (ce->ce_fdsttype > CHET_DT) ||
|
||||
(ce->ce_sdsttype > CHET_DT))
|
||||
return (EINVAL);
|
||||
if ((ce->ce_srcunit > (sc->sc_counts[ce->ce_srctype] - 1)) ||
|
||||
(ce->ce_fdstunit > (sc->sc_counts[ce->ce_fdsttype] - 1)) ||
|
||||
(ce->ce_sdstunit > (sc->sc_counts[ce->ce_sdsttype] - 1)))
|
||||
return (ENODEV);
|
||||
|
||||
/*
|
||||
* Check the request against the changer's capabilities.
|
||||
*/
|
||||
if (((sc->sc_exchangemask[ce->ce_srctype] &
|
||||
(1 << ce->ce_fdsttype)) == 0) ||
|
||||
((sc->sc_exchangemask[ce->ce_fdsttype] &
|
||||
(1 << ce->ce_sdsttype)) == 0))
|
||||
return (EINVAL);
|
||||
|
||||
/*
|
||||
* Calculate the source and destination elements.
|
||||
*/
|
||||
src = sc->sc_firsts[ce->ce_srctype] + ce->ce_srcunit;
|
||||
dst1 = sc->sc_firsts[ce->ce_fdsttype] + ce->ce_fdstunit;
|
||||
dst2 = sc->sc_firsts[ce->ce_sdsttype] + ce->ce_sdstunit;
|
||||
|
||||
/*
|
||||
* Build the SCSI command.
|
||||
*/
|
||||
bzero(&cmd, sizeof(cmd));
|
||||
cmd.opcode = EXCHANGE_MEDIUM;
|
||||
scsi_uto2b(sc->sc_picker, cmd.tea);
|
||||
scsi_uto2b(src, cmd.src);
|
||||
scsi_uto2b(dst1, cmd.fdst);
|
||||
scsi_uto2b(dst2, cmd.sdst);
|
||||
if (ce->ce_flags & CE_INVERT1)
|
||||
cmd.flags |= EXCHANGE_MEDIUM_INV1;
|
||||
if (ce->ce_flags & CE_INVERT2)
|
||||
cmd.flags |= EXCHANGE_MEDIUM_INV2;
|
||||
|
||||
/*
|
||||
* Send command to changer.
|
||||
*/
|
||||
return (scsi_scsi_cmd(sc->sc_link, (struct scsi_generic *)&cmd,
|
||||
sizeof(cmd), NULL, 0, CHRETRIES, 100000, NULL, 0));
|
||||
}
|
||||
|
||||
static int
|
||||
ch_position(sc, cp)
|
||||
struct ch_softc *sc;
|
||||
struct changer_position *cp;
|
||||
{
|
||||
struct scsi_position_to_element cmd;
|
||||
u_int16_t dst;
|
||||
|
||||
/*
|
||||
* Check arguments.
|
||||
*/
|
||||
if (cp->cp_type > CHET_DT)
|
||||
return (EINVAL);
|
||||
if (cp->cp_unit > (sc->sc_counts[cp->cp_type] - 1))
|
||||
return (ENODEV);
|
||||
|
||||
/*
|
||||
* Calculate the destination element.
|
||||
*/
|
||||
dst = sc->sc_firsts[cp->cp_type] + cp->cp_unit;
|
||||
|
||||
/*
|
||||
* Build the SCSI command.
|
||||
*/
|
||||
bzero(&cmd, sizeof(cmd));
|
||||
cmd.opcode = POSITION_TO_ELEMENT;
|
||||
scsi_uto2b(sc->sc_picker, cmd.tea);
|
||||
scsi_uto2b(dst, cmd.dst);
|
||||
if (cp->cp_flags & CP_INVERT)
|
||||
cmd.flags |= POSITION_TO_ELEMENT_INVERT;
|
||||
|
||||
/*
|
||||
* Send command to changer.
|
||||
*/
|
||||
return (scsi_scsi_cmd(sc->sc_link, (struct scsi_generic *)&cmd,
|
||||
sizeof(cmd), NULL, 0, CHRETRIES, 100000, NULL, 0));
|
||||
}
|
||||
|
||||
/*
|
||||
* Perform a READ ELEMENT STATUS on behalf of the user, and return to
|
||||
* the user only the data the user is interested in (i.e. an array of
|
||||
* flags bytes).
|
||||
*/
|
||||
static int
|
||||
ch_usergetelemstatus(sc, chet, uptr)
|
||||
struct ch_softc *sc;
|
||||
int chet;
|
||||
u_int8_t *uptr;
|
||||
{
|
||||
struct read_element_status_header *st_hdr;
|
||||
struct read_element_status_page_header *pg_hdr;
|
||||
struct read_element_status_descriptor *desc;
|
||||
caddr_t data = NULL;
|
||||
#ifdef BOUNCE_BUFFERS
|
||||
int datasize = 0;
|
||||
#endif
|
||||
size_t size, desclen;
|
||||
int avail, i, error = 0;
|
||||
u_int8_t *user_data = NULL;
|
||||
|
||||
/*
|
||||
* If there are no elements of the requested type in the changer,
|
||||
* the request is invalid.
|
||||
*/
|
||||
if (sc->sc_counts[chet] == 0)
|
||||
return (EINVAL);
|
||||
|
||||
/*
|
||||
* Request one descriptor for the given element type. This
|
||||
* is used to determine the size of the descriptor so that
|
||||
* we can allocate enough storage for all of them. We assume
|
||||
* that the first one can fit into 1k.
|
||||
*/
|
||||
#ifdef BOUNCE_BUFFERS
|
||||
data = (caddr_t)vm_bounce_kva_alloc(btoc(1024));
|
||||
if (!data)
|
||||
return (ENOMEM);
|
||||
datasize = 1024;
|
||||
#else
|
||||
data = (caddr_t)malloc(1024, M_DEVBUF, M_WAITOK);
|
||||
#endif
|
||||
if (error = ch_getelemstatus(sc, sc->sc_firsts[chet], 1, data, 1024))
|
||||
goto done;
|
||||
|
||||
st_hdr = (struct read_element_status_header *)data;
|
||||
pg_hdr = (struct read_element_status_page_header *)((char *)st_hdr +
|
||||
sizeof(struct read_element_status_header));
|
||||
desclen = scsi_2btou(pg_hdr->edl);
|
||||
|
||||
size = sizeof(struct read_element_status_header) +
|
||||
sizeof(struct read_element_status_page_header) +
|
||||
(desclen * sc->sc_counts[chet]);
|
||||
|
||||
/*
|
||||
* Reallocate storage for descriptors and get them from the
|
||||
* device.
|
||||
*/
|
||||
#ifdef BOUNCE_BUFFERS
|
||||
vm_bounce_kva_alloc_free((vm_offset_t)data, btoc(datasize));
|
||||
data = (caddr_t)vm_bounce_kva_alloc(btoc(size));
|
||||
if (!data) {
|
||||
error = ENOMEM;
|
||||
goto done;
|
||||
}
|
||||
datasize = size;
|
||||
#else
|
||||
free(data, M_DEVBUF);
|
||||
data = (caddr_t)malloc(size, M_DEVBUF, M_WAITOK);
|
||||
#endif
|
||||
if (error = ch_getelemstatus(sc, sc->sc_firsts[chet],
|
||||
sc->sc_counts[chet], data, size))
|
||||
goto done;
|
||||
|
||||
/*
|
||||
* Fill in the user status array.
|
||||
*/
|
||||
st_hdr = (struct read_element_status_header *)data;
|
||||
avail = scsi_2btou(st_hdr->count);
|
||||
if (avail != sc->sc_counts[chet])
|
||||
printf("%s: warning, READ ELEMENT STATUS avail != count\n",
|
||||
sc->sc_dev.dv_xname);
|
||||
|
||||
user_data = (u_int8_t *)malloc(avail, M_DEVBUF, M_WAITOK);
|
||||
|
||||
desc = (struct read_element_status_descriptor *)((char *)data +
|
||||
sizeof(struct read_element_status_header) +
|
||||
sizeof(struct read_element_status_page_header));
|
||||
for (i = 0; i < avail; ++i) {
|
||||
user_data[i] = desc->flags1;
|
||||
desc = (struct read_element_status_descriptor *)
|
||||
((char *)desc + desclen);
|
||||
}
|
||||
|
||||
/* Copy flags array out to userspace. */
|
||||
error = copyout(user_data, uptr, avail);
|
||||
|
||||
done:
|
||||
#ifdef BOUNCE_BUFFERS
|
||||
if (data != NULL)
|
||||
vm_bounce_kva_alloc_free((vm_offset_t)data, btoc(datasize));
|
||||
#else
|
||||
if (data != NULL)
|
||||
free(data, M_DEVBUF);
|
||||
#endif
|
||||
if (user_data != NULL)
|
||||
free(user_data, M_DEVBUF);
|
||||
return (error);
|
||||
}
|
||||
|
||||
static int
|
||||
ch_getelemstatus(sc, first, count, data, datalen)
|
||||
struct ch_softc *sc;
|
||||
int first, count;
|
||||
caddr_t data;
|
||||
size_t datalen;
|
||||
{
|
||||
struct scsi_read_element_status cmd;
|
||||
|
||||
/*
|
||||
* Build SCSI command.
|
||||
*/
|
||||
bzero(&cmd, sizeof(cmd));
|
||||
cmd.opcode = READ_ELEMENT_STATUS;
|
||||
scsi_uto2b(first, cmd.sea);
|
||||
scsi_uto2b(count, cmd.count);
|
||||
scsi_uto3b(datalen, cmd.len);
|
||||
|
||||
/*
|
||||
* Send command to changer.
|
||||
*/
|
||||
return (scsi_scsi_cmd(sc->sc_link, (struct scsi_generic *)&cmd,
|
||||
sizeof(cmd), (u_char *)data, datalen, CHRETRIES, 100000, NULL, SCSI_DATA_IN));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Ask the device about itself and fill in the parameters in our
|
||||
* softc.
|
||||
*/
|
||||
static int
|
||||
ch_get_params(sc, scsiflags)
|
||||
struct ch_softc *sc;
|
||||
int scsiflags;
|
||||
{
|
||||
struct scsi_mode_sense cmd;
|
||||
struct scsi_mode_sense_data {
|
||||
struct scsi_mode_header header;
|
||||
union {
|
||||
struct page_element_address_assignment ea;
|
||||
struct page_transport_geometry_parameters tg;
|
||||
struct page_device_capabilities cap;
|
||||
} pages;
|
||||
} sense_data;
|
||||
int error, from;
|
||||
u_int8_t *moves, *exchanges;
|
||||
|
||||
/*
|
||||
* Grab info from the element address assignment page.
|
||||
*/
|
||||
bzero(&cmd, sizeof(cmd));
|
||||
bzero(&sense_data, sizeof(sense_data));
|
||||
cmd.op_code = MODE_SENSE;
|
||||
cmd.byte2 |= 0x08; /* disable block descriptors */
|
||||
cmd.page = 0x1d;
|
||||
cmd.length = (sizeof(sense_data) & 0xff);
|
||||
error = scsi_scsi_cmd(sc->sc_link, (struct scsi_generic *)&cmd,
|
||||
sizeof(cmd), (u_char *)&sense_data, sizeof(sense_data), CHRETRIES,
|
||||
6000, NULL, scsiflags | SCSI_DATA_IN);
|
||||
if (error) {
|
||||
printf("%s: could not sense element address page\n",
|
||||
sc->sc_dev.dv_xname);
|
||||
return (error);
|
||||
}
|
||||
|
||||
sc->sc_firsts[CHET_MT] = scsi_2btou(sense_data.pages.ea.mtea);
|
||||
sc->sc_counts[CHET_MT] = scsi_2btou(sense_data.pages.ea.nmte);
|
||||
sc->sc_firsts[CHET_ST] = scsi_2btou(sense_data.pages.ea.fsea);
|
||||
sc->sc_counts[CHET_ST] = scsi_2btou(sense_data.pages.ea.nse);
|
||||
sc->sc_firsts[CHET_IE] = scsi_2btou(sense_data.pages.ea.fieea);
|
||||
sc->sc_counts[CHET_IE] = scsi_2btou(sense_data.pages.ea.niee);
|
||||
sc->sc_firsts[CHET_DT] = scsi_2btou(sense_data.pages.ea.fdtea);
|
||||
sc->sc_counts[CHET_DT] = scsi_2btou(sense_data.pages.ea.ndte);
|
||||
|
||||
/* XXX ask for page trasport geom */
|
||||
|
||||
/*
|
||||
* Grab info from the capabilities page.
|
||||
*/
|
||||
bzero(&cmd, sizeof(cmd));
|
||||
bzero(&sense_data, sizeof(sense_data));
|
||||
cmd.op_code = MODE_SENSE;
|
||||
cmd.byte2 |= 0x08; /* disable block descriptors */
|
||||
cmd.page = 0x1f;
|
||||
cmd.length = (sizeof(sense_data) & 0xff);
|
||||
error = scsi_scsi_cmd(sc->sc_link, (struct scsi_generic *)&cmd,
|
||||
sizeof(cmd), (u_char *)&sense_data, sizeof(sense_data), CHRETRIES,
|
||||
6000, NULL, scsiflags | SCSI_DATA_IN);
|
||||
if (error) {
|
||||
printf("%s: could not sense capabilities page\n",
|
||||
sc->sc_dev.dv_xname);
|
||||
return (error);
|
||||
}
|
||||
|
||||
bzero(sc->sc_movemask, sizeof(sc->sc_movemask));
|
||||
bzero(sc->sc_exchangemask, sizeof(sc->sc_exchangemask));
|
||||
moves = &sense_data.pages.cap.move_from_mt;
|
||||
exchanges = &sense_data.pages.cap.exchange_with_mt;
|
||||
for (from = CHET_MT; from <= CHET_DT; ++from) {
|
||||
sc->sc_movemask[from] = moves[from];
|
||||
sc->sc_exchangemask[from] = exchanges[from];
|
||||
}
|
||||
|
||||
sc->sc_link->flags |= SDEV_MEDIA_LOADED;
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
chunit(dev)
|
||||
dev_t dev;
|
||||
{
|
||||
|
||||
return (CHUNIT(dev));
|
||||
}
|
||||
|
||||
static dev_t
|
||||
chsetunit(dev, unit)
|
||||
dev_t dev;
|
||||
int unit;
|
||||
{
|
||||
|
||||
return (CHSETUNIT(dev, unit));
|
||||
}
|
||||
|
||||
|
||||
static ch_devsw_installed = 0;
|
||||
|
||||
static void
|
||||
ch_drvinit(void *unused)
|
||||
{
|
||||
dev_t dev;
|
||||
|
||||
if( ! ch_devsw_installed ) {
|
||||
dev = makedev(CDEV_MAJOR, 0);
|
||||
cdevsw_add(&dev,&ch_cdevsw, NULL);
|
||||
ch_devsw_installed = 1;
|
||||
}
|
||||
}
|
||||
|
||||
SYSINIT(chdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,ch_drvinit,NULL)
|
966
sys/scsi/od.c
966
sys/scsi/od.c
@ -1,966 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 1995,1996 Shunsuke Akiyama. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by Shunsuke Akiyama.
|
||||
* 4. Neither the name of the author nor the names of any co-contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY Shunsuke Akiyama AND CONTRIBUTORS ``AS IS''
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL Shunsuke Akiyama OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* $Id: od.c,v 1.45 1998/07/30 15:16:05 bde Exp $
|
||||
*/
|
||||
|
||||
/*
|
||||
* Compile option defines:
|
||||
*/
|
||||
|
||||
/*
|
||||
* If drive returns sense key as 0x02 with vendor specific additional
|
||||
* sense code (ASC) and additional sense code qualifier (ASCQ), or
|
||||
* illegal ASC and ASCQ. This cause an error (NOT READY) and retrying.
|
||||
* To suppress this, uncomment following.
|
||||
* Or put "options OD_BOGUS_NOT_READY" entry into your kernel
|
||||
* configuration file.
|
||||
*
|
||||
#define OD_BOGUS_NOT_READY
|
||||
*/
|
||||
|
||||
/*
|
||||
* For an automatic spindown, try this. Again, preferrably as an
|
||||
* option in your config file.
|
||||
* WARNING! Use at your own risk. Joerg's ancient SONY SMO drive
|
||||
* groks it fine, while Shunsuke's Fujitsu chokes on it and times
|
||||
* out.
|
||||
#define OD_AUTO_TURNOFF
|
||||
*/
|
||||
|
||||
#include "opt_bounce.h"
|
||||
#include "opt_devfs.h"
|
||||
#include "opt_scsi.h"
|
||||
#include "opt_od.h"
|
||||
|
||||
#define SPLOD splbio
|
||||
#include <sys/param.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/dkbad.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/conf.h>
|
||||
#include <sys/buf.h>
|
||||
#include <sys/cdio.h>
|
||||
#include <sys/dkstat.h>
|
||||
#include <sys/disklabel.h>
|
||||
#include <sys/diskslice.h>
|
||||
#ifdef DEVFS
|
||||
#include <sys/devfsext.h>
|
||||
#endif /*DEVFS*/
|
||||
#include <scsi/scsi_disk.h>
|
||||
#include <scsi/scsiconf.h>
|
||||
#include <scsi/scsi_debug.h>
|
||||
#include <scsi/scsi_driver.h>
|
||||
|
||||
#include "ioconf.h"
|
||||
|
||||
static u_int32_t odstrats, odqueues;
|
||||
|
||||
#define SECSIZE 512 /* default sector size */
|
||||
#define ODOUTSTANDING 4
|
||||
#define OD_RETRIES 4
|
||||
|
||||
#define PARTITION(dev) dkpart(dev)
|
||||
#define ODUNIT(dev) dkunit(dev)
|
||||
|
||||
/* XXX introduce a dkmodunit() macro for this. */
|
||||
#define ODSETUNIT(DEV, U) \
|
||||
makedev(major(DEV), dkmakeminor((U), dkslice(DEV), dkpart(DEV)))
|
||||
|
||||
struct scsi_data {
|
||||
u_int32_t flags;
|
||||
#define ODINIT 0x04 /* device has been init'd */
|
||||
struct disk_parms {
|
||||
u_char heads; /* Number of heads */
|
||||
u_int16_t cyls; /* Number of cylinders (fictitious) */
|
||||
u_int16_t sectors; /* Number of sectors/track */
|
||||
u_int16_t secsiz; /* Number of bytes/sector */
|
||||
u_int32_t disksize; /* total number sectors */
|
||||
u_int16_t rpm; /* medium rotation rate */
|
||||
} params;
|
||||
struct diskslices *dk_slices; /* virtual drives */
|
||||
struct buf_queue_head buf_queue;
|
||||
int dkunit; /* disk stats unit number */
|
||||
#ifdef DEVFS
|
||||
/* Eventually move all these to common disk struct. */
|
||||
void *b_devfs_token;
|
||||
void *c_devfs_token;
|
||||
void *ctl_devfs_token;
|
||||
#endif
|
||||
};
|
||||
|
||||
static errval od_get_parms __P((int unit, int flags));
|
||||
#ifdef notyet
|
||||
static errval od_reassign_blocks __P((int unit, int block));
|
||||
#endif
|
||||
static u_int32_t od_size __P((int unit, int flags));
|
||||
static int od_sense_handler __P((struct scsi_xfer *));
|
||||
static void odstart __P((u_int32_t, u_int32_t));
|
||||
static void odstrategy1 __P((struct buf *));
|
||||
|
||||
static dev_t odsetunit(dev_t dev, int unit) { return ODSETUNIT(dev, unit); }
|
||||
static int odunit(dev_t dev) { return ODUNIT(dev); }
|
||||
|
||||
static errval od_open __P((dev_t dev, int mode, int fmt, struct proc *p,
|
||||
struct scsi_link *sc_link));
|
||||
static errval od_ioctl(dev_t dev, u_long cmd, caddr_t addr, int flag,
|
||||
struct proc *p, struct scsi_link *sc_link);
|
||||
static errval od_close __P((dev_t dev, int fflag, int fmt, struct proc *p,
|
||||
struct scsi_link *sc_link));
|
||||
static void od_strategy(struct buf *bp, struct scsi_link *sc_link);
|
||||
|
||||
static d_open_t odopen;
|
||||
static d_read_t odread;
|
||||
static d_write_t odwrite;
|
||||
static d_close_t odclose;
|
||||
static d_ioctl_t odioctl;
|
||||
static d_strategy_t odstrategy;
|
||||
|
||||
#define CDEV_MAJOR 70
|
||||
#define BDEV_MAJOR 20
|
||||
static struct cdevsw od_cdevsw = {
|
||||
odopen, odclose, odread, odwrite,
|
||||
odioctl, nostop, nullreset, nodevtotty,
|
||||
seltrue, nommap, odstrategy, "od",
|
||||
NULL, -1, nodump, nopsize,
|
||||
D_DISK, 0, -1 };
|
||||
|
||||
/*
|
||||
* Actually include the interface routines
|
||||
*/
|
||||
SCSI_DEVICE_ENTRIES(od)
|
||||
|
||||
static struct scsi_device od_switch =
|
||||
{
|
||||
od_sense_handler,
|
||||
odstart, /* have a queue, served by this */
|
||||
NULL, /* have no async handler */
|
||||
NULL, /* Use default 'done' routine */
|
||||
"od",
|
||||
0,
|
||||
{0, 0},
|
||||
0, /* Link flags */
|
||||
odattach,
|
||||
"Optical",
|
||||
odopen,
|
||||
sizeof(struct scsi_data),
|
||||
T_OPTICAL,
|
||||
odunit,
|
||||
odsetunit,
|
||||
od_open,
|
||||
od_ioctl,
|
||||
od_close,
|
||||
od_strategy,
|
||||
};
|
||||
|
||||
static __inline void
|
||||
od_registerdev(int unit)
|
||||
{
|
||||
if(dk_ndrive < DK_NDRIVE) {
|
||||
sprintf(dk_names[dk_ndrive], "od%d", unit);
|
||||
dk_wpms[dk_ndrive] = (4*1024*1024/2); /* 4MB/sec */
|
||||
SCSI_DATA(&od_switch, unit)->dkunit = dk_ndrive++;
|
||||
} else {
|
||||
SCSI_DATA(&od_switch, unit)->dkunit = -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* The routine called by the low level scsi routine when it discovers
|
||||
* a device suitable for this driver.
|
||||
*/
|
||||
static errval
|
||||
odattach(struct scsi_link *sc_link)
|
||||
{
|
||||
u_int32_t unit;
|
||||
struct disk_parms *dp;
|
||||
#ifdef DEVFS
|
||||
int mynor;
|
||||
#endif
|
||||
|
||||
struct scsi_data *od = sc_link->sd;
|
||||
|
||||
unit = sc_link->dev_unit;
|
||||
|
||||
dp = &(od->params);
|
||||
|
||||
if (sc_link->opennings > ODOUTSTANDING)
|
||||
sc_link->opennings = ODOUTSTANDING;
|
||||
|
||||
bufq_init(&od->buf_queue);
|
||||
/*
|
||||
* Use the subdriver to request information regarding
|
||||
* the drive. We cannot use interrupts yet, so the
|
||||
* request must specify this.
|
||||
*/
|
||||
scsi_start_unit(sc_link, SCSI_NOSLEEP | SCSI_NOMASK
|
||||
| SCSI_ERR_OK | SCSI_SILENT);
|
||||
od_get_parms(unit, SCSI_NOSLEEP | SCSI_NOMASK | SCSI_SILENT);
|
||||
/*
|
||||
* if we don't have actual parameters, assume 512 bytes/sec
|
||||
* (could happen on removable media - MOD)
|
||||
* -- this avoids the division below from falling over
|
||||
*/
|
||||
if(dp->secsiz == 0) dp->secsiz = SECSIZE;
|
||||
if (dp->disksize != 0) {
|
||||
printf("%luMB (%lu %u byte sectors)",
|
||||
(u_long)(dp->disksize / ((1024L * 1024L) / dp->secsiz)),
|
||||
(u_long)dp->disksize, dp->secsiz);
|
||||
} else {
|
||||
printf("od not present");
|
||||
}
|
||||
|
||||
#ifndef SCSI_REPORT_GEOMETRY
|
||||
if ( (sc_link->flags & SDEV_BOOTVERBOSE) )
|
||||
#endif
|
||||
{
|
||||
sc_print_addr(sc_link);
|
||||
printf("with approximate %d cyls, %d heads, and %d sectors/track",
|
||||
dp->cyls, dp->heads, dp->sectors);
|
||||
}
|
||||
#ifdef OD_AUTO_TURNOFF
|
||||
scsi_stop_unit(sc_link, 0, SCSI_ERR_OK | SCSI_SILENT);
|
||||
#endif /* OD_AUTO_TURNOFF */
|
||||
|
||||
od->flags |= ODINIT;
|
||||
od_registerdev(unit);
|
||||
|
||||
#ifdef DEVFS
|
||||
mynor = dkmakeminor(unit, WHOLE_DISK_SLICE, RAW_PART);
|
||||
od->b_devfs_token = devfs_add_devswf(&od_cdevsw, mynor, DV_BLK,
|
||||
UID_ROOT, GID_OPERATOR, 0640,
|
||||
"od%d", unit);
|
||||
od->c_devfs_token = devfs_add_devswf(&od_cdevsw, mynor, DV_CHR,
|
||||
UID_ROOT, GID_OPERATOR, 0640,
|
||||
"rod%d", unit);
|
||||
mynor = dkmakeminor(unit, 0, 0); /* XXX */
|
||||
od->ctl_devfs_token = devfs_add_devswf(&od_cdevsw,
|
||||
mynor | SCSI_CONTROL_MASK,
|
||||
DV_CHR,
|
||||
UID_ROOT, GID_WHEEL, 0600,
|
||||
"rod%d.ctl", unit);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* open the device. Make sure the partition info is a up-to-date as can be.
|
||||
*/
|
||||
static errval
|
||||
od_open(dev, mode, fmt, p, sc_link)
|
||||
dev_t dev;
|
||||
int mode;
|
||||
int fmt;
|
||||
struct proc *p;
|
||||
struct scsi_link *sc_link;
|
||||
{
|
||||
errval errcode = 0;
|
||||
u_int32_t unit;
|
||||
struct disklabel label;
|
||||
struct scsi_data *od;
|
||||
|
||||
unit = ODUNIT(dev);
|
||||
od = sc_link->sd;
|
||||
|
||||
/*
|
||||
* Make sure the disk has been initialized
|
||||
* At some point in the future, get the scsi driver
|
||||
* to look for a new device if we are not initted
|
||||
*/
|
||||
if ((!od) || (!(od->flags & ODINIT))) {
|
||||
return ENXIO;
|
||||
}
|
||||
|
||||
SC_DEBUG(sc_link, SDEV_DB1,
|
||||
("od_open: dev=0x%lx (unit %lu, partition %d)\n",
|
||||
(u_long)dev, (u_long)unit, PARTITION(dev)));
|
||||
|
||||
/*
|
||||
* Try to start the drive, and try to clear "Unit Attention"
|
||||
* condition, when media had been changed before.
|
||||
* This operation also clears the SDEV_MEDIA_LOADED flag in its
|
||||
* error handling routine.
|
||||
*/
|
||||
scsi_start_unit(sc_link, SCSI_SILENT);
|
||||
scsi_prevent(sc_link, PR_PREVENT, SCSI_ERR_OK | SCSI_SILENT);
|
||||
|
||||
/*
|
||||
* Make sure the drive is ready.
|
||||
*/
|
||||
scsi_test_unit_ready(sc_link, 0);
|
||||
|
||||
SC_DEBUG(sc_link, SDEV_DB3, ("'start' attempted "));
|
||||
|
||||
sc_link->flags |= SDEV_OPEN; /* unit attn becomes an err now */
|
||||
/*
|
||||
* If it's been invalidated, then forget the label.
|
||||
*/
|
||||
if (!(sc_link->flags & SDEV_MEDIA_LOADED)) {
|
||||
/*
|
||||
* If somebody still has it open, then forbid re-entry.
|
||||
*/
|
||||
if (dsisopen(od->dk_slices)) {
|
||||
errcode = ENXIO;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
if (od->dk_slices != NULL)
|
||||
dsgone(&od->dk_slices);
|
||||
}
|
||||
|
||||
/*
|
||||
* This time actually take notice of error returns
|
||||
*/
|
||||
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"));
|
||||
|
||||
/*
|
||||
* Load the physical device parameters
|
||||
*/
|
||||
errcode = od_get_parms(unit, 0); /* sets SDEV_MEDIA_LOADED */
|
||||
if (errcode) {
|
||||
goto bad;
|
||||
}
|
||||
switch (od->params.secsiz) {
|
||||
case SECSIZE :
|
||||
case 1024 :
|
||||
case 2048 :
|
||||
break;
|
||||
default :
|
||||
printf("od%lu: Can't deal with %u bytes logical blocks\n",
|
||||
(u_long)unit, od->params.secsiz);
|
||||
Debugger("od");
|
||||
errcode = ENXIO;
|
||||
goto bad;
|
||||
}
|
||||
SC_DEBUG(sc_link, SDEV_DB3, ("params loaded "));
|
||||
|
||||
/* Build label for whole disk. */
|
||||
bzero(&label, sizeof label);
|
||||
label.d_type = DTYPE_SCSI;
|
||||
label.d_secsize = od->params.secsiz;
|
||||
label.d_nsectors = od->params.sectors;
|
||||
label.d_ntracks = od->params.heads;
|
||||
label.d_ncylinders = od->params.cyls;
|
||||
label.d_secpercyl = od->params.heads * od->params.sectors;
|
||||
label.d_rpm = od->params.rpm; /* maybe wrong */
|
||||
if (label.d_secpercyl == 0)
|
||||
label.d_secpercyl = 64*32;
|
||||
/* XXX as long as it's not 0
|
||||
* - readdisklabel divides by it (?)
|
||||
*/
|
||||
label.d_secperunit = od->params.disksize;
|
||||
|
||||
/* Initialize slice tables. */
|
||||
errcode = dsopen("od", dev, fmt, 0, &od->dk_slices, &label, odstrategy1,
|
||||
(ds_setgeom_t *)NULL, &od_cdevsw);
|
||||
if (errcode != 0)
|
||||
goto bad;
|
||||
SC_DEBUG(sc_link, SDEV_DB3, ("Slice tables initialized "));
|
||||
|
||||
SC_DEBUG(sc_link, SDEV_DB3, ("open %lu %lu\n",
|
||||
(u_long)odstrats, (u_long)odqueues));
|
||||
|
||||
return 0;
|
||||
|
||||
bad:
|
||||
if (!dsisopen(od->dk_slices)) {
|
||||
scsi_prevent(sc_link, PR_ALLOW, SCSI_ERR_OK | SCSI_SILENT);
|
||||
#ifdef OD_AUTO_TURNOFF
|
||||
scsi_stop_unit(sc_link, 0, SCSI_ERR_OK | SCSI_SILENT);
|
||||
#endif /* OD_AUTO_TURNOFF */
|
||||
sc_link->flags &= ~SDEV_OPEN;
|
||||
}
|
||||
return errcode;
|
||||
}
|
||||
|
||||
/*
|
||||
* close the device.. only called if we are the LAST occurence of an open
|
||||
* device. Convenient now but usually a pain.
|
||||
*/
|
||||
static errval
|
||||
od_close(dev, fflag, fmt, p, sc_link)
|
||||
dev_t dev;
|
||||
int fflag;
|
||||
int fmt;
|
||||
struct proc *p;
|
||||
struct scsi_link *sc_link;
|
||||
{
|
||||
struct scsi_data *od;
|
||||
|
||||
od = sc_link->sd;
|
||||
dsclose(dev, fmt, od->dk_slices);
|
||||
if (!dsisopen(od->dk_slices)) {
|
||||
scsi_prevent(sc_link, PR_ALLOW, SCSI_SILENT | SCSI_ERR_OK);
|
||||
#ifdef OD_AUTO_TURNOFF
|
||||
scsi_stop_unit(sc_link, 0, SCSI_ERR_OK | SCSI_SILENT);
|
||||
#endif /* OD_AUTO_TURNOFF */
|
||||
sc_link->flags &= ~SDEV_OPEN;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
odread(dev_t dev, struct uio *uio, int ioflag)
|
||||
{
|
||||
return (physio(odstrategy, NULL, dev, 1, minphys, uio));
|
||||
}
|
||||
|
||||
static int
|
||||
odwrite(dev_t dev, struct uio *uio, int ioflag)
|
||||
{
|
||||
return (physio(odstrategy, NULL, dev, 0, minphys, uio));
|
||||
}
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
static void
|
||||
od_strategy(struct buf *bp, struct scsi_link *sc_link)
|
||||
{
|
||||
u_int32_t opri;
|
||||
struct scsi_data *od;
|
||||
u_int32_t unit;
|
||||
|
||||
odstrats++;
|
||||
unit = ODUNIT((bp->b_dev));
|
||||
od = sc_link->sd;
|
||||
|
||||
/*
|
||||
* If the device has been made invalid, error out
|
||||
*/
|
||||
if (!(sc_link->flags & SDEV_MEDIA_LOADED)) {
|
||||
bp->b_error = EIO;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
/*
|
||||
* Do bounds checking, adjust transfer, and set b_pblkno.
|
||||
*/
|
||||
if (dscheck(bp, od->dk_slices) <= 0)
|
||||
goto done; /* XXX check b_resid */
|
||||
|
||||
opri = SPLOD();
|
||||
|
||||
/*
|
||||
* Use a bounce buffer if necessary
|
||||
*/
|
||||
#ifdef BOUNCE_BUFFERS
|
||||
if (sc_link->flags & SDEV_BOUNCE)
|
||||
vm_bounce_alloc(bp);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Place it in the queue of disk activities for this disk
|
||||
*/
|
||||
bufq_insert_tail(&od->buf_queue, bp);
|
||||
|
||||
/*
|
||||
* Tell the device to get going on the transfer if it's
|
||||
* not doing anything, otherwise just wait for completion
|
||||
*/
|
||||
odstart(unit, 0);
|
||||
|
||||
splx(opri);
|
||||
return /*0*/;
|
||||
bad:
|
||||
bp->b_flags |= B_ERROR;
|
||||
done:
|
||||
|
||||
/*
|
||||
* Correctly set the buf to indicate a completed xfer
|
||||
*/
|
||||
bp->b_resid = bp->b_bcount;
|
||||
biodone(bp);
|
||||
return /*0*/;
|
||||
}
|
||||
|
||||
static void
|
||||
odstrategy1(struct buf *bp)
|
||||
{
|
||||
/*
|
||||
* XXX - do something to make odstrategy() but not this block while
|
||||
* we're doing dsinit() and dsioctl().
|
||||
*/
|
||||
odstrategy(bp);
|
||||
}
|
||||
|
||||
/*
|
||||
* odstart 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 (odstrategy)
|
||||
*
|
||||
* 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
|
||||
* odstart() is called at SPLOD from odstrategy and scsi_done
|
||||
*/
|
||||
static void
|
||||
odstart(u_int32_t unit, u_int32_t flags)
|
||||
{
|
||||
register struct scsi_link *sc_link = SCSI_LINK(&od_switch, unit);
|
||||
register struct scsi_data *od = sc_link->sd;
|
||||
struct buf *bp = 0;
|
||||
struct scsi_rw_big cmd;
|
||||
u_int32_t blkno, nblk;
|
||||
u_int32_t secsize;
|
||||
|
||||
SC_DEBUG(sc_link, SDEV_DB2, ("odstart "));
|
||||
/*
|
||||
* Check if the device has room for another command
|
||||
*/
|
||||
while (sc_link->opennings) {
|
||||
|
||||
/*
|
||||
* 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..
|
||||
*/
|
||||
bp = bufq_first(&od->buf_queue);
|
||||
if (bp == NULL) { /* yes, an assign */
|
||||
return;
|
||||
}
|
||||
bufq_remove(&od->buf_queue, bp);
|
||||
|
||||
/*
|
||||
* 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)) {
|
||||
goto bad;
|
||||
}
|
||||
/*
|
||||
* We have a buf, now we know we are going to go through
|
||||
* With this thing..
|
||||
*/
|
||||
secsize = od->params.secsiz;
|
||||
blkno = bp->b_pblkno;
|
||||
if (bp->b_bcount & (secsize - 1))
|
||||
{
|
||||
goto bad;
|
||||
}
|
||||
nblk = bp->b_bcount / secsize;
|
||||
|
||||
/*
|
||||
* Fill out the scsi command
|
||||
*/
|
||||
cmd.op_code = (bp->b_flags & B_READ)
|
||||
? READ_BIG : WRITE_BIG;
|
||||
scsi_uto4b(blkno, &cmd.addr_3);
|
||||
scsi_uto2b(nblk, &cmd.length2);
|
||||
cmd.byte2 = cmd.reserved = cmd.control = 0;
|
||||
/*
|
||||
* 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_data,
|
||||
bp->b_bcount,
|
||||
OD_RETRIES,
|
||||
100000,
|
||||
bp,
|
||||
flags | ((bp->b_flags & B_READ) ?
|
||||
SCSI_DATA_IN : SCSI_DATA_OUT))
|
||||
== SUCCESSFULLY_QUEUED) {
|
||||
odqueues++;
|
||||
if(od->dkunit >= 0) {
|
||||
dk_xfer[od->dkunit]++;
|
||||
dk_seek[od->dkunit]++; /* don't know */
|
||||
dk_wds[od->dkunit] += bp->b_bcount >> 6;
|
||||
}
|
||||
} else {
|
||||
bad:
|
||||
printf("od%lu: oops not queued\n", (u_long)unit);
|
||||
bp->b_error = EIO;
|
||||
bp->b_flags |= B_ERROR;
|
||||
biodone(bp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Perform special action on behalf of the user
|
||||
* Knows about the internals of this device
|
||||
*/
|
||||
static errval
|
||||
od_ioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p,
|
||||
struct scsi_link *sc_link)
|
||||
{
|
||||
/* struct od_cmd_buf *args; */
|
||||
errval error;
|
||||
struct scsi_data *od;
|
||||
|
||||
/*
|
||||
* Find the device that the user is talking about
|
||||
*/
|
||||
od = sc_link->sd;
|
||||
SC_DEBUG(sc_link, SDEV_DB1, ("odioctl (0x%lx)", cmd));
|
||||
|
||||
/*
|
||||
* If the device is not valid.. abandon ship
|
||||
*/
|
||||
if (!(sc_link->flags & SDEV_MEDIA_LOADED))
|
||||
return EIO;
|
||||
|
||||
switch (cmd) {
|
||||
case DIOCSBAD:
|
||||
error = EINVAL;
|
||||
break;
|
||||
case CDIOCEJECT:
|
||||
error = scsi_stop_unit(sc_link, 1, 0);
|
||||
sc_link->flags &= ~SDEV_MEDIA_LOADED;
|
||||
break;
|
||||
case CDIOCALLOW:
|
||||
error = scsi_prevent(sc_link, PR_ALLOW, 0);
|
||||
break;
|
||||
case CDIOCPREVENT:
|
||||
error = scsi_prevent(sc_link, PR_PREVENT, 0);
|
||||
break;
|
||||
default:
|
||||
error = dsioctl("od", dev, cmd, addr, flag, &od->dk_slices,
|
||||
odstrategy1, (ds_setgeom_t *)NULL);
|
||||
if (error == ENOIOCTL) {
|
||||
if (PARTITION(dev) != RAW_PART) {
|
||||
error = ENOTTY;
|
||||
} else {
|
||||
error = scsi_do_ioctl(dev, cmd, addr,
|
||||
flag, p, sc_link);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
/*
|
||||
* Find out from the device what its capacity is
|
||||
*/
|
||||
static u_int32_t
|
||||
od_size(unit, flags)
|
||||
int unit, flags;
|
||||
{
|
||||
struct scsi_read_cap_data rdcap;
|
||||
struct scsi_read_capacity rdcap_cmd;
|
||||
struct scsi_link *sc_link = SCSI_LINK(&od_switch, unit);
|
||||
struct scsi_data *od = sc_link->sd;
|
||||
struct scsi_mode_sense mdsense_cmd;
|
||||
struct scsi_mode_sense_data {
|
||||
struct scsi_mode_header header;
|
||||
struct blk_desc blk_desc;
|
||||
union disk_pages pages;
|
||||
} scsi_sense;
|
||||
|
||||
/*
|
||||
* make up a scsi command and ask the scsi driver to do
|
||||
* it for you.
|
||||
*/
|
||||
bzero(&rdcap_cmd, sizeof(rdcap_cmd));
|
||||
rdcap_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 *) &rdcap_cmd,
|
||||
sizeof(rdcap_cmd),
|
||||
(u_char *) & rdcap,
|
||||
sizeof(rdcap),
|
||||
OD_RETRIES,
|
||||
10000,
|
||||
NULL,
|
||||
flags | SCSI_DATA_IN) != 0) {
|
||||
return 0;
|
||||
} else {
|
||||
od->params.disksize = scsi_4btou(&rdcap.addr_3) + 1;
|
||||
od->params.secsiz = scsi_4btou(&rdcap.length_3);
|
||||
}
|
||||
|
||||
/*
|
||||
* do a "mode sense page 4" (rigid disk drive geometry)
|
||||
*/
|
||||
bzero(&mdsense_cmd, sizeof(mdsense_cmd));
|
||||
mdsense_cmd.op_code = MODE_SENSE;
|
||||
mdsense_cmd.page = 4;
|
||||
mdsense_cmd.length = 0x20;
|
||||
/*
|
||||
* If the command worked, use the results to fill out
|
||||
* the parameter structure
|
||||
*/
|
||||
if (scsi_scsi_cmd(sc_link,
|
||||
(struct scsi_generic *) &mdsense_cmd,
|
||||
sizeof(mdsense_cmd),
|
||||
(u_char *) & scsi_sense,
|
||||
sizeof(scsi_sense),
|
||||
OD_RETRIES,
|
||||
10000,
|
||||
NULL,
|
||||
flags | SCSI_SILENT | SCSI_DATA_IN) != 0) {
|
||||
|
||||
/* default to a fictitious geometry */
|
||||
od->params.heads = 64;
|
||||
} else {
|
||||
SC_DEBUG(sc_link, SDEV_DB3,
|
||||
("%lu cyls, %d heads, %lu rpm\n",
|
||||
(u_long)scsi_3btou(&scsi_sense.pages.rigid_geometry.ncyl_2),
|
||||
scsi_sense.pages.rigid_geometry.nheads,
|
||||
(u_long)scsi_2btou(
|
||||
&scsi_sense.pages.rigid_geometry.medium_rot_rate_1)));
|
||||
|
||||
od->params.heads = scsi_sense.pages.rigid_geometry.nheads;
|
||||
if (od->params.heads == 0)
|
||||
od->params.heads = 64; /* fictitious */
|
||||
od->params.rpm =
|
||||
scsi_2btou(&scsi_sense.pages.rigid_geometry.medium_rot_rate_1);
|
||||
}
|
||||
|
||||
/*
|
||||
* do a "mode sense page 3" (format device)
|
||||
*/
|
||||
bzero(&mdsense_cmd, sizeof(mdsense_cmd));
|
||||
mdsense_cmd.op_code = MODE_SENSE;
|
||||
mdsense_cmd.page = 3;
|
||||
mdsense_cmd.length = 0x20;
|
||||
/*
|
||||
* If the command worked, use the results to fill out
|
||||
* the parameter structure
|
||||
*/
|
||||
if (scsi_scsi_cmd(sc_link,
|
||||
(struct scsi_generic *) &mdsense_cmd,
|
||||
sizeof(mdsense_cmd),
|
||||
(u_char *) & scsi_sense,
|
||||
sizeof(scsi_sense),
|
||||
OD_RETRIES,
|
||||
10000,
|
||||
NULL,
|
||||
flags | SCSI_SILENT | SCSI_DATA_IN) != 0) {
|
||||
|
||||
/* default to a fictitious geometry */
|
||||
od->params.sectors = 32;
|
||||
} else {
|
||||
SC_DEBUG(sc_link, SDEV_DB3,
|
||||
("%d secs\n",
|
||||
scsi_2btou(&scsi_sense.pages.disk_format.ph_sec_t_1)));
|
||||
|
||||
od->params.sectors =
|
||||
scsi_2btou(&scsi_sense.pages.disk_format.ph_sec_t_1);
|
||||
if (od->params.sectors == 0)
|
||||
od->params.sectors = 32; /* fictitious */
|
||||
}
|
||||
|
||||
return od->params.disksize;
|
||||
}
|
||||
|
||||
#ifdef notyet
|
||||
/*
|
||||
* Tell the device to map out a defective block
|
||||
*/
|
||||
static errval
|
||||
od_reassign_blocks(unit, block)
|
||||
int unit, block;
|
||||
{
|
||||
struct scsi_reassign_blocks scsi_cmd;
|
||||
struct scsi_reassign_blocks_data rbdata;
|
||||
struct scsi_link *sc_link = SCSI_LINK(&od_switch, unit);
|
||||
|
||||
bzero(&scsi_cmd, sizeof(scsi_cmd));
|
||||
bzero(&rbdata, sizeof(rbdata));
|
||||
scsi_cmd.op_code = REASSIGN_BLOCKS;
|
||||
|
||||
rbdata.length_msb = 0;
|
||||
rbdata.length_lsb = sizeof(rbdata.defect_descriptor[0]);
|
||||
scsi_uto4b(block, &rbdata.defect_descriptor[0].dlbaddr_3);
|
||||
|
||||
return scsi_scsi_cmd(sc_link,
|
||||
(struct scsi_generic *) &scsi_cmd,
|
||||
sizeof(scsi_cmd),
|
||||
(u_char *) & rbdata,
|
||||
sizeof(rbdata),
|
||||
OD_RETRIES,
|
||||
20000,
|
||||
NULL,
|
||||
SCSI_DATA_OUT);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Get the scsi driver to send a full inquiry to the
|
||||
* device and use the results to fill out the disk
|
||||
* parameter structure.
|
||||
*/
|
||||
static errval
|
||||
od_get_parms(unit, flags)
|
||||
int unit, flags;
|
||||
{
|
||||
struct scsi_link *sc_link = SCSI_LINK(&od_switch, unit);
|
||||
struct scsi_data *od = sc_link->sd;
|
||||
struct disk_parms *disk_parms = &od->params;
|
||||
u_int32_t sectors;
|
||||
errval retval;
|
||||
|
||||
/*
|
||||
* First check if we have it all loaded
|
||||
*/
|
||||
if (sc_link->flags & SDEV_MEDIA_LOADED)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Use fictitious geometry, this depends on the size of medium.
|
||||
*/
|
||||
sectors = od_size(unit, flags);
|
||||
/* od_size() sets secsiz, disksize, sectors, and heads */
|
||||
|
||||
/* fictitious number of cylinders, so that C*H*S <= total */
|
||||
if (disk_parms->sectors != 0 && disk_parms->heads != 0) {
|
||||
disk_parms->cyls =
|
||||
sectors / (disk_parms->sectors * disk_parms->heads);
|
||||
} else {
|
||||
disk_parms->cyls = 0;
|
||||
}
|
||||
|
||||
if (sectors != 0) {
|
||||
sc_link->flags |= SDEV_MEDIA_LOADED;
|
||||
retval = 0;
|
||||
} else {
|
||||
retval = ENXIO;
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*
|
||||
* sense handler: Called to determine what to do when the
|
||||
* device returns a CHECK CONDITION.
|
||||
*/
|
||||
|
||||
static int
|
||||
od_sense_handler(struct scsi_xfer *xs)
|
||||
{
|
||||
struct scsi_sense_data *sense;
|
||||
struct scsi_sense_extended *ext;
|
||||
int asc, ascq;
|
||||
|
||||
sense = &(xs->sense);
|
||||
ext = (struct scsi_sense_extended *)&(sense->ext.extended);
|
||||
|
||||
/* I don't know what the heck to do with a deferred error,
|
||||
* so I'll just kick it back to the caller.
|
||||
*/
|
||||
if ((sense->error_code & SSD_ERRCODE) == 0x71)
|
||||
return SCSIRET_CONTINUE;
|
||||
|
||||
#ifdef OD_BOGUS_NOT_READY
|
||||
if (((sense->error_code & SSD_ERRCODE) == 0x70) &&
|
||||
((sense->ext.extended.flags & SSD_KEY) == 0x02))
|
||||
/* No point in retrying Not Ready */
|
||||
return SCSIRET_CONTINUE;
|
||||
#endif
|
||||
|
||||
if (((sense->error_code & SSD_ERRCODE) == 0x70) &&
|
||||
((sense->ext.extended.flags & SSD_KEY) == 0x04))
|
||||
/* No point in retrying Hardware Failure */
|
||||
return SCSIRET_CONTINUE;
|
||||
|
||||
if (((sense->error_code & SSD_ERRCODE) == 0x70) &&
|
||||
((sense->ext.extended.flags & SSD_KEY) == 0x05))
|
||||
/* No point in retrying Illegal Requests */
|
||||
return SCSIRET_CONTINUE;
|
||||
|
||||
asc = (ext->extra_len >= 5) ? ext->add_sense_code : 0;
|
||||
ascq = (ext->extra_len >= 6) ? ext->add_sense_code_qual : 0;
|
||||
|
||||
if (asc == 0x11 || asc == 0x30 || asc == 0x31 || asc == 0x53
|
||||
|| asc == 0x5a) {
|
||||
/* Unrecovered errors */
|
||||
return SCSIRET_CONTINUE;
|
||||
}
|
||||
if (asc == 0x21 && ascq == 0) {
|
||||
/* Logical block address out of range */
|
||||
return SCSIRET_CONTINUE;
|
||||
}
|
||||
if (asc == 0x27 && ascq == 0) {
|
||||
/* Write protected */
|
||||
return SCSIRET_CONTINUE;
|
||||
}
|
||||
if (asc == 0x28 && ascq == 0) {
|
||||
/* Not ready to ready transition */
|
||||
/* (medium may have changed) */
|
||||
return SCSIRET_CONTINUE;
|
||||
}
|
||||
if (asc == 0x3a && ascq == 0) {
|
||||
/* Medium not present */
|
||||
return SCSIRET_CONTINUE;
|
||||
}
|
||||
|
||||
/* Retry all disk errors.
|
||||
*/
|
||||
scsi_sense_print(xs);
|
||||
if (xs->retries)
|
||||
printf(", retries:%d\n", xs->retries);
|
||||
else
|
||||
printf(", FAILURE\n");
|
||||
|
||||
return SCSIRET_DO_RETRY;
|
||||
}
|
||||
|
||||
static od_devsw_installed = 0;
|
||||
|
||||
static void od_drvinit(void *unused)
|
||||
{
|
||||
|
||||
if( ! od_devsw_installed ) {
|
||||
cdevsw_add_generic(BDEV_MAJOR, CDEV_MAJOR, &od_cdevsw);
|
||||
od_devsw_installed = 1;
|
||||
}
|
||||
}
|
||||
|
||||
SYSINIT(oddev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,od_drvinit,NULL)
|
326
sys/scsi/pt.c
326
sys/scsi/pt.c
@ -1,326 +0,0 @@
|
||||
/*
|
||||
* pt: Processor Type driver.
|
||||
*
|
||||
* Copyright (C) 1995, HD Associates, Inc.
|
||||
* PO Box 276
|
||||
* Pepperell, MA 01463
|
||||
* 508 433 5266
|
||||
* dufault@hda.com
|
||||
*
|
||||
* This code is contributed to the University of California at Berkeley:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id: pt.c,v 1.29 1998/07/04 22:30:24 julian Exp $
|
||||
*/
|
||||
|
||||
#include "opt_bounce.h"
|
||||
#include "opt_devfs.h"
|
||||
#include "opt_scsi.h"
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/buf.h>
|
||||
#include <sys/conf.h>
|
||||
#include <sys/kernel.h>
|
||||
#ifdef DEVFS
|
||||
#include <sys/devfsext.h>
|
||||
#endif /*DEVFS*/
|
||||
#include <scsi/scsiconf.h>
|
||||
#include <scsi/scsi_debug.h>
|
||||
#include <scsi/scsi_driver.h>
|
||||
|
||||
#include "ioconf.h"
|
||||
|
||||
struct scsi_data {
|
||||
struct buf_queue_head buf_queue;
|
||||
#ifdef DEVFS
|
||||
void *devfs_data_tok;
|
||||
void *devfs_ctl_tok;
|
||||
#endif
|
||||
};
|
||||
|
||||
static d_open_t ptopen;
|
||||
static d_read_t ptread;
|
||||
static d_write_t ptwrite;
|
||||
static d_close_t ptclose;
|
||||
static d_ioctl_t ptioctl;
|
||||
static d_strategy_t ptstrategy;
|
||||
|
||||
#define CDEV_MAJOR 61
|
||||
static struct cdevsw pt_cdevsw =
|
||||
{ ptopen, ptclose, ptread, ptwrite, /*61*/
|
||||
ptioctl, nostop, nullreset, nodevtotty,/* pt */
|
||||
seltrue, nommap, ptstrategy, "pt", NULL, -1 };
|
||||
|
||||
SCSI_DEVICE_ENTRIES(pt)
|
||||
|
||||
static void ptstart(u_int32_t unit, u_int32_t flags);
|
||||
static void pt_strategy(struct buf *bp, struct scsi_link *sc_link);
|
||||
static int pt_sense(struct scsi_xfer *scsi_xfer);
|
||||
|
||||
static struct scsi_device pt_switch =
|
||||
{
|
||||
pt_sense,
|
||||
ptstart, /* we have a queue, and this is how we service it */
|
||||
NULL,
|
||||
NULL,
|
||||
"pt",
|
||||
0,
|
||||
{0, 0},
|
||||
SDEV_ONCE_ONLY, /* Only one open allowed */
|
||||
ptattach,
|
||||
"Processor",
|
||||
ptopen,
|
||||
sizeof(struct scsi_data),
|
||||
T_PROCESSOR,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
pt_strategy,
|
||||
};
|
||||
|
||||
static errval
|
||||
ptattach(struct scsi_link *sc_link)
|
||||
{
|
||||
struct scsi_data *pt = sc_link->sd;
|
||||
|
||||
bufq_init(&pt->buf_queue);
|
||||
|
||||
#ifdef DEVFS
|
||||
pt->devfs_data_tok = devfs_add_devswf(&pt_cdevsw,
|
||||
sc_link->dev_unit,
|
||||
DV_CHR,
|
||||
UID_ROOT, GID_WHEEL, 0600,
|
||||
"pt%d", sc_link->dev_unit);
|
||||
pt->devfs_ctl_tok = devfs_add_devswf(&pt_cdevsw,
|
||||
sc_link->dev_unit | SCSI_CONTROL_MASK,
|
||||
DV_CHR,
|
||||
UID_ROOT, GID_WHEEL, 0600,
|
||||
"pt%d.ctl", sc_link->dev_unit);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* ptstart 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 (ptstrategy)
|
||||
*
|
||||
* 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.
|
||||
* ptstart() is called at splbio
|
||||
*/
|
||||
static void
|
||||
ptstart(unit, flags)
|
||||
u_int32_t unit;
|
||||
u_int32_t flags;
|
||||
{
|
||||
struct scsi_link *sc_link = SCSI_LINK(&pt_switch, unit);
|
||||
struct scsi_data *pt = sc_link->sd;
|
||||
register struct buf *bp = 0;
|
||||
struct
|
||||
{
|
||||
#define PROCESSOR_SEND 0x0A
|
||||
#define PROCESSOR_RECEIVE 0x08
|
||||
u_char op_code;
|
||||
u_char byte2;
|
||||
u_char len[3];
|
||||
u_char control;
|
||||
} cmd;
|
||||
|
||||
|
||||
SC_DEBUG(sc_link, SDEV_DB2, ("ptstart "));
|
||||
/*
|
||||
* 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) {
|
||||
sc_link->flags &= ~SDEV_WAITING;
|
||||
wakeup((caddr_t)sc_link);
|
||||
return;
|
||||
}
|
||||
|
||||
bp = bufq_first(&pt->buf_queue);
|
||||
if (bp == NULL) { /* yes, an assign */
|
||||
return;
|
||||
}
|
||||
bufq_remove(&pt->buf_queue, bp);
|
||||
|
||||
/*
|
||||
* Fill out the scsi command
|
||||
*/
|
||||
bzero(&cmd, sizeof(cmd));
|
||||
if ((bp->b_flags & B_READ) == B_WRITE) {
|
||||
cmd.op_code = PROCESSOR_SEND;
|
||||
flags |= SCSI_DATA_OUT;
|
||||
} else {
|
||||
cmd.op_code = PROCESSOR_RECEIVE;
|
||||
flags |= SCSI_DATA_IN;
|
||||
}
|
||||
|
||||
scsi_uto3b(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_data,
|
||||
bp->b_bcount,
|
||||
0,
|
||||
10000,
|
||||
bp,
|
||||
flags) == SUCCESSFULLY_QUEUED) {
|
||||
} else {
|
||||
printf("pt%lu: oops not queued\n", (u_long)unit);
|
||||
bp->b_flags |= B_ERROR;
|
||||
bp->b_error = EIO;
|
||||
biodone(bp);
|
||||
}
|
||||
} /* go back and see if we can cram more work in.. */
|
||||
}
|
||||
|
||||
static int
|
||||
ptread( dev_t dev, struct uio *uio, int ioflag)
|
||||
{
|
||||
return (physio(ptstrategy, NULL, dev, 1, minphys, uio));
|
||||
}
|
||||
|
||||
static int
|
||||
ptwrite ( dev_t dev, struct uio *uio, int ioflag)
|
||||
{
|
||||
return (physio(ptstrategy, NULL, dev, 0, minphys, uio));
|
||||
}
|
||||
|
||||
static void
|
||||
pt_strategy(struct buf *bp, struct scsi_link *sc_link)
|
||||
{
|
||||
unsigned char unit;
|
||||
u_int32_t opri;
|
||||
struct scsi_data *pt;
|
||||
|
||||
unit = minor((bp->b_dev));
|
||||
pt = sc_link->sd;
|
||||
|
||||
opri = splbio();
|
||||
|
||||
/*
|
||||
* Use a bounce buffer if necessary
|
||||
*/
|
||||
#ifdef BOUNCE_BUFFERS
|
||||
if (sc_link->flags & SDEV_BOUNCE)
|
||||
vm_bounce_alloc(bp);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Place it in the queue of activities for this tape
|
||||
* at the end (a bit silly because we only have one user..
|
||||
* (but it could fork() ))
|
||||
*/
|
||||
bufq_insert_tail(&pt->buf_queue, bp);
|
||||
|
||||
/*
|
||||
* 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..)
|
||||
*/
|
||||
ptstart(unit, 0);
|
||||
|
||||
splx(opri);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* sense handler: Called to determine what to do when the
|
||||
* device returns a CHECK CONDITION.
|
||||
*
|
||||
* For the processor type devices we try to handle the "info" field.
|
||||
*/
|
||||
|
||||
static int
|
||||
pt_sense(struct scsi_xfer *xs)
|
||||
{
|
||||
struct scsi_sense_data *sense = &(xs->sense);
|
||||
struct buf *bp;
|
||||
|
||||
long resid;
|
||||
|
||||
if ((sense->error_code & SSD_ERRCODE_VALID) == 0 ||
|
||||
(sense->ext.extended.flags & SSD_ILI) == 0) {
|
||||
return SCSIRET_CONTINUE; /* let the default handler handle it */
|
||||
}
|
||||
|
||||
resid = ntohl(*((int32_t *) sense->ext.extended.info));
|
||||
|
||||
bp = xs->bp;
|
||||
|
||||
if (resid < 0) {
|
||||
/* It synthesized data in order to fill our request.
|
||||
* Move resid back to cover this.
|
||||
*/
|
||||
xs->resid = -resid;
|
||||
xs->flags |= SCSI_RESID_VALID;
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
/* It wanted to send more data. We can't really do anything
|
||||
* about this.
|
||||
*/
|
||||
return SCSIRET_CONTINUE;
|
||||
}
|
||||
}
|
||||
|
||||
static pt_devsw_installed = 0;
|
||||
|
||||
static void
|
||||
pt_drvinit(void *unused)
|
||||
{
|
||||
dev_t dev;
|
||||
|
||||
if ( ! pt_devsw_installed ) {
|
||||
dev = makedev(CDEV_MAJOR, 0);
|
||||
cdevsw_add(&dev,&pt_cdevsw, NULL);
|
||||
pt_devsw_installed = 1;
|
||||
}
|
||||
}
|
||||
|
||||
SYSINIT(ptdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,pt_drvinit,NULL)
|
||||
|
||||
|
@ -1,351 +0,0 @@
|
||||
/*
|
||||
* Largely written by Julian Elischer (julian@tfs.com)
|
||||
* for TRW Financial Systems.
|
||||
*
|
||||
* TRW Financial Systems, in accordance with their agreement with Carnegie
|
||||
* Mellon University, makes this software available to CMU to distribute
|
||||
* or use in any manner that they see fit as long as this message is kept with
|
||||
* the software. For this reason TFS also grants any other persons or
|
||||
* organisations permission to use or modify this software.
|
||||
*
|
||||
* TFS supplies this software to be publicly redistributed
|
||||
* on the understanding that TFS is not responsible for the correct
|
||||
* functioning of this software in any circumstances.
|
||||
*
|
||||
* Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992
|
||||
*
|
||||
* $Id: scsi_all.h,v 1.15 1997/02/22 09:44:27 peter Exp $
|
||||
*/
|
||||
|
||||
/*
|
||||
* SCSI general interface description
|
||||
*/
|
||||
|
||||
#ifndef _SCSI_SCSI_ALL_H
|
||||
#define _SCSI_SCSI_ALL_H 1
|
||||
/*
|
||||
* SCSI command format
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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_CMD_LUN_SHIFT 5 /* LUN in the cmd is no longer SCSI */
|
||||
|
||||
|
||||
struct scsi_generic
|
||||
{
|
||||
u_char opcode;
|
||||
u_char bytes[11];
|
||||
};
|
||||
|
||||
struct scsi_test_unit_ready
|
||||
{
|
||||
u_char op_code;
|
||||
u_char byte2;
|
||||
u_char unused[3];
|
||||
u_char control;
|
||||
};
|
||||
|
||||
struct scsi_send_diag
|
||||
{
|
||||
u_char op_code;
|
||||
u_char byte2;
|
||||
#define SSD_UOL 0x01
|
||||
#define SSD_DOL 0x02
|
||||
#define SSD_SELFTEST 0x04
|
||||
#define SSD_PF 0x10
|
||||
u_char unused[1];
|
||||
u_char paramlen[2];
|
||||
u_char control;
|
||||
};
|
||||
|
||||
struct scsi_sense
|
||||
{
|
||||
u_char op_code;
|
||||
u_char byte2;
|
||||
u_char unused[2];
|
||||
u_char length;
|
||||
u_char control;
|
||||
};
|
||||
|
||||
struct scsi_inquiry
|
||||
{
|
||||
u_char op_code;
|
||||
u_char byte2;
|
||||
u_char unused[2];
|
||||
u_char length;
|
||||
u_char control;
|
||||
};
|
||||
|
||||
struct scsi_mode_sense
|
||||
{
|
||||
u_char op_code;
|
||||
u_char byte2;
|
||||
#define SMS_DBD 0x08
|
||||
u_char page;
|
||||
#define SMS_PAGE_CODE 0x3F
|
||||
#define SMS_PAGE_CTRL 0xC0
|
||||
#define SMS_PAGE_CTRL_CURRENT 0x00
|
||||
#define SMS_PAGE_CTRL_CHANGEABLE 0x40
|
||||
#define SMS_PAGE_CTRL_DEFAULT 0x80
|
||||
#define SMS_PAGE_CTRL_SAVED 0xC0
|
||||
u_char unused;
|
||||
u_char length;
|
||||
u_char control;
|
||||
};
|
||||
|
||||
struct scsi_mode_sense_big
|
||||
{
|
||||
u_char op_code;
|
||||
u_char byte2; /* same bits as small version */
|
||||
u_char page; /* same bits as small version */
|
||||
u_char unused[4];
|
||||
u_char length[2];
|
||||
u_char control;
|
||||
};
|
||||
|
||||
struct scsi_mode_select
|
||||
{
|
||||
u_char op_code;
|
||||
u_char byte2;
|
||||
#define SMS_SP 0x01
|
||||
#define SMS_PF 0x10
|
||||
u_char unused[2];
|
||||
u_char length;
|
||||
u_char control;
|
||||
};
|
||||
|
||||
struct scsi_mode_select_big
|
||||
{
|
||||
u_char op_code;
|
||||
u_char byte2; /* same bits as small version */
|
||||
u_char unused[5];
|
||||
u_char length[2];
|
||||
u_char control;
|
||||
};
|
||||
|
||||
struct scsi_reserve
|
||||
{
|
||||
u_char op_code;
|
||||
u_char byte2;
|
||||
u_char unused[2];
|
||||
u_char length;
|
||||
u_char control;
|
||||
};
|
||||
|
||||
struct scsi_release
|
||||
{
|
||||
u_char op_code;
|
||||
u_char byte2;
|
||||
u_char unused[2];
|
||||
u_char length;
|
||||
u_char control;
|
||||
};
|
||||
|
||||
struct scsi_prevent
|
||||
{
|
||||
u_char op_code;
|
||||
u_char byte2;
|
||||
u_char unused[2];
|
||||
u_char how;
|
||||
u_char control;
|
||||
};
|
||||
#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
|
||||
*/
|
||||
|
||||
#define TEST_UNIT_READY 0x00
|
||||
#define REQUEST_SENSE 0x03
|
||||
#define INQUIRY 0x12
|
||||
#define MODE_SELECT 0x15
|
||||
#define MODE_SENSE 0x1a
|
||||
#define START_STOP 0x1b
|
||||
#define RESERVE 0x16
|
||||
#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
|
||||
#define READ_ELEMENT_STATUS 0xb8
|
||||
|
||||
|
||||
/*
|
||||
* sense data format
|
||||
*/
|
||||
#define T_DIRECT 0
|
||||
#define T_SEQUENTIAL 1
|
||||
#define T_PRINTER 2
|
||||
#define T_PROCESSOR 3
|
||||
#define T_WORM 4
|
||||
#define T_READONLY 5
|
||||
#define T_SCANNER 6
|
||||
#define T_OPTICAL 7
|
||||
#define T_CHANGER 8
|
||||
#define T_COMM 9
|
||||
#define T_ASC0 10
|
||||
#define T_ASC1 11
|
||||
#define T_TARGET 12
|
||||
#define T_UNKNOWN 13
|
||||
#define T_NTYPES 14
|
||||
|
||||
#define T_NODEVICE 0x1F
|
||||
|
||||
#define T_REMOV 1
|
||||
#define T_FIXED 0
|
||||
|
||||
struct scsi_inquiry_data
|
||||
{
|
||||
u_char device;
|
||||
#define SID_TYPE 0x1F
|
||||
#define SID_QUAL 0xE0
|
||||
#define SID_QUAL_LU_OK 0x00
|
||||
#define SID_QUAL_LU_OFFLINE 0x20
|
||||
#define SID_QUAL_RSVD 0x40
|
||||
#define SID_QUAL_BAD_LU 0x60
|
||||
u_char dev_qual2;
|
||||
#define SID_QUAL2 0x7F
|
||||
#define SID_REMOVABLE 0x80
|
||||
u_char version;
|
||||
#define SID_ANSII 0x07
|
||||
#define SID_ECMA 0x38
|
||||
#define SID_ISO 0xC0
|
||||
u_char response_format;
|
||||
u_char additional_length;
|
||||
u_char unused[2];
|
||||
u_char flags;
|
||||
#define SID_SftRe 0x01
|
||||
#define SID_CmdQue 0x02
|
||||
#define SID_Linked 0x08
|
||||
#define SID_Sync 0x10
|
||||
#define SID_WBus16 0x20
|
||||
#define SID_WBus32 0x40
|
||||
#define SID_RelAdr 0x80
|
||||
char vendor[8];
|
||||
char product[16];
|
||||
char revision[4];
|
||||
u_char extra[8];
|
||||
};
|
||||
|
||||
|
||||
struct scsi_sense_data
|
||||
{
|
||||
/* 1*/ u_char error_code; /* same bits as new version */
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
/* 2*/ u_char blockhi;
|
||||
/* 3*/ u_char blockmed;
|
||||
/* 4*/ u_char blocklow;
|
||||
} unextended;
|
||||
struct
|
||||
{
|
||||
/* 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 24 below) */
|
||||
/*32*/ u_char extra_bytes[24];
|
||||
} extended;
|
||||
}ext;
|
||||
}; /* total of 32 bytes */
|
||||
|
||||
struct scsi_sense_extended
|
||||
{
|
||||
/* 2*/ u_char segment;
|
||||
/* 3*/ u_char flags;
|
||||
#define SSD_KEY 0x0F
|
||||
#define SSD_ILI 0x20
|
||||
#define SSD_EOM 0x40
|
||||
#define SSD_FILEMARK 0x80
|
||||
/* 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
|
||||
/*17*/ u_char sense_key_spec_2;
|
||||
/*18*/ u_char sense_key_spec_3;
|
||||
/*32*/ u_char extra_bytes[14];
|
||||
};
|
||||
|
||||
struct scsi_sense_data_new
|
||||
{
|
||||
/* 1*/ u_char error_code;
|
||||
#define SSD_ERRCODE 0x7F
|
||||
#define SSD_ERRCODE_VALID 0x80
|
||||
union
|
||||
{
|
||||
struct /* this is deprecated, the standard says "DON'T"*/
|
||||
{
|
||||
/* 2*/ u_char blockhi;
|
||||
/* 3*/ u_char blockmed;
|
||||
/* 4*/ u_char blocklow;
|
||||
} unextended;
|
||||
|
||||
struct scsi_sense_extended extended;
|
||||
} ext;
|
||||
}; /* total of 32 bytes */
|
||||
|
||||
struct blk_desc
|
||||
{
|
||||
u_char density;
|
||||
u_char nblocks[3];
|
||||
u_char reserved;
|
||||
u_char blklen[3];
|
||||
};
|
||||
|
||||
struct scsi_mode_header
|
||||
{
|
||||
u_char data_length; /* Sense data length */
|
||||
u_char medium_type;
|
||||
u_char dev_spec;
|
||||
u_char blk_desc_len;
|
||||
};
|
||||
|
||||
struct scsi_mode_header_big
|
||||
{
|
||||
u_char data_length[2]; /* Sense data length */
|
||||
u_char medium_type;
|
||||
u_char dev_spec;
|
||||
u_char unused[2];
|
||||
u_char blk_desc_len[2];
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Status Byte
|
||||
*/
|
||||
#define SCSI_OK 0x00
|
||||
#define SCSI_CHECK 0x02
|
||||
#define SCSI_BUSY 0x08
|
||||
#define SCSI_INTERM 0x10
|
||||
#define SCSI_RSVD 0x18
|
||||
#define SCSI_QUEUE_FULL 0x28
|
||||
#endif /*_SCSI_SCSI_ALL_H*/
|
1370
sys/scsi/scsi_base.c
1370
sys/scsi/scsi_base.c
File diff suppressed because it is too large
Load Diff
@ -1,216 +0,0 @@
|
||||
/*
|
||||
* Written by Julian Elischer (julian@tfs.com)
|
||||
* for TRW Financial Systems.
|
||||
*
|
||||
* TRW Financial Systems, in accordance with their agreement with Carnegie
|
||||
* Mellon University, makes this software available to CMU to distribute
|
||||
* or use in any manner that they see fit as long as this message is kept with
|
||||
* the software. For this reason TFS also grants any other persons or
|
||||
* organisations permission to use or modify this software.
|
||||
*
|
||||
* TFS supplies this software to be publicly redistributed
|
||||
* on the understanding that TFS is not responsible for the correct
|
||||
* functioning of this software in any circumstances.
|
||||
*
|
||||
* Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992
|
||||
*
|
||||
* $Id: scsi_cd.h,v 1.10 1997/02/22 09:44:28 peter Exp $
|
||||
*/
|
||||
#ifndef _SCSI_SCSI_CD_H
|
||||
#define _SCSI_SCSI_CD_H 1
|
||||
|
||||
/*
|
||||
* Define two bits always in the same place in byte 2 (flag byte)
|
||||
*/
|
||||
#define CD_RELADDR 0x01
|
||||
#define CD_MSF 0x02
|
||||
|
||||
/*
|
||||
* SCSI command format
|
||||
*/
|
||||
|
||||
struct scsi_pause
|
||||
{
|
||||
u_char op_code;
|
||||
u_char byte2;
|
||||
u_char unused[6];
|
||||
u_char resume;
|
||||
u_char control;
|
||||
};
|
||||
#define PA_PAUSE 1
|
||||
#define PA_RESUME 0
|
||||
|
||||
struct scsi_play_msf
|
||||
{
|
||||
u_char op_code;
|
||||
u_char byte2;
|
||||
u_char unused;
|
||||
u_char start_m;
|
||||
u_char start_s;
|
||||
u_char start_f;
|
||||
u_char end_m;
|
||||
u_char end_s;
|
||||
u_char end_f;
|
||||
u_char control;
|
||||
};
|
||||
|
||||
struct scsi_play_track
|
||||
{
|
||||
u_char op_code;
|
||||
u_char byte2;
|
||||
u_char unused[2];
|
||||
u_char start_track;
|
||||
u_char start_index;
|
||||
u_char unused1;
|
||||
u_char end_track;
|
||||
u_char end_index;
|
||||
u_char control;
|
||||
};
|
||||
|
||||
struct scsi_play
|
||||
{
|
||||
u_char op_code;
|
||||
u_char byte2;
|
||||
u_char blk_addr[4];
|
||||
u_char unused;
|
||||
u_char xfer_len[2];
|
||||
u_char control;
|
||||
};
|
||||
|
||||
struct scsi_play_big
|
||||
{
|
||||
u_char op_code;
|
||||
u_char byte2; /* same as above */
|
||||
u_char blk_addr[4];
|
||||
u_char xfer_len[4];
|
||||
u_char unused;
|
||||
u_char control;
|
||||
};
|
||||
|
||||
struct scsi_play_rel_big
|
||||
{
|
||||
u_char op_code;
|
||||
u_char byte2; /* same as above */
|
||||
u_char blk_addr[4];
|
||||
u_char xfer_len[4];
|
||||
u_char track;
|
||||
u_char control;
|
||||
};
|
||||
|
||||
struct scsi_read_header
|
||||
{
|
||||
u_char op_code;
|
||||
u_char byte2;
|
||||
u_char blk_addr[4];
|
||||
u_char unused;
|
||||
u_char data_len[2];
|
||||
u_char control;
|
||||
};
|
||||
|
||||
struct scsi_read_subchannel
|
||||
{
|
||||
u_char op_code;
|
||||
u_char byte2;
|
||||
u_char byte3;
|
||||
#define SRS_SUBQ 0x40
|
||||
u_char subchan_format;
|
||||
u_char unused[2];
|
||||
u_char track;
|
||||
u_char data_len[2];
|
||||
u_char control;
|
||||
};
|
||||
|
||||
struct scsi_read_toc
|
||||
{
|
||||
u_char op_code;
|
||||
u_char byte2;
|
||||
u_char unused[4];
|
||||
u_char from_track;
|
||||
u_char data_len[2];
|
||||
u_char control;
|
||||
};
|
||||
|
||||
struct scsi_read_cd_capacity
|
||||
{
|
||||
u_char op_code;
|
||||
u_char byte2;
|
||||
u_char addr_3; /* Most Significant */
|
||||
u_char addr_2;
|
||||
u_char addr_1;
|
||||
u_char addr_0; /* Least Significant */
|
||||
u_char unused[3];
|
||||
u_char control;
|
||||
};
|
||||
|
||||
/*
|
||||
* Opcodes
|
||||
*/
|
||||
|
||||
#define READ_CD_CAPACITY 0x25 /* slightly different from disk */
|
||||
#define READ_SUBCHANNEL 0x42 /* cdrom read Subchannel */
|
||||
#define READ_TOC 0x43 /* cdrom read TOC */
|
||||
#define READ_HEADER 0x44 /* cdrom read header */
|
||||
#define PLAY 0x45 /* cdrom play 'play audio' mode */
|
||||
#define PLAY_MSF 0x47 /* cdrom play Min,Sec,Frames mode */
|
||||
#define PLAY_TRACK 0x48 /* cdrom play track/index mode */
|
||||
#define PLAY_TRACK_REL 0x49 /* cdrom play track/index mode */
|
||||
#define PAUSE 0x4b /* cdrom pause in 'play audio' mode */
|
||||
#define PLAY_BIG 0xa5 /* cdrom pause in 'play audio' mode */
|
||||
#define PLAY_TRACK_REL_BIG 0xa9 /* cdrom play track/index mode */
|
||||
|
||||
|
||||
|
||||
struct scsi_read_cd_cap_data
|
||||
{
|
||||
u_char addr_3; /* Most significant */
|
||||
u_char addr_2;
|
||||
u_char addr_1;
|
||||
u_char addr_0; /* Least significant */
|
||||
u_char length_3; /* Most significant */
|
||||
u_char length_2;
|
||||
u_char length_1;
|
||||
u_char length_0; /* Least significant */
|
||||
};
|
||||
|
||||
union cd_pages
|
||||
{
|
||||
struct audio_page
|
||||
{
|
||||
u_char page_code;
|
||||
#define CD_PAGE_CODE 0x3F
|
||||
#define AUDIO_PAGE 0x0e
|
||||
#define CD_PAGE_PS 0x80
|
||||
u_char param_len;
|
||||
u_char flags;
|
||||
#define CD_PA_SOTC 0x02
|
||||
#define CD_PA_IMMED 0x04
|
||||
u_char unused[2];
|
||||
u_char format_lba;
|
||||
#define CD_PA_FORMAT_LBA 0x0F
|
||||
#define CD_PA_APR_VALID 0x80
|
||||
u_char lb_per_sec[2];
|
||||
struct port_control
|
||||
{
|
||||
u_char channels;
|
||||
#define CHANNEL 0x0F
|
||||
#define CHANNEL_0 1
|
||||
#define CHANNEL_1 2
|
||||
#define CHANNEL_2 4
|
||||
#define CHANNEL_3 8
|
||||
#define LEFT_CHANNEL CHANNEL_0
|
||||
#define RIGHT_CHANNEL CHANNEL_1
|
||||
u_char volume;
|
||||
} port[4];
|
||||
#define LEFT_PORT 0
|
||||
#define RIGHT_PORT 1
|
||||
}audio;
|
||||
};
|
||||
|
||||
struct cd_mode_data
|
||||
{
|
||||
struct scsi_mode_header header;
|
||||
struct blk_desc blk_desc;
|
||||
union cd_pages page;
|
||||
};
|
||||
#endif /*_SCSI_SCSI_CD_H*/
|
||||
|
@ -1,400 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 1996 Jason R. Thorpe <thorpej@and.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Partially based on an autochanger driver written by Stefan Grefen
|
||||
* and on an autochanger driver written by the Systems Programming Group
|
||||
* at the University of Utah Computer Science Department.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgements:
|
||||
* This product includes software developed by Jason R. Thorpe
|
||||
* for And Communications, http://www.and.com/
|
||||
* 4. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id: scsi_changer.h,v 1.9 1997/02/22 09:44:29 peter Exp $
|
||||
*/
|
||||
|
||||
/*
|
||||
* SCSI changer interface description
|
||||
*/
|
||||
|
||||
/*
|
||||
* Partially derived from software written by Stefan Grefen
|
||||
* (grefen@goofy.zdv.uni-mainz.de soon grefen@convex.com)
|
||||
* based on the SCSI System by written Julian Elischer (julian@tfs.com)
|
||||
* for TRW Financial Systems.
|
||||
*
|
||||
* TRW Financial Systems, in accordance with their agreement with Carnegie
|
||||
* Mellon University, makes this software available to CMU to distribute
|
||||
* or use in any manner that they see fit as long as this message is kept with
|
||||
* the software. For this reason TFS also grants any other persons or
|
||||
* organisations permission to use or modify this software.
|
||||
*
|
||||
* TFS supplies this software to be publicly redistributed
|
||||
* on the understanding that TFS is not responsible for the correct
|
||||
* functioning of this software in any circumstances.
|
||||
*
|
||||
* Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992
|
||||
*/
|
||||
|
||||
#ifndef _SCSI_SCSI_CHANGER_H
|
||||
#define _SCSI_SCSI_CHANGER_H 1
|
||||
|
||||
/*
|
||||
* SCSI command format
|
||||
*/
|
||||
|
||||
/*
|
||||
* Exchange the medium in the source element with the medium
|
||||
* located at the destination element.
|
||||
*/
|
||||
struct scsi_exchange_medium {
|
||||
u_int8_t opcode;
|
||||
#define EXCHANGE_MEDIUM 0xa6
|
||||
u_int8_t byte2;
|
||||
u_int8_t tea[2]; /* transport element address */
|
||||
u_int8_t src[2]; /* source address */
|
||||
u_int8_t fdst[2]; /* first destination address */
|
||||
u_int8_t sdst[2]; /* second destination address */
|
||||
u_int8_t flags;
|
||||
#define EXCHANGE_MEDIUM_INV1 0x01
|
||||
#define EXCHANGE_MEDIUM_INV2 0x02
|
||||
u_int8_t control;
|
||||
};
|
||||
|
||||
/*
|
||||
* Cause the medium changer to check all elements for medium and any
|
||||
* other status relevant to the element.
|
||||
*/
|
||||
struct scsi_initialize_elememt_status {
|
||||
u_int8_t opcode;
|
||||
#define INITIALIZE_ELEMENT_STATUS 0x07
|
||||
u_int8_t byte2;
|
||||
u_int8_t reserved[3];
|
||||
u_int8_t control;
|
||||
};
|
||||
|
||||
/*
|
||||
* Request the changer to move a unit of media from the source element
|
||||
* to the destination element.
|
||||
*/
|
||||
struct scsi_move_medium {
|
||||
u_int8_t opcode;
|
||||
#define MOVE_MEDIUM 0xa5
|
||||
u_int8_t byte2;
|
||||
u_int8_t tea[2]; /* transport element address */
|
||||
u_int8_t src[2]; /* source element address */
|
||||
u_int8_t dst[2]; /* destination element address */
|
||||
u_int8_t reserved[2];
|
||||
u_int8_t flags;
|
||||
#define MOVE_MEDIUM_INVERT 0x01
|
||||
u_int8_t control;
|
||||
};
|
||||
|
||||
/*
|
||||
* Position the specified transport element (picker) in front of
|
||||
* the destination element specified.
|
||||
*/
|
||||
struct scsi_position_to_element {
|
||||
u_int8_t opcode;
|
||||
#define POSITION_TO_ELEMENT 0x2b
|
||||
u_int8_t byte2;
|
||||
u_int8_t tea[2]; /* transport element address */
|
||||
u_int8_t dst[2]; /* destination element address */
|
||||
u_int8_t reserved[2];
|
||||
u_int8_t flags;
|
||||
#define POSITION_TO_ELEMENT_INVERT 0x01
|
||||
u_int8_t control;
|
||||
};
|
||||
|
||||
/*
|
||||
* Request that the changer report the status of its internal elements.
|
||||
*/
|
||||
struct scsi_read_element_status {
|
||||
u_int8_t opcode;
|
||||
#define READ_ELEMENT_STATUS 0xb8
|
||||
u_int8_t byte2;
|
||||
#define READ_ELEMENT_STATUS_VOLTAG 0x10 /* report volume tag info */
|
||||
/* ...next 4 bits are an element type code... */
|
||||
u_int8_t sea[2]; /* starting element address */
|
||||
u_int8_t count[2]; /* number of elements */
|
||||
u_int8_t reserved0;
|
||||
u_int8_t len[3]; /* length of data buffer */
|
||||
u_int8_t reserved1;
|
||||
u_int8_t control;
|
||||
};
|
||||
|
||||
struct scsi_request_volume_element_address {
|
||||
u_int8_t opcode;
|
||||
#define REQUEST_VOLUME_ELEMENT_ADDRESS 0xb5
|
||||
u_int8_t byte2;
|
||||
#define REQUEST_VOLUME_ELEMENT_ADDRESS_VOLTAG 0x10
|
||||
/* ...next 4 bits are an element type code... */
|
||||
u_int8_t eaddr[2]; /* element address */
|
||||
u_int8_t count[2]; /* number of elements */
|
||||
u_int8_t reserved0;
|
||||
u_int8_t len[3]; /* length of data buffer */
|
||||
u_int8_t reserved1;
|
||||
u_int8_t control;
|
||||
};
|
||||
|
||||
/* XXX scsi_release */
|
||||
|
||||
/*
|
||||
* Data returned by READ ELEMENT STATUS consists of an 8-byte header
|
||||
* followed by one or more read_element_status_pages.
|
||||
*/
|
||||
struct read_element_status_header {
|
||||
u_int8_t fear[2]; /* first element address reported */
|
||||
u_int8_t count[2]; /* number of elements available */
|
||||
u_int8_t reserved;
|
||||
u_int8_t nbytes[3]; /* byte count of all pages */
|
||||
};
|
||||
|
||||
struct read_element_status_page_header {
|
||||
u_int8_t type; /* element type code; see type codes below */
|
||||
u_int8_t flags;
|
||||
#define READ_ELEMENT_STATUS_AVOLTAG 0x40
|
||||
#define READ_ELEMENT_STATUS_PVOLTAG 0x80
|
||||
u_int8_t edl[2]; /* element descriptor length */
|
||||
u_int8_t reserved;
|
||||
u_int8_t nbytes[3]; /* byte count of all descriptors */
|
||||
};
|
||||
|
||||
struct read_element_status_descriptor {
|
||||
u_int8_t eaddr[2]; /* element address */
|
||||
u_int8_t flags1;
|
||||
|
||||
#define READ_ELEMENT_STATUS_FULL 0x01
|
||||
#define READ_ELEMENT_STATUS_IMPEXP 0x02
|
||||
#define READ_ELEMENT_STATUS_EXCEPT 0x04
|
||||
#define READ_ELEMENT_STATUS_ACCESS 0x08
|
||||
#define READ_ELEMENT_STATUS_EXENAB 0x10
|
||||
#define READ_ELEMENT_STATUS_INENAB 0x20
|
||||
|
||||
#define READ_ELEMENT_STATUS_MT_MASK1 0x05
|
||||
#define READ_ELEMENT_STATUS_ST_MASK1 0x0c
|
||||
#define READ_ELEMENT_STATUS_IE_MASK1 0x3f
|
||||
#define READ_ELEMENT_STATUS_DT_MASK1 0x0c
|
||||
|
||||
u_int8_t reserved0;
|
||||
u_int8_t sense_code;
|
||||
u_int8_t sense_qual;
|
||||
|
||||
/*
|
||||
* dt_scsi_flags and dt_scsi_addr are valid only on data transport
|
||||
* elements. These bytes are undefined for all other element types.
|
||||
*/
|
||||
u_int8_t dt_scsi_flags;
|
||||
|
||||
#define READ_ELEMENT_STATUS_DT_LUNMASK 0x07
|
||||
#define READ_ELEMENT_STATUS_DT_LUVALID 0x10
|
||||
#define READ_ELEMENT_STATUS_DT_IDVALID 0x20
|
||||
#define READ_ELEMENT_STATUS_DT_NOTBUS 0x80
|
||||
|
||||
u_int8_t dt_scsi_addr;
|
||||
|
||||
u_int8_t reserved1;
|
||||
|
||||
u_int8_t flags2;
|
||||
#define READ_ELEMENT_STATUS_INVERT 0x40
|
||||
#define READ_ELEMENT_STATUS_SVALID 0x80
|
||||
u_int8_t ssea[2]; /* source storage element address */
|
||||
|
||||
/*
|
||||
* bytes 12-47: Primary volume tag information.
|
||||
* (field omitted if PVOLTAG = 0)
|
||||
*
|
||||
* bytes 48-83: Alternate volume tag information.
|
||||
* (field omitted if AVOLTAG = 0)
|
||||
*
|
||||
* bytes 84-87: Reserved (moved up if either of the above fields
|
||||
* are omitted)
|
||||
*
|
||||
* bytes 88-end: Vendor-specific: (moved up if either of the
|
||||
* above fields are missing)
|
||||
*/
|
||||
};
|
||||
|
||||
/* XXX add data returned by REQUEST VOLUME ELEMENT ADDRESS */
|
||||
|
||||
/* Element type codes */
|
||||
#define ELEMENT_TYPE_MASK 0x0f /* Note: these aren't bits */
|
||||
#define ELEMENT_TYPE_ALL 0x00
|
||||
#define ELEMENT_TYPE_MT 0x01
|
||||
#define ELEMENT_TYPE_ST 0x02
|
||||
#define ELEMENT_TYPE_IE 0x03
|
||||
#define ELEMENT_TYPE_DT 0x04
|
||||
|
||||
/*
|
||||
* XXX The following definitions should be common to all SCSI device types.
|
||||
*/
|
||||
#define PGCODE_MASK 0x3f /* valid page number bits in pg_code */
|
||||
#define PGCODE_PS 0x80 /* indicates page is savable */
|
||||
|
||||
/*
|
||||
* Device capabilities page.
|
||||
*
|
||||
* This page defines characteristics of the elemenet types in the
|
||||
* medium changer device.
|
||||
*
|
||||
* Note in the definitions below, the following abbreviations are
|
||||
* used:
|
||||
* MT Medium transport element (picker)
|
||||
* ST Storage transport element (slot)
|
||||
* IE Import/export element (portal)
|
||||
* DT Data tranfer element (tape/disk drive)
|
||||
*/
|
||||
struct page_device_capabilities {
|
||||
u_int8_t pg_code; /* page code (0x1f) */
|
||||
u_int8_t pg_length; /* page length (0x12) */
|
||||
|
||||
/*
|
||||
* The STOR_xx bits indicate that an element of a given
|
||||
* type may provide independent storage for a unit of
|
||||
* media. The top four bits of this value are reserved.
|
||||
*/
|
||||
u_int8_t stor;
|
||||
#define STOR_MT 0x01
|
||||
#define STOR_ST 0x02
|
||||
#define STOR_IE 0x04
|
||||
#define STOR_DT 0x08
|
||||
|
||||
u_int8_t reserved0;
|
||||
|
||||
/*
|
||||
* The MOVE_TO_yy bits indicate the changer supports
|
||||
* moving a unit of medium from an element of a given type to an
|
||||
* element of type yy. This is used to determine if a given
|
||||
* MOVE MEDIUM command is legal. The top four bits of each
|
||||
* of these values are reserved.
|
||||
*/
|
||||
u_int8_t move_from_mt;
|
||||
u_int8_t move_from_st;
|
||||
u_int8_t move_from_ie;
|
||||
u_int8_t move_from_dt;
|
||||
#define MOVE_TO_MT 0x01
|
||||
#define MOVE_TO_ST 0x02
|
||||
#define MOVE_TO_IE 0x04
|
||||
#define MOVE_TO_DT 0x08
|
||||
|
||||
u_int8_t reserved1[2];
|
||||
|
||||
/*
|
||||
* Similar to above, but for EXCHANGE MEDIUM.
|
||||
*/
|
||||
u_int8_t exchange_with_mt;
|
||||
u_int8_t exchange_with_st;
|
||||
u_int8_t exchange_with_ie;
|
||||
u_int8_t exchange_with_dt;
|
||||
#define EXCHANGE_WITH_MT 0x01
|
||||
#define EXCHANGE_WITH_ST 0x02
|
||||
#define EXCHANGE_WITH_IE 0x04
|
||||
#define EXCHANGE_WITH_DT 0x08
|
||||
};
|
||||
|
||||
/*
|
||||
* Medium changer elemement address assignment page.
|
||||
*
|
||||
* Some of these fields can be a little confusing, so an explanation
|
||||
* is in order.
|
||||
*
|
||||
* Each component within a a medium changer apparatus is called an
|
||||
* "element".
|
||||
*
|
||||
* The "medium transport element address" is the address of the first
|
||||
* picker (robotic arm). "Number of medium transport elements" tells
|
||||
* us how many pickers exist in the changer.
|
||||
*
|
||||
* The "first storage element address" is the address of the first
|
||||
* slot in the tape or disk magazine. "Number of storage elements" tells
|
||||
* us how many slots exist in the changer.
|
||||
*
|
||||
* The "first import/export element address" is the address of the first
|
||||
* medium portal accessible both by the medium changer and an outside
|
||||
* human operator. This is where the changer might deposit tapes destined
|
||||
* for some vault. The "number of import/export elements" tells us
|
||||
* not many of these portals exist in the changer. NOTE: this number may
|
||||
* be 0.
|
||||
*
|
||||
* The "first data transfer element address" is the address of the first
|
||||
* tape or disk drive in the changer. "Number of data transfer elements"
|
||||
* tells us how many drives exist in the changer.
|
||||
*/
|
||||
struct page_element_address_assignment {
|
||||
u_int8_t pg_code; /* page code (0x1d) */
|
||||
u_int8_t pg_length; /* page length (0x12) */
|
||||
|
||||
/* Medium transport element address */
|
||||
u_int8_t mtea[2];
|
||||
|
||||
/* Number of medium transport elements */
|
||||
u_int8_t nmte[2];
|
||||
|
||||
/* First storage element address */
|
||||
u_int8_t fsea[2];
|
||||
|
||||
/* Number of storage elements */
|
||||
u_int8_t nse[2];
|
||||
|
||||
/* First import/export element address */
|
||||
u_int8_t fieea[2];
|
||||
|
||||
/* Number of import/export elements */
|
||||
u_int8_t niee[2];
|
||||
|
||||
/* First data transfer element address */
|
||||
u_int8_t fdtea[2];
|
||||
|
||||
/* Number of data trafer elements */
|
||||
u_int8_t ndte[2];
|
||||
|
||||
u_int8_t reserved[2];
|
||||
};
|
||||
|
||||
/*
|
||||
* Transport geometry parameters page.
|
||||
*
|
||||
* Defines whether each medium transport element is a member of a set of
|
||||
* elements that share a common robotics subsystem and whether the element
|
||||
* is capable of media rotation. One transport geometry descriptor is
|
||||
* transferred for each medium transport element, beginning with the first
|
||||
* medium transport element (other than the default transport element address
|
||||
* of 0).
|
||||
*/
|
||||
struct page_transport_geometry_parameters {
|
||||
u_int8_t pg_code; /* page code (0x1e) */
|
||||
u_int8_t pg_length; /* page length; variable */
|
||||
|
||||
/* Transport geometry descriptor(s) are here. */
|
||||
|
||||
u_int8_t misc;
|
||||
#define CAN_ROTATE 0x01
|
||||
|
||||
/* Member number in transport element set. */
|
||||
u_int8_t member;
|
||||
};
|
||||
|
||||
#endif /* _SCSI_SCSI_CHANGER_H */
|
@ -1,59 +0,0 @@
|
||||
/*
|
||||
* Use
|
||||
* options SCSIDEBUG
|
||||
*
|
||||
* in the kernel config file to get these macros into effect.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Written by Julian Elischer (julian@tfs.com)
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
#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 */
|
||||
|
@ -1,221 +0,0 @@
|
||||
/*
|
||||
* SCSI interface description
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Largely written by Julian Elischer (julian@tfs.com)
|
||||
* for TRW Financial Systems.
|
||||
*
|
||||
* TRW Financial Systems, in accordance with their agreement with Carnegie
|
||||
* Mellon University, makes this software available to CMU to distribute
|
||||
* or use in any manner that they see fit as long as this message is kept with
|
||||
* the software. For this reason TFS also grants any other persons or
|
||||
* organisations permission to use or modify this software.
|
||||
*
|
||||
* TFS supplies this software to be publicly redistributed
|
||||
* on the understanding that TFS is not responsible for the correct
|
||||
* functioning of this software in any circumstances.
|
||||
*
|
||||
* Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
/*
|
||||
* SCSI command format
|
||||
*/
|
||||
|
||||
#ifndef _SCSI_SCSI_DISK_H
|
||||
#define _SCSI_SCSI_DISK_H 1
|
||||
|
||||
struct scsi_reassign_blocks
|
||||
{
|
||||
u_char op_code;
|
||||
u_char byte2;
|
||||
u_char unused[3];
|
||||
u_char control;
|
||||
};
|
||||
|
||||
struct scsi_rw
|
||||
{
|
||||
u_char op_code;
|
||||
u_char addr_2; /* Most significant */
|
||||
#define SRW_TOPADDR 0x1F /* only 5 bits here */
|
||||
u_char addr_1;
|
||||
u_char addr_0; /* least significant */
|
||||
u_char length;
|
||||
u_char control;
|
||||
};
|
||||
|
||||
struct scsi_rw_big
|
||||
{
|
||||
u_char op_code;
|
||||
u_char byte2;
|
||||
#define SRWB_RELADDR 0x01
|
||||
u_char addr_3; /* Most significant */
|
||||
u_char addr_2;
|
||||
u_char addr_1;
|
||||
u_char addr_0; /* least significant */
|
||||
u_char reserved;
|
||||
u_char length2;
|
||||
u_char length1;
|
||||
u_char control;
|
||||
};
|
||||
|
||||
struct scsi_read_capacity
|
||||
{
|
||||
u_char op_code;
|
||||
u_char byte2;
|
||||
u_char addr_3; /* Most Significant */
|
||||
u_char addr_2;
|
||||
u_char addr_1;
|
||||
u_char addr_0; /* Least Significant */
|
||||
u_char unused[3];
|
||||
u_char control;
|
||||
};
|
||||
|
||||
struct scsi_start_stop
|
||||
{
|
||||
u_char op_code;
|
||||
u_char byte2;
|
||||
u_char unused[2];
|
||||
u_char how;
|
||||
#define SSS_START 0x01
|
||||
#define SSS_LOEJ 0x02
|
||||
u_char control;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Opcodes
|
||||
*/
|
||||
|
||||
#define REASSIGN_BLOCKS 0x07
|
||||
#define READ_COMMAND 0x08
|
||||
#define WRITE_COMMAND 0x0a
|
||||
#define MODE_SELECT 0x15
|
||||
#define MODE_SENSE 0x1a
|
||||
#define START_STOP 0x1b
|
||||
#define PREVENT_ALLOW 0x1e
|
||||
#define READ_CAPACITY 0x25
|
||||
#define READ_BIG 0x28
|
||||
#define WRITE_BIG 0x2a
|
||||
|
||||
|
||||
|
||||
struct scsi_read_cap_data
|
||||
{
|
||||
u_char addr_3; /* Most significant */
|
||||
u_char addr_2;
|
||||
u_char addr_1;
|
||||
u_char addr_0; /* Least significant */
|
||||
u_char length_3; /* Most significant */
|
||||
u_char length_2;
|
||||
u_char length_1;
|
||||
u_char length_0; /* Least significant */
|
||||
};
|
||||
|
||||
struct scsi_reassign_blocks_data
|
||||
{
|
||||
u_char reserved[2];
|
||||
u_char length_msb;
|
||||
u_char length_lsb;
|
||||
struct
|
||||
{
|
||||
u_char dlbaddr_3; /* defect logical block address (MSB) */
|
||||
u_char dlbaddr_2;
|
||||
u_char dlbaddr_1;
|
||||
u_char dlbaddr_0; /* defect logical block address (LSB) */
|
||||
} defect_descriptor[1];
|
||||
};
|
||||
|
||||
union disk_pages /* this is the structure copied from osf */
|
||||
{
|
||||
struct page_disk_format {
|
||||
u_char pg_code; /* page code (should be 3) */
|
||||
#define DISK_PGCODE 0x3F /* only 6 bits valid */
|
||||
u_char pg_length; /* page length (should be 0x16) */
|
||||
u_char trk_z_1; /* tracks per zone (MSB) */
|
||||
u_char trk_z_0; /* tracks per zone (LSB) */
|
||||
u_char alt_sec_1; /* alternate sectors per zone (MSB) */
|
||||
u_char alt_sec_0; /* alternate sectors per zone (LSB) */
|
||||
u_char alt_trk_z_1; /* alternate tracks per zone (MSB) */
|
||||
u_char alt_trk_z_0; /* alternate tracks per zone (LSB) */
|
||||
u_char alt_trk_v_1; /* alternate tracks per volume (MSB) */
|
||||
u_char alt_trk_v_0; /* alternate tracks per volume (LSB) */
|
||||
u_char ph_sec_t_1; /* physical sectors per track (MSB) */
|
||||
u_char ph_sec_t_0; /* physical sectors per track (LSB) */
|
||||
u_char bytes_s_1; /* bytes per sector (MSB) */
|
||||
u_char bytes_s_0; /* bytes per sector (LSB) */
|
||||
u_char interleave_1;/* interleave (MSB) */
|
||||
u_char interleave_0;/* interleave (LSB) */
|
||||
u_char trk_skew_1; /* track skew factor (MSB) */
|
||||
u_char trk_skew_0; /* track skew factor (LSB) */
|
||||
u_char cyl_skew_1; /* cylinder skew (MSB) */
|
||||
u_char cyl_skew_0; /* cylinder skew (LSB) */
|
||||
u_char flags; /* various */
|
||||
#define DISK_FMT_SURF 0x10
|
||||
#define DISK_FMT_RMB 0x20
|
||||
#define DISK_FMT_HSEC 0x40
|
||||
#define DISK_FMT_SSEC 0x80
|
||||
u_char reserved21;
|
||||
u_char reserved22;
|
||||
u_char reserved23;
|
||||
} disk_format;
|
||||
struct page_rigid_geometry {
|
||||
u_char pg_code; /* page code (should be 4) */
|
||||
u_char pg_length; /* page length (should be 0x16) */
|
||||
u_char ncyl_2; /* number of cylinders (MSB) */
|
||||
u_char ncyl_1; /* number of cylinders */
|
||||
u_char ncyl_0; /* number of cylinders (LSB) */
|
||||
u_char nheads; /* number of heads */
|
||||
u_char st_cyl_wp_2; /* starting cyl., write precomp (MSB) */
|
||||
u_char st_cyl_wp_1; /* starting cyl., write precomp */
|
||||
u_char st_cyl_wp_0; /* starting cyl., write precomp (LSB) */
|
||||
u_char st_cyl_rwc_2;/* starting cyl., red. write cur (MSB)*/
|
||||
u_char st_cyl_rwc_1;/* starting cyl., red. write cur */
|
||||
u_char st_cyl_rwc_0;/* starting cyl., red. write cur (LSB)*/
|
||||
u_char driv_step_1; /* drive step rate (MSB) */
|
||||
u_char driv_step_0; /* drive step rate (LSB) */
|
||||
u_char land_zone_2; /* landing zone cylinder (MSB) */
|
||||
u_char land_zone_1; /* landing zone cylinder */
|
||||
u_char land_zone_0; /* landing zone cylinder (LSB) */
|
||||
u_char rpl; /* rotational position locking (2 bits) */
|
||||
u_char rot_offset; /* rotational offset */
|
||||
u_char reserved19;
|
||||
u_char medium_rot_rate_1; /* medium rotation rate (RPM) (MSB) */
|
||||
u_char medium_rot_rate_0; /* medium rotation rate (RPM) (LSB) */
|
||||
u_char reserved22;
|
||||
u_char reserved23;
|
||||
} rigid_geometry;
|
||||
} ;
|
||||
#endif /* _SCSI_SCSI_DISK_H*/
|
@ -1,245 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 1995, HD Associates, Inc.
|
||||
* PO Box 276
|
||||
* Pepperell, MA 01463
|
||||
* 508 433 5266
|
||||
* dufault@hda.com
|
||||
*
|
||||
* This code is contributed to the University of California at Berkeley:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id: scsi_driver.c,v 1.26 1997/09/02 20:06:34 bde Exp $
|
||||
*
|
||||
*/
|
||||
|
||||
#include "opt_scsi.h"
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/buf.h>
|
||||
|
||||
#include <scsi/scsiconf.h>
|
||||
#include <scsi/scsi_debug.h>
|
||||
#include <scsi/scsi_driver.h>
|
||||
|
||||
#define GETUNIT(DEVICE, DEV) \
|
||||
((DEVICE)->getunit) ? (*(DEVICE)->getunit)((DEV)) \
|
||||
: (minor((DEV)) & ~SCSI_CONTROL_MASK)
|
||||
|
||||
/* scsi_device_attach: Attach a SCSI device. This routine will
|
||||
* print out the device address, what it is, then call the type
|
||||
* attach function and when that returns print a newline. If the
|
||||
* type attach will make LOT's of noise it should print a leading
|
||||
* newline and then the address using sc_print_addr. See "sd.c".
|
||||
*/
|
||||
int scsi_device_attach(struct scsi_link *sc_link)
|
||||
{
|
||||
errval errcode;
|
||||
dev_t dev;
|
||||
struct scsi_device *device = sc_link->device;
|
||||
|
||||
if (bootverbose)
|
||||
sc_link->flags |= SDEV_BOOTVERBOSE;
|
||||
|
||||
SC_DEBUG(sc_link, SDEV_DB2,
|
||||
("%s%dattach: ", device->name, sc_link->dev_unit));
|
||||
|
||||
/* Print _sane_ probe info! */
|
||||
printf("%s%d at scbus%d target %d lun %d\n",
|
||||
sc_link->device->name, sc_link->dev_unit,
|
||||
sc_link->scsibus, sc_link->target, sc_link->lun);
|
||||
#ifndef SCSIDEBUG
|
||||
scsi_print_info(sc_link);
|
||||
#endif
|
||||
|
||||
printf("%s%d: %s ", device->name, sc_link->dev_unit, device->desc);
|
||||
/*
|
||||
* XXX some SCSI adapter drivers print out things while the
|
||||
* device-specific attach routine is running. The result is
|
||||
* something of a mess. This hack at least keeps it so each
|
||||
* line will begin with foodev0:.
|
||||
*/
|
||||
sc_print_init();
|
||||
|
||||
dev = scsi_dev_lookup(device->open);
|
||||
|
||||
sc_link->dev = (device->setunit ?
|
||||
(*device->setunit)(dev, sc_link->dev_unit) :
|
||||
makedev(major(dev), sc_link->dev_unit) );
|
||||
|
||||
errcode = (device->attach) ? (*(device->attach))(sc_link) : 0;
|
||||
|
||||
printf("\n");
|
||||
sc_print_finish();
|
||||
|
||||
if (errcode == 0)
|
||||
sc_link->flags |= device->link_flags;
|
||||
|
||||
return errcode;
|
||||
}
|
||||
|
||||
int
|
||||
scsi_open(dev_t dev, int flags, int fmt, struct proc *p,
|
||||
struct scsi_device *device)
|
||||
{
|
||||
errval errcode;
|
||||
u_int32_t unit;
|
||||
struct scsi_link *sc_link;
|
||||
|
||||
if (device == 0)
|
||||
return ENXIO;
|
||||
|
||||
unit = GETUNIT(device, dev);
|
||||
sc_link = SCSI_LINK(device, unit);
|
||||
|
||||
/*
|
||||
* Check the unit is legal
|
||||
*/
|
||||
if (sc_link == 0 || (sc_link->sd == 0 && !(sc_link->flags & SDEV_UK)))
|
||||
return ENXIO;
|
||||
|
||||
/* If it is a "once only" device that is already open return EBUSY.
|
||||
*/
|
||||
if ((sc_link->flags & SDEV_ONCE_ONLY) && (sc_link->flags & SDEV_IS_OPEN))
|
||||
return EBUSY;
|
||||
|
||||
/* For the control device (user ioctl's only) don't call the open
|
||||
* entry.
|
||||
*/
|
||||
if (SCSI_CONTROL(dev) || (device->dev_open == 0))
|
||||
{
|
||||
scsi_test_unit_ready(sc_link, SCSI_SILENT);
|
||||
errcode = 0;
|
||||
}
|
||||
else
|
||||
errcode = (*device->dev_open)(dev, flags, fmt, p, sc_link);
|
||||
|
||||
if (!errcode ) sc_link->flags |= SDEV_IS_OPEN;
|
||||
|
||||
SC_DEBUG(sc_link, SDEV_DB1, ("%sopen: dev=0x%lx (unit %lu) result %d\n",
|
||||
device->name, (u_long)dev, (u_long)unit, errcode));
|
||||
|
||||
return errcode;
|
||||
}
|
||||
|
||||
int
|
||||
scsi_close(dev_t dev, int flags, int fmt, struct proc *p,
|
||||
struct scsi_device *device)
|
||||
{
|
||||
errval errcode;
|
||||
struct scsi_link *sc_link = SCSI_LINK(device, GETUNIT(device, dev));
|
||||
|
||||
SC_DEBUG(sc_link, SDEV_DB1, ("%sclose: Closing device\n", device->name));
|
||||
|
||||
if (SCSI_CONTROL(dev) || (device->dev_close == 0))
|
||||
errcode = 0;
|
||||
else
|
||||
errcode = (*device->dev_close)(dev, flags, fmt, p, sc_link);
|
||||
|
||||
sc_link->flags &= ~SDEV_IS_OPEN;
|
||||
|
||||
return errcode;
|
||||
}
|
||||
|
||||
int
|
||||
scsi_ioctl(dev_t dev, u_int32_t cmd, caddr_t arg, int flags, struct proc *p,
|
||||
struct scsi_device *device)
|
||||
{
|
||||
errval errcode;
|
||||
struct scsi_link *sc_link = SCSI_LINK(device, GETUNIT(device, dev));
|
||||
|
||||
if (SCSI_CONTROL(dev) || (device->dev_ioctl == 0))
|
||||
errcode = scsi_do_ioctl(dev, cmd, arg, flags, p, sc_link);
|
||||
else
|
||||
errcode = (*device->dev_ioctl)(dev, cmd, arg, flags, p, sc_link);
|
||||
|
||||
return errcode;
|
||||
}
|
||||
|
||||
void
|
||||
scsi_minphys(struct buf *bp, struct scsi_device *device)
|
||||
{
|
||||
struct scsi_link *sc_link = SCSI_LINK(device, GETUNIT(device, bp->b_dev));
|
||||
(*sc_link->adapter->scsi_minphys)(bp);
|
||||
}
|
||||
|
||||
void
|
||||
scsi_strategy(struct buf *bp, struct scsi_device *device)
|
||||
{
|
||||
u_int32_t unit = GETUNIT(device, bp->b_dev);
|
||||
struct scsi_link *sc_link = SCSI_LINK(device, unit);
|
||||
|
||||
SC_DEBUG(sc_link, SDEV_DB2, ("\n%sstrategy ", device->name));
|
||||
SC_DEBUG(sc_link, SDEV_DB1, ("%ld bytes @ blk%ld\n",
|
||||
bp->b_bcount, (long)bp->b_blkno));
|
||||
|
||||
if (SCSI_CONTROL(bp->b_dev) || (device->dev_strategy == 0))
|
||||
{
|
||||
bp->b_resid = bp->b_bcount;
|
||||
bp->b_error = EIO;
|
||||
bp->b_flags |= B_ERROR;
|
||||
biodone(bp);
|
||||
}
|
||||
else
|
||||
{
|
||||
bp->b_resid = 0;
|
||||
bp->b_error = 0;
|
||||
|
||||
if (bp->b_bcount == 0)
|
||||
biodone(bp);
|
||||
else
|
||||
{
|
||||
(*sc_link->adapter->scsi_minphys)(bp);
|
||||
(*device->dev_strategy)(bp, sc_link);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int scsi_device_lock(struct scsi_link *sc_link)
|
||||
{
|
||||
int error;
|
||||
while (sc_link->flags & SDEV_XLOCK) {
|
||||
sc_link->flags |= SDEV_WANT;
|
||||
error = tsleep(&sc_link->flags, PRIBIO | PCATCH, "sdevlk",0);
|
||||
if (error)
|
||||
return error;
|
||||
}
|
||||
sc_link->flags |= SDEV_XLOCK;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void scsi_device_unlock(struct scsi_link *sc_link)
|
||||
{
|
||||
sc_link->flags &= ~SDEV_XLOCK;
|
||||
if (sc_link->flags & SDEV_WANT) {
|
||||
sc_link->flags &= ~SDEV_WANT;
|
||||
wakeup(&sc_link->flags);
|
||||
}
|
||||
}
|
@ -1,64 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 1995, HD Associates, Inc.
|
||||
* PO Box 276
|
||||
* Pepperell, MA 01463
|
||||
* 508 433 5266
|
||||
* dufault@hda.com
|
||||
*
|
||||
* This code is contributed to the University of California at Berkeley:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id: scsi_driver.h,v 1.12 1997/06/25 19:07:42 tegge Exp $
|
||||
*
|
||||
*/
|
||||
#ifndef _SCSI__DRIVER_H_
|
||||
#define _SCSI__DRIVER_H_
|
||||
|
||||
#ifdef KERNEL
|
||||
|
||||
struct scsi_link;
|
||||
struct scsi_device;
|
||||
struct buf;
|
||||
struct proc;
|
||||
|
||||
int scsi_device_attach __P((struct scsi_link *));
|
||||
int scsi_device_lock __P((struct scsi_link *));
|
||||
void scsi_device_unlock __P((struct scsi_link *));
|
||||
|
||||
int scsi_open __P((dev_t, int, int, struct proc *, struct scsi_device *));
|
||||
int scsi_close __P((dev_t, int, int, struct proc *, struct scsi_device *));
|
||||
int scsi_ioctl __P((dev_t, u_int32_t, caddr_t, int, struct proc *,
|
||||
struct scsi_device *));
|
||||
void scsi_strategy __P((struct buf *, struct scsi_device *));
|
||||
void scsi_minphys __P((struct buf *, struct scsi_device *));
|
||||
|
||||
#endif /* KERNEL */
|
||||
|
||||
#endif /* _SCSI__DRIVER_H_ */
|
@ -1,63 +0,0 @@
|
||||
/*
|
||||
* Contributed by HD Associates (contact: dufault@hda.com)
|
||||
* Copyright (c) 1992, 1993 HD Associates
|
||||
*
|
||||
* Berkeley style copyright. I've just snarfed it out of stdio.h:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* from: @(#)stdio.h 5.17 (Berkeley) 6/3/91
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
/* generic SCSI header file. We use the same minor number format
|
||||
* as on SGI except that the flag bits aren't available because they
|
||||
* are used as the board index.
|
||||
*
|
||||
* The minor number format is:
|
||||
* FF UUU III (FFUU UIII)
|
||||
*
|
||||
* Where:
|
||||
* FF is the board index
|
||||
* UUU are the LUN
|
||||
* III is the SCSI ID (controller)
|
||||
*/
|
||||
|
||||
#ifndef _SCSI_GENERIC_H_
|
||||
#define _SCSI_GENERIC_H_
|
||||
|
||||
#define G_SCSI_FLAG(DEV) (((DEV) & 0xC0) >> 6)
|
||||
#define G_SCSI_UNIT(DEV) G_SCSI_FLAG(DEV)
|
||||
#define G_SCSI_LUN(DEV) (((DEV) & 0x38) >> 3)
|
||||
#define G_SCSI_ID(DEV) ((DEV) & 0x7)
|
||||
|
||||
#define G_SCSI_MINOR(FLAG, LUN, ID) \
|
||||
(((FLAG) << 6) | ((LUN) << 3) | (ID))
|
||||
|
||||
#endif /* _SCSI_GENERIC_H_ */
|
@ -1,406 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 1992, 1993, 1994, HD Associates, Inc.
|
||||
* PO Box 276
|
||||
* Pepperell, MA 01463
|
||||
* 508 433 5266
|
||||
* dufault@hda.com
|
||||
*
|
||||
* This code is contributed to the University of California at Berkeley:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*End copyright
|
||||
*
|
||||
* $Id: scsi_ioctl.c,v 1.31 1998/06/07 17:12:49 dfr Exp $
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#include "opt_bounce.h"
|
||||
#include "opt_scsi.h"
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.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/fcntl.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/uio.h>
|
||||
|
||||
#include <scsi/scsiconf.h>
|
||||
#include <scsi/scsi_debug.h>
|
||||
#include <sys/scsiio.h>
|
||||
|
||||
static void scsierr(struct buf *, int); /* XXX ??? */
|
||||
|
||||
/*
|
||||
* 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((int)xs->error) {
|
||||
case XS_NOERROR:
|
||||
SC_DEBUG(xs->sc_link,SDEV_DB3,("no error\n"));
|
||||
if (xs->flags & SCSI_RESID_VALID)
|
||||
screq->datalen_used = xs->datalen - xs->resid;
|
||||
else
|
||||
screq->datalen_used = xs->datalen;
|
||||
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 scsistrategy() */
|
||||
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.
|
||||
*
|
||||
* 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]
|
||||
*/
|
||||
static void
|
||||
scsistrategy(struct buf *bp)
|
||||
{
|
||||
errval err;
|
||||
struct scsi_link *sc_link = bp->b_sc_link;
|
||||
scsireq_t *screq;
|
||||
u_int32_t 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;
|
||||
|
||||
#ifdef BOUNCE_BUFFERS
|
||||
if (sc_link->flags & SDEV_BOUNCE)
|
||||
vm_bounce_alloc(bp);
|
||||
#endif
|
||||
|
||||
err = scsi_scsi_cmd(sc_link,
|
||||
(struct scsi_generic *)screq->cmd,
|
||||
screq->cmdlen,
|
||||
(u_char *)bp->b_data,
|
||||
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))
|
||||
{
|
||||
tsleep((caddr_t)bp, PRIBIO, "scsistrat", 0);
|
||||
}
|
||||
splx(s);
|
||||
SC_DEBUG(sc_link,SDEV_DB3,("back from sleep\n"));
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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(dev_t dev, u_long cmd, caddr_t addr, int flags,
|
||||
struct proc *p, struct scsi_link *sc_link)
|
||||
{
|
||||
errval ret = 0;
|
||||
|
||||
/* If we can't write the device we can't permit much:
|
||||
*/
|
||||
|
||||
if (cmd != SCIOCIDENTIFY && cmd != SCIOCGETDEVINFO&& !(flags & FWRITE))
|
||||
return EACCES;
|
||||
|
||||
SC_DEBUG(sc_link,SDEV_DB2, ("scsi_do_ioctl(0x%lx)\n", cmd));
|
||||
switch(cmd)
|
||||
{
|
||||
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 0 /* XXX dufault@hda.com: This looks too rev dependent. Do it always? */
|
||||
if((unsigned int)screq < (unsigned int)KERNBASE)
|
||||
#endif
|
||||
{
|
||||
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) {
|
||||
struct uio auio;
|
||||
struct iovec aiov;
|
||||
long cnt;
|
||||
|
||||
aiov.iov_base = d_addr;
|
||||
aiov.iov_len = len;
|
||||
auio.uio_iov = &aiov;
|
||||
auio.uio_iovcnt = 1;
|
||||
|
||||
auio.uio_resid = len;
|
||||
if (auio.uio_resid < 0)
|
||||
return (EINVAL);
|
||||
|
||||
auio.uio_rw = (rwflag == B_READ) ? UIO_READ : UIO_WRITE;
|
||||
auio.uio_segflg = UIO_USERSPACE;
|
||||
auio.uio_procp = curproc;
|
||||
cnt = len;
|
||||
ret = physio(scsistrategy, bp, dev, rwflag,
|
||||
minphys, &auio);
|
||||
} else {
|
||||
/* if no data, no need to translate it.. */
|
||||
bp->b_data = 0;
|
||||
bp->b_dev = dev;
|
||||
bp->b_flags |= B_BUSY;
|
||||
|
||||
scsistrategy(bp);
|
||||
ret = bp->b_error;
|
||||
}
|
||||
free(bp,M_TEMP);
|
||||
#if 0 /* XXX dufault@hda.com: This looks too rev dependent. Do it always? */
|
||||
if((unsigned int)screq2 < (unsigned int)KERNBASE)
|
||||
#endif
|
||||
{
|
||||
bcopy(screq,screq2,sizeof(scsireq_t));
|
||||
free(screq,M_TEMP);
|
||||
}
|
||||
break;
|
||||
}
|
||||
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:
|
||||
{
|
||||
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;
|
||||
}
|
||||
case SCIOCGETDEVINFO:
|
||||
{
|
||||
struct scsi_devinfo *scd = (struct scsi_devinfo *)addr;
|
||||
struct scsi_link *scl;
|
||||
scl = scsi_link_get(scd->addr.scbus, scd->addr.target,
|
||||
scd->addr.lun);
|
||||
if (scl != 0) {
|
||||
scd->dev = scl->dev;
|
||||
/* XXX buffers better be big enough... */
|
||||
sprintf(scd->devname, "%s%d",
|
||||
scl->device->name, scl->dev_unit);
|
||||
sprintf(scd->adname, "%s%d:%d",
|
||||
scl->adapter->name, scl->adapter_unit,
|
||||
scl->adapter_bus);
|
||||
ret = 0;
|
||||
} else {
|
||||
ret = ENXIO;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
ret = ENOTTY;
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void
|
||||
scsierr(bp,err)
|
||||
struct buf *bp;
|
||||
int err;
|
||||
{
|
||||
bp->b_flags |= B_ERROR;
|
||||
bp->b_error = err;
|
||||
biodone(bp);
|
||||
return;
|
||||
}
|
||||
|
@ -1,37 +0,0 @@
|
||||
/* Messages (1 byte) */ /* I/T (M)andatory or (O)ptional */
|
||||
#define MSG_CMDCOMPLETE 0x00 /* M/M */
|
||||
#define MSG_EXTENDED 0x01 /* O/O */
|
||||
#define MSG_SAVEDATAPOINTER 0x02 /* O/O */
|
||||
#define MSG_RESTOREPOINTERS 0x03 /* O/O */
|
||||
#define MSG_DISCONNECT 0x04 /* O/O */
|
||||
#define MSG_INITIATOR_DET_ERR 0x05 /* M/M */
|
||||
#define MSG_ABORT 0x06 /* O/M */
|
||||
#define MSG_MESSAGE_REJECT 0x07 /* M/M */
|
||||
#define MSG_NOOP 0x08 /* M/M */
|
||||
#define MSG_PARITY_ERROR 0x09 /* M/M */
|
||||
#define MSG_LINK_CMD_COMPLETE 0x0a /* O/O */
|
||||
#define MSG_LINK_CMD_COMPLETEF 0x0b /* O/O */
|
||||
#define MSG_BUS_DEV_RESET 0x0c /* O/M */
|
||||
#define MSG_ABORT_TAG 0x0d /* O/O */
|
||||
#define MSG_CLEAR_QUEUE 0x0e /* O/O */
|
||||
#define MSG_INIT_RECOVERY 0x0f /* O/O */
|
||||
#define MSG_REL_RECOVERY 0x10 /* O/O */
|
||||
#define MSG_TERM_IO_PROC 0x11 /* O/O */
|
||||
|
||||
/* Messages (2 byte) */
|
||||
#define MSG_SIMPLE_Q_TAG 0x20 /* O/O */
|
||||
#define MSG_HEAD_OF_Q_TAG 0x21 /* O/O */
|
||||
#define MSG_ORDERED_Q_TAG 0x22 /* O/O */
|
||||
#define MSG_IGN_WIDE_RESIDUE 0x23 /* O/O */
|
||||
|
||||
/* Identify message */ /* M/M */
|
||||
#define MSG_IDENTIFYFLAG 0x80
|
||||
#define MSG_IDENTIFY(lun, disc) (((disc) ? 0xc0 : MSG_IDENTIFYFLAG) | (lun))
|
||||
#define MSG_ISIDENTIFY(m) ((m) & MSG_IDENTIFYFLAG)
|
||||
|
||||
/* Extended messages (opcode and length) */
|
||||
#define MSG_EXT_SDTR 0x01
|
||||
#define MSG_EXT_SDTR_LEN 0x03
|
||||
|
||||
#define MSG_EXT_WDTR 0x03
|
||||
#define MSG_EXT_WDTR_LEN 0x02
|
@ -1,309 +0,0 @@
|
||||
#include "opt_scsi.h"
|
||||
|
||||
#include <sys/param.h>
|
||||
|
||||
#include <scsi/scsiconf.h>
|
||||
|
||||
/* XXX There should be a way for a type driver to have its own
|
||||
* private senses and add them when it is added.
|
||||
*/
|
||||
|
||||
#if !defined(NO_SCSI_SENSE)
|
||||
|
||||
#include "sd.h"
|
||||
#include "st.h"
|
||||
#define NSPRINT 0
|
||||
#include "pt.h"
|
||||
#include "worm.h"
|
||||
#include "cd.h"
|
||||
#define NSCAN 0
|
||||
#include "od.h"
|
||||
#include "ch.h"
|
||||
#define NCOMM 0
|
||||
|
||||
static struct
|
||||
{
|
||||
u_char asc;
|
||||
u_char ascq;
|
||||
char *desc;
|
||||
} tab[] = {
|
||||
#if (NCH > 0)
|
||||
{0x28, 0x01, "Import or export element accessed" },
|
||||
{0x21, 0x01, "Invalid element address" },
|
||||
{0x3b, 0x0d, "Medium destination element full" },
|
||||
{0x3b, 0x0e, "Medium source element empty" },
|
||||
#endif
|
||||
#if (NOD > 0)
|
||||
{0x58, 0x00, "Generation does not exist" },
|
||||
{0x59, 0x00, "Updated block read" },
|
||||
#endif
|
||||
#if (NSCAN > 0)
|
||||
{0x2c, 0x02, "Invalid combination of windows specified" },
|
||||
{0x60, 0x00, "Lamp failure" },
|
||||
{0x61, 0x02, "Out of focus" },
|
||||
{0x3b, 0x0c, "Position past beginning of medium" },
|
||||
{0x3b, 0x0b, "Position past end of medium" },
|
||||
{0x3b, 0x0a, "Read past beginning of medium" },
|
||||
{0x3b, 0x09, "Read past end of medium" },
|
||||
{0x62, 0x00, "Scan head positioning error" },
|
||||
{0x2c, 0x01, "Too many windows specified" },
|
||||
{0x61, 0x01, "Unable to acquire video" },
|
||||
{0x61, 0x00, "Video acquisition error" },
|
||||
#endif
|
||||
#if (NCD > 0)
|
||||
{0x00, 0x11, "Audio play operation in progress" },
|
||||
{0x00, 0x12, "Audio play operation paused" },
|
||||
{0x00, 0x14, "Audio play operation stopped due to error" },
|
||||
{0x00, 0x13, "Audio play operation successfully completed" },
|
||||
{0x63, 0x00, "End of user area encountered on this track" },
|
||||
{0x64, 0x00, "Illegal mode for this track" },
|
||||
{0x00, 0x15, "No current audio status to return" },
|
||||
{0x18, 0x03, "Recovered data with CIRC" },
|
||||
{0x18, 0x04, "Recovered data with L-EC" },
|
||||
{0x57, 0x00, "Unable to recover table-of-contents" },
|
||||
#endif
|
||||
#if (NWORM > 0)||(NOD > 0)
|
||||
{0x11, 0x07, "Data resynchronization error" },
|
||||
#endif
|
||||
#if (NWORM > 0)||(NCD > 0)||(NOD > 0)
|
||||
{0x11, 0x06, "Circ unrecovered error" },
|
||||
{0x09, 0x02, "Focus servo failure" },
|
||||
{0x11, 0x05, "L-EC uncorrectable error" },
|
||||
{0x17, 0x04, "Recovered data with retries and/or CIRC applied" },
|
||||
{0x09, 0x03, "Spindle servo failure" },
|
||||
{0x09, 0x01, "Tracking servo failure" },
|
||||
#endif
|
||||
#if (NPT > 0)
|
||||
{0x54, 0x00, "SCSI to host system interface failure" },
|
||||
{0x55, 0x00, "System resource failure" },
|
||||
#endif
|
||||
#if (NSPRINT > 0)
|
||||
{0x3b, 0x07, "Failed to sense bottom-of-form" },
|
||||
{0x3b, 0x06, "Failed to sense top-of-form" },
|
||||
{0x3b, 0x05, "Paper jam" },
|
||||
{0x36, 0x00, "Ribbon, ink, or toner failure" },
|
||||
{0x3b, 0x04, "Slew failure" },
|
||||
{0x3b, 0x03, "Tape or electronic vertical forms unit not ready" },
|
||||
#endif
|
||||
#if (NST > 0)
|
||||
{0x14, 0x04, "Block sequence error" },
|
||||
{0x52, 0x00, "Cartridge fault" },
|
||||
{0x14, 0x03, "End-of-data not found" },
|
||||
{0x03, 0x02, "Excessive write errors" },
|
||||
{0x00, 0x01, "Filemark detected" },
|
||||
{0x14, 0x02, "Filemark or setmark not found" },
|
||||
{0x11, 0x08, "Incomplete block read" },
|
||||
{0x11, 0x09, "No gap found" },
|
||||
{0x03, 0x01, "No write current" },
|
||||
{0x2d, 0x00, "Overwrite error on update in place" },
|
||||
{0x50, 0x02, "Position error related to timing" },
|
||||
{0x3b, 0x08, "Reposition error" },
|
||||
{0x00, 0x03, "Setmark detected" },
|
||||
{0x33, 0x00, "Tape length error" },
|
||||
{0x3b, 0x01, "Tape position error at beginning-of-medium" },
|
||||
{0x3b, 0x02, "Tape position error at end-of-medium" },
|
||||
{0x53, 0x01, "Unload tape failure" },
|
||||
{0x50, 0x00, "Write append error" },
|
||||
{0x50, 0x01, "Write append position error" },
|
||||
#endif
|
||||
#if (NST > 0)||(NOD > 0)
|
||||
{0x51, 0x00, "Erase failure" },
|
||||
#endif
|
||||
#if (NST > 0)||(NSCAN > 0)
|
||||
{0x00, 0x04, "Beginning-of-partition/medium detected" },
|
||||
{0x00, 0x05, "End-of-data detected" },
|
||||
{0x00, 0x02, "End-of-partition/medium detected" },
|
||||
{0x0c, 0x00, "Write error" },
|
||||
#endif
|
||||
#if (NST > 0)||(NSPRINT > 0)
|
||||
{0x3b, 0x00, "Sequential positioning error" },
|
||||
#endif
|
||||
#if (NSD > 0)
|
||||
{0x41, 0x00, "Data path failure (should use 40 nn)" },
|
||||
{0x22, 0x00, "Illegal function (should use 20 00, 24 00, or 26 00)" },
|
||||
{0x42, 0x00, "Power-on or self-test failure (should use 40 nn)" },
|
||||
{0x40, 0x00, "Ram failure (should use 40 nn)" },
|
||||
#endif
|
||||
#if (NSD > 0)||(NOD > 0)
|
||||
{0x19, 0x00, "Defect list error" },
|
||||
{0x19, 0x03, "Defect list error in grown list" },
|
||||
{0x19, 0x02, "Defect list error in primary list" },
|
||||
{0x19, 0x01, "Defect list not available" },
|
||||
{0x1c, 0x00, "Defect list not found" },
|
||||
{0x1c, 0x02, "Grown defect list not found" },
|
||||
{0x1c, 0x01, "Primary defect list not found" },
|
||||
{0x5c, 0x00, "RPL status change" },
|
||||
{0x5c, 0x02, "Spindles not synchronized" },
|
||||
{0x5c, 0x01, "Spindles synchronized" },
|
||||
#endif
|
||||
#if (NSD > 0)||(NWORM > 0)||(NOD > 0)
|
||||
{0x13, 0x00, "Address mark not found for data field" },
|
||||
{0x12, 0x00, "Address mark not found for id field" },
|
||||
{0x16, 0x00, "Data synchronization mark error" },
|
||||
{0x32, 0x01, "Defect list update failure" },
|
||||
{0x10, 0x00, "Id CRC or ECC error" },
|
||||
{0x1d, 0x00, "Miscompare during verify operation" },
|
||||
{0x32, 0x00, "No defect spare location available" },
|
||||
{0x01, 0x00, "No index/sector signal" },
|
||||
{0x17, 0x06, "Recovered data without ECC - data auto-reallocated" },
|
||||
{0x17, 0x07, "Recovered data without ECC - recommend reassignment" },
|
||||
{0x17, 0x08, "Recovered data without ECC - recommend rewrite" },
|
||||
{0x1e, 0x00, "Recovered ID with ECC correction" },
|
||||
{0x11, 0x04, "Unrecovered read error - auto reallocate failed" },
|
||||
{0x11, 0x0b, "Unrecovered read error - recommend reassignment" },
|
||||
{0x11, 0x0c, "Unrecovered read error - recommend rewrite the data" },
|
||||
{0x0c, 0x02, "Write error - auto reallocation failed" },
|
||||
{0x0c, 0x01, "Write error recovered with auto reallocation" },
|
||||
#endif
|
||||
#if (NSD > 0)||(NWORM > 0)||(NCD > 0)||(NOD > 0)
|
||||
{0x18, 0x02, "Recovered data - data auto-reallocated" },
|
||||
{0x18, 0x05, "Recovered data - recommend reassignment" },
|
||||
{0x18, 0x06, "Recovered data - recommend rewrite" },
|
||||
{0x17, 0x05, "Recovered data using previous sector id" },
|
||||
{0x18, 0x01, "Recovered data with error correction & retries applied" },
|
||||
#endif
|
||||
#if (NSD > 0)||(NWORM > 0)||(NCD > 0)||(NOD > 0)||(NCH > 0)
|
||||
{0x06, 0x00, "No reference position found" },
|
||||
{0x02, 0x00, "No seek complete" },
|
||||
#endif
|
||||
#if (NSD > 0)||(NSPRINT > 0)||(NOD > 0)
|
||||
{0x31, 0x01, "Format command failed" },
|
||||
#endif
|
||||
#if (NSD > 0)||(NST > 0)
|
||||
{0x30, 0x03, "Cleaning cartridge installed" },
|
||||
#endif
|
||||
#if (NSD > 0)||(NST > 0)||(NOD > 0)
|
||||
{0x11, 0x0a, "Miscorrected error" },
|
||||
#endif
|
||||
#if (NSD > 0)||(NST > 0)||(NWORM > 0)||(NOD > 0)
|
||||
{0x31, 0x00, "Medium format corrupted" },
|
||||
{0x5a, 0x03, "Operator selected write permit" },
|
||||
{0x5a, 0x02, "Operator selected write protect" },
|
||||
{0x27, 0x00, "Write protected" },
|
||||
#endif
|
||||
#if (NSD > 0)||(NST > 0)||(NWORM > 0)||(NSCAN > 0)||(NOD > 0)
|
||||
{0x11, 0x02, "Error too long to correct" },
|
||||
{0x11, 0x03, "Multiple read errors" },
|
||||
{0x11, 0x01, "Read retries exhausted" },
|
||||
#endif
|
||||
#if (NSD > 0)||(NST > 0)||(NWORM > 0)||(NCD > 0)||(NOD > 0)
|
||||
{0x30, 0x02, "Cannot read medium - incompatible format" },
|
||||
{0x30, 0x01, "Cannot read medium - unknown format" },
|
||||
{0x15, 0x02, "Positioning error detected by read of medium" },
|
||||
{0x14, 0x01, "Record not found" },
|
||||
{0x18, 0x00, "Recovered data with error correction applied" },
|
||||
{0x17, 0x03, "Recovered data with negative head offset" },
|
||||
{0x17, 0x02, "Recovered data with positive head offset" },
|
||||
{0x09, 0x00, "Track following error" },
|
||||
#endif
|
||||
#if (NSD > 0)||(NST > 0)||(NWORM > 0)||(NCD > 0)||(NOD > 0)||(NCH > 0)
|
||||
{0x30, 0x00, "Incompatible medium installed" },
|
||||
{0x21, 0x00, "Logical block address out of range" },
|
||||
{0x53, 0x02, "Medium removal prevented" },
|
||||
{0x5a, 0x01, "Operator medium removal request" },
|
||||
#endif
|
||||
#if (NSD > 0)||(NST > 0)||(NWORM > 0)||(NCD > 0)||(NSCAN > 0)||(NOD > 0)
|
||||
{0x17, 0x00, "Recovered data with no error correction applied" },
|
||||
{0x17, 0x01, "Recovered data with retries" },
|
||||
{0x11, 0x00, "Unrecovered read error" },
|
||||
#endif
|
||||
#if (NSD > 0)||(NST > 0)||(NSPRINT > 0)||(NOD > 0)
|
||||
{0x04, 0x04, "Logical unit not ready, format in progress" },
|
||||
#endif
|
||||
#if (NSD > 0)||(NST > 0)||(NSPRINT > 0)||(NWORM > 0)||(NSCAN > 0)||(NOD > 0)
|
||||
{0x03, 0x00, "Peripheral device write fault" },
|
||||
#endif
|
||||
#if (NSD > 0)||(NST > 0)||(NSPRINT > 0)||(NWORM > 0)||(NCD > 0)||(NSCAN > 0)||(NOD > 0)
|
||||
{0x14, 0x00, "Recorded entity not found" },
|
||||
#endif
|
||||
#if (NSD > 0)||(NST > 0)||(NSPRINT > 0)||(NWORM > 0)||(NCD > 0)||(NSCAN > 0)||(NOD > 0)||(NCH > 0)
|
||||
{0x15, 0x01, "Mechanical positioning error" },
|
||||
{0x53, 0x00, "Media load or eject failed" },
|
||||
{0x3a, 0x00, "Medium not present" },
|
||||
{0x07, 0x00, "Multiple peripheral devices selected" },
|
||||
{0x15, 0x00, "Random positioning error" },
|
||||
#endif
|
||||
#if (NSD > 0)||(NST > 0)||(NSPRINT > 0)||(NWORM > 0)||(NCD > 0)||(NSCAN > 0)||(NOD > 0)||(NCH > 0)||(ncomm > 0)
|
||||
{0x2a, 0x02, "Log parameters changed" },
|
||||
{0x08, 0x00, "Logical unit communication failure" },
|
||||
{0x08, 0x02, "Logical unit communication parity error" },
|
||||
{0x08, 0x01, "Logical unit communication time-out" },
|
||||
{0x2a, 0x01, "Mode parameters changed" },
|
||||
{0x2a, 0x00, "Parameters changed" },
|
||||
{0x37, 0x00, "Rounded parameter" },
|
||||
{0x39, 0x00, "Saving parameters not supported" },
|
||||
#endif
|
||||
#if (NSD > 0)||(NST > 0)||(NSPRINT > 0)||(NPT > 0)||(NWORM > 0)||(NCD > 0)||(NSCAN > 0)||(NOD > 0)||(ncomm > 0)
|
||||
{0x2b, 0x00, "Copy cannot execute since host cannot disconnect" },
|
||||
#endif
|
||||
#if (NSD > 0)||(NST > 0)||(NSPRINT > 0)||(NPT > 0)||(NWORM > 0)||(NCD > 0)||(NSCAN > 0)||(NOD > 0)||(NCH > 0)
|
||||
{0x5b, 0x02, "Log counter at maximum" },
|
||||
{0x5b, 0x00, "Log exception" },
|
||||
{0x5b, 0x03, "Log list codes exhausted" },
|
||||
{0x5a, 0x00, "Operator request or state change input (unspecified)" },
|
||||
{0x5b, 0x01, "Threshold condition met" },
|
||||
#endif
|
||||
{0x3f, 0x02, "Changed operating definition" },
|
||||
{0x4a, 0x00, "Command phase error" },
|
||||
{0x2c, 0x00, "Command sequence error" },
|
||||
{0x2f, 0x00, "Commands cleared by another initiator" },
|
||||
{0x4b, 0x00, "Data phase error" },
|
||||
/* {0x40, 0xnn, "Diagnostic failure on component nn (80h-ffh)" }, */
|
||||
{0x0a, 0x00, "Error log overflow" },
|
||||
{0x00, 0x06, "I/O process terminated" },
|
||||
{0x48, 0x00, "Initiator detected error message received" },
|
||||
{0x3f, 0x03, "Inquiry data has changed" },
|
||||
{0x44, 0x00, "Internal target failure" },
|
||||
{0x3d, 0x00, "Invalid bits in identify message" },
|
||||
{0x20, 0x00, "Invalid command operation code" },
|
||||
{0x24, 0x00, "Invalid field in CDB" },
|
||||
{0x26, 0x00, "Invalid field in parameter list" },
|
||||
{0x49, 0x00, "Invalid message error" },
|
||||
{0x05, 0x00, "Logical unit does not respond to selection" },
|
||||
{0x4c, 0x00, "Logical unit failed self-configuration" },
|
||||
{0x3e, 0x00, "Logical unit has not self-configured yet" },
|
||||
{0x04, 0x01, "Logical unit is in process of becoming ready" },
|
||||
{0x04, 0x00, "Logical unit not ready, cause not reportable" },
|
||||
{0x04, 0x02, "Logical unit not ready, initializing command required" },
|
||||
{0x04, 0x03, "Logical unit not ready, manual intervention required" },
|
||||
{0x25, 0x00, "Logical unit not supported" },
|
||||
{0x43, 0x00, "Message error" },
|
||||
{0x3f, 0x01, "Microcode has been changed" },
|
||||
{0x00, 0x00, "No additional sense information" },
|
||||
{0x28, 0x00, "Not ready to ready transition, medium may have changed" },
|
||||
{0x4e, 0x00, "Overlapped commands attempted" },
|
||||
{0x1a, 0x00, "Parameter list length error" },
|
||||
{0x26, 0x01, "Parameter not supported" },
|
||||
{0x26, 0x02, "Parameter value invalid" },
|
||||
{0x29, 0x00, "Power on, reset, or bus device reset occurred" },
|
||||
{0x47, 0x00, "SCSI parity error" },
|
||||
{0x45, 0x00, "Select or reselect failure" },
|
||||
{0x1b, 0x00, "Synchronous data transfer error" },
|
||||
{0x3f, 0x00, "Target operating conditions have changed" },
|
||||
{0x26, 0x03, "Threshold parameters not supported" },
|
||||
{0x46, 0x00, "Unsuccessful soft reset" },
|
||||
};
|
||||
|
||||
char *scsi_sense_desc(int asc, int ascq)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (asc >= 0x80 && asc <= 0xff)
|
||||
return "Vendor Specific ASC";
|
||||
|
||||
if (ascq >= 0x80 && ascq <= 0xff)
|
||||
return "Vendor Specific ASCQ";
|
||||
|
||||
for (i = 0; i < sizeof(tab) / sizeof(tab[0]); i++)
|
||||
if (tab[i].asc == asc && tab[i].ascq == ascq)
|
||||
return tab[i].desc;
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
#else /* NO_SCSI_SENSE */
|
||||
char *scsi_sense_desc(int asc, int ascq)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
#endif
|
@ -1,247 +0,0 @@
|
||||
/*
|
||||
* SCSI tape interface description
|
||||
*/
|
||||
|
||||
/*
|
||||
* Written by Julian Elischer (julian@tfs.com)
|
||||
* for TRW Financial Systems.
|
||||
*
|
||||
* TRW Financial Systems, in accordance with their agreement with Carnegie
|
||||
* Mellon University, makes this software available to CMU to distribute
|
||||
* or use in any manner that they see fit as long as this message is kept with
|
||||
* the software. For this reason TFS also grants any other persons or
|
||||
* organisations permission to use or modify this software.
|
||||
*
|
||||
* TFS supplies this software to be publicly redistributed
|
||||
* on the understanding that TFS is not responsible for the correct
|
||||
* functioning of this software in any circumstances.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
#ifndef SCSI_SCSI_TAPE_H
|
||||
#define SCSI_SCSI_TAPE_H 1
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* SCSI command formats
|
||||
*/
|
||||
|
||||
|
||||
struct scsi_rw_tape
|
||||
{
|
||||
u_char op_code;
|
||||
u_char byte2;
|
||||
#define SRWT_FIXED 0x01
|
||||
u_char len[3];
|
||||
u_char control;
|
||||
};
|
||||
|
||||
struct scsi_space
|
||||
{
|
||||
u_char op_code;
|
||||
u_char byte2;
|
||||
#define SS_CODE 0x03
|
||||
u_char number[3];
|
||||
u_char control;
|
||||
};
|
||||
#define SP_BLKS 0
|
||||
#define SP_FILEMARKS 1
|
||||
#define SP_SEQ_FILEMARKS 2
|
||||
#define SP_EOM 3
|
||||
|
||||
struct scsi_write_filemarks
|
||||
{
|
||||
u_char op_code;
|
||||
u_char byte2;
|
||||
u_char number[3];
|
||||
u_char control;
|
||||
};
|
||||
|
||||
struct scsi_rewind
|
||||
{
|
||||
u_char op_code;
|
||||
u_char byte2;
|
||||
#define SR_IMMED 0x01
|
||||
u_char unused[3];
|
||||
u_char control;
|
||||
};
|
||||
|
||||
/*
|
||||
** Tape erase - AKL: Andreas Klemm <andreas@knobel.gun.de>
|
||||
*/
|
||||
struct scsi_erase
|
||||
{
|
||||
u_char op_code;
|
||||
u_char byte2;
|
||||
#define SE_LONG 0x01 /*
|
||||
** Archive Viper 2525 doesn't allow short
|
||||
** erase, other tapes possibly don't allow
|
||||
** that, too.
|
||||
*/
|
||||
#define SE_IMMED 0x02
|
||||
u_char unused[3];
|
||||
u_char control;
|
||||
};
|
||||
|
||||
struct scsi_load
|
||||
{
|
||||
u_char op_code;
|
||||
u_char byte2;
|
||||
#define SL_IMMED 0x01
|
||||
u_char unused[2];
|
||||
u_char how;
|
||||
u_char control;
|
||||
};
|
||||
#define LD_UNLOAD 0
|
||||
#define LD_LOAD 1
|
||||
#define LD_RETEN 2
|
||||
|
||||
|
||||
struct scsi_blk_limits
|
||||
{
|
||||
u_char op_code;
|
||||
u_char byte2;
|
||||
u_char unused[3];
|
||||
u_char control;
|
||||
};
|
||||
|
||||
/*
|
||||
* Opcodes
|
||||
*/
|
||||
|
||||
#define REWIND 0x01
|
||||
#define READ_BLK_LIMITS 0x05
|
||||
#define READ_COMMAND_TAPE 0x08
|
||||
#define WRITE_COMMAND_TAPE 0x0a
|
||||
#define WRITE_FILEMARKS 0x10
|
||||
#define SPACE 0x11
|
||||
#define ERASE 0x19
|
||||
#define LOAD_UNLOAD 0x1b
|
||||
|
||||
|
||||
|
||||
struct scsi_blk_limits_data
|
||||
{
|
||||
u_char reserved;
|
||||
u_char max_length_2; /* Most significant */
|
||||
u_char max_length_1;
|
||||
u_char max_length_0; /* Least significant */
|
||||
u_char min_length_1; /* Most significant */
|
||||
u_char min_length_0; /* Least significant */
|
||||
};
|
||||
|
||||
/* defines for the device specific byte in the mode select/sense header */
|
||||
#define SMH_DSP_SPEED 0x0F
|
||||
#define SMH_DSP_BUFF_MODE 0x70
|
||||
#define SMH_DSP_BUFF_MODE_OFF 0x00
|
||||
#define SMH_DSP_BUFF_MODE_ON 0x10
|
||||
#define SMH_DSP_BUFF_MODE_MLTI 0x20
|
||||
#define SMH_DSP_WRITE_PROT 0x80
|
||||
|
||||
/* A special for the CIPHER ST150S(old drive) */
|
||||
struct blk_desc_cipher
|
||||
{
|
||||
u_char density;
|
||||
u_char nblocks[3];
|
||||
u_char reserved;
|
||||
u_char blklen[3];
|
||||
u_char other;
|
||||
#define ST150_SEC 0x01 /* soft error count */
|
||||
#define SR150_AUI 0x02 /* autoload inhibit */
|
||||
};
|
||||
|
||||
/*
|
||||
* This structure defines the various mode pages that tapes know about.
|
||||
*/
|
||||
#define PAGE_HEADERLEN 2
|
||||
struct tape_pages
|
||||
{
|
||||
u_char pg_code; /* page code */
|
||||
#define ST_PAGE_CONFIGURATION 0x10
|
||||
#define ST_PAGE_MEDIUM_PART 0x11
|
||||
#define ST_PAGE_MEDIUM_PART2 0x12
|
||||
#define ST_PAGE_MEDIUM_PART3 0x13
|
||||
#define ST_PAGE_MEDIUM_PART4 0x14
|
||||
#define ST_P_CODE 0x3F /* page code */
|
||||
#define ST_P_PS 0x80 /* page savable */
|
||||
u_char pg_length; /* page length */
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
u_char active_format; /* active format for density*/
|
||||
#define ST_P_CAP 0x40 /* change active Partition */
|
||||
#define ST_P_CAF 0x20 /* change active format */
|
||||
#define ST_P_AF 0x1F /* active format */
|
||||
u_char active_partition; /* */
|
||||
u_char write_buffer_full_ratio; /* highwater writing*/
|
||||
u_char read_buffer_empty_ratio; /* lowwater reading*/
|
||||
u_char write_delay_high; /* # 100mSecs before flush*/
|
||||
u_char write_delay_low; /* of buffer to the media */
|
||||
u_char flags1; /* various single bit flags */
|
||||
#define ST_P_DBR 0x80 /* supports data-buffer recovery */
|
||||
#define ST_P_BIS 0x40 /* supports Block_ID */
|
||||
#define ST_P_RSmk 0x20 /* Reports setmarks during reads and spaces */
|
||||
#define ST_P_AVC 0x10 /* Supports Automatic Velocity Control */
|
||||
#define ST_P_SOCF 0x0C /* Stop On Consecutive Filemarks, */
|
||||
#define ST_P_RBO 0x02 /* Recoverd Buffered Data order, 1 = LIFO */
|
||||
#define ST_P_REW 0x01 /* Report Early Warning (see SEW) */
|
||||
u_char gap_size; /*I/B gap, 1=min 0=default */
|
||||
u_char flags2; /* various single bit flags */
|
||||
#define ST_P_EOD 0xE0 /* What is and EOD....*/
|
||||
#define ST_P_EOD_DEF 0x00 /* Drive's default */
|
||||
#define ST_P_EOD_FMT 0x20 /* define by format */
|
||||
#define ST_P_EOD_SOCF 0x40 /* define by SOCF (above) */
|
||||
#define ST_P_EEG 0x10 /* use EOD above */
|
||||
#define ST_P_SEW 0x04 /* Synchronise at Early warning.. flush buffers*/
|
||||
u_char early_warn_high;/* buf size at early warning */
|
||||
u_char early_warn_med; /* after early warning, only */
|
||||
u_char early_warn_low; /* buufer this much data */
|
||||
u_char data_compress_alg; /* 0 = off, 1 = default */
|
||||
u_char reserved; /* The standard says so */
|
||||
} configuration;
|
||||
struct
|
||||
{
|
||||
#define ST_MAXPARTS 16 /*for now*/
|
||||
u_char max_add_parts; /* that drive allows */
|
||||
u_char parts_defined; /* max min(ST_MAXPARTS,max_add_parts) */
|
||||
u_char flags;
|
||||
#define ST_P_FDP 0x80
|
||||
#define ST_P_SDP 0x40
|
||||
#define ST_P_IDP 0x20
|
||||
#define ST_P_PSUM 0x18 /* units of part defs.. */
|
||||
#define ST_P_PSUM_BYTES 0x0 /* units of part defs.. */
|
||||
#define ST_P_PSUM_KBYTES 0x08 /* units of part defs.. */
|
||||
#define ST_P_PSUM_MBYTES 0x10 /* units of part defs.. */
|
||||
u_char medium_format_recog;
|
||||
#define ST_P_REC_NONE 0x00
|
||||
#define ST_P_REC_FMT 0x01 /* can recognise format of new media */
|
||||
#define ST_P_REC_PART 0x02 /* can recognise partitions of new media */
|
||||
#define ST_P_REC_FMT_PART 0x03 /* can recognise format and parts */
|
||||
u_char reserved1;
|
||||
u_char reserved2;
|
||||
struct
|
||||
{
|
||||
u_char high;
|
||||
u_char low;
|
||||
}part[ST_MAXPARTS];
|
||||
} medium_partition;
|
||||
struct
|
||||
{
|
||||
struct
|
||||
{
|
||||
u_char high;
|
||||
u_char low;
|
||||
}part[ST_MAXPARTS];
|
||||
} medium_partition_extra;
|
||||
}pages;
|
||||
};
|
||||
|
||||
|
||||
#endif /*SCSI_SCSI_TAPE_H*/
|
@ -1,128 +0,0 @@
|
||||
#ifndef _SCSI_SCSI_WORM_H
|
||||
#define _SCSI_SCSI_WORM_H
|
||||
|
||||
#define PAGE_HEADERLEN 2
|
||||
|
||||
/*
|
||||
* Opcodes
|
||||
*/
|
||||
|
||||
#define REZERO_UNIT 0x01 /* re-init; XXX belongs to scsi_all? */
|
||||
#define SYNCHRONIZE_CACHE 0x35 /* flush write buffer, close wr chn */
|
||||
#define FIRST_WRITEABLE_ADDR 0xe2 /* return first available LBA */
|
||||
#define RESERVE_TRACK 0xe4 /* reserve a track for later write */
|
||||
#define READ_TRACK_INFORMATION 0xe5 /* get info for a particular track */
|
||||
#define WRITE_TRACK 0xe6 /* open the write channel */
|
||||
#define LOAD_UNLOAD 0xe7 /* resembles part of START_STOP */
|
||||
#define FIXATION 0xe9 /* write leadin/leadout */
|
||||
#define WRITE_SESSION 0xed /* guide to write a new session */
|
||||
#define READ_SESSION_INFO 0xee /* read leadin/leadout lengths */
|
||||
|
||||
struct scsi_rezero_unit
|
||||
{
|
||||
u_char op_code;
|
||||
u_char byte2;
|
||||
u_char reserved[3];
|
||||
u_char control;
|
||||
};
|
||||
|
||||
struct scsi_synchronize_cache
|
||||
{
|
||||
u_char op_code;
|
||||
u_char byte2;
|
||||
u_char reserved[7];
|
||||
u_char control;
|
||||
};
|
||||
|
||||
/* struct scsi_first_writeable_address; */
|
||||
|
||||
struct scsi_reserve_track
|
||||
{
|
||||
u_char op_code;
|
||||
u_char byte2;
|
||||
u_char reserved[3];
|
||||
u_char reserve_length_3; /* MSB */
|
||||
u_char reserve_length_2;
|
||||
u_char reserve_length_1;
|
||||
u_char reserve_length_0; /* LSB */
|
||||
u_char control;
|
||||
};
|
||||
|
||||
/* struct scsi_read_track_information; */
|
||||
|
||||
struct scsi_write_track
|
||||
{
|
||||
u_char op_code;
|
||||
u_char byte2;
|
||||
u_char reserved[3];
|
||||
u_char track_number; /* 0 means: use next available */
|
||||
u_char mode;
|
||||
#define WORM_TRACK_MODE_RAW 0x08
|
||||
#define WORM_TRACK_MODE_AUDIO 0x04
|
||||
#define WORM_TRACK_MODE_MODE1 0x01 /* also audio with preemphasis */
|
||||
#define WORM_TRACK_MODE_MODE2 0x02
|
||||
u_char transfer_length_1; /* number of blocks to transfer, MSB */
|
||||
u_char transfer_length_0; /* LSB */
|
||||
u_char control;
|
||||
#define WORM_TRACK_CONTROL_MIX 0x40 /* mixed mode blocks */
|
||||
};
|
||||
|
||||
struct scsi_load_unload
|
||||
{
|
||||
u_char op_code;
|
||||
u_char byte2;
|
||||
u_char reserved[6];
|
||||
u_char load;
|
||||
#define WORM_LOAD_MEDIUM 0x01
|
||||
u_char control;
|
||||
};
|
||||
|
||||
struct scsi_fixation
|
||||
{
|
||||
u_char op_code;
|
||||
u_char byte2;
|
||||
u_char reserved[6];
|
||||
u_char action;
|
||||
#define WORM_FIXATION_ONP 0x08 /* open next program area (new session) */
|
||||
#define WORM_TOC_TYPE_AUDIO 0x00
|
||||
#define WORM_TOC_TYPE_CDROM 0x01
|
||||
#define WORM_TOC_TYPE_CDROM_1 0x02 /* CD-ROM, first track mode 1 (?) */
|
||||
#define WORM_TOC_TYPE_CDROM_2 0x03 /* CD-ROM, first track mode 2 */
|
||||
#define WORM_TOC_TYPE_CDI 0x04
|
||||
u_char control;
|
||||
};
|
||||
|
||||
struct scsi_write_session
|
||||
{
|
||||
u_char op_code;
|
||||
u_char byte2;
|
||||
u_char reserved[4];
|
||||
u_char action; /* see scsi_fixation above */
|
||||
#define WORM_LOFP_MODE_MODE1 0x10
|
||||
#define WORM_LOFP_MODE_MODE2 0x20
|
||||
u_char transfer_length_2; /* number of blocks to transfer, MSB */
|
||||
u_char transfer_length_1; /* LSB */
|
||||
u_char control;
|
||||
};
|
||||
|
||||
struct scsi_read_session_info
|
||||
{
|
||||
u_char op_code;
|
||||
u_char byte2;
|
||||
u_char reserved[6];
|
||||
u_char transfer_length;
|
||||
u_char control;
|
||||
};
|
||||
|
||||
struct scsi_first_writable_address
|
||||
{
|
||||
u_char op_code;
|
||||
u_char byte2;
|
||||
u_char track_number;
|
||||
u_char mode;
|
||||
u_char reserved[4];
|
||||
u_char transfer_length;
|
||||
u_char control;
|
||||
};
|
||||
|
||||
#endif /* _SCSI_SCSI_WORM_H */
|
1573
sys/scsi/scsiconf.c
1573
sys/scsi/scsiconf.c
File diff suppressed because it is too large
Load Diff
@ -1,618 +0,0 @@
|
||||
/*
|
||||
* Written by Julian Elischer (julian@tfs.com)
|
||||
* for TRW Financial Systems for use under the MACH(2.5) operating system.
|
||||
*
|
||||
* TRW Financial Systems, in accordance with their agreement with Carnegie
|
||||
* Mellon University, makes this software available to CMU to distribute
|
||||
* or use in any manner that they see fit as long as this message is kept with
|
||||
* the software. For this reason TFS also grants any other persons or
|
||||
* organisations permission to use or modify this software.
|
||||
*
|
||||
* TFS supplies this software to be publicly redistributed
|
||||
* on the understanding that TFS is not responsible for the correct
|
||||
* functioning of this software in any circumstances.
|
||||
*
|
||||
* Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992
|
||||
*
|
||||
* $Id: scsiconf.h,v 1.60 1998/05/24 04:52:31 julian Exp $
|
||||
*/
|
||||
#ifndef SCSI_SCSICONF_H
|
||||
#define SCSI_SCSICONF_H 1
|
||||
typedef int boolean;
|
||||
typedef int errval;
|
||||
|
||||
#include <scsi/scsi_all.h>
|
||||
#include <sys/callout.h> /* XXX For ioconf.c */
|
||||
|
||||
/*
|
||||
* 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 its 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.
|
||||
*/
|
||||
|
||||
struct buf;
|
||||
struct scsi_xfer;
|
||||
#ifdef PC98
|
||||
struct cfdata;
|
||||
#endif
|
||||
|
||||
/* Don't poke around inside of "scsi_data". Each low level
|
||||
* driver has its own definition for it.
|
||||
*/
|
||||
struct scsi_data;
|
||||
struct scsi_link; /* scsi_link refers to scsi_device and vice-versa */
|
||||
|
||||
struct proc;
|
||||
|
||||
/*
|
||||
* 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
|
||||
{
|
||||
/* 04*/ int32_t (*scsi_cmd) __P((struct scsi_xfer *xs));
|
||||
/* 08*/ void (*scsi_minphys) __P((struct buf *bp));
|
||||
#ifdef PC98
|
||||
/* 12*/ int32_t (*open_target_lu) __P((struct scsi_link *sc_link,
|
||||
struct cfdata *cf));
|
||||
#else
|
||||
/* 12*/ int32_t (*open_target_lu) __P((void));
|
||||
#endif
|
||||
/* 16*/ int32_t (*close_target_lu) __P((void));
|
||||
/* 20*/ u_int32_t (*adapter_info) __P((int unit)); /* see definitions below */
|
||||
/* 24*/ char *name; /* name of scsi bus controller */
|
||||
/* 32*/ u_long spare[2];
|
||||
};
|
||||
|
||||
/*
|
||||
* return values for scsi_cmd()
|
||||
*/
|
||||
#define SUCCESSFULLY_QUEUED 0
|
||||
#define TRY_AGAIN_LATER 1
|
||||
#define COMPLETE 2
|
||||
#define HAD_ERROR 3 /* do not use this, use COMPLETE */
|
||||
#define ESCAPE_NOT_SUPPORTED 4
|
||||
|
||||
/*
|
||||
* Return value from sense handler. IMHO, These ought to be merged
|
||||
* in with the return codes above, all made negative to distinguish
|
||||
* from valid errno values, and replace "try again later" with "do retry"
|
||||
*/
|
||||
#define SCSIRET_CONTINUE -1 /* Continue with standard sense processing */
|
||||
#define SCSIRET_DO_RETRY -2 /* Retry the command that got this sense */
|
||||
|
||||
/*
|
||||
* Format of adapter_info() response data
|
||||
* e.g. maximum number of entries queuable to a device by the adapter
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
* XXX dufault@hda.com: Each adapter driver has a scsi_device structure
|
||||
* that I don't think should be there.
|
||||
* This structure should be rearranged and cleaned up once the
|
||||
* instance down in the adapter drivers is removed.
|
||||
*/
|
||||
|
||||
/*
|
||||
* XXX this is so that everything that includes this bloated header doesn't
|
||||
* also need to include <sys/conf.h>.
|
||||
*/
|
||||
typedef int yet_another_d_open_t __P((dev_t, int, int, struct proc *));
|
||||
|
||||
struct scsi_device
|
||||
{
|
||||
/* 4*/ errval (*err_handler)(struct scsi_xfer *xs);
|
||||
/* 8*/ void (*start)(u_int32_t unit, u_int32_t flags);
|
||||
/* 12*/ int32_t (*async) __P((void));
|
||||
/* 16*/ int32_t (*done) __P((struct scsi_xfer *xs));
|
||||
/* 20*/ char *name; /* name of device type */
|
||||
/* 24*/ u_int32_t flags; /* device type dependent flags */
|
||||
/* 32*/ int32_t spare[2];
|
||||
/* 36*/ int32_t link_flags; /* set -> sc_link at attach time */
|
||||
/* 40*/ errval (*attach)(struct scsi_link *sc_link);
|
||||
/* 44*/ char *desc; /* Description of device */
|
||||
/* 48*/ yet_another_d_open_t *open;
|
||||
/* 52*/ int sizeof_scsi_data;
|
||||
/* 56*/ int type; /* Type of device this supports */
|
||||
/* 60*/ int (*getunit)(dev_t dev);
|
||||
/* 64*/ dev_t (*setunit)(dev_t dev, int unit);
|
||||
/* 68*/ int (*dev_open)(dev_t dev, int flags, int fmt, struct proc *p,
|
||||
struct scsi_link *sc_link);
|
||||
/* 72*/ int (*dev_ioctl)(dev_t dev, u_long cmd, caddr_t arg, int mode,
|
||||
struct proc *p, struct scsi_link *sc_link);
|
||||
/* 76*/ int (*dev_close)(dev_t dev, int flag, int fmt, struct proc *p,
|
||||
struct scsi_link *sc_link);
|
||||
/* 80*/ void (*dev_strategy)(struct buf *bp, struct scsi_link *sc_link);
|
||||
/* Not initialized after this */
|
||||
/* 84*/ struct extend_array *links;
|
||||
/* 88*/ int free_unit;
|
||||
/* 92*/ struct scsi_device *next; /* Next in list in the registry. */
|
||||
};
|
||||
/*
|
||||
* Macros to access soem fields above.
|
||||
*/
|
||||
#define SCSI_LINK(DEV, UNIT) \
|
||||
((struct scsi_link *)(extend_get((DEV)->links, (UNIT))))
|
||||
|
||||
#define SCSI_DATA(DEV, UNIT) \
|
||||
((SCSI_LINK((DEV), (UNIT)) ? (SCSI_LINK((DEV), (UNIT))->sd) : NULL))
|
||||
|
||||
/*
|
||||
* SCSI_DEVICE_ENTRIES: A macro to generate all the entry points from the
|
||||
* name.
|
||||
*/
|
||||
#define SCSI_DEVICE_ENTRIES(NAME) \
|
||||
static errval NAME##attach(struct scsi_link *sc_link); \
|
||||
extern struct scsi_device NAME##_switch; /* XXX actually static */ \
|
||||
void NAME##init(void) { \
|
||||
scsi_device_register(&NAME##_switch); \
|
||||
} \
|
||||
static int NAME##open(dev_t dev, int flags, int fmt, struct proc *p) { \
|
||||
return scsi_open(dev, flags, fmt, p, &NAME##_switch); \
|
||||
} \
|
||||
static int NAME##ioctl(dev_t dev, u_long cmd, caddr_t addr, \
|
||||
int flag, struct proc *p) { \
|
||||
return scsi_ioctl(dev, cmd, addr, flag, p, &NAME##_switch); \
|
||||
} \
|
||||
static int NAME##close(dev_t dev, int flag, int fmt, struct proc *p) { \
|
||||
return scsi_close(dev, flag, fmt, p, &NAME##_switch); \
|
||||
} \
|
||||
static void NAME##minphys(struct buf *bp) { \
|
||||
scsi_minphys(bp, &NAME##_switch); \
|
||||
} \
|
||||
static void NAME##strategy(struct buf *bp) { \
|
||||
scsi_strategy(bp, &NAME##_switch); \
|
||||
}
|
||||
|
||||
#ifdef KERNEL
|
||||
/* Configuration tables for config.
|
||||
*/
|
||||
/* A unit, type, etc can be SCCONF_ANY to indicate it is a '?'
|
||||
* in the config.
|
||||
*/
|
||||
#define SCCONF_UNSPEC 255
|
||||
#define SCCONF_ANY 254
|
||||
|
||||
struct isa_driver;
|
||||
struct scsi_ctlr_config
|
||||
{
|
||||
int scbus;
|
||||
char *driver;
|
||||
int unit;
|
||||
int bus;
|
||||
};
|
||||
|
||||
struct scsi_device_config
|
||||
{
|
||||
char *name; /* SCSI device name (sd, st, etc) */
|
||||
int unit; /* desired device unit */
|
||||
int cunit; /* Controller unit */
|
||||
int target; /* SCSI ID (target) */
|
||||
int lun; /* SCSI lun */
|
||||
int flags; /* Flags from config */
|
||||
};
|
||||
|
||||
extern void (*scsi_tinit[])(void);
|
||||
extern struct scsi_ctlr_config scsi_cinit[];
|
||||
extern struct scsi_device_config scsi_dinit[];
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Define various devices that we know mis-behave in some way,
|
||||
* and note how they are bad, so we can correct for them
|
||||
*/
|
||||
struct st_mode {
|
||||
/* 4*/ u_int32_t blksiz;
|
||||
/* 6*/ u_int16_t quirks; /* same definitions as in XXX */
|
||||
/* 7*/ u_int8_t density;
|
||||
/* 8*/ u_int8_t spare[1];
|
||||
};
|
||||
|
||||
typedef struct st_mode st_modes[4];
|
||||
|
||||
/* define behaviour codes (quirks) */
|
||||
/* common to all SCSI devices */
|
||||
#define SCSI_Q_NO_SYNC 0x8000
|
||||
#define SCSI_Q_NO_FAST 0x4000
|
||||
#define SCSI_Q_NO_WIDE 0x2000
|
||||
|
||||
/* tape specific ST_Q_* */
|
||||
#define ST_Q_NEEDS_PAGE_0 0x0001
|
||||
#define ST_Q_FORCE_FIXED_MODE 0x0002
|
||||
#define ST_Q_FORCE_VAR_MODE 0x0004
|
||||
#define ST_Q_SNS_HLP 0x0008 /* must do READ for good MODE SENSE */
|
||||
#define ST_Q_IGNORE_LOADS 0x0010
|
||||
#define ST_Q_BLKSIZ 0x0020 /* variable-block media_blksiz > 0 */
|
||||
#define ST_Q_CC_NOMSG 0x0040 /* no messages accepted in CC state */
|
||||
#define ST_Q_NO_1024 0x0080 /* never ever use 1024-byte fix blk */
|
||||
|
||||
#define ST_Q_NO_SYNC SCSI_Q_NO_SYNC
|
||||
#define ST_Q_NO_FAST SCSI_Q_NO_FAST
|
||||
#define ST_Q_NO_WIDE SCSI_Q_NO_WIDE
|
||||
|
||||
/* disk specific SD_Q_* */
|
||||
#define SD_Q_NO_TAGS 0x0001
|
||||
|
||||
#define SD_Q_NO_SYNC SCSI_Q_NO_SYNC
|
||||
#define SD_Q_NO_FAST SCSI_Q_NO_FAST
|
||||
#define SD_Q_NO_WIDE SCSI_Q_NO_WIDE
|
||||
|
||||
/* cd specific CD_Q_* */
|
||||
#define CD_Q_NO_TOUCH 0x0001
|
||||
#define CD_Q_BCD_TRACKS 0x0002
|
||||
#define CD_Q_NO_START 0x0004
|
||||
|
||||
|
||||
/* worm specific WORM_Q_* */
|
||||
#define WORM_Q_PLASMON 0x0001
|
||||
#define WORM_Q_PHILIPS 0x0002
|
||||
/*
|
||||
* 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
|
||||
{
|
||||
u_int8_t target; /* targ of this dev */
|
||||
u_int8_t lun; /* lun of this dev */
|
||||
u_int8_t adapter_targ; /* what are we on the scsi bus*/
|
||||
u_int8_t adapter_unit; /* e.g. the 0 in aha0 */
|
||||
u_int8_t adapter_bus; /* e.g. the 0 in bus0 */
|
||||
u_int8_t scsibus; /* the Nth scsibus */
|
||||
u_int8_t dev_unit; /* e.g. the 0 in sd0 */
|
||||
u_int8_t opennings; /* available operations */
|
||||
u_int8_t active; /* operations in progress */
|
||||
u_int16_t flags; /* flags all devices have */
|
||||
u_int16_t quirks; /* device specific quirks */
|
||||
struct scsi_adapter *adapter; /* adapter entry points etc. */
|
||||
struct scsi_device *device; /* device entry points etc. */
|
||||
struct scsi_xfer *active_xs; /* operations under way */
|
||||
void *fordriver; /* for driver's private user */
|
||||
void *devmodes; /* dev specific mode tables */
|
||||
dev_t dev; /* Device major # (character) */
|
||||
struct scsi_data *sd; /* Device data structure */
|
||||
struct scsi_inquiry_data inqbuf; /* Inquiry data */
|
||||
void *adapter_softc; /* to call foo_scsi_cmd */
|
||||
};
|
||||
|
||||
/* XXX-HA: dufault@hda.com: SDEV_BOUNCE is set down in the adapter drivers
|
||||
* in an sc_link structure to indicate that this host adapter requires
|
||||
* ISA DMA bounce buffers. I think the link structure should
|
||||
* be associated only with the type drive and not the adapter driver,
|
||||
* and the bounce flag should be in something associated with the
|
||||
* adapter driver.
|
||||
* XXX-HA And I added the "supports residuals properly" flag that ALSO goes
|
||||
* in an adapter structure. I figure I'll fix both at once.
|
||||
*
|
||||
* XXX SDEV_OPEN is used for two things: To prevent more than one
|
||||
* open and to make unit attentions errors be logged on the console.
|
||||
* These should be split up; I'm adding SDEV_IS_OPEN to enforce one
|
||||
* open only.
|
||||
*
|
||||
* XXX SDEV_UK is used to mark the "uk" device.
|
||||
*/
|
||||
|
||||
#define SDEV_MEDIA_LOADED 0x0001 /* device figures are still valid */
|
||||
#define SDEV_WAITING 0x0002 /* a process is waiting for this */
|
||||
#define SDEV_OPEN 0x0004 /* at least 1 open session */
|
||||
#define SDEV_BOUNCE 0x0008 /* XXX-HA: unit needs DMA bounce buffer */
|
||||
#define SDEV_DBX 0x00F0 /* debugging flags (scsi_debug.h) */
|
||||
#define SDEV_ONCE_ONLY 0x0100 /* unit can only be opened once */
|
||||
#define SDEV_BOOTVERBOSE 0x0200 /* be noisy during boot */
|
||||
#define SDEV_RESIDS_WORK 0x0400 /* XXX-HA: Residuals work */
|
||||
#define SDEV_TARGET_OPS 0x0800 /* XXX-HA: Supports target ops */
|
||||
#define SDEV_IS_OPEN 0x1000 /* at least 1 open session */
|
||||
#define SDEV_UK 0x2000 /* this is the "uk" device */
|
||||
#define SDEV_XLOCK 0x4000 /* Device is locked */
|
||||
#define SDEV_WANT 0x8000 /* A process is waiting for lock */
|
||||
|
||||
/*
|
||||
* 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 {
|
||||
u_char maxtarg;
|
||||
u_char maxlun;
|
||||
struct scsi_link *adapter_link; /* prototype supplied by adapter */
|
||||
struct scsi_link *(*sc_link)[][8]; /* dynamically allocated */
|
||||
};
|
||||
|
||||
/*
|
||||
* 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
|
||||
{
|
||||
/*04*/ struct scsi_xfer *next; /* when free */
|
||||
/*08*/ u_int32_t flags;
|
||||
/*12*/ struct scsi_link *sc_link; /* all about our device and adapter */
|
||||
/*13*/ u_int8_t retries; /* the number of times to retry */
|
||||
/*16*/ u_int8_t spare[3];
|
||||
/*20*/ int32_t timeout; /* in milliseconds */
|
||||
/*24*/ struct scsi_generic *cmd; /* The scsi command to execute */
|
||||
/*28*/ int32_t cmdlen; /* how long it is */
|
||||
/*32*/ u_char *data; /* dma address OR a uio address */
|
||||
/*36*/ int32_t datalen; /* data len (blank if uio) */
|
||||
/*40*/ int32_t resid; /* how much buffer was not touched */
|
||||
/*44*/ int32_t 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.
|
||||
*/
|
||||
/*84*/ int32_t req_sense_length; /* Explicit request sense length */
|
||||
/*88*/ int32_t status; /* SCSI status */
|
||||
/*100*/ struct scsi_generic cmdstore; /* stash the command in here */
|
||||
/*
|
||||
* Handle for scheduling
|
||||
* command timeouts.
|
||||
*/
|
||||
struct callout_handle timeout_ch;
|
||||
};
|
||||
|
||||
/*
|
||||
* 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 SCSI_ITSDONE 0x10 /* the transfer is as done as it gets */
|
||||
#define ITSDONE 0x10 /* the transfer is as done as it gets */
|
||||
#define SCSI_INUSE 0x20 /* The scsi_xfer block is in use */
|
||||
#define INUSE 0x20 /* The scsi_xfer block is in use */
|
||||
#define SCSI_SILENT 0x40 /* Don't report errors to console */
|
||||
#define SCSI_ERR_OK 0x80 /* An error on this operation is OK. */
|
||||
#define SCSI_RESET 0x100 /* Reset the device in question */
|
||||
#define SCSI_DATA_UIO 0x200 /* The data address refers to a UIO */
|
||||
#define SCSI_DATA_IN 0x400 /* expect data to come INTO memory */
|
||||
#define SCSI_DATA_OUT 0x800 /* expect data to flow OUT of memory */
|
||||
#define SCSI_TARGET 0x1000 /* This defines a TARGET mode op. */
|
||||
#define SCSI_ESCAPE 0x2000 /* Escape operation */
|
||||
#define SCSI_EOF 0x4000 /* The operation should return EOF */
|
||||
#define SCSI_RESID_VALID 0x8000 /* The resid field contains valid data */
|
||||
|
||||
/*
|
||||
* 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 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 */
|
||||
#define XS_TIMEOUT 0x03 /* The device timed out.. turned off? */
|
||||
#define XS_SWTIMEOUT 0x04 /* The Timeout reported was caught by SW */
|
||||
#define XS_BUSY 0x08 /* The device busy, try again later? */
|
||||
#define XS_LENGTH 0x09 /* Illegal length (over/under run) */
|
||||
#define XS_SELTIMEOUT 0x10 /* Device failed to respond to selection */
|
||||
|
||||
#ifdef KERNEL
|
||||
void *extend_get(struct extend_array *ea, int index);
|
||||
void scsi_attachdevs __P((struct scsibus_data *scbus));
|
||||
u_int32_t scsi_read_capacity __P(( struct scsi_link *sc_link,
|
||||
u_int32_t *blk_size, u_int32_t flags));
|
||||
errval scsi_test_unit_ready __P(( struct scsi_link *sc_link, u_int32_t flags));
|
||||
errval scsi_reset_target __P((struct scsi_link *));
|
||||
errval scsi_target_mode __P((struct scsi_link *, int));
|
||||
errval scsi_inquire( struct scsi_link *sc_link,
|
||||
struct scsi_inquiry_data *inqbuf, u_int32_t flags);
|
||||
errval scsi_prevent( struct scsi_link *sc_link, u_int32_t type,u_int32_t flags);
|
||||
struct scsibus_data *scsi_alloc_bus __P((void));
|
||||
errval scsi_probe_bus __P((int, int, int));
|
||||
errval scsi_probe_busses __P(( int, int, int));
|
||||
errval scsi_start_unit( struct scsi_link *sc_link, u_int32_t flags);
|
||||
errval scsi_stop_unit(struct scsi_link *sc_link, u_int32_t eject, u_int32_t flags);
|
||||
void scsi_done(struct scsi_xfer *xs);
|
||||
void scsi_user_done(struct scsi_xfer *xs);
|
||||
errval scsi_scsi_cmd __P(( struct scsi_link *, struct scsi_generic *,
|
||||
u_int32_t, u_char *,
|
||||
u_int32_t, u_int32_t,
|
||||
u_int32_t, struct buf *,
|
||||
u_int32_t));
|
||||
int scsi_do_ioctl __P((dev_t dev, u_long cmd, caddr_t addr, int mode,
|
||||
struct proc *p, struct scsi_link *sc_link));
|
||||
|
||||
struct scsi_link *scsi_link_get __P((int bus, int targ, int lun));
|
||||
dev_t scsi_dev_lookup __P((int (*opener)(dev_t dev, int flags, int fmt,
|
||||
struct proc *p)));
|
||||
|
||||
int scsi_opened_ok __P((dev_t dev, int flag, int type, struct scsi_link *sc_link));
|
||||
errval scsi_set_bus __P((int, struct scsi_link *));
|
||||
|
||||
char *scsi_sense_desc __P((int, int));
|
||||
void scsi_sense_print __P((struct scsi_xfer *));
|
||||
void show_scsi_cmd __P((struct scsi_xfer *));
|
||||
|
||||
void scsi_uto3b __P((u_int32_t , u_char *));
|
||||
u_int32_t scsi_3btou __P((u_char *));
|
||||
int32_t scsi_3btoi __P((u_char *));
|
||||
void scsi_uto4b __P((u_int32_t, u_char *));
|
||||
u_int32_t scsi_4btou __P((u_char *));
|
||||
void scsi_uto2b __P((u_int32_t, u_char *));
|
||||
u_int32_t scsi_2btou __P((u_char *));
|
||||
|
||||
void sc_print_addr __P((struct scsi_link *));
|
||||
void sc_print_start __P((struct scsi_link *));
|
||||
void sc_print_init __P((void));
|
||||
void sc_print_finish __P((void));
|
||||
|
||||
#ifndef SCSIDEBUG
|
||||
void scsi_print_info __P((struct scsi_link *));
|
||||
#endif
|
||||
|
||||
void scsi_device_register __P((struct scsi_device *sd));
|
||||
|
||||
void scsi_configure_start __P((void));
|
||||
void scsi_configure_finish __P((void));
|
||||
|
||||
void ukinit __P((void));
|
||||
|
||||
#ifdef SCSI_2_DEF
|
||||
errval scsi_change_def( struct scsi_link *sc_link, u_int32_t flags);
|
||||
#endif
|
||||
#endif /* KERNEL */
|
||||
|
||||
#define SCSI_EXTERNALLEN (sizeof(struct scsi_link))
|
||||
|
||||
|
||||
/* XXX This belongs in a tape file.
|
||||
*/
|
||||
|
||||
/**********************************************************************
|
||||
from the scsi2 spec
|
||||
Value Tracks Density(bpi) Code Type Reference Note
|
||||
0x1 9 800 NRZI R X3.22-1983 2
|
||||
0x2 9 1600 PE R X3.39-1986 2
|
||||
0x3 9 6250 GCR R X3.54-1986 2
|
||||
0x5 4/9 8000 GCR C X3.136-1986 1
|
||||
0x6 9 3200 PE R X3.157-1987 2
|
||||
0x7 4 6400 IMFM C X3.116-1986 1
|
||||
0x8 4 8000 GCR CS X3.158-1986 1
|
||||
0x9 18 37871 GCR C X3B5/87-099 2
|
||||
0xA 22 6667 MFM C X3B5/86-199 1
|
||||
0xB 4 1600 PE C X3.56-1986 1
|
||||
0xC 24 12690 GCR C HI-TC1 1,5
|
||||
0xD 24 25380 GCR C HI-TC2 1,5
|
||||
0xF 15 10000 GCR C QIC-120 1,5
|
||||
0x10 18 10000 GCR C QIC-150 1,5
|
||||
0x11 26 16000 GCR C QIC-320(525?) 1,5
|
||||
0x12 30 51667 RLL C QIC-1350 1,5
|
||||
0x13 1 61000 DDS CS X3B5/88-185A 4
|
||||
0x14 1 43245 RLL CS X3.202-1991 4
|
||||
0x15 1 45434 RLL CS ECMA TC17 4
|
||||
0x16 48 10000 MFM C X3.193-1990 1
|
||||
0x17 48 42500 MFM C X3B5/91-174 1
|
||||
|
||||
where Code means:
|
||||
NRZI Non Return to Zero, change on ones
|
||||
GCR Group Code Recording
|
||||
PE Phase Encoded
|
||||
IMFM Inverted Modified Frequency Modulation
|
||||
MFM Modified Frequency Modulation
|
||||
DDS Dat Data Storage
|
||||
RLL Run Length Encoding
|
||||
|
||||
where Type means:
|
||||
R Real-to-Real
|
||||
C Cartridge
|
||||
CS cassette
|
||||
|
||||
where Notes means:
|
||||
1 Serial Recorded
|
||||
2 Parallel Recorded
|
||||
3 Old format know as QIC-11
|
||||
4 Helical Scan
|
||||
5 Not ANSI standard, rather industry standard.
|
||||
|
||||
********************************************************************/
|
||||
|
||||
#define HALFINCH_800 0x01
|
||||
#define HALFINCH_1600 0x02
|
||||
#define HALFINCH_6250 0x03
|
||||
#define QIC_11 0x04 /* from Archive 150S Theory of Op. XXX */
|
||||
#define QIC_24 0x05 /* may be bad, works for CIPHER ST150S XXX */
|
||||
#define QIC_120 0x0f
|
||||
#define QIC_150 0x10
|
||||
#define QIC_320 0x11
|
||||
#define QIC_525 0x11
|
||||
#define QIC_1320 0x12
|
||||
#define DDS 0x13
|
||||
#define DAT_1 0x13
|
||||
#define QIC_3080 0x29
|
||||
|
||||
|
||||
/* XXX (dufault@hda.com) This is used only by "su" and "sctarg".
|
||||
* The minor number field conflicts with the disk slice code,
|
||||
* and so it is tough to access the disks through the "su" device.
|
||||
*/
|
||||
|
||||
/* Device number fields:
|
||||
*
|
||||
* NON-FIXED SCSI devices:
|
||||
*
|
||||
* ?FC? ???? ???? ???? MMMMMMMM mmmmmmmm
|
||||
*
|
||||
* F: Fixed device (nexus in number): must be 0.
|
||||
* C: Control device; only user mode ioctl is supported.
|
||||
* ?: Don't know; those bits didn't use to exist, currently always 0.
|
||||
* M: Major device number.
|
||||
* m: Old style minor device number.
|
||||
*
|
||||
* FIXED SCSI devices:
|
||||
*
|
||||
* XXX Conflicts with the slice code. Maybe the slice code can be
|
||||
* changed to respect the F bit?
|
||||
*
|
||||
* ?FC? ?BBB TTTT ?LLL MMMMMMMM mmmmmmmm
|
||||
*
|
||||
* F: Fixed device (nexus in number); must be 1.
|
||||
* C: Control device; only user mode ioctl is supported.
|
||||
* B: SCSI bus
|
||||
* T: SCSI target ID
|
||||
* L: Logical unit
|
||||
* M: Major device number
|
||||
* m: Old style minor device number.
|
||||
*/
|
||||
|
||||
#define SCSI_FIXED_MASK 0x40000000
|
||||
#define SCSI_FIXED(DEV) (((DEV) & SCSI_FIXED_MASK))
|
||||
#define SCSI_CONTROL_MASK 0x20000000
|
||||
#define SCSI_CONTROL(DEV) (((DEV) & SCSI_CONTROL_MASK))
|
||||
|
||||
#define SCSI_BUS(DEV) (((DEV) & 0x07000000) >> 24)
|
||||
#define SCSI_ID(DEV) (((DEV) & 0x00F00000) >> 20)
|
||||
#define SCSI_LUN(DEV) (((DEV) & 0x00070000) >> 16)
|
||||
|
||||
#define SCSI_MKFIXED(B, T, L, P) ( \
|
||||
((B) << 24) | \
|
||||
((T) << 20) | \
|
||||
((L) << 16) | \
|
||||
(P) | \
|
||||
SCSI_FIXED_MASK )
|
||||
|
||||
#endif /*SCSI_SCSICONF_H*/
|
||||
/* END OF FILE */
|
@ -1,319 +0,0 @@
|
||||
/*
|
||||
* sctarg: Target mode user interface
|
||||
*
|
||||
* Copyright (C) 1995, HD Associates, Inc.
|
||||
* PO Box 276
|
||||
* Pepperell, MA 01463
|
||||
* 508 433 5266
|
||||
* dufault@hda.com
|
||||
*
|
||||
* This code is contributed to the University of California at Berkeley:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id: sctarg.c,v 1.27 1998/07/04 22:30:24 julian Exp $
|
||||
*/
|
||||
|
||||
#include "opt_bounce.h"
|
||||
#include "opt_devfs.h"
|
||||
#include "opt_scsi.h"
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/buf.h>
|
||||
#include <sys/conf.h>
|
||||
#include <sys/kernel.h>
|
||||
#ifdef DEVFS
|
||||
#include <sys/devfsext.h>
|
||||
#endif /*DEVFS*/
|
||||
#include <scsi/scsiconf.h>
|
||||
#include <scsi/scsi_debug.h>
|
||||
#include <scsi/scsi_driver.h>
|
||||
|
||||
#include "ioconf.h"
|
||||
|
||||
#define OPEN 0x01
|
||||
|
||||
struct scsi_data {
|
||||
struct buf_queue_head buf_queue;
|
||||
int flags; /* Already open */
|
||||
};
|
||||
|
||||
static d_open_t sctargopen;
|
||||
static d_read_t sctargread;
|
||||
static d_write_t sctargwrite;
|
||||
static d_close_t sctargclose;
|
||||
static d_ioctl_t sctargioctl;
|
||||
static d_strategy_t sctargstrategy;
|
||||
|
||||
#define CDEV_MAJOR 65
|
||||
static struct cdevsw sctarg_cdevsw =
|
||||
{ sctargopen, sctargclose, sctargread, sctargwrite, /*65*/
|
||||
sctargioctl, nostop, nullreset, nodevtotty,/* sctarg */
|
||||
seltrue, nommap, sctargstrategy, "sctarg", NULL, -1 };
|
||||
|
||||
SCSI_DEVICE_ENTRIES(sctarg)
|
||||
|
||||
static errval sctarg_open(dev_t dev, int flags, int fmt, struct proc *p,
|
||||
struct scsi_link *sc_link);
|
||||
static void sctargstart(u_int32_t unit, u_int32_t unused_flags);
|
||||
static void sctarg_strategy(struct buf *bp, struct scsi_link *sc_link);
|
||||
|
||||
static struct scsi_device sctarg_switch =
|
||||
{
|
||||
NULL,
|
||||
sctargstart, /* we have a queue, and this is how we service it */
|
||||
NULL,
|
||||
NULL,
|
||||
"sctarg",
|
||||
0,
|
||||
{0, 0},
|
||||
SDEV_ONCE_ONLY,
|
||||
sctargattach,
|
||||
"Processor Target",
|
||||
sctargopen,
|
||||
sizeof(struct scsi_data),
|
||||
T_TARGET,
|
||||
0,
|
||||
0,
|
||||
sctarg_open,
|
||||
0,
|
||||
0,
|
||||
sctarg_strategy,
|
||||
};
|
||||
|
||||
static errval
|
||||
sctargattach(struct scsi_link *sc_link)
|
||||
{
|
||||
struct scsi_data *sctarg;
|
||||
|
||||
sctarg = sc_link->sd;
|
||||
bufq_init(&sctarg->buf_queue);
|
||||
sctarg->flags = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static errval
|
||||
sctarg_open(dev_t dev, int flags, int fmt, struct proc *p,
|
||||
struct scsi_link *sc_link)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
/* Does this host adapter support target mode operation?
|
||||
*/
|
||||
if ((sc_link->flags & SDEV_TARGET_OPS) == 0)
|
||||
return ENODEV; /* Operation not supported */
|
||||
|
||||
if (SCSI_FIXED(dev)) {
|
||||
sc_link->scsibus = SCSI_BUS(dev);
|
||||
scsi_set_bus(sc_link->scsibus, sc_link);
|
||||
|
||||
sc_link->target = SCSI_ID(dev);
|
||||
sc_link->lun = SCSI_LUN(dev);
|
||||
}
|
||||
|
||||
if (sc_link->scsibus == SCCONF_UNSPEC ||
|
||||
sc_link->target == SCCONF_UNSPEC ||
|
||||
sc_link->lun == SCCONF_UNSPEC)
|
||||
return ENXIO;
|
||||
|
||||
/* XXX: You can have more than one target device on a single
|
||||
* host adapter. We need a reference count.
|
||||
*/
|
||||
if ((sc_link->sd->flags & OPEN) == 0) /* Enable target mode */
|
||||
{
|
||||
ret = scsi_target_mode(sc_link, 1);
|
||||
sc_link->sd->flags |= OPEN;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
sctargread( dev_t dev, struct uio *uio, int ioflag)
|
||||
{
|
||||
return (physio(sctargstrategy, NULL, dev, 1, minphys, uio));
|
||||
}
|
||||
|
||||
static int
|
||||
sctargwrite ( dev_t dev, struct uio *uio, int ioflag)
|
||||
{
|
||||
return (physio(sctargstrategy, NULL, dev, 0, minphys, uio));
|
||||
}
|
||||
|
||||
/*
|
||||
* sctargstart 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 (sctargstrategy)
|
||||
*
|
||||
* 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.
|
||||
* sctargstart() is called at splbio
|
||||
*/
|
||||
static void
|
||||
sctargstart(unit, unused_flags)
|
||||
u_int32_t unit;
|
||||
u_int32_t unused_flags;
|
||||
{
|
||||
struct scsi_link *sc_link = SCSI_LINK(&sctarg_switch, unit);
|
||||
struct scsi_data *sctarg = sc_link->sd;
|
||||
register struct buf *bp = 0;
|
||||
struct
|
||||
{
|
||||
#define PROCESSOR_SEND 0x0A
|
||||
#define PROCESSOR_RECEIVE 0x08
|
||||
u_char op_code;
|
||||
u_char byte2;
|
||||
u_char len[3];
|
||||
u_char control;
|
||||
} cmd;
|
||||
|
||||
u_int32_t flags;
|
||||
|
||||
SC_DEBUG(sc_link, SDEV_DB2, ("sctargstart "));
|
||||
/*
|
||||
* 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) {
|
||||
sc_link->flags &= ~SDEV_WAITING;
|
||||
wakeup((caddr_t)sc_link);
|
||||
return;
|
||||
}
|
||||
|
||||
bp = bufq_first(&sctarg->buf_queue);
|
||||
if (bp == NULL)
|
||||
return;
|
||||
bufq_remove(&sctarg->buf_queue, bp);
|
||||
|
||||
/*
|
||||
* Fill out the scsi command
|
||||
*/
|
||||
bzero(&cmd, sizeof(cmd));
|
||||
flags = SCSI_TARGET;
|
||||
if ((bp->b_flags & B_READ) == B_WRITE) {
|
||||
cmd.op_code = PROCESSOR_SEND;
|
||||
flags |= SCSI_DATA_OUT;
|
||||
} else {
|
||||
cmd.op_code = PROCESSOR_RECEIVE;
|
||||
flags |= SCSI_DATA_IN;
|
||||
}
|
||||
|
||||
scsi_uto3b(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_data,
|
||||
bp->b_bcount,
|
||||
0,
|
||||
100000,
|
||||
bp,
|
||||
flags | SCSI_NOSLEEP) == SUCCESSFULLY_QUEUED) {
|
||||
} else {
|
||||
printf("sctarg%lu: oops not queued\n", (u_long)unit);
|
||||
bp->b_flags |= B_ERROR;
|
||||
bp->b_error = EIO;
|
||||
biodone(bp);
|
||||
}
|
||||
} /* go back and see if we can cram more work in.. */
|
||||
}
|
||||
|
||||
static void
|
||||
sctarg_strategy(struct buf *bp, struct scsi_link *sc_link)
|
||||
{
|
||||
unsigned char unit;
|
||||
u_int32_t opri;
|
||||
struct scsi_data *sctarg;
|
||||
|
||||
unit = minor((bp->b_dev));
|
||||
sctarg = sc_link->sd;
|
||||
|
||||
opri = splbio();
|
||||
|
||||
/*
|
||||
* Use a bounce buffer if necessary
|
||||
*/
|
||||
#ifdef BOUNCE_BUFFERS
|
||||
if (sc_link->flags & SDEV_BOUNCE)
|
||||
vm_bounce_alloc(bp);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Place it at the end of the queue of activities for this device.
|
||||
*/
|
||||
bufq_insert_tail(&sctarg->buf_queue, bp);
|
||||
|
||||
/*
|
||||
* 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..)
|
||||
*/
|
||||
sctargstart(unit, 0);
|
||||
|
||||
splx(opri);
|
||||
return;
|
||||
}
|
||||
|
||||
static sctarg_devsw_installed = 0;
|
||||
#ifdef DEVFS
|
||||
static void *sctarg_devfs_token;
|
||||
#endif
|
||||
|
||||
static void sctarg_drvinit(void *unused)
|
||||
{
|
||||
dev_t dev;
|
||||
|
||||
if( ! sctarg_devsw_installed ) {
|
||||
dev = makedev(CDEV_MAJOR, 0);
|
||||
cdevsw_add(&dev,&sctarg_cdevsw, NULL);
|
||||
sctarg_devsw_installed = 1;
|
||||
#ifdef DEVFS
|
||||
/* XXX should be in ADAPTER code */
|
||||
sctarg_devfs_token =
|
||||
devfs_add_devswf(&sctarg_cdevsw, 0, DV_CHR, 0, 0,
|
||||
0600, "sctarg");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
SYSINIT(sctargdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,sctarg_drvinit,NULL)
|
||||
|
||||
|
1065
sys/scsi/sd.c
1065
sys/scsi/sd.c
File diff suppressed because it is too large
Load Diff
162
sys/scsi/ssc.c
162
sys/scsi/ssc.c
@ -1,162 +0,0 @@
|
||||
/* "superscsi" pseudo device.
|
||||
* "superscsi" supports general SCSI utilities that can iterate
|
||||
* over all SCSI targets, including those without device entry
|
||||
* points.
|
||||
*
|
||||
* "superscsi" supports the SCIOCADDR ioctl to change the BUS, ID, LUN
|
||||
* of the target so that you can get to all devices. The only thing
|
||||
* you can do to "superscsi" is open it, set the target, perform ioctl
|
||||
* calls, and close it.
|
||||
*
|
||||
* Keep "superscsi" protected: you can drive a truck through the
|
||||
* security hole if you don't.
|
||||
*
|
||||
*Begin copyright
|
||||
*
|
||||
* Copyright (C) 1993, 1994, 1995, HD Associates, Inc.
|
||||
* PO Box 276
|
||||
* Pepperell, MA 01463
|
||||
* 508 433 5266
|
||||
* dufault@hda.com
|
||||
*
|
||||
* This code is contributed to the University of California at Berkeley:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*End copyright
|
||||
* $Id: ssc.c,v 1.18 1998/01/24 02:54:52 eivind Exp $
|
||||
*/
|
||||
|
||||
#include "opt_devfs.h"
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/conf.h>
|
||||
#include <sys/disklabel.h>
|
||||
#include <sys/scsiio.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/stat.h>
|
||||
#ifdef DEVFS
|
||||
#include <sys/devfsext.h>
|
||||
#endif /*DEVFS*/
|
||||
#include <scsi/scsiconf.h>
|
||||
|
||||
static d_open_t sscopen;
|
||||
static d_close_t sscclose;
|
||||
static d_ioctl_t sscioctl;
|
||||
|
||||
extern d_open_t suopen;
|
||||
extern d_close_t suclose;
|
||||
extern d_ioctl_t suioctl;
|
||||
|
||||
#define CDEV_MAJOR 49
|
||||
static struct cdevsw ssc_cdevsw =
|
||||
{ sscopen, sscclose, noread, nowrite, /*49*/
|
||||
sscioctl, nostop, nullreset, nodevtotty,
|
||||
seltrue, nommap, nostrategy, "ssc", NULL, -1 };
|
||||
|
||||
static dev_t sscdev = NODEV;
|
||||
|
||||
static int
|
||||
sscopen(dev_t dev, int flag, int type, struct proc *p)
|
||||
{
|
||||
if (sscdev != NODEV)
|
||||
return suopen(sscdev, flag, type, p);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
sscclose(dev_t dev, int fflag, int type, struct proc *p)
|
||||
{
|
||||
|
||||
if (sscdev != NODEV)
|
||||
return suclose(sscdev, fflag, type, p);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
sscioctl(dev_t dev, u_long cmd, caddr_t data, int fflag, struct proc *p)
|
||||
{
|
||||
if (cmd == SCIOCADDR)
|
||||
{
|
||||
struct scsi_addr *sca;
|
||||
dev_t newdev;
|
||||
int ret;
|
||||
|
||||
sca = (struct scsi_addr *) data;
|
||||
newdev = SCSI_MKFIXED(sca->scbus,sca->target,sca->lun,RAW_PART);
|
||||
|
||||
if (sscdev != NODEV)
|
||||
{
|
||||
suclose(sscdev, fflag, S_IFCHR, p);
|
||||
sscdev = NODEV;
|
||||
}
|
||||
|
||||
if ( (ret = suopen(newdev, fflag, S_IFCHR, p)) )
|
||||
return ret;
|
||||
|
||||
sscdev = newdev;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (sscdev != NODEV)
|
||||
return suioctl(sscdev, cmd, data, fflag, p);
|
||||
|
||||
return ENXIO;
|
||||
}
|
||||
|
||||
/*
|
||||
* I've elected not to support any other entries. There really is no
|
||||
* good reason other than I'm not sure how you would use them.
|
||||
*/
|
||||
|
||||
static ssc_devsw_installed = 0;
|
||||
#ifdef DEVFS
|
||||
static void *ssc_devfs_token;
|
||||
#endif
|
||||
|
||||
static void
|
||||
ssc_drvinit(void *unused)
|
||||
{
|
||||
dev_t dev;
|
||||
|
||||
if( ! ssc_devsw_installed ) {
|
||||
dev = makedev(CDEV_MAJOR, 0);
|
||||
cdevsw_add(&dev,&ssc_cdevsw, NULL);
|
||||
ssc_devsw_installed = 1;
|
||||
#ifdef DEVFS
|
||||
ssc_devfs_token =
|
||||
devfs_add_devswf(&ssc_cdevsw, 0, DV_CHR, 0, 0,
|
||||
0600, "ssc");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
SYSINIT(sscdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,ssc_drvinit,NULL)
|
||||
|
2005
sys/scsi/st.c
2005
sys/scsi/st.c
File diff suppressed because it is too large
Load Diff
361
sys/scsi/su.c
361
sys/scsi/su.c
@ -1,361 +0,0 @@
|
||||
/* su: SCSI Universal. This is a universal SCSI device that
|
||||
* has a fixed minor number format. This allows you to refer
|
||||
* to your devices by BUS, ID, LUN instead of st0, st1, ...
|
||||
*
|
||||
* This code looks up the underlying device for a given SCSI
|
||||
* target and uses that driver.
|
||||
*
|
||||
*Begin copyright
|
||||
*
|
||||
* Copyright (C) 1993, 1994, 1995, HD Associates, Inc.
|
||||
* PO Box 276
|
||||
* Pepperell, MA 01463
|
||||
* 508 433 5266
|
||||
* dufault@hda.com
|
||||
*
|
||||
* This code is contributed to the University of California at Berkeley:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*End copyright
|
||||
*
|
||||
* $Id: su.c,v 1.20 1998/07/04 22:30:25 julian Exp $
|
||||
*
|
||||
* Tabstops 4
|
||||
* XXX devfs entries for this device should be handled by generic scsiconfig
|
||||
* Add a bdevsw interface.. ?
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/conf.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/buf.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <scsi/scsiconf.h>
|
||||
#define CDEV_MAJOR 18
|
||||
|
||||
/* These three used by ssc. */
|
||||
extern d_open_t suopen;
|
||||
extern d_close_t suclose;
|
||||
extern d_ioctl_t suioctl;
|
||||
|
||||
static d_read_t suread;
|
||||
static d_write_t suwrite;
|
||||
static d_poll_t supoll;
|
||||
static d_strategy_t sustrategy;
|
||||
|
||||
static struct cdevsw su_cdevsw =
|
||||
{ suopen, suclose, suread, suwrite, /*18*/
|
||||
suioctl, nostop, nullreset, nodevtotty,/* scsi */
|
||||
supoll, nommap, sustrategy, "su", NULL, -1 };
|
||||
|
||||
|
||||
/* Build an old style device number (unit encoded in the minor number)
|
||||
* from a base old one (no flag bits) and a full new one
|
||||
* (BUS, LUN, TARG in the minor number, and flag bits).
|
||||
*
|
||||
* OLDDEV has the major number and device unit only. It was constructed
|
||||
* at attach time and is stored in the scsi_link structure.
|
||||
*
|
||||
* NEWDEV can have whatever in it, but only the old control flags and the
|
||||
* super bit are present. IT CAN'T HAVE ANY UNIT INFORMATION or you'll
|
||||
* wind up with the wrong unit.
|
||||
*/
|
||||
#define OLD_DEV(NEWDEV, OLDDEV) ((OLDDEV) | ((NEWDEV) & 0x080000FF))
|
||||
|
||||
/* cnxio: non existent device entries. */
|
||||
|
||||
static d_open_t nxopen;
|
||||
static d_close_t nxclose;
|
||||
static d_read_t nxread;
|
||||
static d_write_t nxwrite;
|
||||
static d_ioctl_t nxioctl;
|
||||
#define nxstop nostop /* one void return is as good as another */
|
||||
#define nxreset noreset /* one unused function is as good as another */
|
||||
#define nxdevtotty nodevtotty /* one NULL return is as good as another */
|
||||
#define nxmmap nommap /* one -1 return is as good as another */
|
||||
#define nxstrategy nostrategy /* one NULL value is as good as another */
|
||||
static d_dump_t nxdump;
|
||||
#define nxpsize nopsize /* one NULL value is as good as another */
|
||||
|
||||
static struct cdevsw cnxio = {
|
||||
nxopen,
|
||||
nxclose,
|
||||
nxread,
|
||||
nxwrite,
|
||||
nxioctl,
|
||||
nxstop,
|
||||
nxreset,
|
||||
nxdevtotty,
|
||||
seltrue,
|
||||
nxmmap,
|
||||
nxstrategy,
|
||||
"NON",
|
||||
NULL,
|
||||
-1,
|
||||
nxdump,
|
||||
nxpsize,
|
||||
0,
|
||||
0,
|
||||
-1
|
||||
};
|
||||
|
||||
/* getsws: Look up the base dev switch for a given "by minor number" style
|
||||
* device.
|
||||
*/
|
||||
static int
|
||||
getsws(dev_t dev, int type, struct cdevsw **devswpp, dev_t *base)
|
||||
{
|
||||
int ret = 0;
|
||||
struct scsi_link *scsi_link;
|
||||
int chr_dev, blk_dev;
|
||||
|
||||
struct cdevsw *devswp;
|
||||
|
||||
int bus = SCSI_BUS(dev),
|
||||
lun = SCSI_LUN(dev),
|
||||
id = SCSI_ID(dev);
|
||||
|
||||
/* Try to look up the base device by finding the major number in
|
||||
* the scsi_link structure:
|
||||
*/
|
||||
if ((scsi_link = scsi_link_get(bus, id, lun)) == 0 ||
|
||||
scsi_link->dev == NODEV)
|
||||
{
|
||||
ret = ENXIO;
|
||||
devswp = &cnxio;
|
||||
chr_dev = NODEV;
|
||||
blk_dev = NODEV;
|
||||
}
|
||||
else
|
||||
{
|
||||
int bmaj, cmaj;
|
||||
|
||||
cmaj = major(scsi_link->dev);
|
||||
devswp = cdevsw[cmaj];
|
||||
chr_dev = OLD_DEV(dev, scsi_link->dev);
|
||||
bmaj = devswp->d_bmaj;
|
||||
blk_dev = OLD_DEV(dev, makedev(bmaj, minor(scsi_link->dev)));
|
||||
}
|
||||
|
||||
if (devswp)
|
||||
*devswpp = devswp;
|
||||
|
||||
if (type == S_IFCHR)
|
||||
*base = chr_dev;
|
||||
else
|
||||
*base = blk_dev;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
suopen(dev_t dev, int flag, int type, struct proc *p)
|
||||
{
|
||||
struct cdevsw *devswp;
|
||||
dev_t base;
|
||||
|
||||
if (getsws(dev, type, &devswp, &base))
|
||||
{
|
||||
/* Device not configured? Reprobe then try again.
|
||||
*/
|
||||
int bus = SCSI_BUS(dev), lun = SCSI_LUN(dev), id = SCSI_ID(dev);
|
||||
|
||||
if (scsi_probe_bus(bus, id, lun) || getsws(dev, type, &devswp,
|
||||
&base))
|
||||
return ENXIO;
|
||||
}
|
||||
|
||||
/* There is a properly configured underlying device.
|
||||
* Synthesize an appropriate device number:
|
||||
*/
|
||||
return (*devswp->d_open)(base, flag, type, p);
|
||||
}
|
||||
|
||||
int
|
||||
suclose(dev_t dev, int fflag, int type, struct proc *p)
|
||||
{
|
||||
struct cdevsw *devswp;
|
||||
dev_t base;
|
||||
|
||||
(void)getsws(dev, type, &devswp, &base);
|
||||
|
||||
return (*devswp->d_close)(base, fflag, type, p);
|
||||
}
|
||||
|
||||
static void
|
||||
sustrategy(struct buf *bp)
|
||||
{
|
||||
dev_t base;
|
||||
struct cdevsw *devswp;
|
||||
dev_t dev = bp->b_dev;
|
||||
|
||||
/* XXX: I have no way of knowing if this was through the
|
||||
* block or the character entry point.
|
||||
*/
|
||||
(void)getsws(dev, S_IFBLK, &devswp, &base);
|
||||
|
||||
bp->b_dev = base;
|
||||
|
||||
(*devswp->d_strategy)(bp);
|
||||
|
||||
bp->b_dev = dev; /* strat needs a dev_t */
|
||||
}
|
||||
|
||||
int
|
||||
suioctl(dev_t dev, u_long cmd, caddr_t data, int fflag, struct proc *p)
|
||||
{
|
||||
struct cdevsw *devswp;
|
||||
dev_t base;
|
||||
|
||||
/* XXX: I have no way of knowing if this was through the
|
||||
* block or the character entry point.
|
||||
*/
|
||||
(void)getsws(dev, S_IFCHR, &devswp, &base);
|
||||
|
||||
return (*devswp->d_ioctl)(base, cmd, data, fflag, p);
|
||||
}
|
||||
|
||||
static int
|
||||
suread(dev_t dev, struct uio *uio, int ioflag)
|
||||
{
|
||||
dev_t base;
|
||||
struct cdevsw *devswp;
|
||||
|
||||
(void)getsws(dev, S_IFCHR, &devswp, &base);
|
||||
|
||||
return (*devswp->d_read)(base, uio, ioflag);
|
||||
}
|
||||
|
||||
static int
|
||||
suwrite(dev_t dev, struct uio *uio, int ioflag)
|
||||
{
|
||||
dev_t base;
|
||||
struct cdevsw *devswp;
|
||||
|
||||
(void)getsws(dev, S_IFCHR, &devswp, &base);
|
||||
|
||||
return (*devswp->d_write)(base, uio, ioflag);
|
||||
}
|
||||
|
||||
static int
|
||||
supoll(dev_t dev, int events, struct proc *p)
|
||||
{
|
||||
dev_t base;
|
||||
struct cdevsw *devswp;
|
||||
|
||||
(void)getsws(dev, S_IFCHR, &devswp, &base);
|
||||
|
||||
return (*devswp->d_poll)(base, events, p);
|
||||
}
|
||||
|
||||
static int
|
||||
nxopen(dev, flags, fmt, p)
|
||||
dev_t dev;
|
||||
int flags;
|
||||
int fmt;
|
||||
struct proc *p;
|
||||
{
|
||||
|
||||
return (ENXIO);
|
||||
}
|
||||
|
||||
static int
|
||||
nxclose(dev, flags, fmt, p)
|
||||
dev_t dev;
|
||||
int flags;
|
||||
int fmt;
|
||||
struct proc *p;
|
||||
{
|
||||
|
||||
printf("nxclose(0x%x) called\n", dev);
|
||||
return (ENXIO);
|
||||
}
|
||||
|
||||
static int
|
||||
nxread(dev, uio, ioflag)
|
||||
dev_t dev;
|
||||
struct uio *uio;
|
||||
int ioflag;
|
||||
{
|
||||
|
||||
printf("nxread(0x%x) called\n", dev);
|
||||
return (ENXIO);
|
||||
}
|
||||
|
||||
static int
|
||||
nxwrite(dev, uio, ioflag)
|
||||
dev_t dev;
|
||||
struct uio *uio;
|
||||
int ioflag;
|
||||
{
|
||||
|
||||
printf("nxwrite(0x%x) called\n", dev);
|
||||
return (ENXIO);
|
||||
}
|
||||
|
||||
static int
|
||||
nxioctl(dev, cmd, data, flags, p)
|
||||
dev_t dev;
|
||||
u_long cmd;
|
||||
caddr_t data;
|
||||
int flags;
|
||||
struct proc *p;
|
||||
{
|
||||
|
||||
printf("nxioctl(0x%x) called\n", dev);
|
||||
return (ENXIO);
|
||||
}
|
||||
|
||||
static int
|
||||
nxdump(dev)
|
||||
dev_t dev;
|
||||
{
|
||||
|
||||
printf("nxdump(0x%x) called\n", dev);
|
||||
return (ENXIO);
|
||||
}
|
||||
|
||||
static su_devsw_installed = 0;
|
||||
|
||||
static void
|
||||
su_drvinit(void *unused)
|
||||
{
|
||||
dev_t dev;
|
||||
|
||||
if( ! su_devsw_installed ) {
|
||||
dev = makedev(CDEV_MAJOR, 0);
|
||||
cdevsw_add(&dev,&su_cdevsw, NULL);
|
||||
su_devsw_installed = 1;
|
||||
}
|
||||
}
|
||||
|
||||
SYSINIT(sudev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,su_drvinit,NULL)
|
||||
|
||||
|
@ -1,96 +0,0 @@
|
||||
/*
|
||||
* Driver for a device we can't identify.
|
||||
* by Julian Elischer (julian@tfs.com)
|
||||
*
|
||||
* $Id: uk.c,v 1.18 1997/08/02 14:33:16 bde Exp $
|
||||
*
|
||||
* If you find that you are adding any code to this file look closely
|
||||
* at putting it in "scsi_driver.c" instead.
|
||||
*/
|
||||
|
||||
#include <opt_devfs.h>
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/conf.h>
|
||||
#include <sys/kernel.h>
|
||||
#ifdef DEVFS
|
||||
#include <sys/devfsext.h>
|
||||
#endif /*DEVFS*/
|
||||
#include <scsi/scsiconf.h>
|
||||
#include <scsi/scsi_driver.h>
|
||||
|
||||
struct scsi_data {
|
||||
#ifdef DEVFS
|
||||
void *devfs_data_tok;
|
||||
#endif
|
||||
};
|
||||
|
||||
static d_open_t ukopen;
|
||||
static d_close_t ukclose;
|
||||
static d_ioctl_t ukioctl;
|
||||
|
||||
#define CDEV_MAJOR 31
|
||||
static struct cdevsw uk_cdevsw =
|
||||
{ ukopen, ukclose, noread, nowrite, /*31*/
|
||||
ukioctl, nostop, nullreset, nodevtotty,/* unknown */
|
||||
seltrue, nommap, NULL, "uk" ,NULL, -1 };
|
||||
|
||||
SCSI_DEVICE_ENTRIES(uk)
|
||||
|
||||
struct scsi_device uk_switch =
|
||||
{
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
"uk",
|
||||
0,
|
||||
{0, 0},
|
||||
SDEV_ONCE_ONLY|SDEV_UK, /* Only one open allowed */
|
||||
ukattach,
|
||||
"Unknown",
|
||||
ukopen,
|
||||
sizeof(struct scsi_data),
|
||||
T_UNKNOWN,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
};
|
||||
|
||||
|
||||
static uk_devsw_installed = 0;
|
||||
|
||||
static errval
|
||||
ukattach(struct scsi_link *sc_link)
|
||||
{
|
||||
#ifdef DEVFS
|
||||
struct scsi_data *uk = sc_link->sd;
|
||||
|
||||
uk->devfs_data_tok = devfs_add_devswf(&uk_cdevsw,
|
||||
sc_link->dev_unit,
|
||||
DV_CHR,
|
||||
UID_ROOT, GID_WHEEL, 0600,
|
||||
"uk%d", sc_link->dev_unit);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void uk_drvinit(void *unused)
|
||||
{
|
||||
dev_t dev;
|
||||
|
||||
if( ! uk_devsw_installed ) {
|
||||
dev = makedev(CDEV_MAJOR, 0);
|
||||
cdevsw_add(&dev,&uk_cdevsw, NULL);
|
||||
uk_devsw_installed = 1;
|
||||
}
|
||||
}
|
||||
|
||||
SYSINIT(ukdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,uk_drvinit,NULL)
|
||||
|
||||
|
1811
sys/scsi/worm.c
1811
sys/scsi/worm.c
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user