/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
*/
&drstab,
};
/*
* Module linkage information for the kernel.
*/
};
};
int
_init(void)
{
return (mod_install(&modlinkage));
}
int
_fini(void)
{
return (mod_remove(&modlinkage));
}
int
{
}
0,
0,
1,
0
};
(int (*)())drrput,
NULL,
NULL,
};
(int (*)())drwput,
NULL,
NULL,
NULL,
NULL,
};
&drrinit,
&drwinit,
NULL,
};
/*
* This module is pushed directly on top of the bottom driver
* in a DLPI style-2 stream by stropen(). It intercepts
* DL_ATTACH_REQ/DL_DETACH_REQ messages on the write side
* and acks on the read side, calls qassociate where needed.
* The primary purpose is to workaround a DR race condition
* affecting non-DDI compliant DLPI style 2 drivers, which may
* cause the system to panic.
*
* The following action is taken:
* Write side (drwput):
* attach request: hold driver instance assuming ppa == instance.
* This way, the instance cannot be detached while the
* driver is processing DL_ATTACH_REQ.
*
* On a successful hold, store the dip in a ring buffer
* to be processed lated by the read side.
* If hold fails (most likely ppa != instance), we store
* NULL in the ring buffer and read side won't take
* any action on ack.
*
* Read side (drrput):
* attach success: if (dip held on write side) associate queue with dip
* attach failure: if (dip held on write side) release hold on dip
* detach success: associate queue with NULL
* detach failure: do nothing
*
* The module assumes that incoming DL_ATTACH_REQ/DL_DETACH_REQ
* messages are ordered (non-concurrent) and the bottom
* driver processes them and sends acknowledgements in the same
* order. This assumption is reasonable because concurrent
* association results in non-deterministic queue behavior.
* The module is coded carefully such that unordered messages
* do not result in a system panic.
*
* The module handles multiple outstanding messages queued
* in the bottom driver. Messages processed on the write side
* but not yet arrived at read side are placed in the ring buffer
* dr_dip[], between dr_nfirst and dr_nlast. The write side is
* producer and the read side is the consumer. The buffer is full
* when dr_nfirst == dr_nlast.
*
* The current size of the ring buffer is 64 (MAX_DLREQS) per stream.
* During normal testing, we have not seen outstanding messages
* above 10.
*/
struct drstate {
int dr_nfirst;
int dr_nlast;
};
/* ARGSUSED1 */
static int
{
return (EINVAL);
}
if (secpolicy_net_rawaccess(crp) != 0) {
return (EPERM);
}
return (0); /* already open */
}
qprocson(q);
return (0);
}
/* ARGSUSED1 */
static int
{
qprocsoff(q);
return (0);
}
static int
{
case M_PROTO:
case M_PCPROTO:
break;
default:
return (0);
}
/* make sure size is sufficient for dl_primitive */
return (0);
}
switch (dlp->dl_primitive) {
case DL_OK_ACK: {
/* check for proper size, let upper layer deal with error */
return (0);
}
case DL_ATTACH_REQ:
/*
* ddi_assoc_queue_with_devi() will hold dip,
* so release after association.
*
* dip is NULL means we didn't hold dip on read side.
* (unlikely, but possible), so we do nothing.
*/
if (dip) {
}
break;
case DL_DETACH_REQ:
break;
default:
break;
}
break;
}
case DL_ERROR_ACK:
break;
/*
* Release dip on attach failure
*/
if (dip) {
}
break;
default:
break;
}
return (0);
}
/*
* Detect dl attach, hold the dip to prevent it from detaching
*/
static int
{
case M_PROTO:
case M_PCPROTO:
break;
default:
return (0);
}
/* make sure size is sufficient for dl_primitive */
return (0);
}
switch (dlp->dl_primitive) {
case DL_ATTACH_REQ:
/*
* Check for proper size of the message.
*
* If size is correct, get the ppa and attempt to
* hold the device assuming ppa is instance.
*
* If size is wrong, we can't get the ppa, but
* still increment dr_nfirst because the read side
* will get a error ack on DL_ATTACH_REQ.
*/
}
/*
* Check if ring buffer is full. If so, assert in debug
* kernel and produce a warning in non-debug kernel.
*/
}
break;
default:
break;
}
return (0);
}