1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
23 */
24
25 #include <sys/types.h>
26 #include <sys/ksynch.h>
27 #include <sys/kmem.h>
28 #include <sys/file.h>
29 #include <sys/errno.h>
30 #include <sys/open.h>
31 #include <sys/buf.h>
32 #include <sys/uio.h>
33 #include <sys/aio_req.h>
34 #include <sys/cred.h>
35 #include <sys/modctl.h>
36 #include <sys/cmlb.h>
37 #include <sys/conf.h>
38 #include <sys/devops.h>
39 #include <sys/list.h>
40 #include <sys/sysmacros.h>
41 #include <sys/dkio.h>
42 #include <sys/vtoc.h>
43 #include <sys/scsi/scsi.h> /* for DTYPE_DIRECT */
44 #include <sys/kstat.h>
45 #include <sys/fs/dv_node.h>
46 #include <sys/ddi.h>
47 #include <sys/sunddi.h>
48 #include <sys/note.h>
49 #include <sys/blkdev.h>
50
51 #define BD_MAXPART 64
52 #define BDINST(dev) (getminor(dev) / BD_MAXPART)
53 #define BDPART(dev) (getminor(dev) % BD_MAXPART)
54
55 typedef struct bd bd_t;
56 typedef struct bd_xfer_impl bd_xfer_impl_t;
57
58 struct bd {
59 void *d_private;
60 dev_info_t *d_dip;
61 kmutex_t d_ocmutex;
62 kmutex_t d_iomutex;
63 kmutex_t d_statemutex;
64 kcondvar_t d_statecv;
65 enum dkio_state d_state;
66 cmlb_handle_t d_cmlbh;
67 unsigned d_open_lyr[BD_MAXPART]; /* open count */
68 uint64_t d_open_excl; /* bit mask indexed by partition */
69 uint64_t d_open_reg[OTYPCNT]; /* bit mask */
70
71 uint32_t d_qsize;
72 uint32_t d_qactive;
73 uint32_t d_maxxfer;
74 uint32_t d_blkshift;
75 uint64_t d_numblks;
76 ddi_devid_t d_devid;
77
78 kmem_cache_t *d_cache;
79 list_t d_runq;
80 list_t d_waitq;
81 kstat_t *d_ksp;
82 kstat_io_t *d_kiop;
83
84 boolean_t d_rdonly;
85 boolean_t d_removable;
86 boolean_t d_hotpluggable;
87 boolean_t d_use_dma;
88
89 ddi_dma_attr_t d_dma;
90 bd_ops_t d_ops;
91 bd_handle_t d_handle;
92 };
93
94 struct bd_handle {
95 bd_ops_t h_ops;
96 ddi_dma_attr_t *h_dma;
97 dev_info_t *h_parent;
98 dev_info_t *h_child;
99 void *h_private;
100 bd_t *h_bd;
101 char *h_name;
102 char h_addr[20]; /* enough for %X,%X */
103 };
104
105 struct bd_xfer_impl {
106 bd_xfer_t i_public;
107 list_node_t i_linkage;
108 bd_t *i_bd;
109 buf_t *i_bp;
110 uint_t i_num_win;
111 uint_t i_cur_win;
112 off_t i_offset;
113 int (*i_func)(void *, bd_xfer_t *);
114 uint32_t i_blkshift;
115 size_t i_len;
116 size_t i_resid;
117 };
118
119 #define i_dmah i_public.x_dmah
120 #define i_dmac i_public.x_dmac
121 #define i_ndmac i_public.x_ndmac
122 #define i_kaddr i_public.x_kaddr
123 #define i_nblks i_public.x_nblks
124 #define i_blkno i_public.x_blkno
125
126
127 /*
128 * Private prototypes.
129 */
130
131 static int bd_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
132 static int bd_attach(dev_info_t *, ddi_attach_cmd_t);
133 static int bd_detach(dev_info_t *, ddi_detach_cmd_t);
134
135 static int bd_open(dev_t *, int, int, cred_t *);
136 static int bd_close(dev_t, int, int, cred_t *);
137 static int bd_strategy(struct buf *);
138 static int bd_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
139 static int bd_read(dev_t, struct uio *, cred_t *);
140 static int bd_write(dev_t, struct uio *, cred_t *);
141 static int bd_aread(dev_t, struct aio_req *, cred_t *);
142 static int bd_awrite(dev_t, struct aio_req *, cred_t *);
143 static int bd_prop_op(dev_t, dev_info_t *, ddi_prop_op_t, int, char *,
144 caddr_t, int *);
145
146 static int bd_tg_rdwr(dev_info_t *, uchar_t, void *, diskaddr_t, size_t,
147 void *);
148 static int bd_tg_getinfo(dev_info_t *, int, void *, void *);
149 static int bd_xfer_ctor(void *, void *, int);
150 static void bd_xfer_dtor(void *, void *);
151 static void bd_sched(bd_t *);
152 static void bd_submit(bd_t *, bd_xfer_impl_t *);
153 static void bd_runq_exit(bd_xfer_impl_t *, int);
154 static void bd_update_state(bd_t *);
155 static int bd_check_state(bd_t *, enum dkio_state *);
156 static int bd_flush_write_cache(bd_t *, struct dk_callback *);
157
158 struct cmlb_tg_ops bd_tg_ops = {
159 TG_DK_OPS_VERSION_1,
160 bd_tg_rdwr,
161 bd_tg_getinfo,
162 };
163
164 static struct cb_ops bd_cb_ops = {
165 bd_open, /* open */
166 bd_close, /* close */
167 bd_strategy, /* strategy */
168 nodev, /* print */
169 nodev, /* dump */
170 bd_read, /* read */
171 bd_write, /* write */
172 bd_ioctl, /* ioctl */
173 nodev, /* devmap */
174 nodev, /* mmap */
175 nodev, /* segmap */
176 nochpoll, /* poll */
177 bd_prop_op, /* cb_prop_op */
178 0, /* streamtab */
179 D_64BIT | D_MP, /* Driver comaptibility flag */
180 CB_REV, /* cb_rev */
181 bd_aread, /* async read */
182 bd_awrite /* async write */
183 };
184
185 struct dev_ops bd_dev_ops = {
186 DEVO_REV, /* devo_rev, */
187 0, /* refcnt */
188 bd_getinfo, /* getinfo */
189 nulldev, /* identify */
190 nulldev, /* probe */
191 bd_attach, /* attach */
192 bd_detach, /* detach */
193 nodev, /* reset */
194 &bd_cb_ops, /* driver operations */
195 NULL, /* bus operations */
196 NULL, /* power */
197 ddi_quiesce_not_needed, /* quiesce */
198 };
199
200 static struct modldrv modldrv = {
201 &mod_driverops,
202 "Generic Block Device",
203 &bd_dev_ops,
204 };
205
206 static struct modlinkage modlinkage = {
207 MODREV_1, { &modldrv, NULL }
208 };
209
210 static void *bd_state;
211 static krwlock_t bd_lock;
212
213 int
_init(void)214 _init(void)
215 {
216 int rv;
217
218 rv = ddi_soft_state_init(&bd_state, sizeof (struct bd), 2);
219 if (rv != DDI_SUCCESS) {
220 return (rv);
221 }
222 rw_init(&bd_lock, NULL, RW_DRIVER, NULL);
223 rv = mod_install(&modlinkage);
224 if (rv != DDI_SUCCESS) {
225 rw_destroy(&bd_lock);
226 ddi_soft_state_fini(&bd_state);
227 }
228 return (rv);
229 }
230
231 int
_fini(void)232 _fini(void)
233 {
234 int rv;
235
236 rv = mod_remove(&modlinkage);
237 if (rv == DDI_SUCCESS) {
238 rw_destroy(&bd_lock);
239 ddi_soft_state_fini(&bd_state);
240 }
241 return (rv);
242 }
243
244 int
_info(struct modinfo * modinfop)245 _info(struct modinfo *modinfop)
246 {
247 return (mod_info(&modlinkage, modinfop));
248 }
249
250 static int
bd_getinfo(dev_info_t * dip,ddi_info_cmd_t cmd,void * arg,void ** resultp)251 bd_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **resultp)
252 {
253 bd_t *bd;
254 minor_t inst;
255
256 _NOTE(ARGUNUSED(dip));
257
258 inst = BDINST((dev_t)arg);
259
260 switch (cmd) {
261 case DDI_INFO_DEVT2DEVINFO:
262 bd = ddi_get_soft_state(bd_state, inst);
263 if (bd == NULL) {
264 return (DDI_FAILURE);
265 }
266 *resultp = (void *)bd->d_dip;
267 break;
268
269 case DDI_INFO_DEVT2INSTANCE:
270 *resultp = (void *)(intptr_t)inst;
271 break;
272
273 default:
274 return (DDI_FAILURE);
275 }
276 return (DDI_SUCCESS);
277 }
278
279 static int
bd_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)280 bd_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
281 {
282 int inst;
283 bd_handle_t hdl;
284 bd_t *bd;
285 bd_drive_t drive;
286 int rv;
287 char name[16];
288 char kcache[32];
289
290 switch (cmd) {
291 case DDI_ATTACH:
292 break;
293 case DDI_RESUME:
294 /* We don't do anything native for suspend/resume */
295 return (DDI_SUCCESS);
296 default:
297 return (DDI_FAILURE);
298 }
299
300 inst = ddi_get_instance(dip);
301 hdl = ddi_get_parent_data(dip);
302
303 (void) snprintf(name, sizeof (name), "%s%d",
304 ddi_driver_name(dip), ddi_get_instance(dip));
305 (void) snprintf(kcache, sizeof (kcache), "%s_xfer", name);
306
307 if (hdl == NULL) {
308 cmn_err(CE_WARN, "%s: missing parent data!", name);
309 return (DDI_FAILURE);
310 }
311
312 if (ddi_soft_state_zalloc(bd_state, inst) != DDI_SUCCESS) {
313 cmn_err(CE_WARN, "%s: unable to zalloc soft state!", name);
314 return (DDI_FAILURE);
315 }
316 bd = ddi_get_soft_state(bd_state, inst);
317
318 if (hdl->h_dma) {
319 bd->d_dma = *(hdl->h_dma);
320 bd->d_dma.dma_attr_granular =
321 max(DEV_BSIZE, bd->d_dma.dma_attr_granular);
322 bd->d_use_dma = B_TRUE;
323
324 if (bd->d_maxxfer &&
325 (bd->d_maxxfer != bd->d_dma.dma_attr_maxxfer)) {
326 cmn_err(CE_WARN,
327 "%s: inconsistent maximum transfer size!",
328 name);
329 /* We force it */
330 bd->d_maxxfer = bd->d_dma.dma_attr_maxxfer;
331 } else {
332 bd->d_maxxfer = bd->d_dma.dma_attr_maxxfer;
333 }
334 } else {
335 bd->d_use_dma = B_FALSE;
336 if (bd->d_maxxfer == 0) {
337 bd->d_maxxfer = 1024 * 1024;
338 }
339 }
340 bd->d_ops = hdl->h_ops;
341 bd->d_private = hdl->h_private;
342 bd->d_blkshift = 9; /* 512 bytes, to start */
343
344 if (bd->d_maxxfer % DEV_BSIZE) {
345 cmn_err(CE_WARN, "%s: maximum transfer misaligned!", name);
346 bd->d_maxxfer &= ~(DEV_BSIZE - 1);
347 }
348 if (bd->d_maxxfer < DEV_BSIZE) {
349 cmn_err(CE_WARN, "%s: maximum transfer size too small!", name);
350 ddi_soft_state_free(bd_state, inst);
351 return (DDI_FAILURE);
352 }
353
354 bd->d_dip = dip;
355 bd->d_handle = hdl;
356 hdl->h_bd = bd;
357 ddi_set_driver_private(dip, bd);
358
359 mutex_init(&bd->d_iomutex, NULL, MUTEX_DRIVER, NULL);
360 mutex_init(&bd->d_ocmutex, NULL, MUTEX_DRIVER, NULL);
361 mutex_init(&bd->d_statemutex, NULL, MUTEX_DRIVER, NULL);
362 cv_init(&bd->d_statecv, NULL, CV_DRIVER, NULL);
363
364 list_create(&bd->d_waitq, sizeof (bd_xfer_impl_t),
365 offsetof(struct bd_xfer_impl, i_linkage));
366 list_create(&bd->d_runq, sizeof (bd_xfer_impl_t),
367 offsetof(struct bd_xfer_impl, i_linkage));
368
369 bd->d_cache = kmem_cache_create(kcache, sizeof (bd_xfer_impl_t), 8,
370 bd_xfer_ctor, bd_xfer_dtor, NULL, bd, NULL, 0);
371
372 bd->d_ksp = kstat_create(ddi_driver_name(dip), inst, NULL, "disk",
373 KSTAT_TYPE_IO, 1, KSTAT_FLAG_PERSISTENT);
374 if (bd->d_ksp != NULL) {
375 bd->d_ksp->ks_lock = &bd->d_iomutex;
376 kstat_install(bd->d_ksp);
377 bd->d_kiop = bd->d_ksp->ks_data;
378 } else {
379 /*
380 * Even if we cannot create the kstat, we create a
381 * scratch kstat. The reason for this is to ensure
382 * that we can update the kstat all of the time,
383 * without adding an extra branch instruction.
384 */
385 bd->d_kiop = kmem_zalloc(sizeof (kstat_io_t), KM_SLEEP);
386 }
387
388 cmlb_alloc_handle(&bd->d_cmlbh);
389
390 bd->d_state = DKIO_NONE;
391
392 bzero(&drive, sizeof (drive));
393 bd->d_ops.o_drive_info(bd->d_private, &drive);
394 bd->d_qsize = drive.d_qsize;
395 bd->d_maxxfer = drive.d_maxxfer;
396 bd->d_removable = drive.d_removable;
397 bd->d_hotpluggable = drive.d_hotpluggable;
398
399 rv = cmlb_attach(dip, &bd_tg_ops, DTYPE_DIRECT,
400 bd->d_removable, bd->d_hotpluggable,
401 drive.d_lun >= 0 ? DDI_NT_BLOCK_CHAN : DDI_NT_BLOCK,
402 CMLB_FAKE_LABEL_ONE_PARTITION, bd->d_cmlbh, bd);
403 if (rv != 0) {
404 cmlb_free_handle(&bd->d_cmlbh);
405 kmem_cache_destroy(bd->d_cache);
406 mutex_destroy(&bd->d_iomutex);
407 mutex_destroy(&bd->d_ocmutex);
408 mutex_destroy(&bd->d_statemutex);
409 cv_destroy(&bd->d_statecv);
410 list_destroy(&bd->d_waitq);
411 list_destroy(&bd->d_runq);
412 if (bd->d_ksp != NULL) {
413 kstat_delete(bd->d_ksp);
414 bd->d_ksp = NULL;
415 } else {
416 kmem_free(bd->d_kiop, sizeof (kstat_io_t));
417 }
418 ddi_soft_state_free(bd_state, inst);
419 return (DDI_FAILURE);
420 }
421
422 if (bd->d_ops.o_devid_init != NULL) {
423 rv = bd->d_ops.o_devid_init(bd->d_private, dip, &bd->d_devid);
424 if (rv == DDI_SUCCESS) {
425 if (ddi_devid_register(dip, bd->d_devid) !=
426 DDI_SUCCESS) {
427 cmn_err(CE_WARN,
428 "%s: unable to register devid", name);
429 }
430 }
431 }
432
433 /*
434 * Add a zero-length attribute to tell the world we support
435 * kernel ioctls (for layered drivers). Also set up properties
436 * used by HAL to identify removable media.
437 */
438 (void) ddi_prop_create(DDI_DEV_T_NONE, dip, DDI_PROP_CANSLEEP,
439 DDI_KERNEL_IOCTL, NULL, 0);
440 if (bd->d_removable) {
441 (void) ddi_prop_create(DDI_DEV_T_NONE, dip, DDI_PROP_CANSLEEP,
442 "removable-media", NULL, 0);
443 }
444 if (bd->d_hotpluggable) {
445 (void) ddi_prop_create(DDI_DEV_T_NONE, dip, DDI_PROP_CANSLEEP,
446 "hotpluggable", NULL, 0);
447 }
448
449 ddi_report_dev(dip);
450
451 return (DDI_SUCCESS);
452 }
453
454 static int
bd_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)455 bd_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
456 {
457 bd_t *bd;
458
459 bd = ddi_get_driver_private(dip);
460
461 switch (cmd) {
462 case DDI_DETACH:
463 break;
464 case DDI_SUSPEND:
465 /* We don't suspend, but our parent does */
466 return (DDI_SUCCESS);
467 default:
468 return (DDI_FAILURE);
469 }
470 if (bd->d_ksp != NULL) {
471 kstat_delete(bd->d_ksp);
472 bd->d_ksp = NULL;
473 } else {
474 kmem_free(bd->d_kiop, sizeof (kstat_io_t));
475 }
476 cmlb_detach(bd->d_cmlbh, bd);
477 cmlb_free_handle(&bd->d_cmlbh);
478 if (bd->d_devid)
479 ddi_devid_free(bd->d_devid);
480 kmem_cache_destroy(bd->d_cache);
481 mutex_destroy(&bd->d_iomutex);
482 mutex_destroy(&bd->d_ocmutex);
483 mutex_destroy(&bd->d_statemutex);
484 cv_destroy(&bd->d_statecv);
485 list_destroy(&bd->d_waitq);
486 list_destroy(&bd->d_runq);
487 ddi_soft_state_free(bd_state, ddi_get_instance(dip));
488 return (DDI_SUCCESS);
489 }
490
491 static int
bd_xfer_ctor(void * buf,void * arg,int kmflag)492 bd_xfer_ctor(void *buf, void *arg, int kmflag)
493 {
494 bd_xfer_impl_t *xi;
495 bd_t *bd = arg;
496 int (*dcb)(caddr_t);
497
498 if (kmflag == KM_SLEEP) {
499 dcb = DDI_DMA_SLEEP;
500 } else {
501 dcb = DDI_DMA_DONTWAIT;
502 }
503
504 xi = buf;
505 bzero(xi, sizeof (*xi));
506 xi->i_bd = bd;
507
508 if (bd->d_use_dma) {
509 if (ddi_dma_alloc_handle(bd->d_dip, &bd->d_dma, dcb, NULL,
510 &xi->i_dmah) != DDI_SUCCESS) {
511 return (-1);
512 }
513 }
514
515 return (0);
516 }
517
518 static void
bd_xfer_dtor(void * buf,void * arg)519 bd_xfer_dtor(void *buf, void *arg)
520 {
521 bd_xfer_impl_t *xi = buf;
522
523 _NOTE(ARGUNUSED(arg));
524
525 if (xi->i_dmah)
526 ddi_dma_free_handle(&xi->i_dmah);
527 xi->i_dmah = NULL;
528 }
529
530 static bd_xfer_impl_t *
bd_xfer_alloc(bd_t * bd,struct buf * bp,int (* func)(void *,bd_xfer_t *),int kmflag)531 bd_xfer_alloc(bd_t *bd, struct buf *bp, int (*func)(void *, bd_xfer_t *),
532 int kmflag)
533 {
534 bd_xfer_impl_t *xi;
535 int rv;
536 int status;
537 unsigned dir;
538 int (*cb)(caddr_t);
539 size_t len;
540 uint32_t shift;
541
542 if (kmflag == KM_SLEEP) {
543 cb = DDI_DMA_SLEEP;
544 } else {
545 cb = DDI_DMA_DONTWAIT;
546 }
547
548 xi = kmem_cache_alloc(bd->d_cache, kmflag);
549 if (xi == NULL) {
550 bioerror(bp, ENOMEM);
551 return (NULL);
552 }
553
554 ASSERT(bp);
555 ASSERT(bp->b_bcount);
556
557 xi->i_bp = bp;
558 xi->i_func = func;
559 xi->i_blkno = bp->b_lblkno;
560
561 if (bp->b_bcount == 0) {
562 xi->i_len = 0;
563 xi->i_nblks = 0;
564 xi->i_kaddr = NULL;
565 xi->i_resid = 0;
566 xi->i_num_win = 0;
567 goto done;
568 }
569
570 if (bp->b_flags & B_READ) {
571 dir = DDI_DMA_READ;
572 xi->i_func = bd->d_ops.o_read;
573 } else {
574 dir = DDI_DMA_WRITE;
575 xi->i_func = bd->d_ops.o_write;
576 }
577
578 shift = bd->d_blkshift;
579 xi->i_blkshift = shift;
580
581 if (!bd->d_use_dma) {
582 bp_mapin(bp);
583 rv = 0;
584 xi->i_offset = 0;
585 xi->i_num_win =
586 (bp->b_bcount + (bd->d_maxxfer - 1)) / bd->d_maxxfer;
587 xi->i_cur_win = 0;
588 xi->i_len = min(bp->b_bcount, bd->d_maxxfer);
589 xi->i_nblks = xi->i_len >> shift;
590 xi->i_kaddr = bp->b_un.b_addr;
591 xi->i_resid = bp->b_bcount;
592 } else {
593
594 /*
595 * We have to use consistent DMA if the address is misaligned.
596 */
597 if (((bp->b_flags & (B_PAGEIO | B_REMAPPED)) != B_PAGEIO) &&
598 ((uintptr_t)bp->b_un.b_addr & 0x7)) {
599 dir |= DDI_DMA_CONSISTENT | DDI_DMA_PARTIAL;
600 } else {
601 dir |= DDI_DMA_STREAMING | DDI_DMA_PARTIAL;
602 }
603
604 status = ddi_dma_buf_bind_handle(xi->i_dmah, bp, dir, cb,
605 NULL, &xi->i_dmac, &xi->i_ndmac);
606 switch (status) {
607 case DDI_DMA_MAPPED:
608 xi->i_num_win = 1;
609 xi->i_cur_win = 0;
610 xi->i_offset = 0;
611 xi->i_len = bp->b_bcount;
612 xi->i_nblks = xi->i_len >> shift;
613 xi->i_resid = bp->b_bcount;
614 rv = 0;
615 break;
616 case DDI_DMA_PARTIAL_MAP:
617 xi->i_cur_win = 0;
618
619 if ((ddi_dma_numwin(xi->i_dmah, &xi->i_num_win) !=
620 DDI_SUCCESS) ||
621 (ddi_dma_getwin(xi->i_dmah, 0, &xi->i_offset,
622 &len, &xi->i_dmac, &xi->i_ndmac) !=
623 DDI_SUCCESS) ||
624 (P2PHASE(len, shift) != 0)) {
625 (void) ddi_dma_unbind_handle(xi->i_dmah);
626 rv = EFAULT;
627 goto done;
628 }
629 xi->i_len = len;
630 xi->i_nblks = xi->i_len >> shift;
631 xi->i_resid = bp->b_bcount;
632 rv = 0;
633 break;
634 case DDI_DMA_NORESOURCES:
635 rv = EAGAIN;
636 goto done;
637 case DDI_DMA_TOOBIG:
638 rv = EINVAL;
639 goto done;
640 case DDI_DMA_NOMAPPING:
641 case DDI_DMA_INUSE:
642 default:
643 rv = EFAULT;
644 goto done;
645 }
646 }
647
648 done:
649 if (rv != 0) {
650 kmem_cache_free(bd->d_cache, xi);
651 bioerror(bp, rv);
652 return (NULL);
653 }
654
655 return (xi);
656 }
657
658 static void
bd_xfer_free(bd_xfer_impl_t * xi)659 bd_xfer_free(bd_xfer_impl_t *xi)
660 {
661 if (xi->i_dmah) {
662 (void) ddi_dma_unbind_handle(xi->i_dmah);
663 }
664 kmem_cache_free(xi->i_bd->d_cache, xi);
665 }
666
667 static int
bd_open(dev_t * devp,int flag,int otyp,cred_t * credp)668 bd_open(dev_t *devp, int flag, int otyp, cred_t *credp)
669 {
670 dev_t dev = *devp;
671 bd_t *bd;
672 minor_t part;
673 minor_t inst;
674 uint64_t mask;
675 boolean_t ndelay;
676 int rv;
677 diskaddr_t nblks;
678 diskaddr_t lba;
679
680 _NOTE(ARGUNUSED(credp));
681
682 part = BDPART(dev);
683 inst = BDINST(dev);
684
685 if (otyp >= OTYPCNT)
686 return (EINVAL);
687
688 ndelay = (flag & (FNDELAY | FNONBLOCK)) ? B_TRUE : B_FALSE;
689
690 /*
691 * Block any DR events from changing the set of registered
692 * devices while we function.
693 */
694 rw_enter(&bd_lock, RW_READER);
695 if ((bd = ddi_get_soft_state(bd_state, inst)) == NULL) {
696 rw_exit(&bd_lock);
697 return (ENXIO);
698 }
699
700 mutex_enter(&bd->d_ocmutex);
701
702 ASSERT(part < 64);
703 mask = (1U << part);
704
705 bd_update_state(bd);
706
707 if (cmlb_validate(bd->d_cmlbh, 0, bd) != 0) {
708
709 /* non-blocking opens are allowed to succeed */
710 if (!ndelay) {
711 rv = ENXIO;
712 goto done;
713 }
714 } else if (cmlb_partinfo(bd->d_cmlbh, part, &nblks, &lba,
715 NULL, NULL, bd) == 0) {
716
717 /*
718 * We read the partinfo, verify valid ranges. If the
719 * partition is invalid, and we aren't blocking or
720 * doing a raw access, then fail. (Non-blocking and
721 * raw accesses can still succeed to allow a disk with
722 * bad partition data to opened by format and fdisk.)
723 */
724 if ((!nblks) && ((!ndelay) || (otyp != OTYP_CHR))) {
725 rv = ENXIO;
726 goto done;
727 }
728 } else if (!ndelay) {
729 /*
730 * cmlb_partinfo failed -- invalid partition or no
731 * disk label.
732 */
733 rv = ENXIO;
734 goto done;
735 }
736
737 if ((flag & FWRITE) && bd->d_rdonly) {
738 rv = EROFS;
739 goto done;
740 }
741
742 if ((bd->d_open_excl) & (mask)) {
743 rv = EBUSY;
744 goto done;
745 }
746 if (flag & FEXCL) {
747 if (bd->d_open_lyr[part]) {
748 rv = EBUSY;
749 goto done;
750 }
751 for (int i = 0; i < OTYP_LYR; i++) {
752 if (bd->d_open_reg[i] & mask) {
753 rv = EBUSY;
754 goto done;
755 }
756 }
757 }
758
759 if (otyp == OTYP_LYR) {
760 bd->d_open_lyr[part]++;
761 } else {
762 bd->d_open_reg[otyp] |= mask;
763 }
764 if (flag & FEXCL) {
765 bd->d_open_excl |= mask;
766 }
767
768 rv = 0;
769 done:
770 mutex_exit(&bd->d_ocmutex);
771 rw_exit(&bd_lock);
772
773 return (rv);
774 }
775
776 static int
bd_close(dev_t dev,int flag,int otyp,cred_t * credp)777 bd_close(dev_t dev, int flag, int otyp, cred_t *credp)
778 {
779 bd_t *bd;
780 minor_t inst;
781 minor_t part;
782 uint64_t mask;
783 boolean_t last = B_TRUE;
784
785 _NOTE(ARGUNUSED(flag));
786 _NOTE(ARGUNUSED(credp));
787
788 part = BDPART(dev);
789 inst = BDINST(dev);
790
791 ASSERT(part < 64);
792 mask = (1U << part);
793
794 rw_enter(&bd_lock, RW_READER);
795
796 if ((bd = ddi_get_soft_state(bd_state, inst)) == NULL) {
797 rw_exit(&bd_lock);
798 return (ENXIO);
799 }
800
801 mutex_enter(&bd->d_ocmutex);
802 if (bd->d_open_excl & mask) {
803 bd->d_open_excl &= ~mask;
804 }
805 if (otyp == OTYP_LYR) {
806 bd->d_open_lyr[part]--;
807 } else {
808 bd->d_open_reg[otyp] &= ~mask;
809 }
810 for (int i = 0; i < 64; i++) {
811 if (bd->d_open_lyr[part]) {
812 last = B_FALSE;
813 }
814 }
815 for (int i = 0; last && (i < OTYP_LYR); i++) {
816 if (bd->d_open_reg[i]) {
817 last = B_FALSE;
818 }
819 }
820 mutex_exit(&bd->d_ocmutex);
821
822 if (last) {
823 cmlb_invalidate(bd->d_cmlbh, bd);
824 }
825 rw_exit(&bd_lock);
826
827 return (0);
828 }
829
830 static int
bd_read(dev_t dev,struct uio * uio,cred_t * credp)831 bd_read(dev_t dev, struct uio *uio, cred_t *credp)
832 {
833 _NOTE(ARGUNUSED(credp));
834 return (physio(bd_strategy, NULL, dev, B_READ, minphys, uio));
835 }
836
837 static int
bd_write(dev_t dev,struct uio * uio,cred_t * credp)838 bd_write(dev_t dev, struct uio *uio, cred_t *credp)
839 {
840 _NOTE(ARGUNUSED(credp));
841 return (physio(bd_strategy, NULL, dev, B_WRITE, minphys, uio));
842 }
843
844 static int
bd_aread(dev_t dev,struct aio_req * aio,cred_t * credp)845 bd_aread(dev_t dev, struct aio_req *aio, cred_t *credp)
846 {
847 _NOTE(ARGUNUSED(credp));
848 return (aphysio(bd_strategy, anocancel, dev, B_READ, minphys, aio));
849 }
850
851 static int
bd_awrite(dev_t dev,struct aio_req * aio,cred_t * credp)852 bd_awrite(dev_t dev, struct aio_req *aio, cred_t *credp)
853 {
854 _NOTE(ARGUNUSED(credp));
855 return (aphysio(bd_strategy, anocancel, dev, B_WRITE, minphys, aio));
856 }
857
858 static int
bd_strategy(struct buf * bp)859 bd_strategy(struct buf *bp)
860 {
861 minor_t inst;
862 minor_t part;
863 bd_t *bd;
864 diskaddr_t p_lba;
865 diskaddr_t p_nblks;
866 diskaddr_t b_nblks;
867 bd_xfer_impl_t *xi;
868 uint32_t shift;
869 int (*func)(void *, bd_xfer_t *);
870
871 part = BDPART(bp->b_edev);
872 inst = BDINST(bp->b_edev);
873
874 ASSERT(bp);
875
876 bp->b_resid = bp->b_bcount;
877
878 if ((bd = ddi_get_soft_state(bd_state, inst)) == NULL) {
879 bioerror(bp, ENXIO);
880 biodone(bp);
881 return (0);
882 }
883
884 if (cmlb_partinfo(bd->d_cmlbh, part, &p_nblks, &p_lba,
885 NULL, NULL, bd)) {
886 bioerror(bp, ENXIO);
887 biodone(bp);
888 return (0);
889 }
890
891 shift = bd->d_blkshift;
892
893 if ((P2PHASE(bp->b_bcount, (1U << shift)) != 0) ||
894 (bp->b_lblkno > p_nblks)) {
895 bioerror(bp, ENXIO);
896 biodone(bp);
897 return (0);
898 }
899 b_nblks = bp->b_bcount >> shift;
900 if ((bp->b_lblkno == p_nblks) || (bp->b_bcount == 0)) {
901 biodone(bp);
902 return (0);
903 }
904
905 if ((b_nblks + bp->b_lblkno) > p_nblks) {
906 bp->b_resid = ((bp->b_lblkno + b_nblks - p_nblks) << shift);
907 bp->b_bcount -= bp->b_resid;
908 } else {
909 bp->b_resid = 0;
910 }
911 func = (bp->b_flags & B_READ) ? bd->d_ops.o_read : bd->d_ops.o_write;
912
913 xi = bd_xfer_alloc(bd, bp, func, KM_NOSLEEP);
914 if (xi == NULL) {
915 xi = bd_xfer_alloc(bd, bp, func, KM_PUSHPAGE);
916 }
917 if (xi == NULL) {
918 /* bd_request_alloc will have done bioerror */
919 biodone(bp);
920 return (0);
921 }
922 xi->i_blkno = bp->b_lblkno + p_lba;
923
924 bd_submit(bd, xi);
925
926 return (0);
927 }
928
929 static int
bd_ioctl(dev_t dev,int cmd,intptr_t arg,int flag,cred_t * credp,int * rvalp)930 bd_ioctl(dev_t dev, int cmd, intptr_t arg, int flag, cred_t *credp, int *rvalp)
931 {
932 minor_t inst;
933 uint16_t part;
934 bd_t *bd;
935 void *ptr = (void *)arg;
936 int rv;
937
938 part = BDPART(dev);
939 inst = BDINST(dev);
940
941 if ((bd = ddi_get_soft_state(bd_state, inst)) == NULL) {
942 return (ENXIO);
943 }
944
945 rv = cmlb_ioctl(bd->d_cmlbh, dev, cmd, arg, flag, credp, rvalp, bd);
946 if (rv != ENOTTY)
947 return (rv);
948
949 switch (cmd) {
950 case DKIOCGMEDIAINFO: {
951 struct dk_minfo minfo;
952
953 /* make sure our state information is current */
954 bd_update_state(bd);
955 bzero(&minfo, sizeof (minfo));
956 minfo.dki_media_type = DK_FIXED_DISK;
957 minfo.dki_lbsize = (1U << bd->d_blkshift);
958 minfo.dki_capacity = bd->d_numblks;
959 if (ddi_copyout(&minfo, ptr, sizeof (minfo), flag)) {
960 return (EFAULT);
961 }
962 return (0);
963 }
964 case DKIOCINFO: {
965 struct dk_cinfo cinfo;
966 bzero(&cinfo, sizeof (cinfo));
967 cinfo.dki_ctype = DKC_BLKDEV;
968 cinfo.dki_cnum = ddi_get_instance(ddi_get_parent(bd->d_dip));
969 (void) snprintf(cinfo.dki_cname, sizeof (cinfo.dki_cname),
970 "%s", ddi_driver_name(ddi_get_parent(bd->d_dip)));
971 (void) snprintf(cinfo.dki_dname, sizeof (cinfo.dki_dname),
972 "%s", ddi_driver_name(bd->d_dip));
973 cinfo.dki_unit = inst;
974 cinfo.dki_flags = DKI_FMTVOL;
975 cinfo.dki_partition = part;
976 cinfo.dki_maxtransfer = bd->d_maxxfer / DEV_BSIZE;
977 cinfo.dki_addr = 0;
978 cinfo.dki_slave = 0;
979 cinfo.dki_space = 0;
980 cinfo.dki_prio = 0;
981 cinfo.dki_vec = 0;
982 if (ddi_copyout(&cinfo, ptr, sizeof (cinfo), flag)) {
983 return (EFAULT);
984 }
985 return (0);
986 }
987 case DKIOCREMOVABLE: {
988 int i;
989 i = bd->d_removable ? 1 : 0;
990 if (ddi_copyout(&i, ptr, sizeof (i), flag)) {
991 return (EFAULT);
992 }
993 return (0);
994 }
995 case DKIOCHOTPLUGGABLE: {
996 int i;
997 i = bd->d_hotpluggable ? 1 : 0;
998 if (ddi_copyout(&i, ptr, sizeof (i), flag)) {
999 return (EFAULT);
1000 }
1001 return (0);
1002 }
1003 case DKIOCREADONLY: {
1004 int i;
1005 i = bd->d_rdonly ? 1 : 0;
1006 if (ddi_copyout(&i, ptr, sizeof (i), flag)) {
1007 return (EFAULT);
1008 }
1009 return (0);
1010 }
1011 case DKIOCSTATE: {
1012 enum dkio_state state;
1013 if (ddi_copyin(ptr, &state, sizeof (state), flag)) {
1014 return (EFAULT);
1015 }
1016 if ((rv = bd_check_state(bd, &state)) != 0) {
1017 return (rv);
1018 }
1019 if (ddi_copyout(&state, ptr, sizeof (state), flag)) {
1020 return (EFAULT);
1021 }
1022 return (0);
1023 }
1024 case DKIOCFLUSHWRITECACHE: {
1025 struct dk_callback *dkc;
1026
1027 dkc = flag & FKIOCTL ? (void *)arg : NULL;
1028 rv = bd_flush_write_cache(bd, dkc);
1029 return (rv);
1030 }
1031
1032 default:
1033 break;
1034
1035 }
1036 return (ENOTTY);
1037 }
1038
1039 static int
bd_prop_op(dev_t dev,dev_info_t * dip,ddi_prop_op_t prop_op,int mod_flags,char * name,caddr_t valuep,int * lengthp)1040 bd_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op, int mod_flags,
1041 char *name, caddr_t valuep, int *lengthp)
1042 {
1043 bd_t *bd;
1044
1045 bd = ddi_get_soft_state(bd_state, ddi_get_instance(dip));
1046 if (bd == NULL)
1047 return (ddi_prop_op(dev, dip, prop_op, mod_flags,
1048 name, valuep, lengthp));
1049
1050 return (cmlb_prop_op(bd->d_cmlbh, dev, dip, prop_op, mod_flags, name,
1051 valuep, lengthp, BDPART(dev), bd));
1052 }
1053
1054
1055 static int
bd_tg_rdwr(dev_info_t * dip,uchar_t cmd,void * bufaddr,diskaddr_t start,size_t length,void * tg_cookie)1056 bd_tg_rdwr(dev_info_t *dip, uchar_t cmd, void *bufaddr, diskaddr_t start,
1057 size_t length, void *tg_cookie)
1058 {
1059 bd_t *bd;
1060 buf_t *bp;
1061 bd_xfer_impl_t *xi;
1062 int rv;
1063 int (*func)(void *, bd_xfer_t *);
1064
1065 _NOTE(ARGUNUSED(dip));
1066
1067
1068 bd = tg_cookie;
1069 if (P2PHASE(length, (1U << bd->d_blkshift)) != 0) {
1070 /* We can only transfer whole blocks at a time! */
1071 return (EINVAL);
1072 }
1073
1074 bp = getrbuf(KM_SLEEP);
1075
1076 switch (cmd) {
1077 case TG_READ:
1078 bp->b_flags = B_READ;
1079 func = bd->d_ops.o_read;
1080 break;
1081 case TG_WRITE:
1082 bp->b_flags = B_WRITE;
1083 func = bd->d_ops.o_write;
1084 break;
1085 default:
1086 freerbuf(bp);
1087 return (EINVAL);
1088 }
1089
1090 bp->b_un.b_addr = bufaddr;
1091 bp->b_bcount = length;
1092 xi = bd_xfer_alloc(bd, bp, func, KM_SLEEP);
1093 if (xi == NULL) {
1094 rv = geterror(bp);
1095 freerbuf(bp);
1096 return (rv);
1097 }
1098
1099 xi->i_blkno = start;
1100 bd_submit(bd, xi);
1101 (void) biowait(bp);
1102 rv = geterror(bp);
1103 freerbuf(bp);
1104
1105 return (rv);
1106 }
1107
1108 static int
bd_tg_getinfo(dev_info_t * dip,int cmd,void * arg,void * tg_cookie)1109 bd_tg_getinfo(dev_info_t *dip, int cmd, void *arg, void *tg_cookie)
1110 {
1111 bd_t *bd;
1112
1113 _NOTE(ARGUNUSED(dip));
1114 bd = tg_cookie;
1115
1116 switch (cmd) {
1117 case TG_GETPHYGEOM:
1118 case TG_GETVIRTGEOM:
1119 /*
1120 * We don't have any "geometry" as such, let cmlb
1121 * fabricate something.
1122 */
1123 return (ENOTTY);
1124
1125 case TG_GETCAPACITY:
1126 bd_update_state(bd);
1127 *(diskaddr_t *)arg = bd->d_numblks;
1128 return (0);
1129
1130 case TG_GETBLOCKSIZE:
1131 *(uint32_t *)arg = (1U << bd->d_blkshift);
1132 return (0);
1133
1134 case TG_GETATTR:
1135 /*
1136 * It turns out that cmlb really doesn't do much for
1137 * non-writable media, but lets make the information
1138 * available for it in case it does more in the
1139 * future. (The value is currently used for
1140 * triggering special behavior for CD-ROMs.)
1141 */
1142 bd_update_state(bd);
1143 ((tg_attribute_t *)arg)->media_is_writable =
1144 bd->d_rdonly ? B_FALSE : B_TRUE;
1145 return (0);
1146
1147 default:
1148 return (EINVAL);
1149 }
1150 }
1151
1152
1153 static void
bd_sched(bd_t * bd)1154 bd_sched(bd_t *bd)
1155 {
1156 bd_xfer_impl_t *xi;
1157 struct buf *bp;
1158 int rv;
1159
1160 ASSERT(mutex_owned(&bd->d_iomutex));
1161
1162 while ((bd->d_qactive < bd->d_qsize) &&
1163 ((xi = list_remove_head(&bd->d_waitq)) != NULL)) {
1164 bd->d_qactive++;
1165 kstat_waitq_to_runq(bd->d_kiop);
1166 list_insert_tail(&bd->d_runq, xi);
1167
1168 /* Submit the job to driver */
1169 rv = xi->i_func(bd->d_private, &xi->i_public);
1170 if (rv != 0) {
1171 bd->d_qactive--;
1172 kstat_runq_exit(bd->d_kiop);
1173 list_remove(&bd->d_runq, xi);
1174
1175 mutex_exit(&bd->d_iomutex);
1176 bp = xi->i_bp;
1177 bd_xfer_free(xi);
1178 bioerror(bp, rv);
1179 biodone(bp);
1180 mutex_enter(&bd->d_iomutex);
1181 }
1182 }
1183 }
1184
1185 static void
bd_submit(bd_t * bd,bd_xfer_impl_t * xi)1186 bd_submit(bd_t *bd, bd_xfer_impl_t *xi)
1187 {
1188 mutex_enter(&bd->d_iomutex);
1189 list_insert_tail(&bd->d_waitq, xi);
1190 kstat_waitq_enter(bd->d_kiop);
1191 bd_sched(bd);
1192 mutex_exit(&bd->d_iomutex);
1193 }
1194
1195 static void
bd_runq_exit(bd_xfer_impl_t * xi,int err)1196 bd_runq_exit(bd_xfer_impl_t *xi, int err)
1197 {
1198 bd_t *bd = xi->i_bd;
1199 buf_t *bp = xi->i_bp;
1200
1201 ASSERT(mutex_owned(&bd->d_iomutex));
1202
1203 bd->d_qactive--;
1204 kstat_runq_exit(bd->d_kiop);
1205 if (err == 0) {
1206 if (bp->b_flags & B_READ) {
1207 bd->d_kiop->reads++;
1208 bd->d_kiop->nread += (bp->b_bcount - xi->i_resid);
1209 } else {
1210 bd->d_kiop->writes++;
1211 bd->d_kiop->nwritten += (bp->b_bcount - xi->i_resid);
1212 }
1213 }
1214 list_remove(&bd->d_runq, xi);
1215 bd_sched(bd);
1216 }
1217
1218 static void
bd_update_state(bd_t * bd)1219 bd_update_state(bd_t *bd)
1220 {
1221 enum dkio_state state;
1222 bd_media_t media;
1223 boolean_t docmlb = B_FALSE;
1224
1225 bzero(&media, sizeof (media));
1226
1227 mutex_enter(&bd->d_statemutex);
1228 if (bd->d_ops.o_media_info(bd->d_private, &media) == 0) {
1229 if ((1U << bd->d_blkshift) != media.m_blksize) {
1230 if ((media.m_blksize < 512) ||
1231 (!ISP2(media.m_blksize)) ||
1232 (P2PHASE(bd->d_maxxfer, media.m_blksize))) {
1233 cmn_err(CE_WARN,
1234 "%s%d: Invalid media block size (%d)",
1235 ddi_driver_name(bd->d_dip),
1236 ddi_get_instance(bd->d_dip),
1237 media.m_blksize);
1238 /*
1239 * We can't use the media, treat it as
1240 * not present.
1241 */
1242 state = DKIO_EJECTED;
1243 bd->d_numblks = 0;
1244 } else {
1245 bd->d_blkshift = ddi_ffs(media.m_blksize) - 1;
1246 bd->d_numblks = media.m_nblks;
1247 bd->d_rdonly = media.m_readonly;
1248 state = DKIO_INSERTED;
1249 }
1250
1251 /* Device size changed */
1252 docmlb = B_TRUE;
1253
1254 } else {
1255 if (bd->d_numblks != media.m_nblks) {
1256 /* Device size changed */
1257 docmlb = B_TRUE;
1258 }
1259 bd->d_numblks = media.m_nblks;
1260 bd->d_rdonly = media.m_readonly;
1261 state = DKIO_INSERTED;
1262 }
1263
1264 } else {
1265 bd->d_numblks = 0;
1266 state = DKIO_EJECTED;
1267 }
1268 if (state != bd->d_state) {
1269 bd->d_state = state;
1270 cv_broadcast(&bd->d_statecv);
1271 docmlb = B_TRUE;
1272 }
1273 mutex_exit(&bd->d_statemutex);
1274
1275 if (docmlb) {
1276 if (state == DKIO_INSERTED) {
1277 (void) cmlb_validate(bd->d_cmlbh, 0, bd);
1278 } else {
1279 cmlb_invalidate(bd->d_cmlbh, bd);
1280 }
1281 }
1282 }
1283
1284 static int
bd_check_state(bd_t * bd,enum dkio_state * state)1285 bd_check_state(bd_t *bd, enum dkio_state *state)
1286 {
1287 clock_t when;
1288
1289 for (;;) {
1290
1291 bd_update_state(bd);
1292
1293 mutex_enter(&bd->d_statemutex);
1294
1295 if (bd->d_state != *state) {
1296 *state = bd->d_state;
1297 mutex_exit(&bd->d_statemutex);
1298 break;
1299 }
1300
1301 when = drv_usectohz(1000000);
1302 if (cv_reltimedwait_sig(&bd->d_statecv, &bd->d_statemutex,
1303 when, TR_CLOCK_TICK) == 0) {
1304 mutex_exit(&bd->d_statemutex);
1305 return (EINTR);
1306 }
1307
1308 mutex_exit(&bd->d_statemutex);
1309 }
1310
1311 return (0);
1312 }
1313
1314 static int
bd_flush_write_cache_done(struct buf * bp)1315 bd_flush_write_cache_done(struct buf *bp)
1316 {
1317 struct dk_callback *dc = (void *)bp->b_private;
1318
1319 (*dc->dkc_callback)(dc->dkc_cookie, geterror(bp));
1320 kmem_free(dc, sizeof (*dc));
1321 freerbuf(bp);
1322 return (0);
1323 }
1324
1325 static int
bd_flush_write_cache(bd_t * bd,struct dk_callback * dkc)1326 bd_flush_write_cache(bd_t *bd, struct dk_callback *dkc)
1327 {
1328 buf_t *bp;
1329 struct dk_callback *dc;
1330 bd_xfer_impl_t *xi;
1331 int rv;
1332
1333 if (bd->d_ops.o_sync_cache == NULL) {
1334 return (ENOTSUP);
1335 }
1336 if ((bp = getrbuf(KM_SLEEP)) == NULL) {
1337 return (ENOMEM);
1338 }
1339 bp->b_resid = 0;
1340 bp->b_bcount = 0;
1341
1342 xi = bd_xfer_alloc(bd, bp, bd->d_ops.o_sync_cache, KM_SLEEP);
1343 if (xi == NULL) {
1344 rv = geterror(bp);
1345 freerbuf(bp);
1346 return (rv);
1347 }
1348
1349 if (dkc != NULL) {
1350 /* Make a private copy of the callback structure */
1351 dc = kmem_alloc(sizeof (*dc), KM_SLEEP);
1352 *dc = *dkc;
1353 bp->b_private = dc;
1354 bp->b_iodone = bd_flush_write_cache_done;
1355 }
1356
1357 bd_submit(bd, xi);
1358 if (dkc == NULL) {
1359 /* wait synchronously */
1360 (void) biowait(bp);
1361 rv = geterror(bp);
1362 freerbuf(bp);
1363 } else {
1364 /* deferred via callback */
1365 rv = 0;
1366 }
1367 return (rv);
1368 }
1369
1370 /*
1371 * Nexus support.
1372 */
1373 int
bd_bus_ctl(dev_info_t * dip,dev_info_t * rdip,ddi_ctl_enum_t ctlop,void * arg,void * result)1374 bd_bus_ctl(dev_info_t *dip, dev_info_t *rdip, ddi_ctl_enum_t ctlop,
1375 void *arg, void *result)
1376 {
1377 bd_handle_t hdl;
1378
1379 switch (ctlop) {
1380 case DDI_CTLOPS_REPORTDEV:
1381 cmn_err(CE_CONT, "?Block device: %s@%s, %s%d\n",
1382 ddi_node_name(rdip), ddi_get_name_addr(rdip),
1383 ddi_driver_name(rdip), ddi_get_instance(rdip));
1384 return (DDI_SUCCESS);
1385
1386 case DDI_CTLOPS_INITCHILD:
1387 hdl = ddi_get_parent_data((dev_info_t *)arg);
1388 if (hdl == NULL) {
1389 return (DDI_NOT_WELL_FORMED);
1390 }
1391 ddi_set_name_addr((dev_info_t *)arg, hdl->h_addr);
1392 return (DDI_SUCCESS);
1393
1394 case DDI_CTLOPS_UNINITCHILD:
1395 ddi_set_name_addr((dev_info_t *)arg, NULL);
1396 ndi_prop_remove_all((dev_info_t *)arg);
1397 return (DDI_SUCCESS);
1398
1399 default:
1400 return (ddi_ctlops(dip, rdip, ctlop, arg, result));
1401 }
1402 }
1403
1404 /*
1405 * Functions for device drivers.
1406 */
1407 bd_handle_t
bd_alloc_handle(void * private,bd_ops_t * ops,ddi_dma_attr_t * dma,int kmflag)1408 bd_alloc_handle(void *private, bd_ops_t *ops, ddi_dma_attr_t *dma, int kmflag)
1409 {
1410 bd_handle_t hdl;
1411
1412 hdl = kmem_zalloc(sizeof (*hdl), kmflag);
1413 if (hdl != NULL) {
1414 hdl->h_ops = *ops;
1415 hdl->h_dma = dma;
1416 hdl->h_private = private;
1417 }
1418
1419 return (hdl);
1420 }
1421
1422 void
bd_free_handle(bd_handle_t hdl)1423 bd_free_handle(bd_handle_t hdl)
1424 {
1425 kmem_free(hdl, sizeof (*hdl));
1426 }
1427
1428 int
bd_attach_handle(dev_info_t * dip,bd_handle_t hdl)1429 bd_attach_handle(dev_info_t *dip, bd_handle_t hdl)
1430 {
1431 dev_info_t *child;
1432 bd_drive_t drive;
1433
1434 /* if drivers don't override this, make it assume none */
1435 drive.d_lun = -1;
1436 hdl->h_ops.o_drive_info(hdl->h_private, &drive);
1437
1438 hdl->h_parent = dip;
1439 hdl->h_name = "blkdev";
1440
1441 if (drive.d_lun >= 0) {
1442 (void) snprintf(hdl->h_addr, sizeof (hdl->h_addr), "%X,%X",
1443 drive.d_target, drive.d_lun);
1444 } else {
1445 (void) snprintf(hdl->h_addr, sizeof (hdl->h_addr), "%X",
1446 drive.d_target);
1447 }
1448 if (ndi_devi_alloc(dip, hdl->h_name, (pnode_t)DEVI_SID_NODEID,
1449 &child) != NDI_SUCCESS) {
1450 cmn_err(CE_WARN, "%s%d: unable to allocate node %s@%s",
1451 ddi_driver_name(dip), ddi_get_instance(dip),
1452 "blkdev", hdl->h_addr);
1453 return (DDI_FAILURE);
1454 }
1455
1456 ddi_set_parent_data(child, hdl);
1457 hdl->h_child = child;
1458
1459 if (ndi_devi_online(child, 0) == NDI_FAILURE) {
1460 cmn_err(CE_WARN, "%s%d: failed bringing node %s@%s online",
1461 ddi_driver_name(dip), ddi_get_instance(dip),
1462 hdl->h_name, hdl->h_addr);
1463 (void) ndi_devi_free(child);
1464 return (DDI_FAILURE);
1465 }
1466
1467 return (DDI_SUCCESS);
1468 }
1469
1470 int
bd_detach_handle(bd_handle_t hdl)1471 bd_detach_handle(bd_handle_t hdl)
1472 {
1473 int circ;
1474 int rv;
1475 char *devnm;
1476
1477 if (hdl->h_child == NULL) {
1478 return (DDI_SUCCESS);
1479 }
1480 ndi_devi_enter(hdl->h_parent, &circ);
1481 if (i_ddi_node_state(hdl->h_child) < DS_INITIALIZED) {
1482 rv = ddi_remove_child(hdl->h_child, 0);
1483 } else {
1484 devnm = kmem_alloc(MAXNAMELEN + 1, KM_SLEEP);
1485 (void) ddi_deviname(hdl->h_child, devnm);
1486 (void) devfs_clean(hdl->h_parent, devnm + 1, DV_CLEAN_FORCE);
1487 rv = ndi_devi_unconfig_one(hdl->h_parent, devnm + 1, NULL,
1488 NDI_DEVI_REMOVE | NDI_UNCONFIG);
1489 kmem_free(devnm, MAXNAMELEN + 1);
1490 }
1491 if (rv == 0) {
1492 hdl->h_child = NULL;
1493 }
1494
1495 ndi_devi_exit(hdl->h_parent, circ);
1496 return (rv = NDI_SUCCESS ? DDI_SUCCESS : DDI_FAILURE);
1497 }
1498
1499 void
bd_xfer_done(bd_xfer_t * xfer,int err)1500 bd_xfer_done(bd_xfer_t *xfer, int err)
1501 {
1502 bd_xfer_impl_t *xi = (void *)xfer;
1503 buf_t *bp = xi->i_bp;
1504 int rv;
1505 bd_t *bd = xi->i_bd;
1506 size_t len;
1507
1508 mutex_enter(&bd->d_iomutex);
1509 if (err != 0) {
1510 bd_runq_exit(xi, err);
1511 mutex_exit(&bd->d_iomutex);
1512
1513 bp->b_resid += xi->i_resid;
1514 bd_xfer_free(xi);
1515 bioerror(bp, err);
1516 biodone(bp);
1517 return;
1518 }
1519
1520 xi->i_cur_win++;
1521 xi->i_resid -= xi->i_len;
1522
1523 if (xi->i_resid == 0) {
1524 /* Job completed succcessfully! */
1525 bd_runq_exit(xi, 0);
1526 mutex_exit(&bd->d_iomutex);
1527
1528 bd_xfer_free(xi);
1529 biodone(bp);
1530 return;
1531 }
1532
1533 xi->i_blkno += xi->i_nblks;
1534
1535 if (bd->d_use_dma) {
1536 /* More transfer still pending... advance to next DMA window. */
1537 rv = ddi_dma_getwin(xi->i_dmah, xi->i_cur_win,
1538 &xi->i_offset, &len, &xi->i_dmac, &xi->i_ndmac);
1539 } else {
1540 /* Advance memory window. */
1541 xi->i_kaddr += xi->i_len;
1542 xi->i_offset += xi->i_len;
1543 len = min(bp->b_bcount - xi->i_offset, bd->d_maxxfer);
1544 }
1545
1546
1547 if ((rv != DDI_SUCCESS) ||
1548 (P2PHASE(len, (1U << xi->i_blkshift) != 0))) {
1549 bd_runq_exit(xi, EFAULT);
1550 mutex_exit(&bd->d_iomutex);
1551
1552 bp->b_resid += xi->i_resid;
1553 bd_xfer_free(xi);
1554 bioerror(bp, EFAULT);
1555 biodone(bp);
1556 return;
1557 }
1558 xi->i_len = len;
1559 xi->i_nblks = len >> xi->i_blkshift;
1560
1561 /* Submit next window to hardware. */
1562 rv = xi->i_func(bd->d_private, &xi->i_public);
1563 if (rv != 0) {
1564 bd_runq_exit(xi, rv);
1565 mutex_exit(&bd->d_iomutex);
1566
1567 bp->b_resid += xi->i_resid;
1568 bd_xfer_free(xi);
1569 bioerror(bp, rv);
1570 biodone(bp);
1571 return;
1572 }
1573
1574 mutex_exit(&bd->d_iomutex);
1575 }
1576
1577 void
bd_state_change(bd_handle_t hdl)1578 bd_state_change(bd_handle_t hdl)
1579 {
1580 bd_t *bd;
1581
1582 if ((bd = hdl->h_bd) != NULL) {
1583 bd_update_state(bd);
1584 }
1585 }
1586
1587 void
bd_mod_init(struct dev_ops * devops)1588 bd_mod_init(struct dev_ops *devops)
1589 {
1590 static struct bus_ops bd_bus_ops = {
1591 BUSO_REV, /* busops_rev */
1592 nullbusmap, /* bus_map */
1593 NULL, /* bus_get_intrspec (OBSOLETE) */
1594 NULL, /* bus_add_intrspec (OBSOLETE) */
1595 NULL, /* bus_remove_intrspec (OBSOLETE) */
1596 i_ddi_map_fault, /* bus_map_fault */
1597 ddi_dma_map, /* bus_dma_map */
1598 ddi_dma_allochdl, /* bus_dma_allochdl */
1599 ddi_dma_freehdl, /* bus_dma_freehdl */
1600 ddi_dma_bindhdl, /* bus_dma_bindhdl */
1601 ddi_dma_unbindhdl, /* bus_dma_unbindhdl */
1602 ddi_dma_flush, /* bus_dma_flush */
1603 ddi_dma_win, /* bus_dma_win */
1604 ddi_dma_mctl, /* bus_dma_ctl */
1605 bd_bus_ctl, /* bus_ctl */
1606 ddi_bus_prop_op, /* bus_prop_op */
1607 NULL, /* bus_get_eventcookie */
1608 NULL, /* bus_add_eventcall */
1609 NULL, /* bus_remove_eventcall */
1610 NULL, /* bus_post_event */
1611 NULL, /* bus_intr_ctl (OBSOLETE) */
1612 NULL, /* bus_config */
1613 NULL, /* bus_unconfig */
1614 NULL, /* bus_fm_init */
1615 NULL, /* bus_fm_fini */
1616 NULL, /* bus_fm_access_enter */
1617 NULL, /* bus_fm_access_exit */
1618 NULL, /* bus_power */
1619 NULL, /* bus_intr_op */
1620 };
1621
1622 devops->devo_bus_ops = &bd_bus_ops;
1623
1624 /*
1625 * NB: The device driver is free to supply its own
1626 * character entry device support.
1627 */
1628 }
1629
1630 void
bd_mod_fini(struct dev_ops * devops)1631 bd_mod_fini(struct dev_ops *devops)
1632 {
1633 devops->devo_bus_ops = NULL;
1634 }
1635