diff --git a/sys/conf/files b/sys/conf/files index 91905acb3c84..6cd47848d70b 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -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 diff --git a/sys/dev/ic/Makefile b/sys/dev/ic/Makefile index 7b2ef27213f8..2dc62bfec295 100644 --- a/sys/dev/ic/Makefile +++ b/sys/dev/ic/Makefile @@ -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 diff --git a/sys/dev/ic/icp.c b/sys/dev/ic/icp.c index 963a1f54fa2f..4b05e5e365f0 100644 --- a/sys/dev/ic/icp.c +++ b/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 */ #include -__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 #include @@ -101,12 +105,26 @@ __KERNEL_RCSID(0, "$NetBSD: icp.c,v 1.7 2003/01/31 00:26:30 thorpej Exp $"); #include #include +#include +#include + 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); +} diff --git a/sys/dev/ic/icp_ioctl.c b/sys/dev/ic/icp_ioctl.c new file mode 100644 index 000000000000..54ed7f7560d9 --- /dev/null +++ b/sys/dev/ic/icp_ioctl.c @@ -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 . + * + * This is intended to be ABI-compatile with the ioctl interface for + * other OSs. + */ + +#include +__KERNEL_RCSID(0, "$NetBSD: icp_ioctl.c,v 1.1 2003/05/13 15:42:34 thorpej Exp $"); + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +/* 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); +} diff --git a/sys/dev/ic/icp_ioctl.h b/sys/dev/ic/icp_ioctl.h new file mode 100644 index 000000000000..fa4858b19d22 --- /dev/null +++ b/sys/dev/ic/icp_ioctl.h @@ -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 +#include + +#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_ */ diff --git a/sys/dev/ic/icpreg.h b/sys/dev/ic/icpreg.h index 69e5bceaf4b0..92ad371af053 100644 --- a/sys/dev/ic/icpreg.h +++ b/sys/dev/ic/icpreg.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 */ diff --git a/sys/dev/ic/icpsp.c b/sys/dev/ic/icpsp.c index 197253dc151e..fd8024cd0ffd 100644 --- a/sys/dev/ic/icpsp.c +++ b/sys/dev/ic/icpsp.c @@ -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 -__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 #include @@ -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; diff --git a/sys/dev/ic/icpvar.h b/sys/dev/ic/icpvar.h index c166871d83bb..8b21a2efeda6 100644 --- a/sys/dev/ic/icpvar.h +++ b/sys/dev/ic/icpvar.h @@ -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 + /* * 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_ */ diff --git a/sys/dev/ic/ld_icp.c b/sys/dev/ic/ld_icp.c index 65ed0af63b64..d20b5cd5d55d 100644 --- a/sys/dev/ic/ld_icp.c +++ b/sys/dev/ic/ld_icp.c @@ -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 -__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; diff --git a/sys/dev/pci/icp_pci.c b/sys/dev/pci/icp_pci.c index ab87c37819e2..feb26e6ea829 100644 --- a/sys/dev/pci/icp_pci.c +++ b/sys/dev/pci/icp_pci.c @@ -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 -__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 #include @@ -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);