Major update; basically, improve performance somewhat and play nicer with

Intel and AMI IOPs. There still exists one nasty problem with Intel adapters
when under load, which I'm working on.
This commit is contained in:
ad 2001-03-20 13:01:48 +00:00
parent adbed15428
commit ebf5110997
8 changed files with 1585 additions and 1181 deletions

View File

@ -1,7 +1,7 @@
# $NetBSD: Makefile,v 1.2 2000/11/09 12:34:05 ad Exp $
# $NetBSD: Makefile,v 1.3 2001/03/20 13:01:48 ad Exp $
INCSDIR= /usr/include/dev/i2o
INCS= i2o.h iopvar.h
INCS= i2o.h iopio.h
.include <bsd.kinc.mk>

View File

@ -1,10 +1,6 @@
$NetBSD: TODO,v 1.2 2000/12/03 13:17:03 ad Exp $
$NetBSD: TODO,v 1.3 2001/03/20 13:01:48 ad Exp $
o Release MFA if CANT_PROCESS is set?
o Handle device control & private space issues.
o Rid us of kvtop()
o Overhaul message allocation and queueing
o Immediate transfer via the SGL for small payloads, if useful
o Handle device control & private space issues
o Resolve portability issues
o ld_iop: handle removable and non-direct access devices
o iopsp: use maxdevices from parameter group or default
o Driver for LAN class devices
o Driver for LAN class device (some code exists already)

View File

