freebsd-skq/sys/scsi/sctarg.c
Peter Dufault 81e01d44ce Added "scsi target" device that can act as a target for scsi transfers
from an initiator
Added Julian's support for residuals.
Added Julian's fixes to the tape driver
Made compile cleanly with -Wall
Reduce boot up output
1995-04-14 15:10:44 +00:00

272 lines
7.1 KiB
C

/*
* sctarg: 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: sctarg.c,v 1.1 1995/03/04 20:50:46 dufault Exp $
*/
/*
* XXX dufault@hda.com: We need the "kern devconf" stuff, but I'm not
* going to add it until it is done in a simple way that provides
* base behavior in scsi_driver.c
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/buf.h>
#include <sys/proc.h>
#include <scsi/scsi_all.h>
#include <scsi/scsiconf.h>
#define OPEN 0x01
struct scsi_data {
struct buf *buf_queue; /* the queue of pending IO operations */
int flags; /* Already open */
};
errval sctarg_open(dev_t dev, int flags, int fmt, struct proc *p,
struct scsi_link *sc_link);
void sctargstart(u_int32 unit);
errval sctarg_close(dev_t dev, int flag, int fmt, struct proc *p,
struct scsi_link *sc_link);
void sctarg_strategy(struct buf *bp, struct scsi_link *sc_link);
SCSI_DEVICE_ENTRIES(sctarg)
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,
0,
"Processor Target",
sctargopen,
sizeof(struct scsi_data),
T_TARGET,
0,
0,
sctarg_open,
0,
0,
sctarg_strategy,
};
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;
}
errval sctarg_close(dev_t dev, int flags, int fmt, struct proc *p,
struct scsi_link *sc_link)
{
int ret = 0;
/* XXX: You can have more than one target device on a single
* host adapter. We need a reference count.
*/
ret = scsi_target_mode(sc_link, 0);
sc_link->sd->flags &= ~OPEN;
return ret;
}
/*
* 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
*/
void
sctargstart(unit)
u_int32 unit;
{
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 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;
}
if ((bp = sctarg->buf_queue) == NULL) {
return; /* no work to bother with */
}
sctarg->buf_queue = bp->b_actf;
/*
* 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_un.b_addr,
bp->b_bcount,
0,
100000,
bp,
flags | SCSI_NOSLEEP) == SUCCESSFULLY_QUEUED) {
} else {
printf("sctarg%ld: oops not queued\n", unit);
bp->b_flags |= B_ERROR;
bp->b_error = EIO;
biodone(bp);
}
} /* go back and see if we can cram more work in.. */
}
void
sctarg_strategy(struct buf *bp, struct scsi_link *sc_link)
{
struct buf **dp;
unsigned char unit;
u_int32 opri;
struct scsi_data *sctarg;
unit = STUNIT((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.
*/
dp = &(sctarg->buf_queue);
while (*dp) {
dp = &((*dp)->b_actf);
}
*dp = bp;
bp->b_actf = NULL;
/*
* Tell the device to get going on the transfer if it's
* not doing anything, otherwise just wait for completion
* (All a bit silly if we're only allowing 1 open but..)
*/
sctargstart(unit);
splx(opri);
return;
}