blkdev.c revision 679ac1565a070e343ccb5d6dcff1231cc6011ce4
/*
* 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 2012 Nexenta Systems, Inc. All rights reserved.
* Copyright 2012 Garrett D'Amore <garrett@damore.org>. All rights reserved.
* Copyright 2012 Alexey Zaytsev <alexey.zaytsev@gmail.com> All rights reserved.
*/
#include <sys/sysmacros.h>
#define BD_MAXPART 64
typedef struct bd_xfer_impl bd_xfer_impl_t;
struct bd {
void *d_private;
enum dkio_state d_state;
};
struct bd_handle {
void *h_private;
char *h_name;
};
struct bd_xfer_impl {
};
/*
* Private prototypes.
*/
static int bd_strategy(struct buf *);
caddr_t, int *);
void *);
static int bd_tg_getinfo(dev_info_t *, int, void *, void *);
static int bd_xfer_ctor(void *, void *, int);
static void bd_xfer_dtor(void *, void *);
static void bd_runq_exit(bd_xfer_impl_t *, int);
static void bd_update_state(bd_t *);
struct cmlb_tg_ops bd_tg_ops = {
};
bd_open, /* open */
bd_close, /* close */
bd_strategy, /* strategy */
nodev, /* print */
bd_dump, /* dump */
bd_read, /* read */
bd_write, /* write */
bd_ioctl, /* ioctl */
nodev, /* devmap */
nodev, /* mmap */
nodev, /* segmap */
nochpoll, /* poll */
bd_prop_op, /* cb_prop_op */
0, /* streamtab */
CB_REV, /* cb_rev */
bd_aread, /* async read */
bd_awrite /* async write */
};
struct dev_ops bd_dev_ops = {
DEVO_REV, /* devo_rev, */
0, /* refcnt */
bd_getinfo, /* getinfo */
nulldev, /* identify */
nulldev, /* probe */
bd_attach, /* attach */
bd_detach, /* detach */
nodev, /* reset */
&bd_cb_ops, /* driver operations */
NULL, /* bus operations */
NULL, /* power */
ddi_quiesce_not_needed, /* quiesce */
};
"Generic Block Device",
};
static struct modlinkage modlinkage = {
};
static void *bd_state;
int
_init(void)
{
int rv;
if (rv != DDI_SUCCESS) {
return (rv);
}
if (rv != DDI_SUCCESS) {
}
return (rv);
}
int
_fini(void)
{
int rv;
if (rv == DDI_SUCCESS) {
}
return (rv);
}
int
{
}
static int
{
switch (cmd) {
case DDI_INFO_DEVT2DEVINFO:
return (DDI_FAILURE);
}
break;
case DDI_INFO_DEVT2INSTANCE:
break;
default:
return (DDI_FAILURE);
}
return (DDI_SUCCESS);
}
static int
{
int inst;
int rv;
char name[16];
char kcache[32];
switch (cmd) {
case DDI_ATTACH:
break;
case DDI_RESUME:
return (DDI_SUCCESS);
default:
return (DDI_FAILURE);
}
return (DDI_FAILURE);
}
return (DDI_FAILURE);
}
"%s: inconsistent maximum transfer size!",
name);
/* We force it */
} else {
}
} else {
}
}
}
return (DDI_FAILURE);
}
} else {
/*
* Even if we cannot create the kstat, we create a
* scratch kstat. The reason for this is to ensure
* that we can update the kstat all of the time,
* without adding an extra branch instruction.
*/
}
if (rv != 0) {
} else {
}
return (DDI_FAILURE);
}
if (rv == DDI_SUCCESS) {
DDI_SUCCESS) {
"%s: unable to register devid", name);
}
}
}
/*
* Add a zero-length attribute to tell the world we support
* kernel ioctls (for layered drivers). Also set up properties
* used by HAL to identify removable media.
*/
DDI_KERNEL_IOCTL, NULL, 0);
if (bd->d_removable) {
"removable-media", NULL, 0);
}
if (bd->d_hotpluggable) {
"hotpluggable", NULL, 0);
}
return (DDI_SUCCESS);
}
static int
{
switch (cmd) {
case DDI_DETACH:
break;
case DDI_SUSPEND:
/* We don't suspend, but our parent does */
return (DDI_SUCCESS);
default:
return (DDI_FAILURE);
}
} else {
}
return (DDI_SUCCESS);
}
static int
{
dcb = DDI_DMA_SLEEP;
} else {
}
return (-1);
}
}
return (0);
}
static void
{
}
static bd_xfer_impl_t *
int kmflag)
{
int rv;
int status;
unsigned dir;
cb = DDI_DMA_SLEEP;
} else {
}
return (NULL);
}
goto done;
}
dir = DDI_DMA_READ;
} else {
dir = DDI_DMA_WRITE;
}
rv = 0;
} else {
/*
* We have to use consistent DMA if the address is misaligned.
*/
} else {
}
switch (status) {
case DDI_DMA_MAPPED:
rv = 0;
break;
case DDI_DMA_PARTIAL_MAP:
DDI_SUCCESS) ||
DDI_SUCCESS) ||
goto done;
}
rv = 0;
break;
case DDI_DMA_NORESOURCES:
goto done;
case DDI_DMA_TOOBIG:
goto done;
case DDI_DMA_NOMAPPING:
case DDI_DMA_INUSE:
default:
goto done;
}
}
done:
if (rv != 0) {
return (NULL);
}
return (xi);
}
static void
{
}
}
static int
{
int rv;
return (EINVAL);
/*
* Block any DR events from changing the set of registered
* devices while we function.
*/
return (ENXIO);
}
/* non-blocking opens are allowed to succeed */
if (!ndelay) {
goto done;
}
/*
* We read the partinfo, verify valid ranges. If the
* partition is invalid, and we aren't blocking or
* doing a raw access, then fail. (Non-blocking and
* raw accesses can still succeed to allow a disk with
* bad partition data to opened by format and fdisk.)
*/
goto done;
}
} else if (!ndelay) {
/*
* cmlb_partinfo failed -- invalid partition or no
* disk label.
*/
goto done;
}
goto done;
}
goto done;
}
goto done;
}
for (int i = 0; i < OTYP_LYR; i++) {
goto done;
}
}
}
} else {
}
}
rv = 0;
done:
return (rv);
}
static int
{
return (ENXIO);
}
}
} else {
}
for (int i = 0; i < 64; i++) {
}
}
if (bd->d_open_reg[i]) {
}
}
if (last) {
}
return (0);
}
static int
{
int rv;
return (ENXIO);
}
/*
* do cmlb, but do it synchronously unless we already have the
* partition (which we probably should.)
*/
(void *)1)) {
return (ENXIO);
}
return (EINVAL);
}
return (ENOMEM);
}
return (ENOMEM);
}
/*
* Generally, we should have run this entirely synchronously
* at this point and the biowait call should be a no-op. If
* it didn't happen this way, it's a bug in the underlying
* driver not honoring BD_XFER_POLL.
*/
return (rv);
}
void
{
/*
* In a non-debug kernel, bd_strategy will catch !bd as
* well, and will fail nicely.
*/
}
static int
{
}
static int
{
}
static int
{
}
static int
{
}
static int
{
return (0);
}
return (0);
}
return (0);
}
return (0);
}
} else {
}
}
/* bd_request_alloc will have done bioerror */
return (0);
}
return (0);
}
static int
{
int rv;
return (ENXIO);
}
return (rv);
switch (cmd) {
case DKIOCGMEDIAINFO: {
/* make sure our state information is current */
return (EFAULT);
}
return (0);
}
case DKIOCINFO: {
return (EFAULT);
}
return (0);
}
case DKIOCREMOVABLE: {
int i;
return (EFAULT);
}
return (0);
}
case DKIOCHOTPLUGGABLE: {
int i;
return (EFAULT);
}
return (0);
}
case DKIOCREADONLY: {
int i;
return (EFAULT);
}
return (0);
}
case DKIOCSTATE: {
enum dkio_state state;
return (EFAULT);
}
return (rv);
}
return (EFAULT);
}
return (0);
}
case DKIOCFLUSHWRITECACHE: {
return (rv);
}
default:
break;
}
return (ENOTTY);
}
static int
{
}
static int
{
int rv;
int kmflag;
/*
* If we are running in polled mode (such as during dump(9e)
* execution), then we cannot sleep for kernel allocations.
*/
/* We can only transfer whole blocks at a time! */
return (EINVAL);
}
return (ENOMEM);
}
switch (cmd) {
case TG_READ:
break;
case TG_WRITE:
break;
default:
return (EINVAL);
}
return (rv);
}
return (rv);
}
static int
{
switch (cmd) {
case TG_GETPHYGEOM:
case TG_GETVIRTGEOM:
/*
* We don't have any "geometry" as such, let cmlb
* fabricate something.
*/
return (ENOTTY);
case TG_GETCAPACITY:
return (0);
case TG_GETBLOCKSIZE:
return (0);
case TG_GETATTR:
/*
* It turns out that cmlb really doesn't do much for
* non-writable media, but lets make the information
* available for it in case it does more in the
* future. (The value is currently used for
* triggering special behavior for CD-ROMs.)
*/
return (0);
default:
return (EINVAL);
}
}
static void
{
int rv;
/*
* Submit the job to the driver. We drop the I/O mutex
* so that we can deal with the case where the driver
* completion routine calls back into us synchronously.
*/
if (rv != 0) {
} else {
}
}
}
static void
{
}
static void
{
if (err == 0) {
} else {
}
}
}
static void
{
enum dkio_state state;
"%s%d: Invalid media block size (%d)",
/*
* We can't use the media, treat it as
* not present.
*/
} else {
}
/* Device size changed */
} else {
/* Device size changed */
}
}
} else {
}
}
if (docmlb) {
if (state == DKIO_INSERTED) {
} else {
}
}
}
static int
{
for (;;) {
break;
}
when, TR_CLOCK_TICK) == 0) {
return (EINTR);
}
}
return (0);
}
static int
{
return (0);
}
static int
{
struct dk_callback *dc;
int rv;
return (ENOTSUP);
}
return (ENOMEM);
}
return (rv);
}
/* Make an asynchronous flush, but only if there is a callback */
/* Make a private copy of the callback structure */
return (0);
}
/* In case there is no callback, perform a synchronous flush */
return (rv);
}
/*
* Nexus support.
*/
int
{
switch (ctlop) {
case DDI_CTLOPS_REPORTDEV:
return (DDI_SUCCESS);
case DDI_CTLOPS_INITCHILD:
return (DDI_NOT_WELL_FORMED);
}
return (DDI_SUCCESS);
case DDI_CTLOPS_UNINITCHILD:
return (DDI_SUCCESS);
default:
}
}
/*
* Functions for device drivers.
*/
{
}
return (hdl);
}
void
{
}
int
{
/* if drivers don't override this, make it assume none */
} else {
}
&child) != NDI_SUCCESS) {
return (DDI_FAILURE);
}
(void) ndi_devi_free(child);
return (DDI_FAILURE);
}
return (DDI_SUCCESS);
}
int
{
int circ;
int rv;
char *devnm;
return (DDI_SUCCESS);
}
} else {
}
if (rv == 0) {
}
}
void
{
int rv = DDI_SUCCESS;
if (err != 0) {
return;
}
/* Job completed succcessfully! */
bd_runq_exit(xi, 0);
return;
}
/* More transfer still pending... advance to next DMA window. */
} else {
/* Advance memory window. */
}
if ((rv != DDI_SUCCESS) ||
return;
}
/* Submit next window to hardware. */
if (rv != 0) {
}
}
void
{
}
}
void
{
static struct bus_ops bd_bus_ops = {
BUSO_REV, /* busops_rev */
nullbusmap, /* bus_map */
NULL, /* bus_get_intrspec (OBSOLETE) */
NULL, /* bus_add_intrspec (OBSOLETE) */
NULL, /* bus_remove_intrspec (OBSOLETE) */
i_ddi_map_fault, /* bus_map_fault */
NULL, /* bus_dma_map (OBSOLETE) */
ddi_dma_allochdl, /* bus_dma_allochdl */
ddi_dma_freehdl, /* bus_dma_freehdl */
ddi_dma_bindhdl, /* bus_dma_bindhdl */
ddi_dma_unbindhdl, /* bus_dma_unbindhdl */
ddi_dma_flush, /* bus_dma_flush */
ddi_dma_win, /* bus_dma_win */
ddi_dma_mctl, /* bus_dma_ctl */
bd_bus_ctl, /* bus_ctl */
ddi_bus_prop_op, /* bus_prop_op */
NULL, /* bus_get_eventcookie */
NULL, /* bus_add_eventcall */
NULL, /* bus_remove_eventcall */
NULL, /* bus_post_event */
NULL, /* bus_intr_ctl (OBSOLETE) */
NULL, /* bus_config */
NULL, /* bus_unconfig */
NULL, /* bus_fm_init */
NULL, /* bus_fm_fini */
NULL, /* bus_fm_access_enter */
NULL, /* bus_fm_access_exit */
NULL, /* bus_power */
NULL, /* bus_intr_op */
};
/*
* NB: The device driver is free to supply its own
* character entry device support.
*/
}
void
{
}