Add support for dynamic rescan of cache service logical drives, using
the ioctl issued by the ICP RAID management libraries (used by the storcon and iirconfig tools). This requires some infrastructure changes: * Add a "service callback" mechanism that the ld driver (cache service) and the iopsp driver (raw service) can register with the icp parent. Right now this callback allows the children to adjust their notion of how many command openings are available. * Add a mutex around the icp ioctl handler, allowing only one thread to execute an ioctl at a time. * Add a way to freeze the controller command queue. We stop all I/O while processing rescans (due to the semantics of icp_cmd()). * Make icp_cmd() work when !cold. * Add detach support to ld@icp.
This commit is contained in:
parent
f7f6440dff
commit
3178a4f415
287
sys/dev/ic/icp.c
287
sys/dev/ic/icp.c
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: icp.c,v 1.9 2003/05/17 15:34:12 thorpej Exp $ */
|
||||
/* $NetBSD: icp.c,v 1.10 2003/06/13 05:57:30 thorpej Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2002, 2003 The NetBSD Foundation, Inc.
|
||||
@ -76,11 +76,14 @@
|
||||
*
|
||||
* 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>
|
||||
* provided by Achim Leubner <achim.leubner@intel.com>.
|
||||
*
|
||||
* Additional support for dynamic rescan of cacheservice drives by
|
||||
* Jason R. Thorpe of Wasabi Systems, Inc.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: icp.c,v 1.9 2003/05/17 15:34:12 thorpej Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: icp.c,v 1.10 2003/06/13 05:57:30 thorpej Exp $");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
@ -115,6 +118,7 @@ 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 *);
|
||||
void icp_recompute_openings(struct icp_softc *);
|
||||
|
||||
int icp_count; /* total # of controllers, for ioctl interface */
|
||||
|
||||
@ -133,11 +137,9 @@ icp_init(struct icp_softc *icp, const char *intrstr)
|
||||
struct icp_binfo binfo;
|
||||
struct icp_ccb *ic;
|
||||
u_int16_t cdev_cnt;
|
||||
int i, j, state, feat, nsegs, rv, noscsi, nocache;
|
||||
int i, j, state, feat, nsegs, rv;
|
||||
|
||||
state = 0;
|
||||
noscsi = 0;
|
||||
nocache = 0;
|
||||
|
||||
if (intrstr != NULL)
|
||||
aprint_normal("%s: interrupting at %s\n", icp->icp_dv.dv_xname,
|
||||
@ -267,8 +269,8 @@ icp_init(struct icp_softc *icp, const char *intrstr)
|
||||
"%s: scatter/gather not supported (raw service)\n",
|
||||
icp->icp_dv.dv_xname);
|
||||
#endif
|
||||
noscsi = 1;
|
||||
}
|
||||
} else
|
||||
icp->icp_features |= ICP_FEAT_RAWSERVICE;
|
||||
|
||||
/*
|
||||
* Set/get cache service features (scatter/gather).
|
||||
@ -285,8 +287,8 @@ icp_init(struct icp_softc *icp, const char *intrstr)
|
||||
"%s: scatter/gather not supported (cache service)\n",
|
||||
icp->icp_dv.dv_xname);
|
||||
#endif
|
||||
nocache = 1;
|
||||
}
|
||||
} else
|
||||
icp->icp_features |= ICP_FEAT_CACHESERVICE;
|
||||
|
||||
/*
|
||||
* Pull some information from the board and dump.
|
||||
@ -308,14 +310,15 @@ icp_init(struct icp_softc *icp, const char *intrstr)
|
||||
* Determine the number of devices, and number of openings per
|
||||
* device.
|
||||
*/
|
||||
if (!nocache) {
|
||||
if (icp->icp_features & ICP_FEAT_CACHESERVICE) {
|
||||
for (j = 0; j < cdev_cnt && j < ICP_MAX_HDRIVES; j++) {
|
||||
if (!icp_cmd(icp, ICP_CACHESERVICE, ICP_INFO, j, 0,
|
||||
0))
|
||||
continue;
|
||||
|
||||
icp->icp_cdr[j].cd_size = icp->icp_info;
|
||||
icp->icp_ndevs++;
|
||||
if (icp->icp_cdr[j].cd_size != 0)
|
||||
icp->icp_ndevs++;
|
||||
|
||||
if (icp_cmd(icp, ICP_CACHESERVICE, ICP_DEVTYPE, j, 0,
|
||||
0))
|
||||
@ -323,21 +326,17 @@ icp_init(struct icp_softc *icp, const char *intrstr)
|
||||
}
|
||||
}
|
||||
|
||||
if (!noscsi)
|
||||
icp->icp_ndevs += binfo.bi_chan_count;
|
||||
if (icp->icp_features & ICP_FEAT_RAWSERVICE) {
|
||||
icp->icp_nchan = binfo.bi_chan_count;
|
||||
icp->icp_ndevs += icp->icp_nchan;
|
||||
}
|
||||
|
||||
if (icp->icp_ndevs != 0)
|
||||
icp->icp_openings =
|
||||
(icp->icp_nccbs - ICP_NCCB_RESERVE) / icp->icp_ndevs;
|
||||
#ifdef ICP_DEBUG
|
||||
aprint_debug("%s: %d openings per device\n", icp->icp_dv.dv_xname,
|
||||
icp->icp_openings);
|
||||
#endif
|
||||
icp_recompute_openings(icp);
|
||||
|
||||
/*
|
||||
* Attach SCSI channels.
|
||||
*/
|
||||
if (!noscsi) {
|
||||
if (icp->icp_features & ICP_FEAT_RAWSERVICE) {
|
||||
struct icp_ioc_version *iv;
|
||||
struct icp_rawioc *ri;
|
||||
struct icp_getch *gc;
|
||||
@ -380,7 +379,8 @@ icp_init(struct icp_softc *icp, const char *intrstr)
|
||||
icp->icp_bus_id[j] = ICP_MAXID_FC;
|
||||
|
||||
icpa.icpa_unit = j + ICPA_UNIT_SCSI;
|
||||
config_found_sm(&icp->icp_dv, &icpa, icp_print,
|
||||
icp->icp_children[icpa.icpa_unit] =
|
||||
config_found_sm(&icp->icp_dv, &icpa, icp_print,
|
||||
icp_submatch);
|
||||
}
|
||||
}
|
||||
@ -388,13 +388,14 @@ icp_init(struct icp_softc *icp, const char *intrstr)
|
||||
/*
|
||||
* Attach cache devices.
|
||||
*/
|
||||
if (!nocache) {
|
||||
if (icp->icp_features & ICP_FEAT_CACHESERVICE) {
|
||||
for (j = 0; j < cdev_cnt && j < ICP_MAX_HDRIVES; j++) {
|
||||
if (icp->icp_cdr[j].cd_size == 0)
|
||||
continue;
|
||||
|
||||
icpa.icpa_unit = j;
|
||||
config_found_sm(&icp->icp_dv, &icpa, icp_print,
|
||||
icp->icp_children[icpa.icpa_unit] =
|
||||
config_found_sm(&icp->icp_dv, &icpa, icp_print,
|
||||
icp_submatch);
|
||||
}
|
||||
}
|
||||
@ -430,6 +431,165 @@ icp_init(struct icp_softc *icp, const char *intrstr)
|
||||
return (1);
|
||||
}
|
||||
|
||||
void
|
||||
icp_register_servicecb(struct icp_softc *icp, int unit,
|
||||
const struct icp_servicecb *cb)
|
||||
{
|
||||
|
||||
icp->icp_servicecb[unit] = cb;
|
||||
}
|
||||
|
||||
void
|
||||
icp_rescan(struct icp_softc *icp, int unit)
|
||||
{
|
||||
struct icp_attach_args icpa;
|
||||
u_int newsize, newtype;
|
||||
|
||||
/*
|
||||
* NOTE: It is very important that the queue be frozen and not
|
||||
* commands running when this is called. The ioctl mutex must
|
||||
* also be held.
|
||||
*/
|
||||
|
||||
KASSERT(icp->icp_qfreeze != 0);
|
||||
KASSERT(icp->icp_running == 0);
|
||||
KASSERT(unit < ICP_MAX_HDRIVES);
|
||||
|
||||
if (!icp_cmd(icp, ICP_CACHESERVICE, ICP_INFO, unit, 0, 0)) {
|
||||
#ifdef ICP_DEBUG
|
||||
printf("%s: rescan: unit %d ICP_INFO failed -> 0x%04x\n",
|
||||
icp->icp_dv.dv_xname, unit, icp->icp_status);
|
||||
#endif
|
||||
goto gone;
|
||||
}
|
||||
if ((newsize = icp->icp_info) == 0) {
|
||||
#ifdef ICP_DEBUG
|
||||
printf("%s: rescan: unit %d has zero size\n",
|
||||
icp->icp_dv.dv_xname, unit);
|
||||
#endif
|
||||
gone:
|
||||
/*
|
||||
* Host drive is no longer present; detach if a child
|
||||
* is currently there.
|
||||
*/
|
||||
if (icp->icp_cdr[unit].cd_size != 0)
|
||||
icp->icp_ndevs--;
|
||||
icp->icp_cdr[unit].cd_size = 0;
|
||||
if (icp->icp_children[unit] != NULL) {
|
||||
(void) config_detach(icp->icp_children[unit],
|
||||
DETACH_FORCE);
|
||||
icp->icp_children[unit] = NULL;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (icp_cmd(icp, ICP_CACHESERVICE, ICP_DEVTYPE, unit, 0, 0))
|
||||
newtype = icp->icp_info;
|
||||
else {
|
||||
#ifdef ICP_DEBUG
|
||||
printf("%s: rescan: unit %d ICP_DEVTYPE failed\n",
|
||||
icp->icp_dv.dv_xname, unit);
|
||||
#endif
|
||||
newtype = 0; /* XXX? */
|
||||
}
|
||||
|
||||
#ifdef ICP_DEBUG
|
||||
printf("%s: rescan: unit %d old %u/%u, new %u/%u\n",
|
||||
icp->icp_dv.dv_xname, unit, icp->icp_cdr[unit].cd_size,
|
||||
icp->icp_cdr[unit].cd_type, newsize, newtype);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* If the type or size changed, detach any old child (if it exists)
|
||||
* and attach a new one.
|
||||
*/
|
||||
if (icp->icp_children[unit] == NULL ||
|
||||
newsize != icp->icp_cdr[unit].cd_size ||
|
||||
newtype != icp->icp_cdr[unit].cd_type) {
|
||||
if (icp->icp_cdr[unit].cd_size == 0)
|
||||
icp->icp_ndevs++;
|
||||
icp->icp_cdr[unit].cd_size = newsize;
|
||||
icp->icp_cdr[unit].cd_type = newtype;
|
||||
if (icp->icp_children[unit] != NULL)
|
||||
(void) config_detach(icp->icp_children[unit],
|
||||
DETACH_FORCE);
|
||||
|
||||
icpa.icpa_unit = unit;
|
||||
icp->icp_children[unit] = config_found_sm(&icp->icp_dv, &icpa,
|
||||
icp_print, icp_submatch);
|
||||
}
|
||||
|
||||
icp_recompute_openings(icp);
|
||||
}
|
||||
|
||||
void
|
||||
icp_rescan_all(struct icp_softc *icp)
|
||||
{
|
||||
int unit;
|
||||
u_int16_t cdev_cnt;
|
||||
|
||||
/*
|
||||
* This is the old method of rescanning the host drives. We
|
||||
* start by reinitializing the cache service.
|
||||
*/
|
||||
if (!icp_cmd(icp, ICP_CACHESERVICE, ICP_INIT, ICP_LINUX_OS, 0, 0)) {
|
||||
printf("%s: unable to re-initialize cache service for rescan\n",
|
||||
icp->icp_dv.dv_xname);
|
||||
return;
|
||||
}
|
||||
cdev_cnt = (u_int16_t) icp->icp_info;
|
||||
|
||||
/* For each host drive, do the new-style rescan. */
|
||||
for (unit = 0; unit < cdev_cnt && unit < ICP_MAX_HDRIVES; unit++)
|
||||
icp_rescan(icp, unit);
|
||||
|
||||
/* Now detach anything in the slots after cdev_cnt. */
|
||||
for (; unit < ICP_MAX_HDRIVES; unit++) {
|
||||
if (icp->icp_cdr[unit].cd_size != 0) {
|
||||
#ifdef ICP_DEBUG
|
||||
printf("%s: rescan all: unit %d < new cdev_cnt (%d)\n",
|
||||
icp->icp_dv.dv_xname, unit, cdev_cnt);
|
||||
#endif
|
||||
icp->icp_ndevs--;
|
||||
icp->icp_cdr[unit].cd_size = 0;
|
||||
if (icp->icp_children[unit] != NULL) {
|
||||
(void) config_detach(icp->icp_children[unit],
|
||||
DETACH_FORCE);
|
||||
icp->icp_children[unit] = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
icp_recompute_openings(icp);
|
||||
}
|
||||
|
||||
void
|
||||
icp_recompute_openings(struct icp_softc *icp)
|
||||
{
|
||||
int unit, openings;
|
||||
|
||||
if (icp->icp_ndevs != 0)
|
||||
openings =
|
||||
(icp->icp_nccbs - ICP_NCCB_RESERVE) / icp->icp_ndevs;
|
||||
else
|
||||
openings = 0;
|
||||
if (openings == icp->icp_openings)
|
||||
return;
|
||||
icp->icp_openings = openings;
|
||||
|
||||
#ifdef ICP_DEBUG
|
||||
printf("%s: %d device%s, %d openings per device\n",
|
||||
icp->icp_dv.dv_xname, icp->icp_ndevs,
|
||||
icp->icp_ndevs == 1 ? "" : "s", icp->icp_openings);
|
||||
#endif
|
||||
|
||||
for (unit = 0; unit < ICP_MAX_HDRIVES + ICP_MAXBUS; unit++) {
|
||||
if (icp->icp_children[unit] != NULL)
|
||||
(*icp->icp_servicecb[unit]->iscb_openings)(
|
||||
icp->icp_children[unit], icp->icp_openings);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
icp_watchdog(void *cookie)
|
||||
{
|
||||
@ -564,6 +724,17 @@ icp_intr(void *cookie)
|
||||
panic("icp_intr: inactive CCB identified");
|
||||
}
|
||||
|
||||
/*
|
||||
* Try to protect ourselves from the running command count already
|
||||
* being 0 (e.g. if a polled command times out).
|
||||
*/
|
||||
KDASSERT(icp->icp_running != 0);
|
||||
if (--icp->icp_running == 0 &&
|
||||
(icp->icp_flags & ICP_F_WAIT_FREEZE) != 0) {
|
||||
icp->icp_flags &= ~ICP_F_WAIT_FREEZE;
|
||||
wakeup(&icp->icp_qfreeze);
|
||||
}
|
||||
|
||||
switch (icp->icp_status) {
|
||||
case ICP_S_BSY:
|
||||
#ifdef ICP_DEBUG
|
||||
@ -873,7 +1044,7 @@ icp_ccb_enqueue(struct icp_softc *icp, struct icp_ccb *ic)
|
||||
SIMPLEQ_INSERT_TAIL(&icp->icp_ccb_queue, ic, ic_chain);
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
for (; icp->icp_qfreeze == 0;) {
|
||||
if (__predict_false((ic =
|
||||
SIMPLEQ_FIRST(&icp->icp_ucmd_queue)) != NULL)) {
|
||||
struct icp_ucmd_ctx *iu = ic->ic_context;
|
||||
@ -973,7 +1144,9 @@ icp_ccb_unmap(struct icp_softc *icp, struct icp_ccb *ic)
|
||||
int
|
||||
icp_ccb_poll(struct icp_softc *icp, struct icp_ccb *ic, int timo)
|
||||
{
|
||||
int rv;
|
||||
int s, rv;
|
||||
|
||||
s = splbio();
|
||||
|
||||
for (timo = ICP_BUSY_WAIT_MS * 100; timo != 0; timo--) {
|
||||
if (!(*icp->icp_test_busy)(icp))
|
||||
@ -987,11 +1160,22 @@ icp_ccb_poll(struct icp_softc *icp, struct icp_ccb *ic, int timo)
|
||||
|
||||
icp_ccb_submit(icp, ic);
|
||||
|
||||
for (timo *= 10; timo != 0; timo--) {
|
||||
DELAY(100);
|
||||
icp_intr(icp);
|
||||
if ((ic->ic_flags & IC_COMPLETE) != 0)
|
||||
break;
|
||||
if (cold) {
|
||||
for (timo *= 10; timo != 0; timo--) {
|
||||
DELAY(100);
|
||||
icp_intr(icp);
|
||||
if ((ic->ic_flags & IC_COMPLETE) != 0)
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
ic->ic_flags |= IC_WAITING;
|
||||
while ((ic->ic_flags & IC_COMPLETE) == 0) {
|
||||
if ((rv = tsleep(ic, PRIBIO, "icpwccb",
|
||||
mstohz(timo))) != 0) {
|
||||
timo = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (timo != 0) {
|
||||
@ -1011,6 +1195,8 @@ icp_ccb_poll(struct icp_softc *icp, struct icp_ccb *ic, int timo)
|
||||
while ((*icp->icp_test_busy)(icp) != 0)
|
||||
DELAY(10);
|
||||
|
||||
splx(s);
|
||||
|
||||
return (rv);
|
||||
}
|
||||
|
||||
@ -1074,10 +1260,47 @@ icp_ccb_submit(struct icp_softc *icp, struct icp_ccb *ic)
|
||||
ic->ic_cmd.cmd_boardnode = htole32(ICP_LOCALBOARD);
|
||||
ic->ic_cmd.cmd_cmdindex = htole32(ic->ic_ident);
|
||||
|
||||
icp->icp_running++;
|
||||
|
||||
(*icp->icp_copy_cmd)(icp, ic);
|
||||
(*icp->icp_release_event)(icp, ic);
|
||||
}
|
||||
|
||||
int
|
||||
icp_freeze(struct icp_softc *icp)
|
||||
{
|
||||
int s, error = 0;
|
||||
|
||||
s = splbio();
|
||||
if (icp->icp_qfreeze++ == 0) {
|
||||
while (icp->icp_running != 0) {
|
||||
icp->icp_flags |= ICP_F_WAIT_FREEZE;
|
||||
error = tsleep(&icp->icp_qfreeze, PRIBIO|PCATCH,
|
||||
"icpqfrz", 0);
|
||||
if (error != 0 && --icp->icp_qfreeze == 0 &&
|
||||
ICP_HAS_WORK(icp)) {
|
||||
icp_ccb_enqueue(icp, NULL);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
splx(s);
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
void
|
||||
icp_unfreeze(struct icp_softc *icp)
|
||||
{
|
||||
int s;
|
||||
|
||||
s = splbio();
|
||||
KDASSERT(icp->icp_qfreeze != 0);
|
||||
if (--icp->icp_qfreeze == 0 && ICP_HAS_WORK(icp))
|
||||
icp_ccb_enqueue(icp, NULL);
|
||||
splx(s);
|
||||
}
|
||||
|
||||
/* XXX Global - should be per-controller? XXX */
|
||||
static gdt_evt_str icp_event_buffer[ICP_MAX_EVENTS];
|
||||
static int icp_event_oldidx;
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: icp_ioctl.c,v 1.2 2003/05/18 06:18:25 thorpej Exp $ */
|
||||
/* $NetBSD: icp_ioctl.c,v 1.3 2003/06/13 05:57:30 thorpej Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2003 The NetBSD Foundation, Inc.
|
||||
@ -76,7 +76,7 @@
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: icp_ioctl.c,v 1.2 2003/05/18 06:18:25 thorpej Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: icp_ioctl.c,v 1.3 2003/06/13 05:57:30 thorpej Exp $");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
@ -105,6 +105,9 @@ const struct cdevsw icp_cdevsw = {
|
||||
|
||||
extern struct cfdriver icp_cd;
|
||||
|
||||
static struct lock icp_ioctl_mutex =
|
||||
LOCK_INITIALIZER(PRIBIO|PCATCH, "icplk", 0, 0);
|
||||
|
||||
static int
|
||||
icpopen(dev_t dev, int flag, int mode, struct proc *p)
|
||||
{
|
||||
@ -120,7 +123,10 @@ icpopen(dev_t dev, int flag, int mode, struct proc *p)
|
||||
static int
|
||||
icpioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
|
||||
{
|
||||
int error = 0;
|
||||
int error;
|
||||
|
||||
if ((error = lockmgr(&icp_ioctl_mutex, LK_EXCLUSIVE, NULL)) != 0)
|
||||
return (error);
|
||||
|
||||
switch (cmd) {
|
||||
case GDT_IOCTL_GENERAL:
|
||||
@ -129,8 +135,10 @@ icpioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
|
||||
gdt_ucmd_t *ucmd = (void *) data;
|
||||
|
||||
icp = device_lookup(&icp_cd, ucmd->io_node);
|
||||
if (icp == NULL)
|
||||
return (ENXIO);
|
||||
if (icp == NULL) {
|
||||
error = ENXIO;
|
||||
break;
|
||||
}
|
||||
|
||||
error = icp_ucmd(icp, ucmd);
|
||||
break;
|
||||
@ -147,8 +155,10 @@ icpioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
|
||||
gdt_ctrt_t *p = (void *) data;
|
||||
|
||||
icp = device_lookup(&icp_cd, p->io_node);
|
||||
if (icp == NULL)
|
||||
return (ENXIO);
|
||||
if (icp == NULL) {
|
||||
error = ENXIO;
|
||||
break;
|
||||
}
|
||||
|
||||
/* XXX magic numbers */
|
||||
p->oem_id = 0x8000;
|
||||
@ -253,9 +263,34 @@ icpioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
|
||||
memcpy(&icp_stats, data, sizeof(gdt_statist_t));
|
||||
break;
|
||||
|
||||
|
||||
case GDT_IOCTL_RESCAN:
|
||||
{
|
||||
struct icp_softc *icp;
|
||||
gdt_rescan_t *rsc = (void *) data;
|
||||
|
||||
icp = device_lookup(&icp_cd, rsc->io_node);
|
||||
if (icp == NULL) {
|
||||
error = ENXIO;
|
||||
break;
|
||||
}
|
||||
|
||||
error = icp_freeze(icp);
|
||||
if (error)
|
||||
break;
|
||||
if (rsc->flag == 0)
|
||||
icp_rescan_all(icp);
|
||||
else
|
||||
icp_rescan(icp, rsc->hdr_no);
|
||||
icp_unfreeze(icp);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
return (ENOTTY);
|
||||
error = ENOTTY;
|
||||
}
|
||||
|
||||
(void) lockmgr(&icp_ioctl_mutex, LK_RELEASE, NULL);
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: icp_ioctl.h,v 1.1 2003/05/13 15:42:34 thorpej Exp $ */
|
||||
/* $NetBSD: icp_ioctl.h,v 1.2 2003/06/13 05:57:30 thorpej Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2000-03 Intel Corporation
|
||||
@ -171,4 +171,18 @@ typedef struct gdt_statist {
|
||||
} __attribute__((__packed__)) gdt_statist_t;
|
||||
#define GDT_IOCTL_STATIST _IOR('J', 9, gdt_statist_t)
|
||||
|
||||
/* rescan host drives */
|
||||
typedef struct gdt_rescan {
|
||||
u_int16_t io_node;
|
||||
u_int8_t flag;
|
||||
u_int16_t hdr_no;
|
||||
struct {
|
||||
u_int8_t bus;
|
||||
u_int8_t target;
|
||||
u_int8_t lun;
|
||||
u_int8_t cluster_type;
|
||||
} __attribute__((__packed__)) hdr_list[ICP_MAX_HDRIVES];
|
||||
} __attribute__((__packed__)) gdt_rescan_t;
|
||||
#define GDT_IOCTL_RESCAN _IOWR('J', 11, gdt_rescan_t)
|
||||
|
||||
#endif /* _DEV_IC_ICP_IOCTL_H_ */
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: icpreg.h,v 1.2 2003/05/13 15:42:34 thorpej Exp $ */
|
||||
/* $NetBSD: icpreg.h,v 1.3 2003/06/13 05:57:30 thorpej Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2002 The NetBSD Foundation, Inc.
|
||||
@ -71,7 +71,8 @@
|
||||
#define _IC_ICPREG_H_
|
||||
|
||||
#define ICP_MAXBUS 6 /* XXX Why not 5? */
|
||||
#define ICP_MAX_HDRIVES 35 /* 5 busses * 7 targets XXX correct? */
|
||||
#define ICP_MAX_LDRIVES 255 /* max logical drive count */
|
||||
#define ICP_MAX_HDRIVES 100 /* max host drive count */
|
||||
#define ICP_MAXID_FC 127 /* Fibre-channel maximum ID */
|
||||
#define ICP_MAXOFFSETS 128
|
||||
#define ICP_MAXSG 17 /* Max. s/g elements; actually 128 */
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: icpsp.c,v 1.7 2003/05/13 15:42:34 thorpej Exp $ */
|
||||
/* $NetBSD: icpsp.c,v 1.8 2003/06/13 05:57:31 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.7 2003/05/13 15:42:34 thorpej Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: icpsp.c,v 1.8 2003/06/13 05:57:31 thorpej Exp $");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
@ -70,6 +70,7 @@ struct icpsp_softc {
|
||||
struct scsipi_adapter sc_adapter;
|
||||
struct scsipi_channel sc_channel;
|
||||
int sc_busno;
|
||||
int sc_openings;
|
||||
};
|
||||
|
||||
void icpsp_attach(struct device *, struct device *, void *);
|
||||
@ -78,9 +79,15 @@ int icpsp_match(struct device *, struct cfdata *, void *);
|
||||
void icpsp_scsipi_request(struct scsipi_channel *, scsipi_adapter_req_t,
|
||||
void *);
|
||||
|
||||
void icpsp_adjqparam(struct device *, int);
|
||||
|
||||
CFATTACH_DECL(icpsp, sizeof(struct icpsp_softc),
|
||||
icpsp_match, icpsp_attach, NULL, NULL);
|
||||
|
||||
static const struct icp_servicecb icpsp_servicecb = {
|
||||
icpsp_adjqparam,
|
||||
};
|
||||
|
||||
int
|
||||
icpsp_match(struct device *parent, struct cfdata *match, void *aux)
|
||||
{
|
||||
@ -103,8 +110,11 @@ icpsp_attach(struct device *parent, struct device *self, void *aux)
|
||||
icp = (struct icp_softc *)parent;
|
||||
|
||||
sc->sc_busno = icpa->icpa_unit - ICPA_UNIT_SCSI;
|
||||
sc->sc_openings = icp->icp_openings;
|
||||
printf(": physical SCSI channel %d\n", sc->sc_busno);
|
||||
|
||||
icp_register_servicecb(icp, icpa->icpa_unit, &icpsp_servicecb);
|
||||
|
||||
sc->sc_adapter.adapt_dev = &sc->sc_dv;
|
||||
sc->sc_adapter.adapt_nchannels = 1;
|
||||
sc->sc_adapter.adapt_openings = icp->icp_openings;
|
||||
@ -320,3 +330,15 @@ icpsp_intr(struct icp_ccb *ic)
|
||||
icp_ccb_free(icp, ic);
|
||||
scsipi_done(xs);
|
||||
}
|
||||
|
||||
void
|
||||
icpsp_adjqparam(struct device *dv, int openings)
|
||||
{
|
||||
struct icpsp_softc *sc = (struct icpsp_softc *) dv;
|
||||
int s;
|
||||
|
||||
s = splbio();
|
||||
sc->sc_adapter.adapt_openings += openings - sc->sc_openings;
|
||||
sc->sc_openings = openings;
|
||||
splx(s);
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: icpvar.h,v 1.2 2003/05/13 15:42:34 thorpej Exp $ */
|
||||
/* $NetBSD: icpvar.h,v 1.3 2003/06/13 05:57:31 thorpej Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2002, 2003 The NetBSD Foundation, Inc.
|
||||
@ -104,6 +104,14 @@ struct icp_cachedrv {
|
||||
u_int cd_type;
|
||||
};
|
||||
|
||||
/*
|
||||
* Call-backs into the service back-ends (ld for cache service,
|
||||
* icpsp for raw service).
|
||||
*/
|
||||
struct icp_servicecb {
|
||||
void (*iscb_openings)(struct device *, int);
|
||||
};
|
||||
|
||||
/*
|
||||
* Per-controller context.
|
||||
*/
|
||||
@ -124,8 +132,12 @@ struct icp_softc {
|
||||
u_int8_t icp_bus_cnt;
|
||||
u_int8_t icp_bus_id[ICP_MAXBUS];
|
||||
struct icp_cachedrv icp_cdr[ICP_MAX_HDRIVES];
|
||||
const struct icp_servicecb *icp_servicecb[ICP_MAX_HDRIVES + ICP_MAXBUS];
|
||||
struct device *icp_children[ICP_MAX_HDRIVES + ICP_MAXBUS];
|
||||
int icp_ndevs;
|
||||
int icp_openings;
|
||||
int icp_features;
|
||||
int icp_nchan;
|
||||
|
||||
u_int32_t icp_info;
|
||||
u_int32_t icp_info2;
|
||||
@ -139,6 +151,8 @@ struct icp_softc {
|
||||
struct icp_ccb *icp_ccbs;
|
||||
u_int icp_nccbs;
|
||||
u_int icp_flags;
|
||||
u_int icp_qfreeze;
|
||||
u_int icp_running;
|
||||
SIMPLEQ_HEAD(,icp_ccb) icp_ccb_freelist;
|
||||
SIMPLEQ_HEAD(,icp_ccb) icp_ccb_queue;
|
||||
SIMPLEQ_HEAD(,icp_ccb) icp_ucmd_queue;
|
||||
@ -167,8 +181,13 @@ struct icp_softc {
|
||||
int icp_pci_subdevice_id;
|
||||
};
|
||||
|
||||
/* icp_features */
|
||||
#define ICP_FEAT_CACHESERVICE 0x01 /* cache service usable */
|
||||
#define ICP_FEAT_RAWSERVICE 0x02 /* raw service usable */
|
||||
|
||||
/* icp_flags */
|
||||
#define ICP_F_WAIT_CCB 0x01 /* someone waiting for CCBs */
|
||||
#define ICP_F_WAIT_FREEZE 0x02 /* someone waiting for qfreeze */
|
||||
|
||||
#define ICP_HAS_WORK(icp) \
|
||||
(! SIMPLEQ_EMPTY(&(icp)->icp_ccb_queue) || \
|
||||
@ -234,6 +253,14 @@ 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 *);
|
||||
int icp_freeze(struct icp_softc *);
|
||||
void icp_unfreeze(struct icp_softc *);
|
||||
|
||||
void icp_rescan(struct icp_softc *, int);
|
||||
void icp_rescan_all(struct icp_softc *);
|
||||
|
||||
void icp_register_servicecb(struct icp_softc *, int,
|
||||
const struct icp_servicecb *);
|
||||
|
||||
gdt_evt_str *icp_store_event(struct icp_softc *, u_int16_t, u_int16_t,
|
||||
gdt_evt_data *);
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: ld_icp.c,v 1.7 2003/06/07 23:37:25 thorpej Exp $ */
|
||||
/* $NetBSD: ld_icp.c,v 1.8 2003/06/13 05:57:31 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.7 2003/06/07 23:37:25 thorpej Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: ld_icp.c,v 1.8 2003/06/13 05:57:31 thorpej Exp $");
|
||||
|
||||
#include "rnd.h"
|
||||
|
||||
@ -72,6 +72,7 @@ struct ld_icp_softc {
|
||||
};
|
||||
|
||||
void ld_icp_attach(struct device *, struct device *, void *);
|
||||
int ld_icp_detach(struct device *, int);
|
||||
int ld_icp_dobio(struct ld_icp_softc *, void *, int, int, int,
|
||||
struct buf *);
|
||||
int ld_icp_dump(struct ld_softc *, void *, int, int);
|
||||
@ -80,8 +81,14 @@ void ld_icp_intr(struct icp_ccb *);
|
||||
int ld_icp_match(struct device *, struct cfdata *, void *);
|
||||
int ld_icp_start(struct ld_softc *, struct buf *);
|
||||
|
||||
void ld_icp_adjqparam(struct device *, int);
|
||||
|
||||
CFATTACH_DECL(ld_icp, sizeof(struct ld_icp_softc),
|
||||
ld_icp_match, ld_icp_attach, NULL, NULL);
|
||||
ld_icp_match, ld_icp_attach, ld_icp_detach, NULL);
|
||||
|
||||
static const struct icp_servicecb ld_icp_servicecb = {
|
||||
ld_icp_adjqparam,
|
||||
};
|
||||
|
||||
int
|
||||
ld_icp_match(struct device *parent, struct cfdata *match, void *aux)
|
||||
@ -111,6 +118,8 @@ ld_icp_attach(struct device *parent, struct device *self, void *aux)
|
||||
icpa = aux;
|
||||
cd = &icp->icp_cdr[icpa->icpa_unit];
|
||||
|
||||
icp_register_servicecb(icp, icpa->icpa_unit, &ld_icp_servicecb);
|
||||
|
||||
sc->sc_hwunit = icpa->icpa_unit;
|
||||
ld->sc_maxxfer = ICP_MAX_XFER;
|
||||
ld->sc_secsize = ICP_SECTOR_SIZE;
|
||||
@ -169,6 +178,18 @@ ld_icp_attach(struct device *parent, struct device *self, void *aux)
|
||||
ldattach(ld);
|
||||
}
|
||||
|
||||
int
|
||||
ld_icp_detach(struct device *dv, int flags)
|
||||
{
|
||||
int rv;
|
||||
|
||||
if ((rv = ldbegindetach((struct ld_softc *)dv, flags)) != 0)
|
||||
return (rv);
|
||||
ldenddetach((struct ld_softc *) dv);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
ld_icp_dobio(struct ld_icp_softc *sc, void *data, int datasize, int blkno,
|
||||
int dowrite, struct buf *bp)
|
||||
@ -315,3 +336,10 @@ ld_icp_intr(struct icp_ccb *ic)
|
||||
icp_ccb_free(icp, ic);
|
||||
lddone(&sc->sc_ld, bp);
|
||||
}
|
||||
|
||||
void
|
||||
ld_icp_adjqparam(struct device *dv, int openings)
|
||||
{
|
||||
|
||||
ldadjqparam((struct ld_softc *) dv, openings);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user