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