Add support for the user-generated command interface and event logging

required by the ICP-Vortex management tools.  Many thanks to Achim Leubner
at ICP-Vortex for a few bug fixes and for testing.
This commit is contained in:
thorpej 2003-05-13 15:42:33 +00:00
parent bf026fa41a
commit 405790a85a
10 changed files with 1002 additions and 50 deletions

View File

@ -1,4 +1,4 @@
# $NetBSD: files,v 1.610 2003/04/24 20:04:03 ragge Exp $
# $NetBSD: files,v 1.611 2003/05/13 15:42:33 thorpej Exp $
# @(#)files.newconf 7.5 (Berkeley) 5/10/93
@ -323,6 +323,7 @@ file dev/ic/ld_mlx.c ld_mlx
#
device icp {unit = -1}
file dev/ic/icp.c icp needs-flag
file dev/ic/icp_ioctl.c icp
attach ld at icp with ld_icp
file dev/ic/ld_icp.c ld_icp

View File

@ -1,8 +1,9 @@
# $NetBSD: Makefile,v 1.20 2001/05/06 03:26:38 ichiro Exp $
# $NetBSD: Makefile,v 1.21 2003/05/13 15:42:33 thorpej Exp $
INCSDIR= /usr/include/dev/ic
# Only install includes which are used by userland
INCS= bt8xx.h isp_ioctl.h mlxreg.h mlxio.h rrunnerreg.h rrunnervar.h wdcreg.h wi_ieee.h
INCS= bt8xx.h icpreg.h icp_ioctl.h isp_ioctl.h mlxreg.h mlxio.h rrunnerreg.h \
rrunnervar.h wdcreg.h wi_ieee.h
.include <bsd.kinc.mk>

View File