@ -1,7 +1,7 @@
/* $NetBSD: i2o.h,v 1.2 2000/12/03 13:17:03 ad Exp $ */
/* $NetBSD: i2o.h,v 1.3 2001/03/20 13:01:48 ad Exp $ */
/*-
* Copyright (c) 2000 The NetBSD Foundation, Inc.
* Copyright (c) 2000, 2001 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
@ -37,8 +37,8 @@
*/
/*
* I2O structures and constants, as presented by the I2O specification
* revision 1.5 (obtainable from http://www.i2osig.org/). Currently, only
* Structures and constants, as presented by the I2O specification revision
* 1.5 (obtainable from http://www.intelligent-io.com/). Currently, only
* what's useful to us is defined in this file.
*/
@ -51,6 +51,7 @@
/* Organisation IDs */
#define I2O_ORG_DPT 0x001b
#define I2O_ORG_INTEL 0x0028
#define I2O_ORG_AMI 0x1000
/* Macros to assist in building message headers */
@ -96,6 +97,35 @@
#define I2O_STATUS_TRANSACTION_ERROR 0x0b
#define I2O_STATUS_PROGRESS_REPORT 0x80
/* Detailed status codes */
#define I2O_DSC_SUCCESS 0x00
#define I2O_DSC_BAD_KEY 0x02
#define I2O_DSC_TCL_ERROR 0x03
#define I2O_DSC_REPLY_BUFFER_FULL 0x04
#define I2O_DSC_NO_SUCH_PAGE 0x05
#define I2O_DSC_INSUFFICIENT_RESOURCE_SOFT 0x06
#define I2O_DSC_INSUFFICIENT_RESOURCE_HARD 0x07
#define I2O_DSC_CHAIN_BUFFER_TOO_LARGE 0x09
#define I2O_DSC_UNSUPPORTED_FUNCTION 0x0a
#define I2O_DSC_DEVICE_LOCKED 0x0b
#define I2O_DSC_DEVICE_RESET 0x0c
#define I2O_DSC_INAPPROPRIATE_FUNCTION 0x0d
#define I2O_DSC_INVALID_INITIATOR_ADDRESS 0x0e
#define I2O_DSC_INVALID_MESSAGE_FLAGS 0x0f
#define I2O_DSC_INVALID_OFFSET 0x10
#define I2O_DSC_INVALID_PARAMETER 0x11
#define I2O_DSC_INVALID_REQUEST 0x12
#define I2O_DSC_INVALID_TARGET_ADDRESS 0x13
#define I2O_DSC_MESSAGE_TOO_LARGE 0x14
#define I2O_DSC_MESSAGE_TOO_SMALL 0x15
#define I2O_DSC_MISSING_PARAMETER 0x16
#define I2O_DSC_TIMEOUT 0x17
#define I2O_DSC_UNKNOWN_ERROR 0x18
#define I2O_DSC_UNKNOWN_FUNCTION 0x19
#define I2O_DSC_UNSUPPORTED_VERSION 0x1a
#define I2O_DSC_DEVICE_BUSY 0x1b
#define I2O_DSC_DEVICE_NOT_AVAILABLE 0x1c
/* Message versions */
#define I2O_VERSION_10 0x00
#define I2O_VERSION_11 0x01
@ -109,6 +139,7 @@
/* SGL flags. This list covers only a fraction of the possibilities. */
#define I2O_SGL_IGNORE 0x00000000
#define I2O_SGL_SIMPLE 0x10000000
#define I2O_SGL_PAGE_LIST 0x20000000
#define I2O_SGL_BC_32BIT 0x01000000
#define I2O_SGL_BC_64BIT 0x02000000
@ -156,7 +187,7 @@ struct i2o_msg {
#define I2O_MSGFLAGS_STATICMF 0x0100
#define I2O_MSGFLAGS_64BIT 0x0200
#define I2O_MSGFLAGS_MULTI 0x1000
#define I2O_MSGFLAGS_CANT_PROCESS 0x2000
#define I2O_MSGFLAGS_FAIL 0x2000
#define I2O_MSGFLAGS_LAST_REPLY 0x4000
#define I2O_MSGFLAGS_REPLY 0x8000
@ -177,6 +208,26 @@ struct i2o_reply {
} __attribute__ ((__packed__));
/*
* Fault notification reply, returned when a message frame can not be
* processed (i.e I2O_MSGFLAGS_FAIL is set in the reply).
*/
struct i2o_fault_notify {
u_int32_t msgflags;
u_int32_t msgfunc;
u_int32_t msgictx;
u_int32_t msgtctx; /* Not valid! */
u_int8_t lowestver;
u_int8_t highestver;
u_int8_t severity;
u_int8_t failurecode;
u_int16_t failingiop; /* Bits 0-12 only */
u_int16_t failinghostunit;
u_int32_t agelimit;
u_int32_t lowmfa;
u_int32_t highmfa;
};
/*
* Hardware resource table. Not documented here.
*/
@ -604,6 +655,11 @@ struct i2o_util_event_register_reply {
#define I2O_EVENT_EXEC_MODIFIED_LCT 0x00000200
#define I2O_EVENT_EXEC_DDM_AVAILIBILITY 0x00000400
/* LAN class events. */
#define I2O_EVENT_LAN_LINK_DOWN 0x00000001
#define I2O_EVENT_LAN_LINK_UP 0x00000002
#define I2O_EVENT_LAN_MEDIA_CHANGE 0x00000004
/*
* ================= Utility parameter groups =================
*/
@ -723,7 +779,7 @@ struct i2o_rbs_reply {
u_int32_t msgictx;
u_int32_t msgtctx;
u_int16_t detail;
u_int8_t reserved;
u_int8_t retrycount;
u_int8_t reqstatus;
u_int32_t transfercount;
u_int64_t offset; /* Error replies only */
@ -846,7 +902,8 @@ struct i2o_scsi_reply {
u_int32_t msgfunc;
u_int32_t msgictx;
u_int32_t msgtctx;
u_int16_t detail;
u_int8_t scsistatus;
u_int8_t hbastatus;
u_int8_t reserved;
u_int8_t reqstatus;
u_int32_t datalen;
@ -911,4 +968,153 @@ struct i2o_param_scsi_device_info {
u_int64_t negsyncrate;
} __attribute__ ((__packed__));
/*
* ================= LAN class messages =================
*/
#define I2O_LAN_PACKET_SEND 0x3b
struct i2o_lan_packet_send {
u_int32_t msgflags;
u_int32_t msgfunc;
u_int32_t msgictx;
u_int32_t tcw;
};
#define I2O_LAN_TCW_ACCESS_PRI_MASK 0x00000007
#define I2O_LAN_TCW_SUPPRESS_CRC 0x00000008
#define I2O_LAN_TCW_SUPPRESS_LOOPBACK 0x00000010
#define I2O_LAN_TCW_CKSUM_NETWORK 0x00000020
#define I2O_LAN_TCW_CKSUM_TRANSPORT 0x00000040
#define I2O_LAN_TCW_REPLY_BATCH 0x00000000
#define I2O_LAN_TCW_REPLY_IMMEDIATELY 0x40000000
#define I2O_LAN_TCW_REPLY_UNSUCCESSFUL 0x80000000
#define I2O_LAN_TCW_REPLY_NONE 0xc0000000
#define I2O_LAN_SDU_SEND 0x3d
struct i2o_lan_sdu_send {
u_int32_t msgflags;
u_int32_t msgfunc;
u_int32_t msgictx;
u_int32_t tcw; /* As per PACKET_SEND. */
};
#define I2O_LAN_RECIEVE_POST 0x3e
struct i2o_lan_recieve_post {
u_int32_t msgflags;
u_int32_t msgfunc;
u_int32_t msgictx;
u_int32_t bktcnt;
};
#define I2O_LAN_RESET 0x35
struct i2o_lan_reset {
u_int32_t msgflags;
u_int32_t msgfunc;
u_int32_t msgictx;
u_int16_t reserved;
u_int16_t resrcflags;
};
#define I2O_LAN_RESRC_RETURN_BUCKETS 0x0001
#define I2O_LAN_RESRC_RETURN_XMITS 0x0002
#define I2O_LAN_SUSPEND 0x37
struct i2o_lan_suspend {
u_int32_t msgflags;
u_int32_t msgfunc;
u_int32_t msgictx;
u_int16_t reserved;
u_int16_t resrcflags; /* As per RESET. */
};
#define I2O_LAN_DSC_SUCCESS 0x00
#define I2O_LAN_DSC_DEVICE_FAILURE 0x01
#define I2O_LAN_DSC_DESTINATION_NOT_FOUND 0x02
#define I2O_LAN_DSC_TRANSMIT_ERROR 0x03
#define I2O_LAN_DSC_TRANSMIT_ABORTED 0x04
#define I2O_LAN_DSC_RECEIVE_ERROR 0x05
#define I2O_LAN_DSC_RECEIVE_ABORTED 0x06
#define I2O_LAN_DSC_DMA_ERROR 0x07
#define I2O_LAN_DSC_BAD_PACKET_DETECTED 0x08
#define I2O_LAN_DSC_OUT_OF_MEMORY 0x09
#define I2O_LAN_DSC_BUCKET_OVERRUN 0x0a
#define I2O_LAN_DSC_IOP_INTERNAL_ERROR 0x0b
#define I2O_LAN_DSC_CANCELED 0x0c
#define I2O_LAN_DSC_INVALID_TRANSACTION_CONTEXT 0x0d
#define I2O_LAN_DSC_DEST_ADDRESS_DETECTED 0x0e
#define I2O_LAN_DSC_DEST_ADDRESS_OMITTED 0x0f
#define I2O_LAN_DSC_PARTIAL_PACKET_RETURNED 0x10
#define I2O_LAN_DSC_TEMP_SUSPENDED_STATE 0x11
/*
* ================= LAN class parameter groups =================
*/
#define I2O_PARAM_LAN_DEVICE_INFO 0x0000
struct i2o_param_lan_device_info {
u_int16_t lantype;
u_int16_t flags;
u_int8_t addrfmt;
u_int8_t reserved1;
u_int16_t reserved2;
u_int32_t minpktsize;
u_int32_t maxpktsize;
u_int8_t hwaddr[8];
u_int64_t maxtxbps;
u_int64_t maxrxbps;
};
#define I2O_LAN_TYPE_ETHERNET 0x0030
#define I2O_LAN_TYPE_100BASEVG 0x0040
#define I2O_LAN_TYPE_TOKEN_RING 0x0050
#define I2O_LAN_TYPE_FDDI 0x0060
#define I2O_LAN_TYPE_FIBRECHANNEL 0x0070
#define I2O_PARAM_LAN_MAC_ADDRESS 0x0001
struct i2o_param_lan_mac_address {
u_int8_t activeaddr[8];
u_int8_t localaddr[8];
u_int8_t addrmask[8];
u_int8_t filtermask[4];
u_int8_t hwfiltermask[4];
u_int32_t maxmcastaddr;
u_int32_t maxfilterperfect;
u_int32_t maxfilterimperfect;
};
#define I2O_PARAM_LAN_MCAST_MAC_ADDRESS 0x0002
/*
* This one's a table, not a scalar.
*/
#define I2O_PARAM_LAN_BATCH_CONTROL 0x0003
struct i2o_param_lan_batch_control {
u_int32_t batchflags;
u_int32_t risingloaddly;
u_int32_t risingloadthresh;
u_int32_t fallingloaddly;
u_int32_t fallingloadthresh;
u_int32_t maxbatchcount;
u_int32_t maxbatchdelay;
u_int32_t transcompdelay;
};
#define I2O_PARAM_LAN_OPERATION 0x0004
struct i2o_param_lan_operation {
u_int32_t pktprepad;
u_int32_t userflags;
u_int32_t pktorphanlimit;
};
#define I2O_PARAM_LAN_MEDIA_OPERATION 0x0005
struct i2o_param_lan_media_operation {
u_int32_t connectortype;
u_int32_t connectiontype;
u_int32_t curtxbps;
u_int32_t currxbps;
u_int8_t fullduplex;
u_int8_t linkstatus;
u_int8_t badpkthandling;
};
#endif /* !defined _I2O_I2O_H_ */

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,7 @@
/* $NetBSD: iopsp.c,v 1.4 2001/02/07 17:05:46 ad Exp $ */
/* $NetBSD: iopsp.c,v 1.5 2001/03/20 13:01:49 ad Exp $ */
/*-
* Copyright (c) 2000 The NetBSD Foundation, Inc.
* Copyright (c) 2000, 2001 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
@ -37,8 +37,8 @@
*/
/*
* Raw SCSI/FC-AL device support for I2O. I2O presents SCSI devices
* individually; we group them by controller port.
* Raw SCSI device support for I2O. IOPs present SCSI devices individually;
* we group them by controlling port.
*/
#include "opt_i2o.h"
@ -64,10 +64,11 @@
#include <dev/scsipi/scsiconf.h>
#include <dev/i2o/i2o.h>
#include <dev/i2o/iopreg.h>
#include <dev/i2o/iopio.h>
#include <dev/i2o/iopvar.h>
#include <dev/i2o/iopspvar.h>
static void iopsp_adjqparam(struct device *, int);
static void iopsp_attach(struct device *, struct device *, void *);
static void iopsp_intr(struct device *, struct iop_msg *, void *);
static int iopsp_ioctl(struct scsipi_link *, u_long, caddr_t, int,
@ -91,7 +92,7 @@ struct cfattach iopsp_ca = {
};
/*
* Match SCSI and fibre channel ports.
* Match a supported device.
*/
static int
iopsp_match(struct device *parent, struct cfdata *match, void *aux)
@ -108,7 +109,7 @@ iopsp_match(struct device *parent, struct cfdata *match, void *aux)
if (ia->ia_class != I2O_CLASS_BUS_ADAPTER_PORT)
return (0);
if (iop_param_op((struct iop_softc *)parent, ia->ia_tid, 0,
if (iop_param_op((struct iop_softc *)parent, ia->ia_tid, NULL, 0,
I2O_PARAM_HBA_CTLR_INFO, &param, sizeof(param)) != 0)
return (0);
@ -130,13 +131,11 @@ iopsp_attach(struct device *parent, struct device *self, void *aux)
struct i2o_param_op_results pr;
struct i2o_param_read_results prr;
union {
struct i2o_param_device_identity di;
struct i2o_param_hba_ctlr_info ci;
struct i2o_param_hba_scsi_ctlr_info sci;
struct i2o_param_hba_scsi_port_info spi;
} p;
} __attribute__ ((__packed__)) param;
char ident[64];
int fcal, rv;
#ifdef I2OVERBOSE
int size;
@ -145,7 +144,6 @@ iopsp_attach(struct device *parent, struct device *self, void *aux)
ia = (struct iop_attach_args *)aux;
sc = (struct iopsp_softc *)self;
iop = (struct iop_softc *)parent;
sc->sc_tid = ia->ia_tid;
/* Register us as an initiator. */
sc->sc_ii.ii_dv = self;
@ -153,14 +151,11 @@ iopsp_attach(struct device *parent, struct device *self, void *aux)
sc->sc_ii.ii_flags = 0;
sc->sc_ii.ii_tid = ia->ia_tid;
sc->sc_ii.ii_reconfig = iopsp_reconfig;
if (iop_initiator_register(iop, &sc->sc_ii) != 0) {
printf("%s: unable to register as an initiator",
sc->sc_dv.dv_xname);
return;
}
sc->sc_ii.ii_adjqparam = iopsp_adjqparam;
iop_initiator_register(iop, &sc->sc_ii);
rv = iop_param_op(iop, ia->ia_tid, 0, I2O_PARAM_HBA_CTLR_INFO, &param,
sizeof(param));
rv = iop_param_op(iop, ia->ia_tid, NULL, 0, I2O_PARAM_HBA_CTLR_INFO,
&param, sizeof(param));
if (rv != 0) {
printf("%s: unable to get parameters (0x%04x; %d)\n",
sc->sc_dv.dv_xname, I2O_PARAM_HBA_CTLR_INFO, rv);
@ -173,23 +168,12 @@ iopsp_attach(struct device *parent, struct device *self, void *aux)
* Say what the device is. If we can find out what the controling
* device is, say what that is too.
*/
printf(": %s SCSI port", fcal ? "FC-AL" : "SE/LVD");
if (iop_param_op(iop, ia->ia_tid, 0, I2O_PARAM_DEVICE_IDENTITY, &param,
sizeof(param)) == 0) {
iop_strvis(iop, param.p.di.vendorinfo,
sizeof(param.p.di.vendorinfo), ident, sizeof(ident));
printf(" <%s, ", ident);
iop_strvis(iop, param.p.di.productinfo,
sizeof(param.p.di.productinfo), ident, sizeof(ident));
printf("%s, ", ident);
iop_strvis(iop, param.p.di.revlevel,
sizeof(param.p.di.revlevel), ident, sizeof(ident));
printf("%s> ", ident);
}
printf(": SCSI port");
iop_print_ident(iop, ia->ia_tid);
printf("\n");
rv = iop_param_op(iop, ia->ia_tid, 0, I2O_PARAM_HBA_SCSI_CTLR_INFO,
&param, sizeof(param));
rv = iop_param_op(iop, ia->ia_tid, NULL, 0,
I2O_PARAM_HBA_SCSI_CTLR_INFO, &param, sizeof(param));
if (rv != 0) {
printf("%s: unable to get parameters (0x%04x; %d)\n",
sc->sc_dv.dv_xname, I2O_PARAM_HBA_SCSI_CTLR_INFO, rv);
@ -217,7 +201,7 @@ iopsp_attach(struct device *parent, struct device *self, void *aux)
sc_link->scsipi_scsi.max_target =
fcal ? IOPSP_MAX_FCAL_TARGET : param.p.sci.maxdatawidth - 1;
sc_link->scsipi_scsi.max_lun = IOPSP_MAX_LUN;
sc_link->openings = iop->sc_maxqueuecnt / 4; /* XXX */
sc_link->openings = 1;
#ifdef I2OVERBOSE
/*
@ -232,13 +216,13 @@ iopsp_attach(struct device *parent, struct device *self, void *aux)
/* Build the two maps, and attach to scsipi. */
if (iopsp_reconfig(self) != 0) {
printf("%s: bus scan failed\n", sc->sc_dv.dv_xname);
printf("%s: configure failed\n", sc->sc_dv.dv_xname);
goto bad;
}
config_found(self, sc_link, scsiprint);
return;
bad:
bad:
iop_initiator_unregister(iop, &sc->sc_ii);
}
@ -258,7 +242,7 @@ iopsp_reconfig(struct device *dv)
struct i2o_param_read_results prr;
struct i2o_param_scsi_device_info sdi;
} __attribute__ ((__packed__)) param;
int tid, nent, i, targ, lun, size, s, rv;
u_int tid, nent, i, targ, lun, size, s, rv, bptid;
u_short *tidmap;
#ifdef I2OVERBOSE
struct iopsp_target *it;
@ -270,7 +254,7 @@ iopsp_reconfig(struct device *dv)
sc_link = &sc->sc_link;
/* Anything to do? */
if (iop->sc_lct->changeindicator == sc->sc_chgindicator)
if (iop->sc_chgind == sc->sc_chgind)
return (0);
/*
@ -289,20 +273,28 @@ iopsp_reconfig(struct device *dv)
sc->sc_targetmap[i].it_flags &= ~IT_PRESENT;
#endif
/*
* A quick hack to handle Intel's stacked bus port arrangement.
*/
bptid = sc->sc_ii.ii_tid;
nent = iop->sc_nlctent;
for (le = iop->sc_lct->entry; nent != 0; nent--, le++)
if ((le16toh(le->classid) & 4095) ==
I2O_CLASS_BUS_ADAPTER_PORT &&
(le32toh(le->usertid) & 4095) == bptid) {
bptid = le32toh(le->localtid) & 4095;
break;
}
nent = iop->sc_nlctent;
for (i = 0, le = iop->sc_lct->entry; i < nent; i++, le++) {
switch (le16toh(le->classid) & 4095) {
case I2O_CLASS_SCSI_PERIPHERAL:
break;
default:
if ((le16toh(le->classid) & 4095) != I2O_CLASS_SCSI_PERIPHERAL)
continue;
}
if (((le32toh(le->usertid) >> 12) & 4095) != sc->sc_tid)
if (((le32toh(le->usertid) >> 12) & 4095) != bptid)
continue;
tid = le32toh(le->localtid) & 4095;
rv = iop_param_op(iop, tid, 0, I2O_PARAM_SCSI_DEVICE_INFO,
rv = iop_param_op(iop, tid, NULL, 0, I2O_PARAM_SCSI_DEVICE_INFO,
&param, sizeof(param));
if (rv != 0) {
printf("%s: unable to get parameters (0x%04x; %d)\n",
@ -312,22 +304,14 @@ iopsp_reconfig(struct device *dv)
}
targ = le32toh(param.sdi.identifier);
lun = param.sdi.luninfo[1];
/* If the device is in use by a DDM, ignore it. */
if ((le32toh(le->usertid) & 4095) != 4095) {
#ifdef I2OVERBOSE
if (sc->sc_tidmap == NULL ||
IOPSP_TIDMAP(sc->sc_tidmap, targ, lun) !=
IOPSP_TID_INUSE)
printf("%s: target %d,%d (tid %d): in use by"
" tid %d\n", sc->sc_dv.dv_xname,
targ, lun, tid,
le32toh(le->usertid) & 4095);
#endif
IOPSP_TIDMAP(tidmap, targ, lun) = IOPSP_TID_INUSE;
#if defined(DIAGNOSTIC) || defined(I2ODEBUG)
if (targ > sc_link->scsipi_scsi.max_target ||
lun > sc_link->scsipi_scsi.max_lun) {
printf("%s: target %d,%d (tid %d): bad target/LUN\n",
sc->sc_dv.dv_xname, targ, lun, tid);
continue;
}
IOPSP_TIDMAP(tidmap, targ, lun) = (u_short)tid;
#endif
#ifdef I2OVERBOSE
/*
@ -354,6 +338,21 @@ iopsp_reconfig(struct device *dv)
printf("synchronous at %dMHz, offset 0x%x\n",
it->it_syncrate, it->it_offset);
#endif
/* Ignore the device if it's in use by somebody else. */
if ((le32toh(le->usertid) & 4095) != I2O_TID_NONE) {
#ifdef I2OVERBOSE
if (sc->sc_tidmap == NULL ||
IOPSP_TIDMAP(sc->sc_tidmap, targ, lun) !=
IOPSP_TID_INUSE)
printf("%s: target %d,%d (tid %d): in use by"
" tid %d\n", sc->sc_dv.dv_xname,
targ, lun, tid,
le32toh(le->usertid) & 4095);
#endif
IOPSP_TIDMAP(tidmap, targ, lun) = IOPSP_TID_INUSE;
} else
IOPSP_TIDMAP(tidmap, targ, lun) = (u_short)tid;
}
#ifdef I2OVERBOSE
@ -368,7 +367,7 @@ iopsp_reconfig(struct device *dv)
free(sc->sc_tidmap, M_DEVBUF);
sc->sc_tidmap = tidmap;
splx(s);
sc->sc_chgindicator = iop->sc_lct->changeindicator;
sc->sc_chgind = iop->sc_chgind;
return (0);
}
@ -392,12 +391,12 @@ iopsp_rescan(struct iopsp_softc *sc)
{
struct iop_softc *iop;
struct iop_msg *im;
struct i2o_hba_bus_scan *mb;
struct i2o_hba_bus_scan mf;
int rv;
iop = (struct iop_softc *)sc->sc_dv.dv_parent;
rv = lockmgr(&iop->sc_conflock, LK_EXCLUSIVE | LK_RECURSEFAIL, NULL);
rv = lockmgr(&iop->sc_conflock, LK_EXCLUSIVE, NULL);
if (rv != 0) {
#ifdef I2ODEBUG
printf("iopsp_rescan: unable to acquire lock\n");
@ -405,29 +404,25 @@ iopsp_rescan(struct iopsp_softc *sc)
return (rv);
}
/* XXX If it's boot time, the bus will already have been scanned. */
if (curproc != &proc0) {
if ((rv = iop_msg_alloc(iop, &sc->sc_ii, &im, IM_NOINTR)) != 0)
goto done;
im = iop_msg_alloc(iop, &sc->sc_ii, IM_WAIT);
mb = (struct i2o_hba_bus_scan *)im->im_msg;
mb->msgflags = I2O_MSGFLAGS(i2o_hba_bus_scan);
mb->msgfunc = I2O_MSGFUNC(sc->sc_tid, I2O_HBA_BUS_SCAN);
mb->msgictx = sc->sc_ii.ii_ictx;
mb->msgtctx = im->im_tctx;
mf.msgflags = I2O_MSGFLAGS(i2o_hba_bus_scan);
mf.msgfunc = I2O_MSGFUNC(sc->sc_ii.ii_tid, I2O_HBA_BUS_SCAN);
mf.msgictx = sc->sc_ii.ii_ictx;
mf.msgtctx = im->im_tctx;
rv = iop_msg_enqueue(iop, im, 5*60*1000);
iop_msg_free(iop, &sc->sc_ii, im);
if (rv != 0)
goto done;
rv = iop_msg_post(iop, im, &mf, 5*60*1000);
iop_msg_free(iop, im);
if (rv != 0)
printf("%s: bus rescan failed (error %d)\n",
sc->sc_dv.dv_xname, rv);
if ((rv = iop_lct_get(iop)) != 0)
goto done;
}
if ((rv = iop_lct_get(iop)) != 0)
goto done;
/* Rebuild the target/LUN -> TID map, release lock, and return. */
rv = iopsp_reconfig(&sc->sc_dv);
done:
done:
lockmgr(&iop->sc_conflock, LK_RELEASE, NULL);
return (rv);
}
@ -442,8 +437,9 @@ iopsp_scsi_cmd(struct scsipi_xfer *xs)
struct iopsp_softc *sc;
struct iop_msg *im;
struct iop_softc *iop;
struct i2o_scsi_scb_exec *mb;
int error, flags, tid;
struct i2o_scsi_scb_exec *mf;
int error, flags, tid, imf;
u_int32_t mb[IOP_MAX_MSG_SIZE / sizeof(u_int32_t)];
sc_link = xs->sc_link;
flags = xs->xs_control;
@ -472,63 +468,62 @@ iopsp_scsi_cmd(struct scsipi_xfer *xs)
}
#if defined(I2ODEBUG) || defined(SCSIDEBUG)
if (xs->cmdlen > 16)
if (xs->cmdlen > sizeof(mf->cdb))
panic("%s: CDB too large\n", sc->sc_dv.dv_xname);
#endif
if (iop_msg_alloc(iop, &sc->sc_ii, &im,
(flags & (XS_CTL_POLL | XS_CTL_NOSLEEP)) != 0 ? IM_NOWAIT : 0)) {
xs->error = XS_DRIVER_STUFFUP;
return (TRY_AGAIN_LATER);
}
imf = (flags & (XS_CTL_POLL | XS_CTL_NOSLEEP)) != 0 ? IM_POLL : 0;
im = iop_msg_alloc(iop, &sc->sc_ii, imf);
im->im_dvcontext = xs;
mb = (struct i2o_scsi_scb_exec *)im->im_msg;
mb->msgflags = I2O_MSGFLAGS(i2o_scsi_scb_exec);
mb->msgfunc = I2O_MSGFUNC(tid, I2O_SCSI_SCB_EXEC);
mb->msgictx = sc->sc_ii.ii_ictx;
mb->msgtctx = im->im_tctx;
mb->flags = xs->cmdlen | I2O_SCB_FLAG_ENABLE_DISCONNECT |
mf = (struct i2o_scsi_scb_exec *)mb;
mf->msgflags = I2O_MSGFLAGS(i2o_scsi_scb_exec);
mf->msgfunc = I2O_MSGFUNC(tid, I2O_SCSI_SCB_EXEC);
mf->msgictx = sc->sc_ii.ii_ictx;
mf->msgtctx = im->im_tctx;
mf->flags = xs->cmdlen | I2O_SCB_FLAG_ENABLE_DISCONNECT |
I2O_SCB_FLAG_SENSE_DATA_IN_MESSAGE;
memcpy(mb->cdb, xs->cmd, xs->cmdlen);
mb->datalen = xs->datalen;
mf->datalen = xs->datalen;
memcpy(mf->cdb, xs->cmd, xs->cmdlen);
if ((xs->sc_link->quirks & SDEV_NOTAG) == 0 &&
(xs->xs_control & XS_CTL_POLL) != 0) {
if (xs->bp != NULL && (xs->bp->b_flags & B_ASYNC) != 0)
mb->flags |= I2O_SCB_FLAG_ORDERED_QUEUE_TAG;
mf->flags |= I2O_SCB_FLAG_ORDERED_QUEUE_TAG;
else
mb->flags |= I2O_SCB_FLAG_SIMPLE_QUEUE_TAG;
mf->flags |= I2O_SCB_FLAG_SIMPLE_QUEUE_TAG;
}
if (xs->datalen != 0) {
error = iop_msg_map(iop, im, xs->data, xs->datalen,
(flags & XS_CTL_DATA_OUT) == 0);
error = iop_msg_map_bio(iop, im, mb, xs->data, xs->datalen,
(flags & XS_CTL_DATA_OUT) != 0);
if (error) {
#ifdef I2ODEBUG
printf("%s: error %d mapping xfer\n",
sc->sc_dv.dv_xname, error);
#endif
xs->error = XS_DRIVER_STUFFUP;
iop_msg_free(iop, &sc->sc_ii, im);
iop_msg_free(iop, im);
return (COMPLETE);
}
if ((flags & XS_CTL_DATA_IN) == 0)
mb->flags |= I2O_SCB_FLAG_XFER_TO_DEVICE;
mf->flags |= I2O_SCB_FLAG_XFER_TO_DEVICE;
else
mb->flags |= I2O_SCB_FLAG_XFER_FROM_DEVICE;
mf->flags |= I2O_SCB_FLAG_XFER_FROM_DEVICE;
}
/*
* If the command is allowed to execute asynchronously, enqueue it
* with the IOP.
*/
if ((flags & XS_CTL_POLL) == 0) {
iop_msg_enqueue(iop, im, 0);
if (iop_msg_post(iop, im, mb, 0)) {
if (xs->datalen != 0)
iop_msg_unmap(iop, im);
iop_msg_free(iop, im);
xs->error = XS_DRIVER_STUFFUP;
return (COMPLETE);
}
return (SUCCESSFULLY_QUEUED);
}
if (iop_msg_send(iop, im, xs->timeout)) {
if (iop_msg_post(iop, im, mb, xs->timeout)) {
scsi_print_addr(xs->sc_link);
printf("timeout; aborting command\n");
if (iopsp_scsi_abort(sc, tid, im)) {
@ -537,6 +532,7 @@ iopsp_scsi_cmd(struct scsipi_xfer *xs)
}
xs->error = XS_DRIVER_STUFFUP;
}
return (COMPLETE);
}
@ -547,25 +543,23 @@ static int
iopsp_scsi_abort(struct iopsp_softc *sc, int atid, struct iop_msg *aim)
{
struct iop_msg *im;
struct i2o_scsi_scb_abort *mb;
struct i2o_scsi_scb_abort mf;
struct iop_softc *iop;
int rv;
int rv, s;
iop = (struct iop_softc *)sc->sc_dv.dv_parent;
im = iop_msg_alloc(iop, &sc->sc_ii, IM_POLL);
rv = iop_msg_alloc(iop, &sc->sc_ii, &im, IM_NOWAIT | IM_NOINTR);
if (rv != 0)
return (rv);
mf.msgflags = I2O_MSGFLAGS(i2o_scsi_scb_abort);
mf.msgfunc = I2O_MSGFUNC(atid, I2O_SCSI_SCB_ABORT);
mf.msgictx = sc->sc_ii.ii_ictx;
mf.msgtctx = im->im_tctx;
mf.tctxabort = aim->im_tctx;
mb = (struct i2o_scsi_scb_abort *)im->im_msg;
mb->msgflags = I2O_MSGFLAGS(i2o_scsi_scb_abort);
mb->msgfunc = I2O_MSGFUNC(atid, I2O_SCSI_SCB_ABORT);
mb->msgictx = sc->sc_ii.ii_ictx;
mb->msgtctx = im->im_tctx;
mb->tctxabort = aim->im_tctx;
rv = iop_msg_send(iop, im, 1000);
iop_msg_free(iop, &sc->sc_ii, im);
s = splbio();
rv = iop_msg_post(iop, im, &mf, 30000);
splx(s);
iop_msg_free(iop, im);
return (rv);
}
@ -579,9 +573,8 @@ iopsp_intr(struct device *dv, struct iop_msg *im, void *reply)
struct scsipi_xfer *xs;
struct iopsp_softc *sc;
struct i2o_scsi_reply *rb;
struct iop_softc *iop;
u_int hba_status, scsi_status, detail;
int sl;
struct iop_softc *iop;
u_int sl;
sc = (struct iopsp_softc *)dv;
xs = (struct scsipi_xfer *)im->im_dvcontext;
@ -589,14 +582,14 @@ iopsp_intr(struct device *dv, struct iop_msg *im, void *reply)
SC_DEBUG(xs->sc_link, SDEV_DB2, ("iopsp_intr\n"));
if (xs->error == XS_NOERROR) {
if ((rb->msgflags & I2O_MSGFLAGS_FAIL) != 0) {
xs->error = XS_DRIVER_STUFFUP;
xs->resid = xs->datalen;
} else {
rb = reply;
detail = le16toh(rb->detail);
hba_status = (detail >> 8) & 0xff;
scsi_status = detail & 0xff;
if (hba_status != I2O_SCSI_DSC_SUCCESS) {
switch (hba_status) {
if (rb->hbastatus != I2O_SCSI_DSC_SUCCESS) {
switch (rb->hbastatus) {
case I2O_SCSI_DSC_ADAPTER_BUSY:
case I2O_SCSI_DSC_SCSI_BUS_RESET:
case I2O_SCSI_DSC_BUS_BUSY:
@ -615,20 +608,15 @@ iopsp_intr(struct device *dv, struct iop_msg *im, void *reply)
xs->error = XS_DRIVER_STUFFUP;
break;
}
#ifdef I2ODEBUG
printf("%s: HBA status 0x%02x\n", sc->sc_dv.dv_xname,
hba_status);
#endif
} else if (scsi_status != SCSI_OK) {
switch (scsi_status) {
rb->hbastatus);
} else if (rb->scsistatus != SCSI_OK) {
switch (rb->scsistatus) {
case SCSI_CHECK:
xs->error = XS_SENSE;
sl = le32toh(rb->senselen);
if (xs->req_sense_length != 0 &&
xs->req_sense_length < sl)
sl = xs->req_sense_length;
if (sl > sizeof(xs->sense.scsi_sense))
sl = le32toh(rb->senselen);
sl = sizeof(xs->sense.scsi_sense);
memcpy(&xs->sense.scsi_sense, rb->sense, sl);
break;
case SCSI_BUSY:
@ -641,13 +629,14 @@ iopsp_intr(struct device *dv, struct iop_msg *im, void *reply)
} else
xs->error = XS_NOERROR;
xs->resid = le32toh(rb->datalen) - xs->datalen;
xs->status = scsi_status;
xs->resid = xs->datalen - le32toh(rb->datalen);
xs->status = rb->scsistatus;
}
/* Free the message wrapper and pass the news to scsipi. */
iop_msg_unmap(iop, im);
iop_msg_free(iop, &sc->sc_ii, im);
if (xs->datalen != 0)
iop_msg_unmap(iop, im);
iop_msg_free(iop, im);
xs->xs_status |= XS_STS_DONE;
scsipi_done(xs);
}
@ -663,12 +652,35 @@ iopsp_ioctl(struct scsipi_link *sc_link, u_long cmd, caddr_t data, int flag,
switch (cmd) {
case SCBUSIOLLSCAN:
rv = iopsp_rescan(sc_link->adapter_softc);
/*
* If it's boot time, the bus will have been scanned and the
* maps built. Locking would stop re-configuration, but we
* want to fake success.
*/
if (p != &proc0)
rv = iopsp_rescan(sc_link->adapter_softc);
else
rv = 0;
break;
default:
rv = ENXIO;
rv = ENOTTY;
break;
}
return (rv);
}
/*
* The number of openings available to us has changed, so inform scsipi.
*/
static void
iopsp_adjqparam(struct device *dv, int mpi)
{
int s;
/* XXX */
s = splbio();
((struct iopsp_softc *)dv)->sc_link.openings = mpi;
splx(s);
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: iopspvar.h,v 1.2 2000/11/09 12:51:36 ad Exp $ */
/* $NetBSD: iopspvar.h,v 1.3 2001/03/20 13:01:49 ad Exp $ */
/*-
* Copyright (c) 2000 The NetBSD Foundation, Inc.
@ -62,9 +62,8 @@ struct iopsp_softc {
struct scsipi_adapter sc_adapter; /* scsipi adapter */
struct scsipi_link sc_link; /* Prototype link */
struct iop_initiator sc_ii; /* I2O initiator state */
u_int sc_tid; /* Bus port TID */
u_short *sc_tidmap; /* Target/LUN -> TID map */
u_int sc_chgindicator; /* Last LCT change # */
u_int sc_chgind; /* Last LCT change # */
#ifdef I2OVERBOSE
struct iopsp_target *sc_targetmap; /* Target information */
#endif

View File

@ -1,7 +1,7 @@
/* $NetBSD: iopvar.h,v 1.4 2001/01/03 21:04:01 ad Exp $ */
/* $NetBSD: iopvar.h,v 1.5 2001/03/20 13:01:49 ad Exp $ */
/*-
* Copyright (c) 2000 The NetBSD Foundation, Inc.
* Copyright (c) 2000, 2001 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
@ -39,47 +39,6 @@
#ifndef _I2O_IOPVAR_H_
#define _I2O_IOPVAR_H_
/* Per-IOP statistics; not particularly useful at the moment. */
struct iop_stat {
int is_cur_swqueue;
int is_peak_swqueue;
int is_cur_hwqueue;
int is_peak_hwqueue;
int64_t is_requests;
int64_t is_bytes;
};
/*
* XXX The following should be adjusted if and when:
*
* o MAXPHYS exceeds 64kB.
* o A new message or reply is defined in i2o.h.
*
* As it stands, these make for a message frame of 200 bytes.
*/
#define IOP_MAX_SGL_SIZE 132 /* Maximum S/G list size */
#define IOP_MAX_BASE_MSG_SIZE 68 /* Maximum base message size */
#define IOP_MAX_XFER 65536 /* Maximum transfer size */
#define IOP_MAX_MSG_XFERS 3 /* Maximum transfer count per msg */
#define IOP_MAX_SGL_ENTRIES (IOP_MAX_SGL_SIZE / 8)
#define IOP_MAX_MSG_SIZE (IOP_MAX_BASE_MSG_SIZE + IOP_MAX_SGL_SIZE)
/* Linux sez that some IOPs don't like reply frame sizes other than 128. */
#define IOP_MAX_REPLY_SIZE 128
#define IOP_MAX_HW_QUEUECNT 256
#define IOP_MAX_HW_REPLYCNT 256
struct iop_tidmap {
u_short it_tid;
u_short it_flags;
char it_dvname[sizeof(((struct device *)NULL)->dv_xname)];
};
#define IT_CONFIGURED 0x02 /* target configured */
#ifdef _KERNEL
#include "locators.h"
/*
@ -97,26 +56,25 @@ struct iop_xfer {
* Message wrapper.
*/
struct iop_msg {
SIMPLEQ_ENTRY(iop_msg) im_queue; /* Next queued message */
TAILQ_ENTRY(iop_msg) im_hash; /* Hash chain */
SLIST_ENTRY(iop_msg) im_chain; /* Next free message */
u_int im_flags; /* Control flags */
u_int im_tctx; /* Transaction context */
void *im_dvcontext; /* Un*x device context */
u_int32_t im_msg[IOP_MAX_MSG_SIZE / sizeof(u_int32_t)];
struct i2o_reply *im_rb; /* Reply buffer */
u_int im_reqstatus; /* Status from reply */
struct iop_xfer im_xfer[IOP_MAX_MSG_XFERS];
};
#define IM_SYSMASK 0x00ff
#define IM_REPLIED 0x0001 /* Message has been replied to */
#define IM_ALLOCED 0x0002 /* This message wrapper is allocated */
#define IM_SGLOFFADJ 0x0008 /* S/G list offset adjusted */
#define IM_DISCARD 0x0010 /* Discard message wrapper once sent */
#define IM_WAITING 0x0020 /* Waiting for completion */
#define IM_SGLOFFADJ 0x0004 /* S/G list offset adjusted */
#define IM_DISCARD 0x0008 /* Discard message wrapper once sent */
#define IM_FAIL 0x0010 /* Transaction error returned */
#define IM_USERMASK 0xff00
#define IM_NOWAIT 0x0100 /* Don't sleep when processing */
#define IM_NOICTX 0x0200 /* No initiator context field */
#define IM_NOINTR 0x0400 /* Don't interrupt when complete */
#define IM_NOSTATUS 0x0800 /* Don't check status if waiting */
#define IM_WAIT 0x0100 /* Wait (sleep) for completion */
#define IM_POLL 0x0200 /* Wait (poll) for completion */
#define IM_NOSTATUS 0x0400 /* Don't check status if waiting */
struct iop_initiator {
LIST_ENTRY(iop_initiator) ii_list;
@ -124,17 +82,27 @@ struct iop_initiator {
void (*ii_intr)(struct device *, struct iop_msg *, void *);
int (*ii_reconfig)(struct device *);
void (*ii_adjqparam)(struct device *, int);
struct device *ii_dv;
int ii_flags;
int ii_ictx; /* Initiator context */
int ii_stctx; /* Static transaction context */
int ii_tid;
};
#define II_DISCARD 0x0001 /* Don't track state; discard msg wrappers */
#define II_CONFIGURED 0x0002 /* Already configured */
#define II_UTILITY 0x0004 /* Utility initiator (not a `real device') */
#define II_UTILITY 0x0004 /* Utility initiator (not a real device) */
#define IOP_ICTX 0
#define IOP_INIT_CODE 0x80
/*
* Parameter group op (for async parameter retrievals).
*/
struct iop_pgop {
struct i2o_param_op_list_header olh;
struct i2o_param_op_all_template oat;
} __attribute__ ((__packed__));
/*
* Per-IOP context.
@ -150,19 +118,21 @@ struct iop_softc {
bus_size_t sc_memsize; /* register window size */
struct i2o_hrt *sc_hrt; /* hardware resource table */
struct iop_tidmap *sc_tidmap; /* tid map (per-lct-entry flags) */
struct i2o_lct *sc_lct; /* logical configuration table */
int sc_nlctent; /* number of LCT entries */
struct iop_tidmap *sc_tidmap; /* tid map (per-lct-entry flags) */
struct i2o_status sc_status; /* status */
struct iop_stat sc_stat; /* counters */
int sc_flags; /* IOP-wide flags */
int sc_maxreplycnt; /* reply queue size */
u_int32_t sc_chgindicator;/* autoconfig vs. LCT change ind. */
int sc_maxib;
int sc_maxob;
int sc_curib;
u_int32_t sc_chgind; /* autoconfig vs. LCT change ind. */
LIST_HEAD(, iop_initiator) sc_iilist;/* initiator list */
SIMPLEQ_HEAD(,iop_msg) sc_queue;/* software queue */
int sc_maxqueuecnt; /* maximum # of msgs on h/w queue */
int sc_nii;
int sc_nuii;
struct iop_initiator sc_eventii;/* IOP event handler */
struct proc *sc_reconf_proc;/* reconfiguration process */
struct iop_msg *sc_ims;
SLIST_HEAD(, iop_msg) sc_im_freelist;
caddr_t sc_ptb;
/*
@ -172,6 +142,8 @@ struct iop_softc {
int sc_rep_size;
bus_addr_t sc_rep_phys;
caddr_t sc_rep;
struct i2o_status sc_status; /* status */
};
#define IOP_OPEN 0x01 /* Device interface open */
#define IOP_HAVESTATUS 0x02 /* Successfully retrieved status */
@ -186,20 +158,22 @@ struct iop_attach_args {
void iop_init(struct iop_softc *, const char *);
int iop_intr(void *);
int iop_lct_get(struct iop_softc *);
int iop_param_op(struct iop_softc *, int, int, int, void *, int);
int iop_param_op(struct iop_softc *, int, struct iop_initiator *, int,
int, void *, int);
int iop_print_ident(struct iop_softc *, int);
int iop_simple_cmd(struct iop_softc *, int, int, int, int, int);
void iop_strvis(struct iop_softc *, const char *, int, char *, int);
int iop_initiator_register(struct iop_softc *, struct iop_initiator *);
void iop_initiator_register(struct iop_softc *, struct iop_initiator *);
void iop_initiator_unregister(struct iop_softc *, struct iop_initiator *);
int iop_msg_alloc(struct iop_softc *, struct iop_initiator *,
struct iop_msg **, int);
int iop_msg_enqueue(struct iop_softc *, struct iop_msg *, int);
void iop_msg_free(struct iop_softc *, struct iop_initiator *,
struct iop_msg *);
int iop_msg_map(struct iop_softc *, struct iop_msg *, void *, int, int);
int iop_msg_send(struct iop_softc *, struct iop_msg *, int);
struct iop_msg *iop_msg_alloc(struct iop_softc *, struct iop_initiator *, int);
void iop_msg_free(struct iop_softc *, struct iop_msg *);
int iop_msg_map(struct iop_softc *, struct iop_msg *, u_int32_t *, void *,
int, int);
int iop_msg_map_bio(struct iop_softc *, struct iop_msg *, u_int32_t *,
void *, int, int);
int iop_msg_post(struct iop_softc *, struct iop_msg *, void *, int);
void iop_msg_unmap(struct iop_softc *, struct iop_msg *);
int iop_util_abort(struct iop_softc *, struct iop_initiator *, int, int,
@ -207,32 +181,4 @@ int iop_util_abort(struct iop_softc *, struct iop_initiator *, int, int,
int iop_util_claim(struct iop_softc *, struct iop_initiator *, int, int);
int iop_util_eventreg(struct iop_softc *, struct iop_initiator *, int);
#endif /* _KERNEL */
/*
* ioctl() interface.
*/
struct ioppt_buf {
void *ptb_data;
size_t ptb_datalen;
int ptb_out;
};
struct ioppt {
void *pt_msg;
size_t pt_msglen;
void *pt_reply;
size_t pt_replylen;
int pt_timo;
int pt_nbufs;
struct ioppt_buf pt_bufs[IOP_MAX_MSG_XFERS];
};
#define IOPIOCPT _IOWR('u', 0, struct ioppt)
#define IOPIOCGLCT _IOWR('u', 1, struct iovec)
#define IOPIOCGSTATUS _IOWR('u', 2, struct iovec)
#define IOPIOCRECONFIG _IO('u', 3)
#define IOPIOCGTIDMAP _IOWR('u', 4, struct iovec)
#endif /* !_I2O_IOPVAR_H_ */

View File

@ -1,7 +1,7 @@
/* $NetBSD: ld_iop.c,v 1.5 2001/02/06 12:22:24 ad Exp $ */
/* $NetBSD: ld_iop.c,v 1.6 2001/03/20 13:01:49 ad Exp $ */
/*-
* Copyright (c) 2000 The NetBSD Foundation, Inc.
* Copyright (c) 2000, 2001 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
@ -63,27 +63,31 @@
#include <dev/ldvar.h>
#include <dev/i2o/i2o.h>
#include <dev/i2o/iopio.h>
#include <dev/i2o/iopvar.h>
#define LD_IOP_MAXQUEUECNT 64 /* XXX */
#define LD_IOP_TIMEOUT 10*1000*1000
#define LD_IOP_TIMEOUT 30*1000
#define LD_IOP_CLAIMED 0x01
#define LD_IOP_NEW_EVTMASK 0x02
struct ld_iop_softc {
struct ld_softc sc_ld;
struct iop_initiator sc_ii;
struct iop_initiator sc_eventii;
int sc_claimed;
u_int sc_tid;
int sc_flags;
};
static void ld_iop_adjqparam(struct device *, int);
static void ld_iop_attach(struct device *, struct device *, void *);
static int ld_iop_detach(struct device *, int);
static int ld_iop_dump(struct ld_softc *, void *, int, int);
static int ld_iop_flush(struct ld_softc *);
static void ld_iop_intr(struct device *, struct iop_msg *, void *);
static void ld_iop_intr_event(struct device *, struct iop_msg *, void *);
static int ld_iop_start(struct ld_softc *, struct buf *);
static int ld_iop_match(struct device *, struct cfdata *, void *);
static int ld_iop_start(struct ld_softc *, struct buf *);
static void ld_iop_unconfig(struct ld_iop_softc *, int);
struct cfattach ld_iop_ca = {
sizeof(struct ld_iop_softc),
@ -93,21 +97,22 @@ struct cfattach ld_iop_ca = {
};
#ifdef I2OVERBOSE
static const char *ld_iop_errors[] = {
static const char * const ld_iop_errors[] = {
"success",
"media error",
"failure communicating with device",
"access error",
"device failure",
"device is not ready",
"device not ready",
"media not present",
"media locked by another user",
"media locked",
"media failure",
"failure communicating to device",
"device bus failure",
"device locked by another user",
"device write protected",
"protocol failure",
"bus failure",
"access violation",
"media write protected",
"device reset",
"volume has changed, waiting for acknowledgement",
"volume changed, waiting for acknowledgement",
"timeout",
};
#endif
@ -129,7 +134,7 @@ ld_iop_attach(struct device *parent, struct device *self, void *aux)
struct ld_iop_softc *sc;
struct iop_softc *iop;
int rv, evreg, enable;
char ident[64 + 1], *typestr, *fixedstr;
char *typestr, *fixedstr;
u_int cachesz;
struct {
struct i2o_param_op_results pr;
@ -137,75 +142,69 @@ ld_iop_attach(struct device *parent, struct device *self, void *aux)
union {
struct i2o_param_rbs_cache_control cc;
struct i2o_param_rbs_device_info bdi;
struct i2o_param_device_identity di;
struct i2o_param_rbs_operation op;
} p;
} param;
} param /* XXX gcc __attribute__ ((__packed__)) */;
sc = (struct ld_iop_softc *)self;
ld = &sc->sc_ld;
iop = (struct iop_softc *)parent;
ia = (struct iop_attach_args *)aux;
sc->sc_tid = ia->ia_tid;
evreg = 0;
/* Register us as an initiator. */
sc->sc_ii.ii_dv = self;
sc->sc_ii.ii_intr = ld_iop_intr;
sc->sc_ii.ii_adjqparam = ld_iop_adjqparam;
sc->sc_ii.ii_flags = 0;
sc->sc_ii.ii_tid = ia->ia_tid;
if (iop_initiator_register(iop, &sc->sc_ii) != 0) {
printf("%s: unable to register initiator\n", self->dv_xname);
return;
}
iop_initiator_register(iop, &sc->sc_ii);
/* Register another initiator to handle events from the device. */
sc->sc_eventii.ii_dv = self;
sc->sc_eventii.ii_intr = ld_iop_intr_event;
sc->sc_eventii.ii_flags = II_DISCARD | II_UTILITY;
sc->sc_eventii.ii_tid = ia->ia_tid;
if (iop_initiator_register(iop, &sc->sc_eventii) != 0) {
printf("%s: unable to register initiator", self->dv_xname);
goto bad;
}
if (iop_util_eventreg(iop, &sc->sc_eventii, 0xffffffff)) {
iop_initiator_register(iop, &sc->sc_eventii);
rv = iop_util_eventreg(iop, &sc->sc_eventii,
I2O_EVENT_GEN_EVENT_MASK_MODIFIED |
I2O_EVENT_GEN_DEVICE_RESET |
I2O_EVENT_GEN_STATE_CHANGE |
I2O_EVENT_GEN_GENERAL_WARNING);
if (rv != 0) {
printf("%s: unable to register for events", self->dv_xname);
goto bad;
}
evreg = 1;
/*
* Start out with one queued command. The `iop' driver will adjust
* the queue parameters once we're up and running.
*/
ld->sc_maxqueuecnt = 1;
ld->sc_maxxfer = IOP_MAX_XFER;
ld->sc_maxqueuecnt = LD_IOP_MAXQUEUECNT;
ld->sc_dump = ld_iop_dump;
ld->sc_flush = ld_iop_flush;
ld->sc_start = ld_iop_start;
/* Say what the device is. */
printf(": ");
if (iop_param_op(iop, ia->ia_tid, 0, I2O_PARAM_DEVICE_IDENTITY, &param,
sizeof(param)) == 0) {
iop_strvis(iop, param.p.di.vendorinfo,
sizeof(param.p.di.vendorinfo), ident, sizeof(ident));
printf("<%s, ", ident);
iop_strvis(iop, param.p.di.productinfo,
sizeof(param.p.di.productinfo), ident, sizeof(ident));
printf("%s, ", ident);
iop_strvis(iop, param.p.di.revlevel,
sizeof(param.p.di.revlevel), ident, sizeof(ident));
printf("%s> ", ident);
}
printf(":");
iop_print_ident(iop, ia->ia_tid);
/*
* Claim the device so that we don't get any nasty surprises. Allow
* failure.
*/
sc->sc_claimed = !iop_util_claim(iop, &sc->sc_ii, 0,
rv = iop_util_claim(iop, &sc->sc_ii, 0,
I2O_UTIL_CLAIM_CAPACITY_SENSITIVE |
I2O_UTIL_CLAIM_NO_PEER_SERVICE |
I2O_UTIL_CLAIM_NO_MANAGEMENT_SERVICE |
I2O_UTIL_CLAIM_PRIMARY_USER);
sc->sc_flags = rv ? 0 : LD_IOP_CLAIMED;
rv = iop_param_op(iop, ia->ia_tid, 0, I2O_PARAM_RBS_DEVICE_INFO,
rv = iop_param_op(iop, ia->ia_tid, NULL, 0, I2O_PARAM_RBS_DEVICE_INFO,
&param, sizeof(param));
if (rv != 0) {
printf("%s: unable to get parameters (0x%04x; %d)\n",
@ -243,7 +242,7 @@ ld_iop_attach(struct device *parent, struct device *self, void *aux)
enable = 0;
break;
case I2O_RBS_TYPE_CDROM:
typestr = "cdrom";
typestr = "CD-ROM";
enable = 0;
break;
case I2O_RBS_TYPE_OPTICAL:
@ -264,15 +263,15 @@ ld_iop_attach(struct device *parent, struct device *self, void *aux)
} else
fixedstr = "fixed";
printf("%s, %s", typestr, fixedstr);
printf(" %s, %s", typestr, fixedstr);
/*
* Determine if the device has an private cache. If so, print the
* cache size. Even if the device doesn't appear to have a cache,
* we perform a flush at shutdown, as it is still valid to do so.
* we perform a flush at shutdown.
*/
rv = iop_param_op(iop, ia->ia_tid, 0, I2O_PARAM_RBS_CACHE_CONTROL,
&param, sizeof(param));
rv = iop_param_op(iop, ia->ia_tid, NULL, 0,
I2O_PARAM_RBS_CACHE_CONTROL, &param, sizeof(param));
if (rv != 0) {
printf("%s: unable to get parameters (0x%04x; %d)\n",
ld->sc_dv.dv_xname, I2O_PARAM_RBS_CACHE_CONTROL, rv);
@ -286,9 +285,9 @@ ld_iop_attach(struct device *parent, struct device *self, void *aux)
/*
* Configure the DDM's timeout functions to time out all commands
* after 10 seconds.
* after 30 seconds.
*/
rv = iop_param_op(iop, ia->ia_tid, 0, I2O_PARAM_RBS_OPERATION,
rv = iop_param_op(iop, ia->ia_tid, NULL, 0, I2O_PARAM_RBS_OPERATION,
&param, sizeof(param));
if (rv != 0) {
printf("%s: unable to get parameters (0x%04x; %d)\n",
@ -296,17 +295,24 @@ ld_iop_attach(struct device *parent, struct device *self, void *aux)
goto bad;
}
param.p.op.timeoutbase = htole32(LD_IOP_TIMEOUT);
param.p.op.rwvtimeoutbase = htole32(LD_IOP_TIMEOUT);
param.p.op.timeoutbase = htole32(LD_IOP_TIMEOUT * 1000);
param.p.op.rwvtimeoutbase = htole32(LD_IOP_TIMEOUT * 1000);
param.p.op.rwvtimeout = 0;
rv = iop_param_op(iop, ia->ia_tid, 1, I2O_PARAM_RBS_OPERATION,
rv = iop_param_op(iop, ia->ia_tid, NULL, 1, I2O_PARAM_RBS_OPERATION,
&param, sizeof(param));
#ifdef notdef
/*
* Intel RAID adapters don't like the above, but do post a
* `parameter changed' event. Perhaps we're doing something
* wrong...
*/
if (rv != 0) {
printf("%s: unable to set parameters (0x%04x; %d)\n",
ld->sc_dv.dv_xname, I2O_PARAM_RBS_OPERATION, rv);
goto bad;
}
#endif
if (enable)
ld->sc_flags |= LDF_ENABLED;
@ -316,14 +322,43 @@ ld_iop_attach(struct device *parent, struct device *self, void *aux)
ldattach(ld);
return;
bad:
if (sc->sc_claimed)
bad:
ld_iop_unconfig(sc, evreg);
}
static void
ld_iop_unconfig(struct ld_iop_softc *sc, int evreg)
{
struct iop_softc *iop;
int s;
iop = (struct iop_softc *)sc->sc_ld.sc_dv.dv_parent;
if ((sc->sc_flags & LD_IOP_CLAIMED) != 0)
iop_util_claim(iop, &sc->sc_ii, 1,
I2O_UTIL_CLAIM_PRIMARY_USER);
if (evreg)
iop_util_eventreg(iop, &sc->sc_eventii, 0);
if (sc->sc_eventii.ii_intr != NULL)
iop_initiator_unregister(iop, &sc->sc_eventii);
if (evreg) {
/*
* Mask off events, and wait up to 5 seconds for a reply.
* Note that some adapters won't reply to this (XXX We
* should check the event capabilities).
*/
sc->sc_flags &= ~LD_IOP_NEW_EVTMASK;
iop_util_eventreg(iop, &sc->sc_eventii,
I2O_EVENT_GEN_EVENT_MASK_MODIFIED);
s = splbio();
if ((sc->sc_flags & LD_IOP_NEW_EVTMASK) == 0)
tsleep(&sc->sc_eventii, PRIBIO, "ld_iopevt", hz * 5);
splx(s);
#ifdef I2ODEBUG
if ((sc->sc_flags & LD_IOP_NEW_EVTMASK) == 0)
printf("%s: didn't reply to event unregister",
sc->sc_ld.sc_dv.dv_xname);
#endif
}
iop_initiator_unregister(iop, &sc->sc_eventii);
iop_initiator_unregister(iop, &sc->sc_ii);
}
@ -335,12 +370,11 @@ ld_iop_detach(struct device *self, int flags)
int rv;
sc = (struct ld_iop_softc *)self;
iop = (struct iop_softc *)self->dv_parent;
if ((rv = ldbegindetach(&sc->sc_ld, flags)) != 0)
return (rv);
iop = (struct iop_softc *)self->dv_parent;
/*
* Abort any requests queued with the IOP, but allow requests that
* are already in progress to complete.
@ -351,18 +385,9 @@ ld_iop_detach(struct device *self, int flags)
ldenddetach(&sc->sc_ld);
/* Un-claim the target, and un-register us as an initiator. */
if ((sc->sc_ld.sc_flags & LDF_ENABLED) != 0) {
if (sc->sc_claimed) {
rv = iop_util_claim(iop, &sc->sc_ii, 1,
I2O_UTIL_CLAIM_PRIMARY_USER);
if (rv != 0)
return (rv);
}
iop_util_eventreg(iop, &sc->sc_eventii, 0);
iop_initiator_unregister(iop, &sc->sc_eventii);
iop_initiator_unregister(iop, &sc->sc_ii);
}
/* Un-claim the target, and un-register our initiators. */
if ((sc->sc_ld.sc_flags & LDF_ENABLED) != 0)
ld_iop_unconfig(sc, 1);
return (0);
}
@ -373,16 +398,15 @@ ld_iop_start(struct ld_softc *ld, struct buf *bp)
struct iop_msg *im;
struct iop_softc *iop;
struct ld_iop_softc *sc;
struct i2o_rbs_block_read *mb;
int rv, flags, write;
struct i2o_rbs_block_read *mf;
u_int rv, flags, write;
u_int64_t ba;
u_int32_t mb[IOP_MAX_MSG_SIZE / sizeof(u_int32_t)];
sc = (struct ld_iop_softc *)ld;
iop = (struct iop_softc *)ld->sc_dv.dv_parent;
im = NULL;
if ((rv = iop_msg_alloc(iop, &sc->sc_ii, &im, IM_NOWAIT)) != 0)
goto bad;
im = iop_msg_alloc(iop, &sc->sc_ii, 0);
im->im_dvcontext = bp;
write = ((bp->b_flags & B_READ) == 0);
@ -406,28 +430,25 @@ ld_iop_start(struct ld_softc *ld, struct buf *bp)
* both reads and writes, as it's almost identical to the
* block_write structure.
*/
mb = (struct i2o_rbs_block_read *)im->im_msg;
mb->msgflags = I2O_MSGFLAGS(i2o_rbs_block_read);
mb->msgfunc = I2O_MSGFUNC(sc->sc_tid,
mf = (struct i2o_rbs_block_read *)mb;
mf->msgflags = I2O_MSGFLAGS(i2o_rbs_block_read);
mf->msgfunc = I2O_MSGFUNC(sc->sc_ii.ii_tid,
write ? I2O_RBS_BLOCK_WRITE : I2O_RBS_BLOCK_READ);
mb->msgictx = sc->sc_ii.ii_ictx;
mb->msgtctx = im->im_tctx;
mb->flags = flags | (1 << 16); /* flags & time multiplier */
mb->datasize = bp->b_bcount;
mb->lowoffset = (u_int32_t)ba;
mb->highoffset = (u_int32_t)(ba >> 32);
mf->msgictx = sc->sc_ii.ii_ictx;
mf->msgtctx = im->im_tctx;
mf->flags = flags | (1 << 16); /* flags & time multiplier */
mf->datasize = bp->b_bcount;
mf->lowoffset = (u_int32_t)ba;
mf->highoffset = (u_int32_t)(ba >> 32);
/* Map the data transfer. */
if ((rv = iop_msg_map(iop, im, bp->b_data, bp->b_bcount, write)) != 0)
goto bad;
/* Enqueue the command. */
iop_msg_enqueue(iop, im, 0);
return (0);
bad:
if (im != NULL)
iop_msg_free(iop, &sc->sc_ii, im);
/* Map the data transfer and enqueue the command. */
rv = iop_msg_map_bio(iop, im, mb, bp->b_data, bp->b_bcount, write);
if (rv == 0) {
if ((rv = iop_msg_post(iop, im, mb, 0)) != 0) {
iop_msg_unmap(iop, im);
iop_msg_free(iop, im);
}
}
return (rv);
}
@ -437,37 +458,35 @@ ld_iop_dump(struct ld_softc *ld, void *data, int blkno, int blkcnt)
struct iop_msg *im;
struct iop_softc *iop;
struct ld_iop_softc *sc;
struct i2o_rbs_block_write *mb;
struct i2o_rbs_block_write *mf;
int rv, bcount;
u_int64_t ba;
u_int32_t mb[IOP_MAX_MSG_SIZE / sizeof(u_int32_t)];
sc = (struct ld_iop_softc *)ld;
iop = (struct iop_softc *)ld->sc_dv.dv_parent;
bcount = blkcnt * ld->sc_secsize;
ba = (u_int64_t)blkno * ld->sc_secsize;
im = iop_msg_alloc(iop, &sc->sc_ii, IM_POLL);
rv = iop_msg_alloc(iop, &sc->sc_ii, &im, IM_NOWAIT | IM_NOINTR);
if (rv != 0)
return (rv);
mf = (struct i2o_rbs_block_write *)mb;
mf->msgflags = I2O_MSGFLAGS(i2o_rbs_block_write);
mf->msgfunc = I2O_MSGFUNC(sc->sc_ii.ii_tid, I2O_RBS_BLOCK_WRITE);
mf->msgictx = sc->sc_ii.ii_ictx;
mf->msgtctx = im->im_tctx;
mf->flags = I2O_RBS_BLOCK_WRITE_CACHE_WT | (1 << 16);
mf->datasize = bcount;
mf->lowoffset = (u_int32_t)ba;
mf->highoffset = (u_int32_t)(ba >> 32);
mb = (struct i2o_rbs_block_write *)im->im_msg;
mb->msgflags = I2O_MSGFLAGS(i2o_rbs_block_write);
mb->msgfunc = I2O_MSGFUNC(sc->sc_tid, I2O_RBS_BLOCK_WRITE);
mb->msgictx = sc->sc_ii.ii_ictx;
mb->msgtctx = im->im_tctx;
mb->flags = I2O_RBS_BLOCK_WRITE_CACHE_WT | (1 << 16);
mb->datasize = bcount;
mb->lowoffset = (u_int32_t)ba;
mb->highoffset = (u_int32_t)(ba >> 32);
if ((rv = iop_msg_map(iop, im, data, bcount, 1)) != 0) {
iop_msg_free(iop, &sc->sc_ii, im);
if ((rv = iop_msg_map(iop, im, mb, data, bcount, 1)) != 0) {
iop_msg_free(iop, im);
return (rv);
}
rv = (iop_msg_send(iop, im, 5000) != 0 ? EIO : 0);
rv = iop_msg_post(iop, im, mb, LD_IOP_TIMEOUT * 2);
iop_msg_unmap(iop, im);
iop_msg_free(iop, &sc->sc_ii, im);
iop_msg_free(iop, im);
return (rv);
}
@ -477,25 +496,25 @@ ld_iop_flush(struct ld_softc *ld)
struct iop_msg *im;
struct iop_softc *iop;
struct ld_iop_softc *sc;
struct i2o_rbs_cache_flush *mb;
struct i2o_rbs_cache_flush mf;
int rv;
sc = (struct ld_iop_softc *)ld;
iop = (struct iop_softc *)ld->sc_dv.dv_parent;
im = iop_msg_alloc(iop, &sc->sc_ii, IM_WAIT);
rv = iop_msg_alloc(iop, &sc->sc_ii, &im, IM_NOWAIT | IM_NOINTR);
if (rv != 0)
return (rv);
mf.msgflags = I2O_MSGFLAGS(i2o_rbs_cache_flush);
mf.msgfunc = I2O_MSGFUNC(sc->sc_ii.ii_tid, I2O_RBS_CACHE_FLUSH);
mf.msgictx = sc->sc_ii.ii_ictx;
mf.msgtctx = im->im_tctx;
mf.flags = 1 << 16; /* time multiplier */
mb = (struct i2o_rbs_cache_flush *)im->im_msg;
mb->msgflags = I2O_MSGFLAGS(i2o_rbs_cache_flush);
mb->msgfunc = I2O_MSGFUNC(sc->sc_tid, I2O_RBS_CACHE_FLUSH);
mb->msgictx = sc->sc_ii.ii_ictx;
mb->msgtctx = im->im_tctx;
mb->flags = 1 << 16; /* time multiplier */
rv = iop_msg_send(iop, im, 10000);
iop_msg_free(iop, &sc->sc_ii, im);
/*
* XXX Aincent disks will return an error here. Also, we shouldn't
* be polling on completion while the system is running.
*/
rv = iop_msg_post(iop, im, &mf, LD_IOP_TIMEOUT * 2);
iop_msg_free(iop, im);
return (rv);
}
@ -506,8 +525,8 @@ ld_iop_intr(struct device *dv, struct iop_msg *im, void *reply)
struct buf *bp;
struct ld_iop_softc *sc;
struct iop_softc *iop;
int err, detail;
#ifdef I2OVERBOSE
int detail;
const char *errstr;
#endif
@ -516,30 +535,31 @@ ld_iop_intr(struct device *dv, struct iop_msg *im, void *reply)
sc = (struct ld_iop_softc *)dv;
iop = (struct iop_softc *)dv->dv_parent;
#ifdef I2OVERBOSE
if (rb->reqstatus != I2O_STATUS_SUCCESS) {
err = ((rb->msgflags & I2O_MSGFLAGS_FAIL) != 0);
if (!err && rb->reqstatus != I2O_STATUS_SUCCESS) {
detail = le16toh(rb->detail);
#ifdef I2OVERBOSE
if (detail > sizeof(ld_iop_errors) / sizeof(ld_iop_errors[0]))
errstr = "unknown error";
errstr = "<unknown>";
else
errstr = ld_iop_errors[detail];
printf("%s: %s\n", dv->dv_xname, errstr);
printf("%s: error 0x%04x: %s\n", dv->dv_xname, detail, errstr);
#else
if (rb->reqstatus != I2O_STATUS_SUCCESS) {
printf("%s: error 0x%04x\n", dv->dv_xname, detail);
#endif
err = 1;
}
if (err) {
bp->b_flags |= B_ERROR;
bp->b_error = EIO;
#ifndef notyet
bp->b_resid = bp->b_bcount;
} else
bp->b_resid = 0;
#else
}
bp->b_resid = bp->b_bcount - le32toh(rb->transfercount);
#endif
bp->b_resid = bp->b_bcount - le32toh(rb->transfercount);
iop_msg_unmap(iop, im);
iop_msg_free(iop, &sc->sc_ii, im);
iop_msg_free(iop, im);
lddone(&sc->sc_ld, bp);
}
@ -547,15 +567,40 @@ static void
ld_iop_intr_event(struct device *dv, struct iop_msg *im, void *reply)
{
struct i2o_util_event_register_reply *rb;
struct ld_iop_softc *sc;
u_int event;
rb = reply;
event = le32toh(rb->event);
if ((rb->msgflags & I2O_MSGFLAGS_FAIL) != 0)
return;
event = le32toh(rb->event);
sc = (struct ld_iop_softc *)dv;
if (event == I2O_EVENT_GEN_EVENT_MASK_MODIFIED) {
sc->sc_flags |= LD_IOP_NEW_EVTMASK;
wakeup(&sc->sc_eventii);
#ifndef I2ODEBUG
if (event == I2O_EVENT_GEN_EVENT_MASK_MODIFIED)
return;
#endif
}
printf("%s: event 0x%08x received\n", dv->dv_xname, event);
}
static void
ld_iop_adjqparam(struct device *dv, int mpi)
{
struct iop_softc *iop;
/*
* AMI controllers seem to loose the plot if you hand off lots of
* queued commands.
*/
iop = (struct iop_softc *)dv->dv_parent;
if (le16toh(I2O_ORG_AMI) == iop->sc_status.orgid && mpi > 64)
mpi = 64;
ldadjqparam((struct ld_softc *)dv, mpi);
}