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:
parent
bf026fa41a
commit
405790a85a
@ -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
|
||||
|
@ -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>
|
||||
|
456
sys/dev/ic/icp.c
456
sys/dev/ic/icp.c
@ -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
259
sys/dev/ic/icp_ioctl.c
Normal 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
174
sys/dev/ic/icp_ioctl.h
Normal 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_ */
|
@ -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 */
|
||||
|
@ -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;
|
||||
|
@ -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_ */
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user