@ -1,11 +1,11 @@
/* $NetBSD: icp.c,v 1.7 2003/01/31 00:26:30 thorpej Exp $ */
/* $NetBSD: icp.c,v 1.8 2003/05/13 15:42:33 thorpej Exp $ */
/*-
* Copyright (c) 2002 The NetBSD Foundation, Inc.
* Copyright (c) 2002, 2003 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Andrew Doran.
* by Andrew Doran, and by Jason R. Thorpe of Wasabi Systems, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@ -73,10 +73,14 @@
*
* Re-worked for NetBSD by Andrew Doran. Test hardware kindly supplied by
* Intel.
*
* Support for the ICP-Vortex management tools added by
* Jason R. Thorpe of Wasabi Systems, Inc., based on code
* provided by Achim Leubner <achim.leubner@intel.com>
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: icp.c,v 1.7 2003/01/31 00:26:30 thorpej Exp $");
__KERNEL_RCSID(0, "$NetBSD: icp.c,v 1.8 2003/05/13 15:42:33 thorpej Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@ -101,12 +105,26 @@ __KERNEL_RCSID(0, "$NetBSD: icp.c,v 1.7 2003/01/31 00:26:30 thorpej Exp $");
#include <dev/ic/icpreg.h>
#include <dev/ic/icpvar.h>
#include <dev/scsipi/scsipi_all.h>
#include <dev/scsipi/scsiconf.h>
int icp_async_event(struct icp_softc *, int);
void icp_ccb_submit(struct icp_softc *icp, struct icp_ccb *ic);
void icp_chain(struct icp_softc *);
int icp_print(void *, const char *);
int icp_submatch(struct device *, struct cfdata *, void *);
void icp_watchdog(void *);
void icp_ucmd_intr(struct icp_ccb *);
int icp_count; /* total # of controllers, for ioctl interface */
/*
* Statistics for the ioctl interface to query.
*
* XXX Global. They should probably be made per-controller
* XXX at some point.
*/
gdt_statist_t icp_stats;
int
icp_init(struct icp_softc *icp, const char *intrstr)
@ -127,6 +145,7 @@ icp_init(struct icp_softc *icp, const char *intrstr)
SIMPLEQ_INIT(&icp->icp_ccb_queue);
SIMPLEQ_INIT(&icp->icp_ccb_freelist);
SIMPLEQ_INIT(&icp->icp_ucmd_queue);
callout_init(&icp->icp_wdog_callout);
/*
@ -225,6 +244,7 @@ icp_init(struct icp_softc *icp, const char *intrstr)
goto bail_out;
}
cdev_cnt = (u_int16_t)icp->icp_info;
icp->icp_fw_vers = icp->icp_service;
if (!icp_cmd(icp, ICP_SCSIRAWSERVICE, ICP_INIT, 0, 0, 0)) {
aprint_error("%s: raw service init error %d\n",
@ -383,6 +403,12 @@ icp_init(struct icp_softc *icp, const char *intrstr)
* Start the watchdog.
*/
icp_watchdog(icp);
/*
* Count the controller, and we're done!
*/
icp_count++;
return (0);
bail_out:
@ -414,7 +440,7 @@ icp_watchdog(void *cookie)
s = splbio();
icp_intr(icp);
if (! SIMPLEQ_EMPTY(&icp->icp_ccb_queue))
if (ICP_HAS_WORK(icp))
icp_ccb_enqueue(icp, NULL);
splx(s);
@ -457,11 +483,38 @@ icp_submatch(struct device *parent, struct cfdata *cf, void *aux)
}
int
icp_async_event(struct icp_softc *icp, int val)
icp_async_event(struct icp_softc *icp, int service)
{
/* XXX */
return (1);
if (service == ICP_SCREENSERVICE) {
if (icp->icp_status == ICP_S_MSG_REQUEST) {
/* XXX */
}
} else {
if ((icp->icp_fw_vers & 0xff) >= 0x1a) {
icp->icp_evt.size = 0;
icp->icp_evt.eu.async.ionode = icp->icp_dv.dv_unit;
icp->icp_evt.eu.async.status = icp->icp_status;
/*
* Severity and event string are filled in by the
* hardware interface interrupt handler.
*/
printf("%s: %s\n", icp->icp_dv.dv_xname,
icp->icp_evt.event_string);
} else {
icp->icp_evt.size = sizeof(icp->icp_evt.eu.async);
icp->icp_evt.eu.async.ionode = icp->icp_dv.dv_unit;
icp->icp_evt.eu.async.service = service;
icp->icp_evt.eu.async.status = icp->icp_status;
icp->icp_evt.eu.async.info = icp->icp_info;
/* XXXJRT FIX THIS */
*(u_int32_t *) icp->icp_evt.eu.async.scsi_coord =
icp->icp_info2;
}
icp_store_event(icp, GDT_ES_ASYNC, service, &icp->icp_evt);
}
return (0);
}
int
@ -482,6 +535,7 @@ icp_intr(void *cookie)
(*icp->icp_intr)(icp, &ctx);
icp->icp_status = ctx.cmd_status;
icp->icp_service = ctx.service;
icp->icp_info = ctx.info;
icp->icp_info2 = ctx.info2;
@ -493,6 +547,9 @@ icp_intr(void *cookie)
case ICP_SPEZINDEX:
printf("%s: uninitialized or unknown service (%d/%d)\n",
icp->icp_dv.dv_xname, ctx.info, ctx.info2);
icp->icp_evt.size = sizeof(icp->icp_evt.eu.driver);
icp->icp_evt.eu.driver.ionode = icp->icp_dv.dv_unit;
icp_store_event(icp, GDT_ES_DRIVER, 4, &icp->icp_evt);
return (1);
}
@ -502,15 +559,20 @@ icp_intr(void *cookie)
ic = &icp->icp_ccbs[ctx.istatus - 2];
ic->ic_status = icp->icp_status;
if ((ic->ic_flags & IC_ALLOCED) == 0)
if ((ic->ic_flags & IC_ALLOCED) == 0) {
/* XXX ICP's "iir" driver just sends an event here. */
panic("icp_intr: inactive CCB identified");
}
switch (icp->icp_status) {
case ICP_S_BSY:
#ifdef ICP_DEBUG
printf("%s: ICP_S_BSY received\n", icp->icp_dv.dv_xname);
#endif
SIMPLEQ_INSERT_HEAD(&icp->icp_ccb_queue, ic, ic_chain);
if (__predict_false((ic->ic_flags & IC_UCMD) != 0))
SIMPLEQ_INSERT_HEAD(&icp->icp_ucmd_queue, ic, ic_chain);
else
SIMPLEQ_INSERT_HEAD(&icp->icp_ccb_queue, ic, ic_chain);
break;
default:
@ -521,7 +583,7 @@ icp_intr(void *cookie)
else if (ic->ic_intr != NULL)
(*ic->ic_intr)(ic);
if (! SIMPLEQ_EMPTY(&icp->icp_ccb_queue))
if (ICP_HAS_WORK(icp))
icp_ccb_enqueue(icp, NULL);
break;
@ -530,6 +592,39 @@ icp_intr(void *cookie)
return (1);
}
struct icp_ucmd_ctx {
gdt_ucmd_t *iu_ucmd;
u_int32_t iu_cnt;
};
void
icp_ucmd_intr(struct icp_ccb *ic)
{
struct icp_softc *icp = (void *) ic->ic_dv;
struct icp_ucmd_ctx *iu = ic->ic_context;
gdt_ucmd_t *ucmd = iu->iu_ucmd;
ucmd->status = icp->icp_status;
ucmd->info = icp->icp_info;
if (iu->iu_cnt != 0) {
bus_dmamap_sync(icp->icp_dmat,
icp->icp_scr_dmamap,
ICP_SCRATCH_UCMD, iu->iu_cnt,
BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
memcpy(ucmd->data,
icp->icp_scr + ICP_SCRATCH_UCMD, iu->iu_cnt);
}
icp->icp_ucmd_ccb = NULL;
ic->ic_flags |= IC_COMPLETE;
wakeup(ic);
}
/*
* NOTE: We assume that it is safe to sleep here!
*/
int
icp_cmd(struct icp_softc *icp, u_int8_t service, u_int16_t opcode,
u_int32_t arg1, u_int32_t arg2, u_int32_t arg3)
@ -543,7 +638,7 @@ icp_cmd(struct icp_softc *icp, u_int8_t service, u_int16_t opcode,
retries = ICP_RETRIES;
do {
ic = icp_ccb_alloc(icp);
ic = icp_ccb_alloc_wait(icp);
memset(&ic->ic_cmd, 0, sizeof(ic->ic_cmd));
ic->ic_cmd.cmd_opcode = htole16(opcode);
@ -598,6 +693,119 @@ icp_cmd(struct icp_softc *icp, u_int8_t service, u_int16_t opcode,
return (icp->icp_status == ICP_S_OK);
}
int
icp_ucmd(struct icp_softc *icp, gdt_ucmd_t *ucmd)
{
struct icp_ccb *ic;
struct icp_ucmd_ctx iu;
u_int32_t cnt;
int error;
if (ucmd->service == ICP_CACHESERVICE) {
if (ucmd->command.cmd_opcode == ICP_IOCTL) {
cnt = ucmd->command.cmd_packet.ic.ic_bufsize;
if (cnt > GDT_SCRATCH_SZ) {
printf("%s: scratch buffer too small (%d/%d)\n",
icp->icp_dv.dv_xname, GDT_SCRATCH_SZ, cnt);
return (EINVAL);
}
} else {
cnt = ucmd->command.cmd_packet.cc.cc_blockcnt *
ICP_SECTOR_SIZE;
if (cnt > GDT_SCRATCH_SZ) {
printf("%s: scratch buffer too small (%d/%d)\n",
icp->icp_dv.dv_xname, GDT_SCRATCH_SZ, cnt);
return (EINVAL);
}
}
} else {
cnt = ucmd->command.cmd_packet.rc.rc_sdlen +
ucmd->command.cmd_packet.rc.rc_sense_len;
if (cnt > GDT_SCRATCH_SZ) {
printf("%s: scratch buffer too small (%d/%d)\n",
icp->icp_dv.dv_xname, GDT_SCRATCH_SZ, cnt);
return (EINVAL);
}
}
iu.iu_ucmd = ucmd;
iu.iu_cnt = cnt;
ic = icp_ccb_alloc_wait(icp);
memset(&ic->ic_cmd, 0, sizeof(ic->ic_cmd));
ic->ic_cmd.cmd_opcode = htole16(ucmd->command.cmd_opcode);
if (ucmd->service == ICP_CACHESERVICE) {
if (ucmd->command.cmd_opcode == ICP_IOCTL) {
struct icp_ioctlcmd *icmd, *uicmd;
icmd = &ic->ic_cmd.cmd_packet.ic;
uicmd = &ucmd->command.cmd_packet.ic;
icmd->ic_subfunc = htole16(uicmd->ic_subfunc);
icmd->ic_channel = htole32(uicmd->ic_channel);
icmd->ic_bufsize = htole32(uicmd->ic_bufsize);
icmd->ic_addr =
htole32(icp->icp_scr_seg[0].ds_addr +
ICP_SCRATCH_UCMD);
} else {
struct icp_cachecmd *cc, *ucc;
cc = &ic->ic_cmd.cmd_packet.cc;
ucc = &ucmd->command.cmd_packet.cc;
cc->cc_deviceno = htole16(ucc->cc_deviceno);
cc->cc_blockno = htole32(ucc->cc_blockno);
cc->cc_blockcnt = htole32(ucc->cc_blockcnt);
cc->cc_addr = htole32(0xffffffffU);
cc->cc_nsgent = htole32(1);
cc->cc_sg[0].sg_addr =
htole32(icp->icp_scr_seg[0].ds_addr +
ICP_SCRATCH_UCMD);
cc->cc_sg[0].sg_len = htole32(cnt);
}
} else {
struct icp_rawcmd *rc, *urc;
rc = &ic->ic_cmd.cmd_packet.rc;
urc = &ucmd->command.cmd_packet.rc;
rc->rc_direction = htole32(urc->rc_direction);
rc->rc_sdata = htole32(0xffffffffU);
rc->rc_sdlen = htole32(urc->rc_sdlen);
rc->rc_clen = htole32(urc->rc_clen);
memcpy(rc->rc_cdb, urc->rc_cdb, sizeof(rc->rc_cdb));
rc->rc_target = urc->rc_target;
rc->rc_lun = urc->rc_lun;
rc->rc_bus = urc->rc_bus;
rc->rc_sense_len = htole32(urc->rc_sense_len);
rc->rc_sense_addr =
htole32(icp->icp_scr_seg[0].ds_addr +
ICP_SCRATCH_UCMD + urc->rc_sdlen);
rc->rc_nsgent = htole32(1);
rc->rc_sg[0].sg_addr =
htole32(icp->icp_scr_seg[0].ds_addr + ICP_SCRATCH_UCMD);
rc->rc_sg[0].sg_len = htole32(cnt - urc->rc_sense_len);
}
ic->ic_service = ucmd->service;
ic->ic_cmdlen = sizeof(ic->ic_cmd);
ic->ic_context = &iu;
/*
* XXX What units are ucmd->timeout in? Until we know, we
* XXX just pull a number out of thin air.
*/
if (__predict_false((error = icp_ccb_wait_user(icp, ic, 30000)) != 0))
printf("%s: error %d waiting for ucmd to complete\n",
icp->icp_dv.dv_xname, error);
/* icp_ucmd_intr() has updated ucmd. */
icp_ccb_free(icp, ic);
return (error);
}
struct icp_ccb *
icp_ccb_alloc(struct icp_softc *icp)
{
@ -605,7 +813,29 @@ icp_ccb_alloc(struct icp_softc *icp)
int s;
s = splbio();
ic = SIMPLEQ_FIRST(&icp->icp_ccb_freelist);
if (__predict_false((ic =
SIMPLEQ_FIRST(&icp->icp_ccb_freelist)) == NULL)) {
splx(s);
return (NULL);
}
SIMPLEQ_REMOVE_HEAD(&icp->icp_ccb_freelist, ic_chain);
splx(s);
ic->ic_flags = IC_ALLOCED;
return (ic);
}
struct icp_ccb *
icp_ccb_alloc_wait(struct icp_softc *icp)
{
struct icp_ccb *ic;
int s;
s = splbio();
while ((ic = SIMPLEQ_FIRST(&icp->icp_ccb_freelist)) == NULL) {
icp->icp_flags |= ICP_F_WAIT_CCB;
(void) tsleep(&icp->icp_ccb_freelist, PRIBIO, "icpccb", 0);
}
SIMPLEQ_REMOVE_HEAD(&icp->icp_ccb_freelist, ic_chain);
splx(s);
@ -622,6 +852,10 @@ icp_ccb_free(struct icp_softc *icp, struct icp_ccb *ic)
ic->ic_flags = 0;
ic->ic_intr = NULL;
SIMPLEQ_INSERT_HEAD(&icp->icp_ccb_freelist, ic, ic_chain);
if (__predict_false((icp->icp_flags & ICP_F_WAIT_CCB) != 0)) {
icp->icp_flags &= ~ICP_F_WAIT_CCB;
wakeup(&icp->icp_ccb_freelist);
}
splx(s);
}
@ -632,14 +866,46 @@ icp_ccb_enqueue(struct icp_softc *icp, struct icp_ccb *ic)
s = splbio();
if (ic != NULL)
SIMPLEQ_INSERT_TAIL(&icp->icp_ccb_queue, ic, ic_chain);
if (ic != NULL) {
if (__predict_false((ic->ic_flags & IC_UCMD) != 0))
SIMPLEQ_INSERT_TAIL(&icp->icp_ucmd_queue, ic, ic_chain);
else
SIMPLEQ_INSERT_TAIL(&icp->icp_ccb_queue, ic, ic_chain);
}
while ((ic = SIMPLEQ_FIRST(&icp->icp_ccb_queue)) != NULL) {
for (;;) {
if (__predict_false((ic =
SIMPLEQ_FIRST(&icp->icp_ucmd_queue)) != NULL)) {
struct icp_ucmd_ctx *iu = ic->ic_context;
gdt_ucmd_t *ucmd = iu->iu_ucmd;
/*
* All user-generated commands share the same
* scratch space, so if one is already running,
* we have to stall the command queue.
*/
if (icp->icp_ucmd_ccb != NULL)
break;
icp->icp_ucmd_ccb = ic;
if (iu->iu_cnt != 0) {
memcpy(icp->icp_scr + ICP_SCRATCH_UCMD,
ucmd->data, iu->iu_cnt);
bus_dmamap_sync(icp->icp_dmat,
icp->icp_scr_dmamap,
ICP_SCRATCH_UCMD, iu->iu_cnt,
BUS_DMASYNC_PREREAD |
BUS_DMASYNC_PREWRITE);
}
} else if ((ic = SIMPLEQ_FIRST(&icp->icp_ccb_queue)) == NULL)
break;
if ((*icp->icp_test_busy)(icp))
break;
icp_ccb_submit(icp, ic);
SIMPLEQ_REMOVE_HEAD(&icp->icp_ccb_queue, ic_chain);
if (__predict_false((ic->ic_flags & IC_UCMD) != 0))
SIMPLEQ_REMOVE_HEAD(&icp->icp_ucmd_queue, ic_chain);
else
SIMPLEQ_REMOVE_HEAD(&icp->icp_ccb_queue, ic_chain);
}
splx(s);
@ -751,9 +1017,11 @@ icp_ccb_wait(struct icp_softc *icp, struct icp_ccb *ic, int timo)
s = splbio();
icp_ccb_enqueue(icp, ic);
if ((rv = tsleep(ic, PRIBIO, "icpwccb", mstohz(timo))) != 0) {
splx(s);
return (rv);
while ((ic->ic_flags & IC_COMPLETE) == 0) {
if ((rv = tsleep(ic, PRIBIO, "icpwccb", mstohz(timo))) != 0) {
splx(s);
return (rv);
}
}
splx(s);
@ -766,6 +1034,28 @@ icp_ccb_wait(struct icp_softc *icp, struct icp_ccb *ic, int timo)
return (0);
}
int
icp_ccb_wait_user(struct icp_softc *icp, struct icp_ccb *ic, int timo)
{
int s, rv;
ic->ic_dv = &icp->icp_dv;
ic->ic_intr = icp_ucmd_intr;
ic->ic_flags |= IC_UCMD;
s = splbio();
icp_ccb_enqueue(icp, ic);
while ((ic->ic_flags & IC_COMPLETE) == 0) {
if ((rv = tsleep(ic, PRIBIO, "icpwuccb", mstohz(timo))) != 0) {
splx(s);
return (rv);
}
}
splx(s);
return (0);
}
void
icp_ccb_submit(struct icp_softc *icp, struct icp_ccb *ic)
{
@ -781,3 +1071,129 @@ icp_ccb_submit(struct icp_softc *icp, struct icp_ccb *ic)
(*icp->icp_copy_cmd)(icp, ic);
(*icp->icp_release_event)(icp, ic);
}
/* XXX Global - should be per-controller? XXX */
static gdt_evt_str icp_event_buffer[ICP_MAX_EVENTS];
static int icp_event_oldidx;
static int icp_event_lastidx;
gdt_evt_str *
icp_store_event(struct icp_softc *icp, u_int16_t source, u_int16_t idx,
gdt_evt_data *evt)
{
gdt_evt_str *e;
/* no source == no event */
if (source == 0)
return (NULL);
e = &icp_event_buffer[icp_event_lastidx];
if (e->event_source == source && e->event_idx == idx &&
((evt->size != 0 && e->event_data.size != 0 &&
memcmp(&e->event_data.eu, &evt->eu, evt->size) == 0) ||
(evt->size == 0 && e->event_data.size == 0 &&
strcmp((char *) e->event_data.event_string,
(char *) evt->event_string) == 0))) {
e->last_stamp = time.tv_sec;
e->same_count++;
} else {
if (icp_event_buffer[icp_event_lastidx].event_source != 0) {
icp_event_lastidx++;
if (icp_event_lastidx == ICP_MAX_EVENTS)
icp_event_lastidx = 0;
if (icp_event_lastidx == icp_event_oldidx) {
icp_event_oldidx++;
if (icp_event_oldidx == ICP_MAX_EVENTS)
icp_event_oldidx = 0;
}
}
e = &icp_event_buffer[icp_event_lastidx];
e->event_source = source;
e->event_idx = idx;
e->first_stamp = e->last_stamp = time.tv_sec;
e->same_count = 1;
e->event_data = *evt;
e->application = 0;
}
return (e);
}
int
icp_read_event(struct icp_softc *icp, int handle, gdt_evt_str *estr)
{
gdt_evt_str *e;
int eindex, s;
s = splbio();
if (handle == -1)
eindex = icp_event_oldidx;
else
eindex = handle;
estr->event_source = 0;
if (eindex < 0 || eindex >= ICP_MAX_EVENTS) {
splx(s);
return (eindex);
}
e = &icp_event_buffer[eindex];
if (e->event_source != 0) {
if (eindex != icp_event_lastidx) {
eindex++;
if (eindex == ICP_MAX_EVENTS)
eindex = 0;
} else
eindex = -1;
memcpy(estr, e, sizeof(gdt_evt_str));
}
splx(s);
return (eindex);
}
void
icp_readapp_event(struct icp_softc *icp, u_int8_t application,
gdt_evt_str *estr)
{
gdt_evt_str *e;
int found = 0, eindex, s;
s = splbio();
eindex = icp_event_oldidx;
for (;;) {
e = &icp_event_buffer[eindex];
if (e->event_source == 0)
break;
if ((e->application & application) == 0) {
e->application |= application;
found = 1;
break;
}
if (eindex == icp_event_lastidx)
break;
eindex++;
if (eindex == ICP_MAX_EVENTS)
eindex = 0;
}
if (found)
memcpy(estr, e, sizeof(gdt_evt_str));
else
estr->event_source = 0;
splx(s);
}
void
icp_clear_events(struct icp_softc *icp)
{
int s;
s = splbio();
icp_event_oldidx = icp_event_lastidx = 0;
memset(icp_event_buffer, 0, sizeof(icp_event_buffer));
splx(s);
}

259
sys/dev/ic/icp_ioctl.c Normal file
View File

@ -0,0 +1,259 @@
/* $NetBSD: icp_ioctl.c,v 1.1 2003/05/13 15:42:34 thorpej Exp $ */
/*-
* Copyright (c) 2003 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Jason R. Thorpe of Wasabi Systems, Inc.
*
* 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 NetBSD
* Foundation, Inc. and its contributors.
* 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
*/
/*
* Copyright (c) 2000-01 Intel Corporation
* 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.
*
* 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.
*/
/*
* icp_ioctl.c: Ioctl interface for the ICP-Vortex management tools.
*
* Based on ICP's FreeBSD "iir" driver ioctl interface, written by
* Achim Leubner <achim.leubner@intel.com>.
*
* This is intended to be ABI-compatile with the ioctl interface for
* other OSs.
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: icp_ioctl.c,v 1.1 2003/05/13 15:42:34 thorpej Exp $");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/device.h>
#include <sys/proc.h>
#include <sys/conf.h>
#include <sys/ioctl.h>
#include <machine/bus.h>
#include <dev/ic/icpreg.h>
#include <dev/ic/icpvar.h>
/* These are simply the same as ICP's "iir" driver for FreeBSD. */
#define ICP_DRIVER_VERSION 1
#define ICP_DRIVER_SUBVERSION 3
static dev_type_open(icpopen);
static dev_type_ioctl(icpioctl);
const struct cdevsw icp_cdevsw = {
icpopen, nullclose, noread, nowrite, icpioctl,
nostop, notty, nopoll, nommap, nokqfilter,
};
extern struct cfdriver icp_cd;
static int
icpopen(dev_t dev, int flag, int mode, struct proc *p)
{
if (device_lookup(&icp_cd, minor(dev)) == NULL)
return (ENXIO);
return (0);
}
static int
icpioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
{
int error = 0;
switch (cmd) {
case GDT_IOCTL_GENERAL:
{
struct icp_softc *icp;
gdt_ucmd_t *ucmd = (void *) data;
icp = device_lookup(&icp_cd, ucmd->io_node);
if (icp == NULL)
return (ENXIO);
error = icp_ucmd(icp, ucmd);
break;
}
case GDT_IOCTL_DRVERS:
*(int *) data =
(ICP_DRIVER_VERSION << 8) | ICP_DRIVER_SUBVERSION;
break;
case GDT_IOCTL_CTRTYPE:
{
struct icp_softc *icp;
gdt_ctrt_t *p = (void *) data;
icp = device_lookup(&icp_cd, p->io_node);
if (icp == NULL)
return (ENXIO);
/* XXX magic numbers */
p->oem_id = 0x8000;
p->type = 0xfd;
p->info = (icp->icp_pci_bus << 8) | (icp->icp_pci_device << 3);
p->ext_type = 0x6000 | icp->icp_pci_subdevice_id;
p->device_id = icp->icp_pci_device_id;
p->sub_device_id = icp->icp_pci_subdevice_id;
break;
}
case GDT_IOCTL_OSVERS:
{
gdt_osv_t *p = (void *) data;
p->oscode = 12;
/*
* __NetBSD_Version__ is encoded thusly:
*
* MMmmrrpp00
*
* M = major version
* m = minor version
* r = release ["",A-Z[A-Z] but numeric]
* p = patchlevel
*
* Since the ABI is not supposed to change between
* patchlevels of the same major/minor version, we
* will encode major/minor/release into the returned
* data.
*/
p->version = __NetBSD_Version__ / 100000000;
p->subversion = (__NetBSD_Version__ / 1000000) % 100;
p->revision = (__NetBSD_Version__ / 10000) % 100;
strcpy(p->name, ostype);
break;
}
case GDT_IOCTL_CTRCNT:
*(int *) data = icp_count;
break;
case GDT_IOCTL_EVENT:
{
struct icp_softc *icp;
gdt_event_t *p = (void *) data;
gdt_evt_str *e = &p->dvr;
int s;
icp = device_lookup(&icp_cd, minor(dev));
switch (p->erase) {
case 0xff:
switch (p->dvr.event_source) {
case GDT_ES_TEST:
e->event_data.size =
sizeof(e->event_data.eu.test);
break;
case GDT_ES_DRIVER:
e->event_data.size =
sizeof(e->event_data.eu.driver);
break;
case GDT_ES_SYNC:
e->event_data.size =
sizeof(e->event_data.eu.sync);
break;
default:
e->event_data.size =
sizeof(e->event_data.eu.async);
break;
}
s = splbio();
icp_store_event(icp, e->event_source, e->event_idx,
&e->event_data);
splx(s);
break;
case 0xfe:
s = splbio();
icp_clear_events(icp);
splx(s);
break;
case 0:
p->handle = icp_read_event(icp, p->handle, e);
break;
default:
icp_readapp_event(icp, (u_int8_t) p->erase, e);
break;
}
break;
}
case GDT_IOCTL_STATIST:
memcpy(&icp_stats, data, sizeof(gdt_statist_t));
break;
default:
return (ENOTTY);
}
return (error);
}

174
sys/dev/ic/icp_ioctl.h Normal file
View File

@ -0,0 +1,174 @@
/* $NetBSD: icp_ioctl.h,v 1.1 2003/05/13 15:42:34 thorpej Exp $ */
/*
* Copyright (c) 2000-03 Intel Corporation
* 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.
*
* 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.
*/
/*
* ioctl interface to ICP-Vortex RAID controllers. Facilitates use of
* ICP's configuration tools.
*/
#ifndef _DEV_IC_ICP_IOCTL_H_
#define _DEV_IC_ICP_IOCTL_H_
#include <sys/ioccom.h>
#include <dev/ic/icpreg.h>
#define GDT_SCRATCH_SZ 3072 /* 3KB scratch buffer */
/* general ioctl */
typedef struct gdt_ucmd {
u_int16_t io_node;
u_int16_t service;
u_int32_t timeout;
u_int16_t status;
u_int32_t info;
struct {
u_int32_t cmd_boardnode;
u_int32_t cmd_cmdindex;
u_int16_t cmd_opcode;
union {
struct icp_rawcmd rc;
struct icp_ioctlcmd ic;
struct icp_cachecmd cc;
} cmd_packet;
} __attribute__((__packed__)) command;
u_int8_t data[GDT_SCRATCH_SZ];
} __attribute__((__packed__)) gdt_ucmd_t;
#define GDT_IOCTL_GENERAL _IOWR('J', 0, gdt_ucmd_t)
/* get driver version */
#define GDT_IOCTL_DRVERS _IOWR('J', 1, int)
/* get controller type */
typedef struct gdt_ctrt {
u_int16_t io_node;
u_int16_t oem_id;
u_int16_t type;
u_int32_t info;
u_int8_t access;
u_int8_t remote;
u_int16_t ext_type;
u_int16_t device_id;
u_int16_t sub_device_id;
} __attribute__((__packed__)) gdt_ctrt_t;
#define GDT_IOCTL_CTRTYPE _IOR('J', 2, gdt_ctrt_t)
/* get OS version */
typedef struct gdt_osv {
u_int8_t oscode;
u_int8_t version;
u_int8_t subversion;
u_int16_t revision;
char name[64];
} __attribute__((__packed__)) gdt_osv_t;
#define GDT_IOCTL_OSVERS _IOR('J', 3, gdt_osv_t)
/* get controller count */
#define GDT_IOCTL_CTRCNT _IOR('J', 5, int)
/* 6 -- lock host drive? */
/* 7 -- lock channel? */
/* get event */
#define GDT_ES_ASYNC 1
#define GDT_ES_DRIVER 2
#define GDT_ES_TEST 3
#define GDT_ES_SYNC 4
typedef struct {
u_int16_t size; /* size of structure */
union {
char stream[16];
struct {
u_int16_t ionode;
u_int16_t service;
u_int32_t index;
} __attribute__((__packed__)) driver;
struct {
u_int16_t ionode;
u_int16_t service;
u_int16_t status;
u_int32_t info;
u_int8_t scsi_coord[3];
} __attribute__((__packed__)) async;
struct {
u_int16_t ionode;
u_int16_t service;
u_int16_t status;
u_int32_t info;
u_int16_t hostdrive;
u_int8_t scsi_coord[3];
u_int8_t sense_key;
} __attribute__((__packed__)) sync;
struct {
u_int32_t l1;
u_int32_t l2;
u_int32_t l3;
u_int32_t l4;
} __attribute__((__packed__)) test;
} eu;
u_int32_t severity;
u_int8_t event_string[256];
} __attribute__((__packed__)) gdt_evt_data;
typedef struct {
u_int32_t first_stamp;
u_int32_t last_stamp;
u_int16_t same_count;
u_int16_t event_source;
u_int16_t event_idx;
u_int8_t application;
u_int8_t reserved;
gdt_evt_data event_data;
} __attribute__((__packed__)) gdt_evt_str;
typedef struct gdt_event {
int erase;
int handle;
gdt_evt_str dvr;
} __attribute__((__packed__)) gdt_event_t;
#define GDT_IOCTL_EVENT _IOWR('J', 7, gdt_event_t)
/* get statistics */
typedef struct gdt_statist {
u_int16_t io_count_act;
u_int16_t io_count_max;
u_int16_t req_queue_act;
u_int16_t req_queue_max;
u_int16_t cmd_index_act;
u_int16_t cmd_index_max;
u_int16_t sg_count_act;
u_int16_t sg_count_max;
} __attribute__((__packed__)) gdt_statist_t;
#define GDT_IOCTL_STATIST _IOR('J', 9, gdt_statist_t)
#endif /* _DEV_IC_ICP_IOCTL_H_ */

View File

@ -1,4 +1,4 @@
/* $NetBSD: icpreg.h,v 1.1 2002/04/22 21:05:21 ad Exp $ */
/* $NetBSD: icpreg.h,v 1.2 2003/05/13 15:42:34 thorpej Exp $ */
/*-
* Copyright (c) 2002 The NetBSD Foundation, Inc.
@ -82,6 +82,7 @@
#define ICP_LOCALBOARD 0 /* Board node always 0 */
#define ICP_MAX_CMDS 124
#define ICP_SECTOR_SIZE 0x200 /* Always 512 bytes for cache devs */
#define ICP_MAX_EVENTS 0x100 /* event buffer */
/* DPMEM constants */
#define ICP_MPR_MAGIC 0xc0ffee11
@ -140,17 +141,8 @@
#define ICP_IO_CHANNEL 0x20000 /* default IO channel */
#define ICP_INVALID_CHANNEL 0xffff /* invalid channel */
/* IOCTLs */
#define ICPIOCTL_MASK ('J' << 8)
#define ICPIOCTL_GENERAL (ICPIOCTL_MASK | 0) /* general IOCTL */
#define ICPIOCTL_DRVERS (ICPIOCTL_MASK | 1) /* get driver version */
#define ICPIOCTL_CTRTYPE (ICPIOCTL_MASK | 2) /* get controller type */
#define ICPIOCTL_CTRCNT (ICPIOCTL_MASK | 5) /* get controller count */
#define ICPIOCTL_LOCKDRV (ICPIOCTL_MASK | 6) /* lock host drive */
#define ICPIOCTL_LOCKCHN (ICPIOCTL_MASK | 7) /* lock channel */
#define ICPIOCTL_EVENT (ICPIOCTL_MASK | 8) /* read controller events */
/* Service errors */
#define ICP_S_MSG_REQUEST 0 /* screen service: async evt message */
#define ICP_S_OK 1 /* no error */
#define ICP_S_BSY 7 /* controller busy */
#define ICP_S_RAW_SCSI 12 /* raw service: target error */

View File

@ -1,4 +1,4 @@
/* $NetBSD: icpsp.c,v 1.6 2002/10/02 16:33:32 thorpej Exp $ */
/* $NetBSD: icpsp.c,v 1.7 2003/05/13 15:42:34 thorpej Exp $ */
/*-
* Copyright (c) 2002 The NetBSD Foundation, Inc.
@ -37,7 +37,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: icpsp.c,v 1.6 2002/10/02 16:33:32 thorpej Exp $");
__KERNEL_RCSID(0, "$NetBSD: icpsp.c,v 1.7 2003/05/13 15:42:34 thorpej Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@ -162,7 +162,11 @@ icpsp_scsipi_request(struct scsipi_channel *chan, scsipi_adapter_req_t req,
/*
* Allocate a CCB.
*/
ic = icp_ccb_alloc(icp);
if (__predict_false((ic = icp_ccb_alloc(icp)) == NULL)) {
xs->error = XS_RESOURCE_SHORTAGE;
scsipi_done(xs);
return;
}
rc = &ic->ic_cmd.cmd_packet.rc;
ic->ic_sg = rc->rc_sg;
ic->ic_service = ICP_SCSIRAWSERVICE;

View File

@ -1,11 +1,11 @@
/* $NetBSD: icpvar.h,v 1.1 2002/04/22 21:05:21 ad Exp $ */
/* $NetBSD: icpvar.h,v 1.2 2003/05/13 15:42:34 thorpej Exp $ */
/*-
* Copyright (c) 2002 The NetBSD Foundation, Inc.
* Copyright (c) 2002, 2003 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Andrew Doran.
* by Andrew Doran, and by Jason R. Thorpe of Wasabi Systems, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@ -41,6 +41,8 @@
#include "locators.h"
#include <dev/ic/icp_ioctl.h>
/*
* Miscellaneous constants.
*/
@ -48,9 +50,11 @@
#define ICP_WATCHDOG_FREQ 5
#define ICP_BUSY_WAIT_MS 2500
#define ICP_MAX_XFER 65536
#define ICP_SCRATCH_SIZE 8192
#define ICP_UCMD_SCRATCH_SIZE 4096
#define ICP_SCRATCH_SIZE (8192 + ICP_UCMD_SCRATCH_SIZE)
#define ICP_SCRATCH_SENSE \
(ICP_SCRATCH_SIZE - sizeof(struct scsipi_sense_data) * ICP_NCCBS)
#define ICP_SCRATCH_UCMD (ICP_SCRATCH_SENSE - ICP_UCMD_SCRATCH_SIZE)
#define ICP_NCCBS ICP_MAX_CMDS
#define ICP_NCCB_RESERVE 4
@ -90,6 +94,7 @@ struct icp_ccb {
#define IC_WAITING 0x04 /* We have waiters */
#define IC_COMPLETE 0x08 /* Command completed */
#define IC_ALLOCED 0x10 /* CCB allocated */
#define IC_UCMD 0x20 /* user ioctl */
/*
* Logical drive information.
@ -114,6 +119,7 @@ struct icp_softc {
bus_addr_t icp_iobase;
int icp_class;
u_int16_t icp_fw_vers;
u_int16_t icp_ic_all_size;
u_int8_t icp_bus_cnt;
u_int8_t icp_bus_id[ICP_MAXBUS];
@ -124,6 +130,7 @@ struct icp_softc {
u_int32_t icp_info;
u_int32_t icp_info2;
u_int16_t icp_status;
u_int16_t icp_service;
bus_dmamap_t icp_scr_dmamap;
bus_dma_segment_t icp_scr_seg[1];
@ -131,10 +138,17 @@ struct icp_softc {
struct icp_ccb *icp_ccbs;
u_int icp_nccbs;
u_int icp_flags;
SIMPLEQ_HEAD(,icp_ccb) icp_ccb_freelist;
SIMPLEQ_HEAD(,icp_ccb) icp_ccb_queue;
SIMPLEQ_HEAD(,icp_ccb) icp_ucmd_queue;
struct callout icp_wdog_callout;
struct icp_ccb *icp_ucmd_ccb;
/* Temporary buffer for event data. */
gdt_evt_data icp_evt;
void (*icp_copy_cmd)(struct icp_softc *, struct icp_ccb *);
u_int8_t (*icp_get_status)(struct icp_softc *);
void (*icp_intr)(struct icp_softc *, struct icp_intr_ctx *);
@ -142,8 +156,46 @@ struct icp_softc {
struct icp_ccb *);
void (*icp_set_sema0)(struct icp_softc *);
int (*icp_test_busy)(struct icp_softc *);
/*
* This info is needed by the user ioctl interface needed to
* support the ICP configuration tools.
*/
int icp_pci_bus;
int icp_pci_device;
int icp_pci_device_id;
int icp_pci_subdevice_id;
};
/* icp_flags */
#define ICP_F_WAIT_CCB 0x01 /* someone waiting for CCBs */
#define ICP_HAS_WORK(icp) \
(! SIMPLEQ_EMPTY(&(icp)->icp_ccb_queue) || \
! SIMPLEQ_EMPTY(&(icp)->icp_ucmd_queue))
#define ICP_STAT_INCR(icp, x) \
do { \
/* XXX Globals, for now. XXX */ \
icp_stats. ## x ## _act++; \
if (icp_stats. ## x ## _act > icp_stats. ## x ## _max) \
icp_stats. ## x ## _max = icp_stats. ## x ## _act; \
} while (/*CONSTCOND*/0)
#define ICP_STAT_SET(icp, x, v) \
do { \
/* XXX Globals, for now. XXX */ \
icp_stats. ## x ## _act = (v); \
if (icp_stats. ## x ## _act > icp_stats. ## x ## _max) \
icp_stats. ## x ## _max = icp_stats. ## x ## _act; \
} while (/*CONSTCOND*/0)
#define ICP_STAT_DECR(icp, x) \
do { \
/* XXX Globals, for now. XXX */ \
icp_stats. ## x ## _act--; \
} while (/*CONSTCOND*/0)
#define ICP_ISA 0x01
#define ICP_EISA 0x02
#define ICP_PCI 0x03
@ -156,6 +208,9 @@ struct icp_softc {
int icp_init(struct icp_softc *, const char *);
int icp_intr(void *);
extern int icp_count;
extern gdt_statist_t icp_stats;
/*
* Consumer interface.
*/
@ -168,13 +223,22 @@ struct icp_attach_args {
#define ICPA_UNIT_SCSI 100
struct icp_ccb *icp_ccb_alloc(struct icp_softc *);
struct icp_ccb *icp_ccb_alloc_wait(struct icp_softc *);
void icp_ccb_enqueue(struct icp_softc *, struct icp_ccb *);
void icp_ccb_free(struct icp_softc *, struct icp_ccb *);
int icp_ccb_map(struct icp_softc *, struct icp_ccb *, void *, int, int);
int icp_ccb_poll(struct icp_softc *, struct icp_ccb *, int);
void icp_ccb_unmap(struct icp_softc *, struct icp_ccb *);
int icp_ccb_wait(struct icp_softc *, struct icp_ccb *, int);
int icp_ccb_wait_user(struct icp_softc *, struct icp_ccb *, int);
int icp_cmd(struct icp_softc *, u_int8_t, u_int16_t, u_int32_t, u_int32_t,
u_int32_t);
int icp_ucmd(struct icp_softc *, gdt_ucmd_t *);
gdt_evt_str *icp_store_event(struct icp_softc *, u_int16_t, u_int16_t,
gdt_evt_data *);
int icp_read_event(struct icp_softc *, int, gdt_evt_str *);
void icp_readapp_event(struct icp_softc *, u_int8_t, gdt_evt_str *);
void icp_clear_events(struct icp_softc *);
#endif /* !_IC_ICPVAR_H_ */

View File

@ -1,4 +1,4 @@
/* $NetBSD: ld_icp.c,v 1.5 2002/10/02 16:33:33 thorpej Exp $ */
/* $NetBSD: ld_icp.c,v 1.6 2003/05/13 15:42:34 thorpej Exp $ */
/*-
* Copyright (c) 2002 The NetBSD Foundation, Inc.
@ -41,7 +41,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: ld_icp.c,v 1.5 2002/10/02 16:33:33 thorpej Exp $");
__KERNEL_RCSID(0, "$NetBSD: ld_icp.c,v 1.6 2003/05/13 15:42:34 thorpej Exp $");
#include "rnd.h"
@ -183,7 +183,13 @@ ld_icp_dobio(struct ld_icp_softc *sc, void *data, int datasize, int blkno,
/*
* Allocate a command control block.
*/
ic = icp_ccb_alloc(icp);
if (__predict_false((ic = icp_ccb_alloc(icp)) == NULL)) {
/*
* XXX Redo the way buffer queueing is done in
* XXX the ld driver.
*/
return (EAGAIN);
}
/*
* Map the data transfer.
@ -259,7 +265,7 @@ ld_icp_flush(struct ld_softc *ld)
sc = (struct ld_icp_softc *)ld;
icp = (struct icp_softc *)ld->sc_dv.dv_parent;
ic = icp_ccb_alloc(icp);
ic = icp_ccb_alloc_wait(icp);
ic->ic_cmd.cmd_opcode = htole16(ICP_FLUSH);
cc = &ic->ic_cmd.cmd_packet.cc;
@ -295,6 +301,18 @@ ld_icp_intr(struct icp_ccb *ic)
bp->b_flags |= B_ERROR;
bp->b_error = EIO;
bp->b_resid = bp->b_bcount;
icp->icp_evt.size = sizeof(icp->icp_evt.eu.sync);
icp->icp_evt.eu.sync.ionode = icp->icp_dv.dv_unit;
icp->icp_evt.eu.sync.service = icp->icp_service;
icp->icp_evt.eu.sync.status = icp->icp_status;
icp->icp_evt.eu.sync.info = icp->icp_info;
icp->icp_evt.eu.sync.hostdrive = sc->sc_hwunit;
if (icp->icp_status >= 0x8000)
icp_store_event(icp, GDT_ES_SYNC, 0, &icp->icp_evt);
else
icp_store_event(icp, GDT_ES_SYNC, icp->icp_service,
&icp->icp_evt);
} else
bp->b_resid = 0;

View File

@ -1,4 +1,4 @@
/* $NetBSD: icp_pci.c,v 1.7 2003/01/31 00:07:42 thorpej Exp $ */
/* $NetBSD: icp_pci.c,v 1.8 2003/05/13 15:42:34 thorpej Exp $ */
/*-
* Copyright (c) 2002 The NetBSD Foundation, Inc.
@ -76,7 +76,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: icp_pci.c,v 1.7 2003/01/31 00:07:42 thorpej Exp $");
__KERNEL_RCSID(0, "$NetBSD: icp_pci.c,v 1.8 2003/05/13 15:42:34 thorpej Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@ -152,6 +152,8 @@ __KERNEL_RCSID(0, "$NetBSD: icp_pci.c,v 1.7 2003/01/31 00:07:42 thorpej Exp $");
#define ICP_MPR_LDOOR 0x20 /* u_int8_t, PCI to local doorbell */
#define ICP_MPR_EDOOR 0x2c /* volatile u_int8_t, locl to PCI doorbell */
#define ICP_EDOOR_EN 0x34 /* u_int8_t, board interrupts enable */
#define ICP_SEVERITY 0xefc /* u_int8_t, event severity */
#define ICP_EVT_BUF 0xf00 /* u_int8_t [256], event buffer */
#define ICP_I960_SZ 0x1000
/* DPRAM PCI MPR controllers */
@ -569,6 +571,12 @@ icp_pci_attach(struct device *parent, struct device *self, void *aux)
else
aprint_normal("ICP-Vortex RAID controller\n");
icp->icp_pci_bus = pa->pa_bus;
icp->icp_pci_device = pa->pa_device;
icp->icp_pci_device_id = pa->pa_id;
icp->icp_pci_subdevice_id = pci_conf_read(pa->pa_pc, pa->pa_tag,
PCI_SUBSYS_ID_REG);
if (icp_init(icp, intrstr))
goto bail_out;
@ -760,9 +768,24 @@ icp_mpr_intr(struct icp_softc *icp, struct icp_intr_ctx *ctx)
ctx->info2 = bus_space_read_4(icp->icp_dpmemt, icp->icp_dpmemh,
ICP_MPR_INFO + sizeof(u_int32_t));
/*
* XXX Read async event string here.
*/
if (ctx->istatus == ICP_ASYNCINDEX) {
if (ctx->service != ICP_SCREENSERVICE &&
(icp->icp_fw_vers & 0xff) >= 0x1a) {
int i;
icp->icp_evt.severity =
bus_space_read_1(icp->icp_dpmemt,
icp->icp_dpmemh, ICP_SEVERITY);
for (i = 0;
i < sizeof(icp->icp_evt.event_string); i++) {
icp->icp_evt.event_string[i] =
bus_space_read_1(icp->icp_dpmemt,
icp->icp_dpmemh, ICP_EVT_BUF + i);
if (icp->icp_evt.event_string[i] == '\0')
break;
}
}
}
bus_space_write_1(icp->icp_dpmemt, icp->icp_dpmemh, ICP_MPR_EDOOR,
0xff);