Initial commit of OpenSPARC T2 architecture model.
[OpenSPARC-T2-SAM] / legion / src / support / hsimd / hsimd.c
CommitLineData
920dae64
AT
1/*
2* ========== Copyright Header Begin ==========================================
3*
4* OpenSPARC T2 Processor File: hsimd.c
5* Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
6* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES.
7*
8* The above named program is free software; you can redistribute it and/or
9* modify it under the terms of the GNU General Public
10* License version 2 as published by the Free Software Foundation.
11*
12* The above named program is distributed in the hope that it will be
13* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
14* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15* General Public License for more details.
16*
17* You should have received a copy of the GNU General Public
18* License along with this work; if not, write to the Free Software
19* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
20*
21* ========== Copyright Header End ============================================
22*/
23/*
24 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
25 * Use is subject to license terms.
26 */
27
28#pragma ident "@(#)hsimd.c 1.1 06/02/06 SMI"
29
30/*
31 * Source code for the HSIMD "SPARC simulator" Dummy driver
32 * uses systems calls via simulator to accomplish
33 * base level open, seek, read, and write operations
34 */
35
36
37#include <sys/types.h>
38#include <sys/dklabel.h>
39#include <sys/errno.h>
40#include <sys/uio.h>
41#include <sys/buf.h>
42#include <sys/modctl.h>
43#include <sys/open.h>
44#include <sys/poll.h>
45#include <sys/conf.h>
46#include <sys/cmn_err.h>
47#include <sys/stat.h>
48#include <sys/sysmacros.h>
49#include <sys/ddi.h>
50#include <sys/sunddi.h>
51
52#include <sys/nexusdebug.h>
53#include <sys/debug.h>
54
55#include <sys/dkbad.h>
56#include <sys/dklabel.h>
57#include <sys/dkio.h>
58#include <sys/vtoc.h>
59#include <sys/file.h>
60
61#define HSIMD_UNIT(x) (getminor(x) >> 3)
62#define HSIMD_SLICE(x) (getminor(x) & 0x7)
63#define HSIMD_NSLICES 8
64
65struct hsimd_label {
66 daddr_t blockno; /* Starting block number */
67 daddr_t nblocks; /* Number of blocks */
68};
69
70struct hsimd_unit { /* unit structure - one per unit */
71 dev_info_t *dip; /* opaque devinfo info. */
72
73 kmutex_t hsimd_mutex; /* mutex to protect condition var */
74 kcondvar_t hsimd_cnd; /* Used to protect device */
75 int device_busy;
76 struct buf *active; /* currently active buf */
77 struct hsimd_label label[8]; /* slice information */
78 uint_t flags;
79 struct dk_map32 hsimd_map[NDKMAP];
80 struct dk_vtoc hsimd_vtoc;
81 struct dk_geom hsimd_g;
82 uchar_t hsimd_asciilabel[LEN_DKL_ASCII];
83 uint8_t hsimd_lvalid;
84};
85
86#define HSIMD_ATTACH 0x1
87#define HSIMD_RW 0x2
88
89void *hsimd_state_head; /* opaque handle top of state structs */
90#define getsoftc(unit) \
91 ((struct hsimd_unit *)ddi_get_soft_state(hsimd_state_head, (unit)))
92
93
94/* Autoconfig Declarations */
95static int hsimd_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd,
96 void *arg, void **result);
97static int hsimd_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
98static int hsimd_detach(dev_info_t *, ddi_detach_cmd_t);
99
100/* Driver function Declarations */
101static int hsimd_read(dev_t dev, struct uio *uiop, cred_t *credp);
102static int hsimd_write(dev_t dev, struct uio *uiop, cred_t *credp);
103static int hsimd_strategy(register struct buf *bp);
104static int hsimd_dump(dev_t dev, caddr_t addr, daddr_t blkno, int nblk);
105static int hsimd_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
106static int hsimd_prop_op(dev_t dev, dev_info_t *dip,
107 ddi_prop_op_t prop_op, int mod_flags, char *name,
108 caddr_t valuep, int *lengthp);
109
110static int hsimd_get_valid_geometry(struct hsimd_unit *hsimd_p);
111
112#ifdef DEBUG
113static int debug_info;
114static int debug_print_level;
115#endif
116
117static struct driver_minor_data {
118 char *name;
119 int minor;
120 int type;
121} hsimd_minor_data[] = {
122 {"a", 0, S_IFBLK},
123 {"b", 1, S_IFBLK},
124 {"c", 2, S_IFBLK},
125 {"d", 3, S_IFBLK},
126 {"e", 4, S_IFBLK},
127 {"f", 5, S_IFBLK},
128 {"g", 6, S_IFBLK},
129 {"h", 7, S_IFBLK},
130 {"a,raw", 0, S_IFCHR},
131 {"b,raw", 1, S_IFCHR},
132 {"c,raw", 2, S_IFCHR},
133 {"d,raw", 3, S_IFCHR},
134 {"e,raw", 4, S_IFCHR},
135 {"f,raw", 5, S_IFCHR},
136 {"g,raw", 6, S_IFCHR},
137 {"h,raw", 7, S_IFCHR},
138 {0}
139};
140
141/*
142 * The hsimd_cb_ops struct enables the kernel to find the
143 * rest of the driver entry points.
144 */
145static struct cb_ops hsimd_cb_ops = {
146 nulldev, /* driver open routine */
147 nulldev, /* driver close routine */
148 hsimd_strategy, /* driver strategy routine - block devs only */
149 nodev, /* driver print routine */
150 hsimd_dump, /* driver dump routine */
151 hsimd_read, /* driver read routine */
152 hsimd_write, /* driver write routine */
153 hsimd_ioctl, /* driver ioctl routine */
154 nodev, /* driver devmap routine */
155 nulldev, /* driver mmap routine */
156 nulldev, /* driver segmap routine */
157 nochpoll, /* driver chpoll routine */
158 hsimd_prop_op, /* driver prop_op routine */
159 0, /* driver cb_str - STREAMS only */
160 D_NEW | D_MP, /* driver compatibility flag */
161};
162
163/*
164 * The hsimd_ops struct enables the kernel to find the
165 * hsimd loadable module routines.
166 */
167static struct dev_ops hsimd_ops =
168{
169 DEVO_REV, /* revision number */
170 0, /* device reference count */
171 hsimd_getinfo, /* driver get_dev_info */
172 nulldev, /* confirm device ID */
173 nulldev, /* device probe for non-self-id */
174 hsimd_attach, /* attach routine */
175 hsimd_detach, /* device detach */
176 nodev, /* device reset */
177 &hsimd_cb_ops, /* device oper struct */
178 (struct bus_ops *)0, /* bus operations */
179};
180
181extern struct mod_ops mod_driverops;
182/*
183 * The hsimd_drv structure provides the linkage between the vd driver
184 * (for loadable drivers) and the dev_ops structure for this driver
185 * (hsimd_ops).
186 */
187static struct modldrv modldrv = {
188 &mod_driverops, /* type of module - driver */
189 "hsimd", /* name of module */
190 &hsimd_ops /* *Drv_dev_ops */
191};
192
193static struct modlinkage modlinkage = {
194 MODREV_1, (void *)&modldrv, NULL
195};
196
197/*
198 * _init is called by the autoloading code when the special file is
199 * first opened, or by modload().
200 */
201int
202_init(void)
203{
204 register int error;
205 if ((error = ddi_soft_state_init(&hsimd_state_head,
206 sizeof (struct hsimd_unit), 1)) != 0) {
207 return (error);
208 }
209 if ((error = mod_install(&modlinkage)) != 0)
210 ddi_soft_state_fini(&hsimd_state_head);
211 return (error);
212}
213
214/*
215 * _info is called by modinfo().
216 */
217int
218_info(struct modinfo *modinfop)
219{
220 return (mod_info(&modlinkage, modinfop));
221}
222
223/*
224 * _fini is called by
225 * modunload() just before the driver is unloaded from system memory.
226 */
227int
228_fini(void)
229{
230 int status;
231
232 if ((status = mod_remove(&modlinkage)) != 0)
233 return (status);
234 ddi_soft_state_fini(&hsimd_state_head);
235 return (status);
236}
237
238
239/*
240 * hsimd_attach()
241 *
242 * Allocate unit structures.
243 * Map the hsimd device registers into kernel virtual memory.
244 * Add the hsimd driver to the level X interrupt chain.
245 * Initialize the hsimd device
246 * Turn on the interrupts.
247 */
248static int
249hsimd_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
250{
251 struct hsimd_unit *hsimd_p;
252 struct driver_minor_data *dmdp;
253 int unit_no; /* attaching unit's number */
254 int i;
255 int nblks;
256 struct dk_map32 *lmap;
257
258 unit_no = ddi_get_instance(dip);
259
260 if (cmd != DDI_ATTACH)
261 return (DDI_FAILURE);
262
263 DPRINTF(HSIMD_ATTACH, ("hsimd attaching instance %u\n", unit_no));
264
265 /*
266 * Allocate a unit structure for this unit.
267 * Each hsimd_unit struct is allocated as zeroed memory.
268 * Store away its address for future use.
269 */
270 if (ddi_soft_state_zalloc(hsimd_state_head, unit_no) != 0)
271 return (DDI_FAILURE);
272
273 /* assign a pointer to this unit's state struct */
274 hsimd_p = getsoftc(unit_no);
275 hsimd_p->flags = 0;
276 hsimd_p->dip = dip;
277
278 /*
279 * Initialize the unit structures. The unit structure for
280 * each unit is initialized when hsimd_attach is called for that unit.
281 */
282
283 /*
284 * Initialize the hsimd mutex.
285 */
286 mutex_init(&hsimd_p->hsimd_mutex, "hsimd mutex",
287 MUTEX_DRIVER, NULL);
288
289 cv_init(&hsimd_p->hsimd_cnd, "hsimd condition variable", CV_DRIVER,
290 NULL);
291
292 /*
293 * Get geometry and label from disk
294 */
295 if (hsimd_get_valid_geometry(hsimd_p) != 0) {
296 cmn_err(CE_WARN, "hsimd: attach: label not valid");
297 mutex_destroy(&hsimd_p->hsimd_mutex);
298 ddi_soft_state_free(hsimd_state_head, unit_no);
299 return (DDI_FAILURE);
300 }
301
302 hsimd_p->hsimd_lvalid = 1; /* mark label valid */
303 lmap = hsimd_p->hsimd_map;
304 nblks = hsimd_p->hsimd_g.dkg_nsect * hsimd_p->hsimd_g.dkg_nhead;
305 for (i = 0; i < V_NUMPAR; i++) {
306 hsimd_p->label[i].blockno = lmap->dkl_cylno * nblks;
307 hsimd_p->label[i].nblocks = lmap->dkl_nblk;
308 lmap++;
309 }
310 /* The driver is now commited - all sanity checks done */
311
312 for (dmdp = hsimd_minor_data; dmdp->name != NULL; dmdp++) {
313 if (ddi_create_minor_node(dip, dmdp->name, dmdp->type,
314 (unit_no << 3) | dmdp->minor,
315 DDI_NT_BLOCK, NULL) == DDI_FAILURE) {
316 ddi_remove_minor_node(dip, NULL);
317 cmn_err(CE_NOTE,
318 "ddi_create_minor_node failed for unit %d\n",
319 unit_no);
320
321 mutex_destroy(&hsimd_p->hsimd_mutex);
322 ddi_soft_state_free(hsimd_state_head, unit_no);
323 DPRINTF(HSIMD_ATTACH, ("hsimd attach failed\n"));
324 return (DDI_FAILURE);
325 }
326 }
327 ddi_report_dev(dip);
328
329 DPRINTF(HSIMD_ATTACH, ("hsimd attach done\n"));
330 return (DDI_SUCCESS);
331}
332
333static int
334hsimd_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
335{
336 int instance;
337
338 switch (cmd) {
339 case DDI_DETACH:
340
341 instance = ddi_get_instance(devi);
342
343 ddi_remove_minor_node(devi, NULL);
344 ddi_soft_state_free(hsimd_state_head, instance);
345 return (DDI_SUCCESS);
346
347 case DDI_SUSPEND:
348 return (DDI_SUCCESS);
349 }
350 cmn_err(CE_CONT,
351 "%s: detach failed.\n", "hsimd");
352 return (DDI_FAILURE);
353}
354
355/*
356 * xx_getinfo is called from the framework to determine the devinfo pointer
357 * or instance number corresponding to a given dev_info_t.
358 */
359/*ARGSUSED*/
360static int
361hsimd_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
362{
363 int error;
364 struct hsimd_unit *hsimd_p;
365 int instance;
366
367 switch (infocmd) {
368 case DDI_INFO_DEVT2DEVINFO:
369 instance = HSIMD_UNIT(getminor((dev_t)arg));
370
371 if ((hsimd_p = getsoftc(instance)) == NULL) {
372 *result = NULL;
373 error = DDI_FAILURE;
374 } else {
375 *result = hsimd_p->dip;
376 error = DDI_SUCCESS;
377 }
378 break;
379 case DDI_INFO_DEVT2INSTANCE:
380 instance = HSIMD_UNIT(getminor((dev_t)arg));
381 *result = (void *) instance;
382 error = DDI_SUCCESS;
383 break;
384 default:
385 error = DDI_FAILURE;
386 }
387
388 return (error);
389}
390
391/* Normal Device Driver routines */
392
393/*
394 * Read system call.
395 */
396/*ARGSUSED*/
397static int
398hsimd_read(dev_t dev, struct uio *uiop, cred_t *credp)
399{
400 int retval = 0; /* return value (errno) for system call */
401
402 retval = physio(hsimd_strategy, (struct buf *)0, dev,
403 B_READ, minphys, uiop);
404
405 return (retval);
406}
407
408
409/*
410 * Write system call.
411 */
412/*ARGSUSED*/
413static int
414hsimd_write(dev_t dev, struct uio *uiop, cred_t *credp)
415{
416 uint_t retval = 0; /* return value (errno) for system call */
417
418 retval = physio(hsimd_strategy, (struct buf *)0, dev,
419 B_WRITE, minphys, uiop);
420
421 return (retval);
422}
423
424/*
425 * Setup and start a transfer on the device.
426 * checks operation, hangs buf struct off hsimd_unit, calls hsimdstart
427 * if not already busy.
428 */
429
430static int
431hcall_diskio(int dir, uint64_t pa, size_t size, off_t offset)
432{
433 size_t osize = size;
434 extern size_t hv_disk_read(uint64_t, uint64_t, size_t);
435 extern size_t hv_disk_write(uint64_t, uint64_t, size_t);
436
437 if (dir) {
438 size = hv_disk_read(offset, pa, size);
439 DPRINTF(HSIMD_RW, ("hsimd Disk Read from offset %lx, "
440 "%lx bytes into RA %lx, size=%lx\n",
441 offset, osize, pa, size));
442 } else {
443 size = hv_disk_write(offset, pa, size);
444 DPRINTF(HSIMD_RW, ("hsimd Disk Write to offset %lx, "
445 "%lx bytes from RA %lx, size=%lx\n",
446 offset, osize, pa, size));
447 }
448 if (size == (size_t)-1) {
449 cmn_err(CE_WARN, "hsimd: hcall_diskio error from hv_disk_%s"
450 "(offset=%lx pa=%lx size=%lx)\n",
451 (dir ? "read" : "write"), offset, pa, osize);
452 }
453 return (size);
454}
455
456#define va2tsize(v) (MMU_PAGESIZE - ((uint64_t)(v) & MMU_PAGEOFFSET))
457
458static ssize_t
459hsimd_diskio(int dir, caddr_t vadr, size_t sz, off_t offset)
460{
461 caddr_t va;
462 uint64_t pa;
463 size_t size, tsize;
464 size_t asize;
465 va = vadr;
466 size = sz;
467
468 DPRINTF(HSIMD_RW, ("hsimd vadr %p sz = %lx\n", vadr, sz));
469
470 while (size) {
471 pa = va_to_pa(va);
472 if (pa == (uint64_t)-1)
473 return (sz - size);
474
475 tsize = min(size, va2tsize(va));
476
477 DPRINTF(HSIMD_RW, ("hsimd va = %p, pa = %lx, tsize = %lx\n",
478 va, pa, tsize));
479 asize = hcall_diskio(dir, pa, tsize, offset);
480
481 if (asize == (size_t)-1 || asize == 0)
482 return (sz - size);
483
484 size -= asize;
485 va += asize;
486 offset += asize;
487 }
488 DPRINTF(HSIMD_RW, ("\n"));
489 return (sz);
490}
491
492static int
493hsimd_dump(dev_t dev, caddr_t addr, daddr_t blkno, int nblk)
494{
495 struct hsimd_unit *hsimd_p;
496 uint_t unit_no;
497 uint_t slice_no;
498 off_t diskoffset; /* Byte offset into the disk */
499 size_t size; /* Transfer size in bytes */
500
501 unit_no = HSIMD_UNIT(dev);
502 slice_no = HSIMD_SLICE(dev);
503
504 hsimd_p = getsoftc(unit_no);
505 if (hsimd_p == NULL) {
506 cmn_err(CE_WARN, "hsimd: no softstate for unit %d", unit_no);
507 return (ENXIO);
508 }
509
510 if (!hsimd_p->hsimd_lvalid) {
511 cmn_err(CE_WARN, "hsimd: invalid disk label %d", unit_no);
512 return (ENXIO);
513 }
514
515 if (blkno >= hsimd_p->label[slice_no].nblocks) {
516 return (ENOSPC);
517 }
518
519 if ((blkno + nblk) > hsimd_p->label[slice_no].nblocks) {
520 return (ENOSPC);
521 }
522
523 size = nblk * DEV_BSIZE;
524 diskoffset = (hsimd_p->label[slice_no].blockno + blkno) * DEV_BSIZE;
525 (void) hsimd_diskio(B_WRITE & B_READ, addr, size, diskoffset);
526
527 return (0);
528}
529
530/*ARGSUSED*/
531static int
532hsimd_strategy(struct buf *bp)
533{
534 struct hsimd_unit *hsimd_p;
535 uint_t unit_no;
536 uint_t slice_no;
537 uint_t blk_no;
538
539 off_t diskoffset; /* Byte offset into the disk */
540 size_t size; /* Transfer size in bytes */
541 caddr_t addr; /* Buffer virtual address */
542 ssize_t tsize; /* Actual transfer size */
543
544 unit_no = HSIMD_UNIT(bp->b_edev);
545 slice_no = HSIMD_SLICE(bp->b_edev);
546 hsimd_p = getsoftc(unit_no);
547 if (hsimd_p == NULL) {
548 cmn_err(CE_WARN, "hsimd: no softstate for unit %d", unit_no);
549 bp->b_error = ENXIO;
550 goto bad;
551 }
552
553 if (!hsimd_p->hsimd_lvalid) {
554 cmn_err(CE_WARN, "hsimd: invalid disk label %d", unit_no);
555 bp->b_error = ENXIO;
556 goto bad;
557 }
558
559 blk_no = (uint_t)bp->b_blkno;
560
561 /* error if requested blk past end of partition */
562 /* XXX - end of requested blk */
563 if ((blk_no) >= hsimd_p->label[slice_no].nblocks) {
564 bp->b_error = ENOSPC;
565 goto bad;
566 }
567
568 /* error if requested blk past end of partition */
569 /* XXX - end of requested blk */
570 if ((blk_no + (bp->b_bcount / DEV_BSIZE)) >
571 hsimd_p->label[slice_no].nblocks) {
572 bp->b_error = ENOSPC;
573 goto bad;
574 }
575
576 /* error if transfer count not multiple of sector size */
577 if (bp->b_bcount & (DEV_BSIZE - 1)) {
578 bp->b_error = EINVAL;
579 goto bad;
580 }
581
582 /*
583 * Put buf request in the controller's queue, FIFO
584 */
585
586 mutex_enter(&hsimd_p->hsimd_mutex);
587 while (hsimd_p->device_busy) {
588 cv_wait(&hsimd_p->hsimd_cnd, &hsimd_p->hsimd_mutex);
589 }
590 hsimd_p->device_busy = 1;
591 mutex_exit(&hsimd_p->hsimd_mutex);
592
593
594 if (bp->b_flags & B_READ) {
595 hsimd_p->flags = DDI_DMA_READ;
596 DPRINTF(HSIMD_RW, ("hsimd read xfer instance 0x%x slice %d "
597 "block no 0x%x data count 0x%x Data addr 0x%p\n",
598 unit_no, slice_no, blk_no, bp->b_bcount, bp->b_un.b_addr));
599 } else {
600 hsimd_p->flags = DDI_DMA_WRITE;
601 DPRINTF(HSIMD_RW, ("hsimd write xfer instance 0x%x slice %d "
602 "block no 0x%x data count 0x%x Data addr 0x%p\n",
603 unit_no, slice_no, blk_no, bp->b_bcount, bp->b_un.b_addr));
604 }
605
606
607 /*
608 * bp->b_blkno : Disk Block number relative to the slice
609 * bp->b_bcount : byte count
610 */
611
612 hsimd_p->active = bp;
613
614
615 /*
616 * hypervisor call(s) to do the transfer
617 */
618 bp_mapin(bp);
619 addr = bp->b_un.b_addr;
620 diskoffset = (hsimd_p->label[slice_no].blockno + blk_no) * DEV_BSIZE;
621 size = bp->b_bcount;
622 tsize = hsimd_diskio(bp->b_flags & B_READ, addr, size, diskoffset);
623 bp_mapout(bp);
624
625 bp->b_resid = 0;
626
627 if (tsize != size) {
628 bp->b_resid = size;
629 bp->b_flags |= B_ERROR;
630 }
631
632 (void) biodone(bp);
633
634 mutex_enter(&hsimd_p->hsimd_mutex);
635
636 hsimd_p->device_busy = 0;
637
638 cv_signal(&hsimd_p->hsimd_cnd);
639
640 mutex_exit(&hsimd_p->hsimd_mutex);
641
642 return (0);
643
644bad:
645 bp->b_resid = bp->b_bcount;
646 bp->b_flags |= B_ERROR;
647 (void) biodone(bp);
648 return (0);
649}
650
651static int
652hsimd_get_valid_geometry(struct hsimd_unit *hsimd_p)
653{
654 struct dk_label *dkl;
655 caddr_t addr;
656 uint_t diskoffset;
657 size_t size, tsize;
658
659 dkl = kmem_zalloc(sizeof (struct dk_label),
660 KM_SLEEP);
661 addr = (caddr_t)dkl;
662 diskoffset = 0; /* first block */
663 size = sizeof (*dkl);
664 tsize = hsimd_diskio(B_READ, addr, size, diskoffset);
665 if (tsize < sizeof (*dkl)) {
666 cmn_err(CE_WARN, "hsimd:get_valid_geometry can't get vtoc");
667 kmem_free(dkl, sizeof (struct dk_label));
668 return (-1);
669 }
670 /*
671 * Check magic number of the label
672 */
673 if (dkl->dkl_magic != DKL_MAGIC) {
674 kmem_free(dkl, sizeof (*dkl));
675 return (-1);
676 }
677 /*
678 * Fill in disk geometry from label.
679 */
680 hsimd_p->hsimd_g.dkg_ncyl = dkl->dkl_ncyl;
681 hsimd_p->hsimd_g.dkg_acyl = dkl->dkl_acyl;
682 hsimd_p->hsimd_g.dkg_bcyl = 0;
683 hsimd_p->hsimd_g.dkg_nhead = dkl->dkl_nhead;
684 hsimd_p->hsimd_g.dkg_bhead = dkl->dkl_bhead;
685 hsimd_p->hsimd_g.dkg_nsect = dkl->dkl_nsect;
686
687 /*
688 * Fill in partition table.
689 */
690
691 bcopy(dkl->dkl_map, hsimd_p->hsimd_map,
692 NDKMAP * sizeof (struct dk_map32));
693
694 /*
695 * Fill in VTOC Structure.
696 */
697 bcopy((caddr_t)&dkl->dkl_vtoc, (caddr_t)&hsimd_p->hsimd_vtoc,
698 sizeof (struct dk_vtoc));
699 bcopy(dkl->dkl_asciilabel,
700 hsimd_p->hsimd_asciilabel, LEN_DKL_ASCII);
701
702 kmem_free(dkl, sizeof (*dkl));
703 return (0);
704}
705
706static void
707hsimd_build_user_vtoc(struct hsimd_unit *un, struct vtoc *vtoc)
708{
709
710 int i;
711 int nblks;
712 struct dk_map2 *lpart;
713 struct dk_map32 *lmap;
714 struct partition *vpart;
715
716
717 /*
718 * Return vtoc structure fields in the provided VTOC area, addressed
719 * by *vtoc.
720 *
721 */
722
723 bzero((caddr_t)vtoc, sizeof (struct vtoc));
724
725 vtoc->v_bootinfo[0] = un->hsimd_vtoc.v_bootinfo[0];
726 vtoc->v_bootinfo[1] = un->hsimd_vtoc.v_bootinfo[1];
727 vtoc->v_bootinfo[2] = un->hsimd_vtoc.v_bootinfo[2];
728
729 vtoc->v_sanity = VTOC_SANE;
730 vtoc->v_version = un->hsimd_vtoc.v_version;
731
732 bcopy((caddr_t)un->hsimd_vtoc.v_volume, (caddr_t)vtoc->v_volume,
733 LEN_DKL_VVOL);
734
735 vtoc->v_sectorsz = DEV_BSIZE;
736 vtoc->v_nparts = un->hsimd_vtoc.v_nparts;
737
738 bcopy((caddr_t)un->hsimd_vtoc.v_reserved, (caddr_t)vtoc->v_reserved,
739 sizeof (vtoc->v_reserved));
740 /*
741 * Convert partitioning information.
742 *
743 * Note the conversion from starting cylinder number
744 * to starting sector number.
745 */
746 lmap = un->hsimd_map;
747 lpart = un->hsimd_vtoc.v_part;
748 vpart = vtoc->v_part;
749
750 nblks = un->hsimd_g.dkg_nsect * un->hsimd_g.dkg_nhead;
751 for (i = 0; i < V_NUMPAR; i++) {
752 vpart->p_tag = lpart->p_tag;
753 vpart->p_flag = lpart->p_flag;
754 vpart->p_start = lmap->dkl_cylno * nblks;
755 vpart->p_size = lmap->dkl_nblk;
756
757 lmap++;
758 lpart++;
759 vpart++;
760 vtoc->timestamp[i] = (time_t)un->hsimd_vtoc.v_timestamp[i];
761 }
762
763 bcopy((caddr_t)un->hsimd_asciilabel, (caddr_t)vtoc->v_asciilabel,
764 LEN_DKL_ASCII);
765
766}
767
768/* ARGSUSED3 */
769static int
770hsimd_ioctl(dev_t dev, int cmd, intptr_t arg, int flag,
771 cred_t *cred_p, int *rval_p)
772{
773 struct hsimd_unit *hsimd_p;
774 struct dk_cinfo *info;
775 struct vtoc vtoc;
776 uint_t unit_no, slice_no;
777
778 unit_no = HSIMD_UNIT(dev);
779 slice_no = HSIMD_SLICE(dev);
780 hsimd_p = getsoftc(unit_no);
781 if (hsimd_p == NULL) {
782 cmn_err(CE_WARN, "hsimd: no softstate for unit %d", unit_no);
783 return (ENXIO);
784 }
785
786 switch (cmd) {
787
788 case DKIOCINFO:
789 /*
790 * Controller Information
791 */
792 info = (struct dk_cinfo *)
793 kmem_zalloc(sizeof (struct dk_cinfo), KM_SLEEP);
794 info->dki_ctype = DKC_DIRECT;
795 info->dki_cnum = ddi_get_instance(ddi_get_parent(hsimd_p->dip));
796 (void) strcpy(info->dki_cname,
797 ddi_get_name(ddi_get_parent(hsimd_p->dip)));
798 /*
799 * Unit Information
800 */
801 info->dki_unit = ddi_get_instance(hsimd_p->dip);
802 info->dki_slave = 0;
803 (void) strcpy(info->dki_dname, ddi_get_name(hsimd_p->dip));
804 info->dki_flags = DKI_FMTVOL;
805 info->dki_partition = slice_no;
806
807 /*
808 * Max Transfer size of this device in blocks
809 */
810 info->dki_maxtransfer = PAGESIZE / DEV_BSIZE;
811 info->dki_addr = 0;
812 info->dki_space = 0;
813 info->dki_prio = 0;
814 info->dki_vec = 0;
815 if (ddi_copyout((caddr_t)info, (caddr_t)arg,
816 sizeof (struct dk_cinfo), flag)) {
817 kmem_free(info, sizeof (struct dk_cinfo));
818 return (EFAULT);
819 } else {
820 kmem_free(info, sizeof (struct dk_cinfo));
821 return (0);
822 }
823 case DKIOCGVTOC:
824 /*
825 * Get the label (vtoc, geometry and partition map) directly
826 * from the disk, in case if it got modified by another host
827 * sharing the disk in a multi initiator configuration.
828 */
829 if (!hsimd_p->hsimd_lvalid) {
830 cmn_err(CE_WARN, "hsimd: invalid disk label %d",
831 unit_no);
832 return (ENXIO);
833 }
834 mutex_enter(&hsimd_p->hsimd_mutex);
835 hsimd_build_user_vtoc(hsimd_p, &vtoc);
836 mutex_exit(&hsimd_p->hsimd_mutex);
837
838#ifdef _MULTI_DATAMODEL
839 switch (ddi_model_convert_from(flag & FMODELS)) {
840 case DDI_MODEL_ILP32: {
841 struct vtoc32 vtoc32;
842
843 vtoctovtoc32(vtoc, vtoc32);
844 if (ddi_copyout(&vtoc32, (void *)arg,
845 sizeof (struct vtoc32), flag))
846 return (EFAULT);
847 break;
848 }
849
850 case DDI_MODEL_NONE:
851 if (ddi_copyout(&vtoc, (void *)arg,
852 sizeof (struct vtoc), flag))
853 return (EFAULT);
854 break;
855 }
856#else
857 if (ddi_copyout((caddr_t)&vtoc, (caddr_t)arg,
858 sizeof (struct vtoc), flag))
859 return (EFAULT);
860#endif
861 return (0);
862 case DKIOCGGEOM:
863 if (ddi_copyout((caddr_t)&hsimd_p->hsimd_g,
864 (caddr_t)arg, sizeof (struct dk_geom), flag))
865 return (EFAULT);
866 else
867 return (0);
868 default:
869 cmn_err(CE_WARN, "hsimd_ioctl: cmd %x not implemented",
870 cmd);
871 }
872 return (0);
873}
874
875static int
876hsimd_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op, int mod_flags,
877 char *name, caddr_t valuep, int *lengthp)
878{
879 int nblocks, length, km_flags;
880 caddr_t buffer;
881 struct hsimd_unit *hsimd_p;
882 int instance;
883
884 if (dev != DDI_DEV_T_ANY)
885 instance = HSIMD_UNIT(dev);
886 else
887 instance = ddi_get_instance(dip);
888
889 hsimd_p = getsoftc(instance);
890
891 if (!hsimd_p->hsimd_lvalid) {
892 cmn_err(CE_CONT, "hsimd_prop_op: invalid label\n");
893 return (DDI_PROP_NOT_FOUND);
894 }
895
896 if (strcmp(name, "nblocks") == 0) {
897 mutex_enter(&hsimd_p->hsimd_mutex);
898 nblocks = (int)hsimd_p->label[HSIMD_SLICE(dev)].nblocks;
899 mutex_exit(&hsimd_p->hsimd_mutex);
900
901 /*
902 * get callers length set return length.
903 */
904 length = *lengthp; /* Get callers length */
905 *lengthp = sizeof (int); /* Set callers length */
906
907 /*
908 * If length only request or prop length == 0, get out now.
909 * (Just return length, no value at this level.)
910 */
911 if (prop_op == PROP_LEN) {
912 *lengthp = sizeof (int);
913 return (DDI_PROP_SUCCESS);
914 }
915
916 /*
917 * Allocate buffer, if required. Either way,
918 * set `buffer' variable.
919 */
920 switch (prop_op) {
921
922 case PROP_LEN_AND_VAL_ALLOC:
923
924 km_flags = KM_NOSLEEP;
925
926 if (mod_flags & DDI_PROP_CANSLEEP)
927 km_flags = KM_SLEEP;
928
929 buffer = (caddr_t)kmem_alloc((size_t)sizeof (int),
930 km_flags);
931 if (buffer == NULL) {
932 cmn_err(CE_WARN,
933 "no mem for property\n");
934 return (DDI_PROP_NO_MEMORY);
935 }
936 *(caddr_t *)valuep = buffer; /* Set callers buf ptr */
937 break;
938
939 case PROP_LEN_AND_VAL_BUF:
940
941 if (sizeof (int) > (length))
942 return (DDI_PROP_BUF_TOO_SMALL);
943
944 buffer = valuep; /* get callers buf ptr */
945 break;
946 }
947 *((int *)buffer) = nblocks;
948 return (DDI_PROP_SUCCESS);
949 }
950
951 /*
952 * not mine pass it on.
953 */
954 return (ddi_prop_op(dev, dip, prop_op, mod_flags,
955 name, valuep, lengthp));
956}