2021-10-11 22:19:34 -03:00

261 lines
6.4 KiB
C

static char sccsid[] = "@(#)30 1.18 src/bos/kernel/specfs/pdevsubs.c, sysspecfs, bos41J, 9513A_all 3/28/95 16:44:48";
/*
* COMPONENT_NAME: (SYSPFS) Physical File System
*
* FUNCTIONS: devstrat, devdump
*
* ORIGINS: 27, 83
*
* IBM CONFIDENTIAL -- (IBM Confidential Restricted when
* combined with the aggregated modules for this product)
* SOURCE MATERIALS
* (C) COPYRIGHT International Business Machines Corp. 1988, 1989, 1993
* All Rights Reserved
*
* US Government Users Restricted Rights - Use, duplication or
* disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
*/
/*
* LEVEL 1, 5 Years Bull Confidential Information
*/
#include "sys/user.h"
#include "sys/types.h"
#include "sys/sysmacros.h"
#include "sys/buf.h"
#include "sys/device.h"
#include "sys/uio.h"
#include "sys/errno.h"
#include "sys/dev.h"
#ifdef _POWER_MP
#include <sys/processor.h>
#include <sys/low.h>
#include <sys/ppda.h>
#include <sys/proc.h>
#include "../ios/bio_locks.h"
#endif
extern devcnt;
#ifdef _POWER_MP
struct buf *g_stratlist = NULL; /* Global 'strategylist' */
/*
* NAME: strat_offl
*
* FUNCTION: run on the MP MASTER processor,
* invoke strategy() on all the funneled buffers
* from the global strategy list.
*
* PARAMETERS:
*
* RETURN : void
*
*/
void
strat_offl()
{
int ipri;
struct buf *bp;
ipri = STRATLIST_LOCK(); /* enter critical section */
while (g_stratlist != NULL) {
bp = g_stratlist ;
/*
* Remove the first buffer from the global strategy list.
* The global strategy list is a simple linked list
* based upon the av_back list pointer to preserve the
* av_forw list pointer which is used by strategy().
*/
g_stratlist = bp->av_back;
bp->av_back = NULL;
/*
* Call the strategy() routine
*/
STRATLIST_UNLOCK(ipri); /* end of critical section */
(void) (*devsw[major(bp->b_dev)].d_strategy) (bp);
ipri = STRATLIST_LOCK(); /* enter critical section */
}
STRATLIST_UNLOCK(ipri); /* end of critical section */
}
#endif /* _POWER_MP */
/*
* NAME: devstrat (bp)
*
* FUNCTION: request block data transfer to/from a block device
*
* PARAMETERS: bp - pointer to the buf structure that
* represents the request
*
* RETURN : ENODEV - Invalid device number or no d_strategy()
*
*/
devstrat (bp)
struct buf *bp;
{
int rc;
#ifdef _POWER_MP
struct buf *bp_cur;
int waslocked;
int wasfunneled;
int tmpipri, ipri;
struct mstsave *curcsa;
extern mpc_msg_t strat_mpc_msg;
#endif /* _POWER_MP */
#ifdef _POWER_MP
curcsa = CSA;
bp_cur = bp;
while ( bp_cur != NULL) {
/* set B_MPSAFE_INITIAL to register the MPSAFE state of */
/* this buffer to the BIO module (see biodone()) */
if (bp_cur->b_flags & B_MPSAFE)
bp_cur->b_flags |= B_MPSAFE_INITIAL;
else
bp_cur->b_flags &= ~B_MPSAFE_INITIAL;
/* Clear the MPSAFE state, if the driver is a none MP-SAFE one */
if (!(devsw[major (bp_cur->b_dev)].d_opts & DEV_MPSAFE))
bp_cur->b_flags &= ~B_MPSAFE;
bp_cur = bp_cur->av_forw;
}
#endif
if (major (bp->b_dev) < devcnt)
{
#ifdef _POWER_MP
if (waslocked = ((curcsa->prev == NULL) &&
IS_LOCKED(&kernel_lock)))
unlockl(&kernel_lock);
tmpipri = curcsa->intpri;
if (devsw[major (bp->b_dev)].d_opts & DEV_MPSAFE) {
/* MP SAFE driver, */
/* direct call to the d_stategy entry point. */
(void) (*devsw[major (bp->b_dev)].d_strategy) (bp);
} else if ((curcsa->prev == NULL) &&
(curcsa->intpri == INTBASE)) {
/* At INTBASE priority level and in a thread context */
/* Funneling is done the same way as in DD_ENT */
/* by calling switch_cpu() to let the schedule */
/* do the migration */
wasfunneled = switch_cpu(MP_MASTER, SET_PROCESSOR_ID);
(void) (*devsw[major (bp->b_dev)].d_strategy) (bp);
if (!wasfunneled)
switch_cpu(0, RESET_PROCESSOR_ID);
} else if ( CPUID != MP_MASTER) {
/* Not at INTBASE priority level or not in a thread context */
/* Funneling is done by linking the given buffer to global */
/* strategy list and kick off strategy() on the MPMASTER */
/* processor by calling mpc_send(). */
/* note: the global strategy list is a simple linked list based */
/* on the av_back list pointer since av_forw is used to pass a */
/* list of buffer to stategy(). (see sys/buf.h) */
ipri = STRATLIST_LOCK();
/* insert the given buffer in the FIFO global strategy list */
if (g_stratlist != NULL) {
bp_cur = g_stratlist;
while (bp_cur->av_back != NULL)
bp_cur = bp_cur->av_back;
bp_cur->av_back = bp;
} else {
g_stratlist = bp;
}
bp->av_back = NULL;
STRATLIST_UNLOCK(ipri);
ASSERT(curcsa->intpri == INTIODONE);
mpc_send(MP_MASTER, strat_mpc_msg);
} else {
/* Running on the MP_MASTER cpu, */
/* direct call to the d_stategy entry point. */
(void) (*devsw[major (bp->b_dev)].d_strategy) (bp);
}
assert(curcsa->intpri == tmpipri);
if (waslocked)
lockl(&kernel_lock, LOCK_SHORT);
#else
DD_ENT((void) ,(*devsw[major(bp->b_dev)].d_strategy)
(bp), IPRI_OTHER, major(bp->b_dev));
#endif /* _POWER_MP */
rc = 0;
}
else
rc = ENODEV;
return rc;
}
/*
* NAME: devdump (devno, uiop, cmd, arg, chan, ext)
*
* FUNCTION: initiate a memory dump to a device
*
* PARAMETERS: devno - Block device number
* uiop - uiomove args
* cmd - dump command
* arg - address of parameter block
* ext - extension parameter
*
* RETURN : ENODEV - Invalid device number or no d_dump()
*
*/
devdump (devno, uiop, cmd, arg, chan, ext)
dev_t devno;
struct uio *uiop;
int cmd, arg, chan, ext;
{
int rc;
if (major (devno) < devcnt)
{
DD_ENT(rc = ,(*devsw[major(devno)].d_dump)
(devno, uiop, cmd, arg, chan, ext),IPRI_OTHER,major(devno));
}
else
rc = ENODEV;
return rc;
}
/*
* NAME: devwrite(rdev, uiop, chan, ext)
*
* FUNCTION: write to a device
*
* PARAMETERS: devno - device number of device to write to
* uiop - write location information
* chan - device channel number
* ext - extended write parameter
*
* RETURN : ENODEV - Invalid device number or no d_write()
*
*/
devwrite (
dev_t devno, /* dev num of device to write */
struct uio uiop, /* write location information */
chan_t chan, /* device channel number */
int ext) /* extended write parameter */
{
int rc;
if (major(devno) < devcnt)
rc = (*devsw[major(devno)].d_write)(devno, uiop, chan, ext);
else
rc = ENODEV;
return rc;
}