blkdev.c revision bc220884124d127a3046646c2c9fb8d86fe654a9
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore * CDDL HEADER START
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore * The contents of this file are subject to the terms of the
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore * Common Development and Distribution License (the "License").
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore * You may not use this file except in compliance with the License.
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore * or http://www.opensolaris.org/os/licensing.
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore * See the License for the specific language governing permissions
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore * and limitations under the License.
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore * When distributing Covered Code, include this CDDL HEADER in each
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore * If applicable, add the following below this CDDL HEADER, with the
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore * fields enclosed by brackets "[]" replaced with your own identifying
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore * information: Portions Copyright [yyyy] [name of copyright owner]
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore * CDDL HEADER END
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
a3e090fb13431e72eb6751b653b906929410443bAlexey Zaytsev * Copyright 2011, 2012 Nexenta Systems, Inc. All rights reserved.
cd21e7c548ae2a3b5e522244bf798f2a6b4ba02dGarrett D'Amore * Copyright 2012 Garrett D'Amore <garrett@damore.org>. All rights reserved.
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore#include <sys/scsi/scsi.h> /* for DTYPE_DIRECT */
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore#define BDINST(dev) (getminor(dev) / BD_MAXPART)
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore#define BDPART(dev) (getminor(dev) % BD_MAXPART)
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore unsigned d_open_lyr[BD_MAXPART]; /* open count */
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore uint64_t d_open_excl; /* bit mask indexed by partition */
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore uint64_t d_open_reg[OTYPCNT]; /* bit mask */
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore * Private prototypes.
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amorestatic int bd_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amorestatic int bd_attach(dev_info_t *, ddi_attach_cmd_t);
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amorestatic int bd_detach(dev_info_t *, ddi_detach_cmd_t);
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amorestatic int bd_open(dev_t *, int, int, cred_t *);
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amorestatic int bd_close(dev_t, int, int, cred_t *);
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amorestatic int bd_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
86e3bca69f59096fa71848f8e8614c38ac86a24aGarrett D'Amorestatic int bd_dump(dev_t, caddr_t, daddr_t, int);
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amorestatic int bd_read(dev_t, struct uio *, cred_t *);
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amorestatic int bd_write(dev_t, struct uio *, cred_t *);
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amorestatic int bd_aread(dev_t, struct aio_req *, cred_t *);
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amorestatic int bd_awrite(dev_t, struct aio_req *, cred_t *);
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amorestatic int bd_prop_op(dev_t, dev_info_t *, ddi_prop_op_t, int, char *,
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amorestatic int bd_tg_rdwr(dev_info_t *, uchar_t, void *, diskaddr_t, size_t,
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amorestatic int bd_tg_getinfo(dev_info_t *, int, void *, void *);
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amorestatic int bd_xfer_ctor(void *, void *, int);
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amorestatic void bd_xfer_dtor(void *, void *);
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amorestatic void bd_submit(bd_t *, bd_xfer_impl_t *);
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amorestatic void bd_runq_exit(bd_xfer_impl_t *, int);
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amorestatic int bd_check_state(bd_t *, enum dkio_state *);
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amorestatic int bd_flush_write_cache(bd_t *, struct dk_callback *);
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore 0, /* streamtab */
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore D_64BIT | D_MP, /* Driver comaptibility flag */
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore 0, /* refcnt */
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore "Generic Block Device",
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore rv = ddi_soft_state_init(&bd_state, sizeof (struct bd), 2);
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amorebd_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **resultp)
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amorebd_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore /* We don't do anything native for suspend/resume */
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore (void) snprintf(name, sizeof (name), "%s%d",
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore ddi_driver_name(dip), ddi_get_instance(dip));
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore (void) snprintf(kcache, sizeof (kcache), "%s_xfer", name);
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore cmn_err(CE_WARN, "%s: missing parent data!", name);
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore if (ddi_soft_state_zalloc(bd_state, inst) != DDI_SUCCESS) {
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore cmn_err(CE_WARN, "%s: unable to zalloc soft state!", name);
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore max(DEV_BSIZE, bd->d_dma.dma_attr_granular);
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore (bd->d_maxxfer != bd->d_dma.dma_attr_maxxfer)) {
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore "%s: inconsistent maximum transfer size!",
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore /* We force it */
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore bd->d_blkshift = 9; /* 512 bytes, to start */
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore cmn_err(CE_WARN, "%s: maximum transfer misaligned!", name);
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore cmn_err(CE_WARN, "%s: maximum transfer size too small!", name);
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore mutex_init(&bd->d_iomutex, NULL, MUTEX_DRIVER, NULL);
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore mutex_init(&bd->d_ocmutex, NULL, MUTEX_DRIVER, NULL);
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore mutex_init(&bd->d_statemutex, NULL, MUTEX_DRIVER, NULL);
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore cv_init(&bd->d_statecv, NULL, CV_DRIVER, NULL);
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore list_create(&bd->d_waitq, sizeof (bd_xfer_impl_t),
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore list_create(&bd->d_runq, sizeof (bd_xfer_impl_t),
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore bd->d_cache = kmem_cache_create(kcache, sizeof (bd_xfer_impl_t), 8,
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore bd_xfer_ctor, bd_xfer_dtor, NULL, bd, NULL, 0);
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore bd->d_ksp = kstat_create(ddi_driver_name(dip), inst, NULL, "disk",
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore * Even if we cannot create the kstat, we create a
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore * scratch kstat. The reason for this is to ensure
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore * that we can update the kstat all of the time,
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore * without adding an extra branch instruction.
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore bd->d_kiop = kmem_zalloc(sizeof (kstat_io_t), KM_SLEEP);
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore bd->d_ops.o_drive_info(bd->d_private, &drive);
bc220884124d127a3046646c2c9fb8d86fe654a9Alexey Zaytsev if (drive.d_maxxfer && drive.d_maxxfer < bd->d_maxxfer)
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore rv = cmlb_attach(dip, &bd_tg_ops, DTYPE_DIRECT,
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore drive.d_lun >= 0 ? DDI_NT_BLOCK_CHAN : DDI_NT_BLOCK,
86e3bca69f59096fa71848f8e8614c38ac86a24aGarrett D'Amore CMLB_FAKE_LABEL_ONE_PARTITION, bd->d_cmlbh, 0);
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore rv = bd->d_ops.o_devid_init(bd->d_private, dip, &bd->d_devid);
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore * Add a zero-length attribute to tell the world we support
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore * kernel ioctls (for layered drivers). Also set up properties
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore * used by HAL to identify removable media.
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore (void) ddi_prop_create(DDI_DEV_T_NONE, dip, DDI_PROP_CANSLEEP,
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore (void) ddi_prop_create(DDI_DEV_T_NONE, dip, DDI_PROP_CANSLEEP,
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore (void) ddi_prop_create(DDI_DEV_T_NONE, dip, DDI_PROP_CANSLEEP,
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amorebd_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore /* We don't suspend, but our parent does */
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore ddi_soft_state_free(bd_state, ddi_get_instance(dip));
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amorebd_xfer_ctor(void *buf, void *arg, int kmflag)
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore if (ddi_dma_alloc_handle(bd->d_dip, &bd->d_dma, dcb, NULL,
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amorebd_xfer_alloc(bd_t *bd, struct buf *bp, int (*func)(void *, bd_xfer_t *),
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore (bp->b_bcount + (bd->d_maxxfer - 1)) / bd->d_maxxfer;
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore xi->i_len = min(bp->b_bcount, bd->d_maxxfer);
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore * We have to use consistent DMA if the address is misaligned.
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore if (((bp->b_flags & (B_PAGEIO | B_REMAPPED)) != B_PAGEIO) &&
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore dir |= DDI_DMA_CONSISTENT | DDI_DMA_PARTIAL;
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore status = ddi_dma_buf_bind_handle(xi->i_dmah, bp, dir, cb,
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore if ((ddi_dma_numwin(xi->i_dmah, &xi->i_num_win) !=
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore (ddi_dma_getwin(xi->i_dmah, 0, &xi->i_offset,
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amorebd_open(dev_t *devp, int flag, int otyp, cred_t *credp)
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore ndelay = (flag & (FNDELAY | FNONBLOCK)) ? B_TRUE : B_FALSE;
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore * Block any DR events from changing the set of registered
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore * devices while we function.
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore if ((bd = ddi_get_soft_state(bd_state, inst)) == NULL) {
86e3bca69f59096fa71848f8e8614c38ac86a24aGarrett D'Amore if (cmlb_validate(bd->d_cmlbh, 0, 0) != 0) {
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore /* non-blocking opens are allowed to succeed */
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore } else if (cmlb_partinfo(bd->d_cmlbh, part, &nblks, &lba,
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore * We read the partinfo, verify valid ranges. If the
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore * partition is invalid, and we aren't blocking or
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore * doing a raw access, then fail. (Non-blocking and
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore * raw accesses can still succeed to allow a disk with
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore * bad partition data to opened by format and fdisk.)
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore if ((!nblks) && ((!ndelay) || (otyp != OTYP_CHR))) {
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore } else if (!ndelay) {
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore * cmlb_partinfo failed -- invalid partition or no
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore * disk label.
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore for (int i = 0; i < OTYP_LYR; i++) {
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amorebd_close(dev_t dev, int flag, int otyp, cred_t *credp)
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore if ((bd = ddi_get_soft_state(bd_state, inst)) == NULL) {
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore for (int i = 0; i < 64; i++) {
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore for (int i = 0; last && (i < OTYP_LYR); i++) {
86e3bca69f59096fa71848f8e8614c38ac86a24aGarrett D'Amorebd_dump(dev_t dev, caddr_t caddr, daddr_t blkno, int nblk)
86e3bca69f59096fa71848f8e8614c38ac86a24aGarrett D'Amore if ((bd = ddi_get_soft_state(bd_state, inst)) == NULL) {
86e3bca69f59096fa71848f8e8614c38ac86a24aGarrett D'Amore * do cmlb, but do it synchronously unless we already have the
86e3bca69f59096fa71848f8e8614c38ac86a24aGarrett D'Amore * partition (which we probably should.)
86e3bca69f59096fa71848f8e8614c38ac86a24aGarrett D'Amore if (cmlb_partinfo(bd->d_cmlbh, part, &psize, &pstart, NULL, NULL,
86e3bca69f59096fa71848f8e8614c38ac86a24aGarrett D'Amore (void *)1)) {
86e3bca69f59096fa71848f8e8614c38ac86a24aGarrett D'Amore xi = bd_xfer_alloc(bd, bp, bd->d_ops.o_write, KM_NOSLEEP);
86e3bca69f59096fa71848f8e8614c38ac86a24aGarrett D'Amore * Generally, we should have run this entirely synchronously
86e3bca69f59096fa71848f8e8614c38ac86a24aGarrett D'Amore * at this point and the biowait call should be a no-op. If
86e3bca69f59096fa71848f8e8614c38ac86a24aGarrett D'Amore * it didn't happen this way, it's a bug in the underlying
86e3bca69f59096fa71848f8e8614c38ac86a24aGarrett D'Amore * driver not honoring BD_XFER_POLL.
9d75dfda4910937c194437c3e1e45ca07c889ee5Alexey Zaytsev * In a non-debug kernel, bd_strategy will catch !bd as
9d75dfda4910937c194437c3e1e45ca07c889ee5Alexey Zaytsev * well, and will fail nicely.
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amorebd_read(dev_t dev, struct uio *uio, cred_t *credp)
9d75dfda4910937c194437c3e1e45ca07c889ee5Alexey Zaytsev return (physio(bd_strategy, NULL, dev, B_READ, bd_minphys, uio));
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amorebd_write(dev_t dev, struct uio *uio, cred_t *credp)
9d75dfda4910937c194437c3e1e45ca07c889ee5Alexey Zaytsev return (physio(bd_strategy, NULL, dev, B_WRITE, bd_minphys, uio));
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amorebd_aread(dev_t dev, struct aio_req *aio, cred_t *credp)
9d75dfda4910937c194437c3e1e45ca07c889ee5Alexey Zaytsev return (aphysio(bd_strategy, anocancel, dev, B_READ, bd_minphys, aio));
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amorebd_awrite(dev_t dev, struct aio_req *aio, cred_t *credp)
9d75dfda4910937c194437c3e1e45ca07c889ee5Alexey Zaytsev return (aphysio(bd_strategy, anocancel, dev, B_WRITE, bd_minphys, aio));
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore if ((bd = ddi_get_soft_state(bd_state, inst)) == NULL) {
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore if (cmlb_partinfo(bd->d_cmlbh, part, &p_nblks, &p_lba,
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore if ((P2PHASE(bp->b_bcount, (1U << shift)) != 0) ||
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore if ((bp->b_lblkno == p_nblks) || (bp->b_bcount == 0)) {
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore bp->b_resid = ((bp->b_lblkno + b_nblks - p_nblks) << shift);
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore func = (bp->b_flags & B_READ) ? bd->d_ops.o_read : bd->d_ops.o_write;
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore xi = bd_xfer_alloc(bd, bp, func, KM_NOSLEEP);
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore xi = bd_xfer_alloc(bd, bp, func, KM_PUSHPAGE);
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore /* bd_request_alloc will have done bioerror */
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amorebd_ioctl(dev_t dev, int cmd, intptr_t arg, int flag, cred_t *credp, int *rvalp)
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore if ((bd = ddi_get_soft_state(bd_state, inst)) == NULL) {
86e3bca69f59096fa71848f8e8614c38ac86a24aGarrett D'Amore rv = cmlb_ioctl(bd->d_cmlbh, dev, cmd, arg, flag, credp, rvalp, 0);
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore /* make sure our state information is current */
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore if (ddi_copyout(&minfo, ptr, sizeof (minfo), flag)) {
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore cinfo.dki_cnum = ddi_get_instance(ddi_get_parent(bd->d_dip));
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore (void) snprintf(cinfo.dki_cname, sizeof (cinfo.dki_cname),
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore "%s", ddi_driver_name(ddi_get_parent(bd->d_dip)));
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore (void) snprintf(cinfo.dki_dname, sizeof (cinfo.dki_dname),
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore cinfo.dki_maxtransfer = bd->d_maxxfer / DEV_BSIZE;
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore if (ddi_copyout(&cinfo, ptr, sizeof (cinfo), flag)) {
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore if (ddi_copyout(&i, ptr, sizeof (i), flag)) {
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore if (ddi_copyout(&i, ptr, sizeof (i), flag)) {
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore if (ddi_copyout(&i, ptr, sizeof (i), flag)) {
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore if (ddi_copyin(ptr, &state, sizeof (state), flag)) {
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore if ((rv = bd_check_state(bd, &state)) != 0) {
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore if (ddi_copyout(&state, ptr, sizeof (state), flag)) {
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amorebd_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op, int mod_flags,
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore bd = ddi_get_soft_state(bd_state, ddi_get_instance(dip));
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore return (ddi_prop_op(dev, dip, prop_op, mod_flags,
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore return (cmlb_prop_op(bd->d_cmlbh, dev, dip, prop_op, mod_flags, name,
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amorebd_tg_rdwr(dev_info_t *dip, uchar_t cmd, void *bufaddr, diskaddr_t start,
86e3bca69f59096fa71848f8e8614c38ac86a24aGarrett D'Amore * If we are running in polled mode (such as during dump(9e)
86e3bca69f59096fa71848f8e8614c38ac86a24aGarrett D'Amore * execution), then we cannot sleep for kernel allocations.
86e3bca69f59096fa71848f8e8614c38ac86a24aGarrett D'Amore bd = ddi_get_soft_state(bd_state, ddi_get_instance(dip));
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore if (P2PHASE(length, (1U << bd->d_blkshift)) != 0) {
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore /* We can only transfer whole blocks at a time! */
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amorebd_tg_getinfo(dev_info_t *dip, int cmd, void *arg, void *tg_cookie)
86e3bca69f59096fa71848f8e8614c38ac86a24aGarrett D'Amore bd = ddi_get_soft_state(bd_state, ddi_get_instance(dip));
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore * We don't have any "geometry" as such, let cmlb
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore * fabricate something.
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore * It turns out that cmlb really doesn't do much for
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore * non-writable media, but lets make the information
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore * available for it in case it does more in the
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore * future. (The value is currently used for
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore * triggering special behavior for CD-ROMs.)
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore ((tg_attribute_t *)arg)->media_is_writable =
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore ((xi = list_remove_head(&bd->d_waitq)) != NULL)) {
86e3bca69f59096fa71848f8e8614c38ac86a24aGarrett D'Amore * Submit the job to the driver. We drop the I/O mutex
86e3bca69f59096fa71848f8e8614c38ac86a24aGarrett D'Amore * so that we can deal with the case where the driver
86e3bca69f59096fa71848f8e8614c38ac86a24aGarrett D'Amore * completion routine calls back into us synchronously.
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore rv = xi->i_func(bd->d_private, &xi->i_public);
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore bd->d_kiop->nread += (bp->b_bcount - xi->i_resid);
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore bd->d_kiop->nwritten += (bp->b_bcount - xi->i_resid);
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore if (bd->d_ops.o_media_info(bd->d_private, &media) == 0) {
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore if ((1U << bd->d_blkshift) != media.m_blksize) {
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore (P2PHASE(bd->d_maxxfer, media.m_blksize))) {
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore "%s%d: Invalid media block size (%d)",
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore * We can't use the media, treat it as
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore * not present.
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore bd->d_blkshift = ddi_ffs(media.m_blksize) - 1;
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore /* Device size changed */
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore /* Device size changed */
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amorebd_check_state(bd_t *bd, enum dkio_state *state)
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore if (cv_reltimedwait_sig(&bd->d_statecv, &bd->d_statemutex,
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore struct dk_callback *dc = (void *)bp->b_private;
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore (*dc->dkc_callback)(dc->dkc_cookie, geterror(bp));
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amorebd_flush_write_cache(bd_t *bd, struct dk_callback *dkc)
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore xi = bd_xfer_alloc(bd, bp, bd->d_ops.o_sync_cache, KM_SLEEP);
f097ef9c335ca15d17a8caba066fb2da38a3a1beAlexey Zaytsev /* Make an asynchronous flush, but only if there is a callback */
f097ef9c335ca15d17a8caba066fb2da38a3a1beAlexey Zaytsev if (dkc != NULL && dkc->dkc_callback != NULL) {
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore /* Make a private copy of the callback structure */
f097ef9c335ca15d17a8caba066fb2da38a3a1beAlexey Zaytsev /* In case there is no callback, perform a synchronous flush */
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore * Nexus support.
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amorebd_bus_ctl(dev_info_t *dip, dev_info_t *rdip, ddi_ctl_enum_t ctlop,
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore cmn_err(CE_CONT, "?Block device: %s@%s, %s%d\n",
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore ddi_node_name(rdip), ddi_get_name_addr(rdip),
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore ddi_driver_name(rdip), ddi_get_instance(rdip));
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore hdl = ddi_get_parent_data((dev_info_t *)arg);
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore ddi_set_name_addr((dev_info_t *)arg, hdl->h_addr);
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore return (ddi_ctlops(dip, rdip, ctlop, arg, result));
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore * Functions for device drivers.
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amorebd_alloc_handle(void *private, bd_ops_t *ops, ddi_dma_attr_t *dma, int kmflag)
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amorebd_attach_handle(dev_info_t *dip, bd_handle_t hdl)
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore /* if drivers don't override this, make it assume none */
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore hdl->h_ops.o_drive_info(hdl->h_private, &drive);
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore (void) snprintf(hdl->h_addr, sizeof (hdl->h_addr), "%X,%X",
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore (void) snprintf(hdl->h_addr, sizeof (hdl->h_addr), "%X",
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore if (ndi_devi_alloc(dip, hdl->h_name, (pnode_t)DEVI_SID_NODEID,
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore cmn_err(CE_WARN, "%s%d: unable to allocate node %s@%s",
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore ddi_driver_name(dip), ddi_get_instance(dip),
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore if (ndi_devi_online(child, 0) == NDI_FAILURE) {
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore cmn_err(CE_WARN, "%s%d: failed bringing node %s@%s online",
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore ddi_driver_name(dip), ddi_get_instance(dip),
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore if (i_ddi_node_state(hdl->h_child) < DS_INITIALIZED) {
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore devnm = kmem_alloc(MAXNAMELEN + 1, KM_SLEEP);
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore (void) devfs_clean(hdl->h_parent, devnm + 1, DV_CLEAN_FORCE);
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore rv = ndi_devi_unconfig_one(hdl->h_parent, devnm + 1, NULL,
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore return (rv = NDI_SUCCESS ? DDI_SUCCESS : DDI_FAILURE);
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore /* Job completed succcessfully! */
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore /* More transfer still pending... advance to next DMA window. */
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore rv = ddi_dma_getwin(xi->i_dmah, xi->i_cur_win,
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore &xi->i_offset, &len, &xi->i_dmac, &xi->i_ndmac);
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore /* Advance memory window. */
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore len = min(bp->b_bcount - xi->i_offset, bd->d_maxxfer);
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore (P2PHASE(len, (1U << xi->i_blkshift) != 0))) {
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore /* Submit next window to hardware. */
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore rv = xi->i_func(bd->d_private, &xi->i_public);
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore * NB: The device driver is free to supply its own
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore * character entry device support.