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, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22 /*
23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 #pragma ident "%Z%%M% %I% %E% SMI"
28
29 #include <sys/types.h>
30 #include <sys/conf.h>
31 #include <sys/dditypes.h>
32 #include <sys/ddi.h>
33 #include <sys/sunddi.h>
34
35 #include <sys/errno.h>
36 #include <sys/debug.h>
37 #include <sys/open.h>
38 #include <sys/file.h>
39 #include <sys/cmn_err.h>
40 #include <sys/varargs.h>
41 #include <sys/fs/pc_label.h>
42
43 #include <sys/hdio.h>
44 #include <sys/dkio.h>
45 #include <sys/dktp/dadkio.h>
46
47 #include <sys/dklabel.h>
48
49 #include <sys/vtoc.h>
50
51
52 #include <sys/types.h>
53 #include <sys/conf.h>
54 #include <sys/dditypes.h>
55 #include <sys/ddi.h>
56 #include <sys/sunddi.h>
57 #include <sys/dktp/cm.h>
58
59 #include <sys/dktp/fdisk.h>
60
61 #include <sys/pccard.h>
62 #include <sys/pcmcia/pcata.h>
63
64 #define MIN_SEC_SIZE 512
65
66 static int pcata_redo_vtoc(ata_soft_t *softp, buf_t *fdiskbp);
67 static buf_t *pcata_lblk_alloc(dev_t dev);
68
69 /* Check media insertion/ejection status */
70 static int pcata_check_media(ata_soft_t *rs, enum dkio_state state);
71
72 /*
73 * Queue a request and call start routine.
74 *
75 * If the request is not a special buffer request,
76 * do validation on it and generate both an absolute
77 * block number (which we will leave in b_resid),
78 * and a actual block count value (which we will
79 * leave in av_back).
80 */
81
82 int
pcata_strategy(buf_t * bp)83 pcata_strategy(buf_t *bp)
84 {
85 ata_soft_t *softp;
86 ata_unit_t *unitp;
87 void *instance;
88 daddr_t blkno;
89 int part;
90 int ret;
91
92 #ifdef ATA_DEBUG
93 if (pcata_debug & DIO)
94 cmn_err(CE_CONT, "_strategy\n");
95 #endif
96 bp->b_resid = bp->b_bcount;
97
98 if (pcata_getinfo(NULL, DDI_INFO_DEVT2INSTANCE, (void *)bp->b_edev,
99 &instance) != DDI_SUCCESS) {
100 cmn_err(CE_CONT, "_strategy: pcata_getinfo ENODEV\n");
101 bioerror(bp, ENODEV);
102 biodone(bp);
103 return (0);
104 }
105
106 if (!(softp = ddi_get_soft_state(pcata_soft,
107 (int)(uintptr_t)instance))) {
108 bioerror(bp, ENXIO);
109 biodone(bp);
110 return (0);
111 }
112
113 if (!(CARD_PRESENT_VALID(softp))) {
114 #ifdef ATA_DEBUG
115 if (pcata_debug & DIO)
116 cmn_err(CE_CONT, "_strategy card_state = %d bp=%p\n",
117 softp->card_state,
118 (void *)bp);
119 #endif
120 bioerror(bp, ENXIO);
121 biodone(bp);
122 return (0);
123 }
124
125 if (bp->b_bcount & (NBPSCTR-1)) {
126 bioerror(bp, ENXIO);
127 biodone(bp);
128 return (0);
129 }
130
131 #ifdef ATA_DEBUG
132 if (pcata_debug & DIO) {
133 cmn_err(CE_CONT, "_strategy: bp->b_private = %p\n",
134 (void *)bp->b_private);
135 cmn_err(CE_CONT, "_strategy %s request for buf: %p\n",
136 bp->b_flags & B_READ ? "read" : "write", (void *)bp);
137 }
138 #endif
139
140 mutex_enter(&softp->ata_mutex);
141
142 /*
143 * pointer to structure for physical drive
144 */
145 /*
146 * XXX/lcl since we don't traverse a_forw with some bits from minor
147 * (aka the UNIT macro) this means only 1 physical disk
148 * this error occurs everywhere ab_link is used!
149 */
150 unitp = softp->ab_link;
151 if (!unitp) {
152 mutex_exit(&softp->ata_mutex);
153 bioerror(bp, ENXIO);
154 biodone(bp);
155 return (0);
156 }
157
158 /*
159 * A normal read/write command.
160 *
161 * If the transfer size would take it past the end of the
162 * partition, trim it down. Also trim it down to a multiple
163 * of the block size.
164 */
165 bp->b_flags &= ~(B_DONE|B_ERROR);
166 bp->av_forw = NULL;
167 blkno = bp->b_blkno;
168 part = LPART(bp->b_edev);
169
170
171 /*
172 * Map block number within partition to absolute
173 * block number.
174 */
175 #ifdef ATA_DEBUG
176 if (pcata_debug & DIO)
177 cmn_err(CE_CONT, "_strategy "
178 "%c%d: %s block %ld mapped to %ld dev %lx\n",
179 (part > 15 ? 'p' : 's'),
180 (part > 15 ? part - 16 : part),
181 bp->b_flags & B_READ ? "read" : "write",
182 blkno,
183 blkno + unitp->lbl.pmap[part].p_start,
184 bp->b_edev);
185 #endif
186
187 /* make sure this partition exists */
188 if (unitp->lbl.pmap[part].p_size == 0) {
189 #ifdef ATA_DEBUG
190 cmn_err(CE_CONT, "_strategy:invalid slice part=%d\n", part);
191 #endif
192 mutex_exit(&softp->ata_mutex);
193 bioerror(bp, ENXIO);
194 biodone(bp);
195 return (0);
196 }
197
198 /* make sure the I/O begins at a block within the partition */
199 if (blkno < 0 || blkno >= unitp->lbl.pmap[part].p_size) {
200 #ifdef ATA_DEBUG
201 cmn_err(CE_CONT, "_strategy:block number out of range\n");
202 #endif
203 mutex_exit(&softp->ata_mutex);
204 bioerror(bp, ENXIO);
205 biodone(bp);
206 return (0);
207 }
208
209 /* XXX/lcl check to make sure I/O doesn't go past end of partition */
210
211 /* put block number into b_resid and number of blocks into av_back */
212 bp->b_resid = bp->b_bcount;
213 bp->av_back = (buf_t *)(ROUNDUP(bp->b_bcount, NBPSCTR) >> SCTRSHFT);
214
215 blkno += unitp->lbl.pmap[part].p_start;
216
217 ret = pcata_start(unitp, bp, blkno);
218 mutex_exit(&softp->ata_mutex);
219
220 if (ret != CTL_SEND_SUCCESS) {
221 bp->b_resid = bp->b_bcount;
222 #ifdef ATA_DEBUG
223 cmn_err(CE_CONT, "_strategy: ata_start failed bp 0x%p\n",
224 (void *)bp);
225 #endif
226 bioerror(bp, EIO);
227 biodone(bp);
228 return (0);
229 }
230
231 /*
232 * If the disk block to be written to is disk block 0, it would
233 * mean the partition table is changing from underneath us
234 * we shoud trap and update the in memory image.
235 * By now the buffer is mapped in and we should be able to
236 * use the contents as the new fdisk partition.
237 */
238 if ((bp->b_flags & B_WRITE) && ((bp->b_flags & B_ERROR) != B_ERROR) &&
239 blkno == 0) {
240 if (pcata_redo_vtoc(softp, bp)) {
241 bioerror(bp, EFAULT);
242 biodone(bp);
243 return (0);
244 }
245 }
246
247 return (0);
248 }
249
250 /*
251 * This routine implements the ioctl calls for the ATA
252 */
253 #define COPYOUT(a, b, c, f) \
254 ddi_copyout((caddr_t)(a), (caddr_t)(b), sizeof (c), f)
255 #define COPYIN(a, b, c, f) \
256 ddi_copyin((caddr_t)(a), (caddr_t)(b), sizeof (c), f)
257
258 /* ARGSUSED3 */
259 int
pcata_ioctl(dev_t dev,int cmd,intptr_t arg,int flag,cred_t * cred_p,int * rval_p)260 pcata_ioctl(
261 dev_t dev,
262 int cmd,
263 intptr_t arg,
264 int flag,
265 cred_t *cred_p,
266 int *rval_p)
267 {
268 uint32_t data[512 / (sizeof (uint32_t))];
269 void *instance;
270 ata_soft_t *softp;
271 ata_unit_t *unitp;
272 struct dk_cinfo *info;
273 int i, status;
274 int err;
275 enum dkio_state state;
276
277 #ifdef ATA_DEBUG
278 if (pcata_debug & DIO) cmn_err(CE_CONT, "_ioctl\n");
279 #endif
280 if (pcata_getinfo(NULL, DDI_INFO_DEVT2INSTANCE, (void *)dev,
281 &instance) != DDI_SUCCESS)
282 return (ENODEV);
283
284 if (!(softp = ddi_get_soft_state(pcata_soft,
285 (int)(uintptr_t)instance))) {
286 return (ENXIO);
287 }
288
289
290 #ifdef ATA_DEBUG
291 if (pcata_debug & DENT) {
292 char *cmdname;
293
294 switch (cmd) {
295 case DKIOCINFO: cmdname = "DKIOCINFO "; break;
296 case DKIOCREMOVABLE: cmdname = "DKIOCREMOVABLE "; break;
297 case DKIOCGMEDIAINFO: cmdname = "DKIOCGMEDIAINFO "; break;
298 case DKIOCGGEOM: cmdname = "DKIOCGGEOM "; break;
299 case DKIOCGAPART: cmdname = "DKIOCGAPART "; break;
300 case DKIOCSAPART: cmdname = "DKIOCSAPART "; break;
301 case DKIOCGVTOC: cmdname = "DKIOCGVTOC "; break;
302 case DKIOCSVTOC: cmdname = "DKIOCSVTOC "; break;
303 case DKIOCG_VIRTGEOM: cmdname = "DKIOCG_VIRTGEOM "; break;
304 case DKIOCG_PHYGEOM: cmdname = "DKIOCG_PHYGEOM "; break;
305 case DKIOCEJECT: cmdname = "DKIOCEJECT *"; break;
306 case DKIOCSGEOM: cmdname = "DKIOCSGEOM *"; break;
307 case DKIOCSTATE: cmdname = "DKIOCSTATE *"; break;
308 case DKIOCADDBAD: cmdname = "DKIOCADDBAD *"; break;
309 case DKIOCGETDEF: cmdname = "DKIOCGETDEF *"; break;
310 case DKIOCPARTINFO: cmdname = "DKIOCPARTINFO *"; break;
311 case DIOCTL_RWCMD: cmdname = "DIOCTL_RWCMD "; break;
312 default: cmdname = "UNKNOWN *"; break;
313 }
314 cmn_err(CE_CONT,
315 "_ioctl%d: cmd %x(%s) arg %p softp %p\n",
316 (int)(uintptr_t)instance, cmd, cmdname, (void *)arg,
317 (void *)softp);
318 }
319 #endif
320
321 /*
322 * We should process DKIOCSTATE cmd even if CARD is not PRESENT.
323 * The DKIOCSTATE command should BLOCK if there is no change in state.
324 * Only when softp->state != state the control returns to the caller.
325 * This check is done in pcata_check_media().
326 * There are 3 states for the device.
327 * DKIO_NONE
328 * DKIO_INSERTED
329 * DKIO_EJECTED
330 * The state transitions are as follows
331 * DKIO_NONE-DKIO_INSERTED-DKIO_EJECTED-DKIO_NONE-DKIO_INSERTED...
332 */
333 if (cmd == DKIOCSTATE) {
334 if (ddi_copyin((caddr_t)arg, (caddr_t)&state,
335 sizeof (state), flag)) {
336 return (EFAULT);
337 }
338
339 /*
340 * This function is used by the volume management
341 * to check the pcata card state
342 */
343 if (err = pcata_check_media(softp, state)) {
344 return (err);
345 }
346
347 if (ddi_copyout((caddr_t)&softp->media_state,
348 (caddr_t)arg, sizeof (softp->media_state), flag)) {
349 return (EFAULT);
350 }
351 return (0);
352 }
353
354 if (!(CARD_PRESENT_VALID(softp))) {
355 return (ENODEV);
356 }
357
358
359 /*
360 * we can respond to get geom ioctl() only while the driver has
361 * not completed initialization.
362 */
363 if ((softp->flags & PCATA_READY) == 0 && cmd != DKIOCG_PHYGEOM) {
364 (void) pcata_readywait(softp);
365 if (!(softp->flags & PCATA_READY))
366 return (EFAULT);
367 }
368
369 ASSERT(softp->ab_link);
370 unitp = softp->ab_link;
371 bzero((caddr_t)data, sizeof (data));
372
373 switch (cmd) {
374 case DKIOCGGEOM:
375 case DKIOCSGEOM:
376 case DKIOCGAPART:
377 case DKIOCSAPART:
378 case DKIOCGVTOC:
379 case DKIOCSVTOC:
380 status = 0;
381 mutex_enter(&softp->label_mutex);
382 status = pcata_lbl_ioctl(dev, cmd, arg, flag);
383 mutex_exit(&softp->label_mutex);
384 return (status);
385 }
386
387 switch (cmd) {
388
389 case DKIOCINFO:
390
391 info = (struct dk_cinfo *)data;
392 /*
393 * Controller Information
394 */
395 info->dki_ctype = DKC_PCMCIA_ATA;
396 info->dki_cnum = ddi_get_instance(softp->dip);
397 (void) strcpy(info->dki_cname,
398 ddi_get_name(ddi_get_parent(softp->dip)));
399
400 /*
401 * Unit Information
402 */
403 info->dki_unit = ddi_get_instance(softp->dip);
404 info->dki_slave = 0;
405 (void) strcpy(info->dki_dname, "card");
406 info->dki_flags = DKI_FMTVOL;
407 info->dki_partition = LPART(dev);
408 info->dki_maxtransfer = softp->ab_max_transfer;
409
410 /*
411 * We can't get from here to there yet
412 */
413 info->dki_addr = 0;
414 info->dki_space = 0;
415 info->dki_prio = 0;
416 info->dki_vec = 0;
417
418 if (COPYOUT(data, arg, struct dk_cinfo, flag))
419 return (EFAULT);
420 break;
421
422 case DKIOCG_VIRTGEOM:
423 case DKIOCG_PHYGEOM:
424
425 {
426 struct dk_geom dkg;
427 status = 0;
428
429 bzero((caddr_t)&dkg, sizeof (struct dk_geom));
430 mutex_enter(&softp->ata_mutex);
431 unitp = softp->ab_link;
432 if (unitp != 0) {
433 dkg.dkg_ncyl = unitp->au_cyl;
434 dkg.dkg_acyl = unitp->au_acyl;
435 dkg.dkg_pcyl = unitp->au_cyl+unitp->au_acyl;
436 dkg.dkg_nhead = unitp->au_hd;
437 dkg.dkg_nsect = unitp->au_sec;
438 } else
439 status = EFAULT;
440 mutex_exit(&softp->ata_mutex);
441 if (status)
442 return (EFAULT);
443
444 if (ddi_copyout((caddr_t)&dkg, (caddr_t)arg,
445 sizeof (struct dk_geom), flag))
446 return (EFAULT);
447 else
448 return (0);
449 }
450
451 case DKIOCGMEDIAINFO:
452
453 {
454 struct dk_minfo media_info;
455 int secsize;
456
457 media_info.dki_media_type = DK_FIXED_DISK;
458 /*
459 * atarp_secsize contains the unformatted sector size.
460 * Using this we determine the actual sector size.
461 * sector sizes are a multiple of MIN_SEC_SIZE(512).
462 */
463 secsize = softp->ab_rpbp[0]->atarp_secsiz;
464 secsize = (((secsize)/MIN_SEC_SIZE) * MIN_SEC_SIZE);
465 media_info.dki_lbsize = secsize;
466 media_info.dki_capacity = unitp->au_cyl * unitp->au_hd *
467 unitp->au_sec;
468 if (ddi_copyout((caddr_t)&media_info, (caddr_t)arg,
469 sizeof (struct dk_minfo), flag))
470 return (EFAULT);
471 else
472 return (0);
473 }
474
475 case DKIOCREMOVABLE:
476
477 {
478 /*
479 * Supporting volmgt by returning a constant
480 * since PCMCIA is a removable media.
481 * Refer to PSARC/1996/004.
482 */
483 i = 1;
484 if (ddi_copyout((caddr_t)&i, (caddr_t)arg, sizeof (int),
485 flag)) {
486 return (EFAULT);
487 }
488 break;
489 }
490
491 case DIOCTL_RWCMD:
492 {
493 int rw;
494 int status;
495 struct dadkio_rwcmd rwcmd;
496 struct buf *bp;
497 struct iovec aiov;
498 struct uio auio;
499
500 #if defined(_MULTI_DATAMODEL)
501 switch (ddi_model_convert_from(flag & FMODELS)) {
502
503 case DDI_MODEL_ILP32: {
504 struct dadkio_rwcmd32 rwcmd32;
505
506 if (ddi_copyin((caddr_t)arg, (caddr_t)&rwcmd32,
507 sizeof (struct dadkio_rwcmd32), flag)) {
508 return (EFAULT);
509 }
510 rwcmd.cmd = rwcmd32.cmd;
511 rwcmd.flags = rwcmd32.flags;
512 rwcmd.blkaddr = (daddr_t)rwcmd32.blkaddr;
513 rwcmd.buflen = rwcmd32.buflen;
514 rwcmd.bufaddr = (caddr_t)(uintptr_t)rwcmd32.bufaddr;
515 break;
516 }
517
518 case DDI_MODEL_NONE:
519 if (ddi_copyin((caddr_t)arg, (caddr_t)&rwcmd,
520 sizeof (struct dadkio_rwcmd), flag)) {
521 return (EFAULT);
522 }
523 break;
524 }
525 #else /* _MULTI_DATAMODEL */
526 if (ddi_copyin((caddr_t)arg, (caddr_t)&rwcmd,
527 sizeof (struct dadkio_rwcmd), flag)) {
528 return (EFAULT);
529 }
530 #endif /* _MULTI_DATAMODEL */
531
532 switch (rwcmd.cmd) {
533 case DADKIO_RWCMD_READ:
534 rw = B_READ;
535 break;
536 case DADKIO_RWCMD_WRITE:
537 rw = B_WRITE;
538 break;
539 default:
540 return (EINVAL);
541 }
542
543 bp = getrbuf(KM_SLEEP);
544 bp->b_back = (buf_t *)&rwcmd; /* ioctl packet */
545 bp->b_private = (void *)0xBEE;
546
547 bzero((caddr_t)&aiov, sizeof (struct iovec));
548 aiov.iov_base = rwcmd.bufaddr;
549 aiov.iov_len = rwcmd.buflen;
550
551 bzero((caddr_t)&auio, sizeof (struct uio));
552 auio.uio_iov = &aiov;
553 auio.uio_iovcnt = 1;
554 auio.uio_resid = rwcmd.buflen;
555 auio.uio_segflg = flag & FKIOCTL ? UIO_SYSSPACE : UIO_USERSPACE;
556
557 status = physio(pcata_strategy, bp, dev, rw, pcata_min, &auio);
558
559 freerbuf(bp);
560
561 return (status);
562 }
563
564 case DKIOCEJECT:
565 /*
566 * Since we do not have hardware support for ejecting
567 * a pcata card, we must not support the generic eject
568 * ioctl (DKIOCEJECT) which is used for eject(1) command
569 * because it leads the user to expect behavior that is
570 * not present.
571 */
572 return (ENOSYS);
573
574 case HDKIOCSCMD:
575 case HDKIOCGDIAG:
576 break;
577 default:
578 return (ENOTTY);
579 }
580 return (0);
581 }
582
583 int
pcata_lbl_ioctl(dev_t dev,int cmd,intptr_t arg,int flag)584 pcata_lbl_ioctl(dev_t dev, int cmd, intptr_t arg, int flag)
585 {
586 uint32_t data[512 / (sizeof (uint32_t))];
587 void *instance;
588 ata_soft_t *softp;
589 ata_unit_t *unitp;
590 int i;
591 struct vtoc vtoc;
592
593 if (pcata_getinfo(NULL, DDI_INFO_DEVT2INSTANCE, (void *)dev,
594 &instance) != DDI_SUCCESS)
595 return (ENODEV);
596
597 if (!(softp = ddi_get_soft_state(pcata_soft,
598 (int)(uintptr_t)instance))) {
599 return (ENXIO);
600 }
601
602 if (!(CARD_PRESENT_VALID(softp))) {
603 return (ENODEV);
604 }
605
606 ASSERT(softp->ab_link);
607 bzero((caddr_t)data, sizeof (data));
608 unitp = softp->ab_link;
609
610 switch (cmd) {
611 case DKIOCGGEOM:
612 case DKIOCGAPART:
613 case DKIOCGVTOC:
614 if (pcata_update_vtoc(softp, dev))
615 return (EFAULT);
616 }
617
618 switch (cmd) {
619 case DKIOCGGEOM:
620 {
621 struct dk_geom up;
622
623 pcdsklbl_dgtoug(&up, &unitp->lbl.ondsklbl);
624 if (COPYOUT(&up, arg, struct dk_geom, flag)) {
625 return (EFAULT);
626 }
627 break;
628 }
629
630 case DKIOCSGEOM:
631 i = sizeof (struct dk_geom);
632 if (ddi_copyin((caddr_t)arg, (caddr_t)data, i, flag))
633 return (EFAULT);
634 pcdsklbl_ugtodg((struct dk_geom *)data, &unitp->lbl.ondsklbl);
635 break;
636
637 case DKIOCGAPART:
638 /*
639 * Return the map for all logical partitions.
640 */
641 #if defined(_MULTI_DATAMODEL)
642 switch (ddi_model_convert_from(flag & FMODELS)) {
643 case DDI_MODEL_ILP32: {
644 struct dk_map32 dk_map32[NDKMAP];
645 int i;
646
647 for (i = 0; i < NDKMAP; i++) {
648 dk_map32[i].dkl_cylno =
649 unitp->lbl.un_map[i].dkl_cylno;
650 dk_map32[i].dkl_nblk =
651 unitp->lbl.un_map[i].dkl_nblk;
652 }
653 i = NDKMAP * sizeof (struct dk_map32);
654 if (ddi_copyout(dk_map32, (caddr_t)arg, i, flag))
655 return (EFAULT);
656 break;
657 }
658
659 case DDI_MODEL_NONE:
660 i = NDKMAP * sizeof (struct dk_map);
661 if (ddi_copyout((caddr_t)unitp->lbl.un_map,
662 (caddr_t)arg, i, flag))
663 return (EFAULT);
664 break;
665 }
666
667 #else /* _MULTI_DATAMODEL */
668 i = NDKMAP * sizeof (struct dk_map);
669 if (ddi_copyout((caddr_t)unitp->lbl.un_map,
670 (caddr_t)arg, i, flag))
671 return (EFAULT);
672 #endif /* _MULTI_DATAMODEL */
673 break;
674
675 case DKIOCSAPART:
676 /*
677 * Set the map for all logical partitions.
678 */
679 #if defined(_MULTI_DATAMODEL)
680 switch (ddi_model_convert_from(flag & FMODELS)) {
681 case DDI_MODEL_ILP32: {
682 struct dk_map32 dk_map32[NDKMAP];
683 int i;
684
685 i = NDKMAP * sizeof (struct dk_map32);
686 if (ddi_copyin((caddr_t)arg, dk_map32, i, flag))
687 return (EFAULT);
688 for (i = 0; i < NDKMAP; i++) {
689 unitp->lbl.un_map[i].dkl_cylno =
690 dk_map32[i].dkl_cylno;
691 unitp->lbl.un_map[i].dkl_nblk =
692 dk_map32[i].dkl_nblk;
693 }
694 i = NDKMAP * sizeof (struct dk_map32);
695 break;
696 }
697
698 case DDI_MODEL_NONE:
699 i = NDKMAP * sizeof (struct dk_map);
700 if (ddi_copyout((caddr_t)unitp->lbl.un_map,
701 (caddr_t)arg, i, flag))
702 return (EFAULT);
703 break;
704 }
705 break;
706 #else /* _MULTI_DATAMODEL */
707 i = NDKMAP * sizeof (struct dk_map);
708 if (ddi_copyin((caddr_t)arg, (caddr_t)data, i, flag))
709 return (EFAULT);
710 bcopy((caddr_t)data, (caddr_t)unitp->lbl.un_map, i);
711 break;
712 #endif /* _MULTI_DATAMODEL */
713
714 case DKIOCGVTOC:
715 #if defined(_MULTI_DATAMODEL)
716 switch (ddi_model_convert_from(flag & FMODELS)) {
717 case DDI_MODEL_ILP32: {
718 struct vtoc32 vtoc32;
719
720 pcdsklbl_ondsklabel_to_vtoc(&unitp->lbl, &vtoc);
721 vtoctovtoc32(vtoc, vtoc32);
722 if (ddi_copyout(&vtoc32, (caddr_t)arg,
723 sizeof (struct vtoc32), flag))
724 return (EFAULT);
725 break;
726 }
727
728 case DDI_MODEL_NONE:
729 pcdsklbl_ondsklabel_to_vtoc(&unitp->lbl, &vtoc);
730 if (ddi_copyout((caddr_t)&vtoc, (caddr_t)arg,
731 sizeof (struct vtoc), flag))
732 return (EFAULT);
733 break;
734 }
735 return (0);
736 #else /* _MULTI_DATAMODEL */
737 pcdsklbl_ondsklabel_to_vtoc(&unitp->lbl, &vtoc);
738 if (ddi_copyout((caddr_t)&vtoc, (caddr_t)arg,
739 sizeof (struct vtoc), flag))
740 return (EFAULT);
741 return (0);
742 #endif /* _MULTI_DATAMODEL */
743
744 case DKIOCSVTOC:
745 #if defined(_MULTI_DATAMODEL)
746 switch (ddi_model_convert_from(flag & FMODELS)) {
747 case DDI_MODEL_ILP32: {
748 struct vtoc32 vtoc32;
749
750 if (ddi_copyin((caddr_t)arg, &vtoc32,
751 sizeof (struct vtoc32), flag))
752 return (EFAULT);
753 vtoc32tovtoc(vtoc32, vtoc);
754
755 if (pcata_write_dskvtoc(softp, dev, &unitp->lbl, &vtoc))
756 return (EFAULT);
757 break;
758 }
759
760 case DDI_MODEL_NONE:
761 if (ddi_copyin((caddr_t)arg, (caddr_t)&vtoc,
762 sizeof (struct vtoc), flag))
763 return (EFAULT);
764
765 if (pcata_write_dskvtoc(softp, dev, &unitp->lbl, &vtoc))
766 return (EFAULT);
767
768 break;
769 }
770 #else /* _MULTI_DATAMODEL */
771 if (ddi_copyin((caddr_t)arg, (caddr_t)&vtoc,
772 sizeof (struct vtoc), flag))
773 return (EFAULT);
774
775 if (pcata_write_dskvtoc(softp, dev, &unitp->lbl, &vtoc))
776 return (EFAULT);
777
778 break;
779 #endif /* _MULTI_DATAMODEL */
780 }
781 return (0);
782 }
783
784 /* ARGSUSED */
785 int
pcata_open(dev_t * dev_p,int flag,int otyp,cred_t * cred_p)786 pcata_open(dev_t *dev_p, int flag, int otyp, cred_t *cred_p)
787 {
788 register dev_t dev = *dev_p;
789 ata_soft_t *softp;
790 void *instance;
791 int i;
792
793 #ifdef ATA_DEBUG
794 if (pcata_debug & DIO)
795 cmn_err(CE_CONT, "_open: "
796 "dev_p=%p dev=%x flag=%x otyp=%x cred_p=%p\n",
797 (void *)dev_p, (int)dev, flag, otyp, (void *)cred_p);
798 #endif
799 if (pcata_getinfo(NULL, DDI_INFO_DEVT2INSTANCE, (void *) *dev_p,
800 &instance) != DDI_SUCCESS)
801 return (ENODEV);
802
803 softp = ddi_get_soft_state(pcata_soft, (int)(uintptr_t)instance);
804
805 /*
806 * open and getinfo may be called before attach completes
807 */
808 for (i = 0; i < 300; i++) {
809 if (softp->flags & PCATA_READY)
810 break;
811 drv_usecwait(10000);
812 }
813 if (!pcata_readywait(softp))
814 return (ENXIO);
815
816 #ifdef ATA_DEBUG
817 if (pcata_debug & DIO)
818 cmn_err(CE_CONT,
819 "_open: part=%d blk_open=%x chr_open=%x lyr_open=%d\n",
820 LPART(dev), softp->blk_open, softp->chr_open,
821 softp->lyr_open[LPART(dev)]);
822 #endif
823
824 mutex_enter(&(softp)->ata_mutex);
825 /*
826 * Only honor FEXCL. If a regular open or a layered open
827 * is still outstanding on the device, the exclusive open
828 * must fail.
829 */
830 if (flag & FEXCL) {
831 if ((softp->chr_open & (1 << LPART(dev))) ||
832 (softp->blk_open & (1 << LPART(dev))) ||
833 (softp->lyr_open[LPART(dev)])) {
834 mutex_exit(&(softp)->ata_mutex);
835 return (EAGAIN);
836 }
837 }
838
839 switch (otyp) {
840 case OTYP_BLK:
841 softp->blk_open |= (1 << LPART(dev));
842 break;
843 case OTYP_CHR:
844 softp->chr_open |= (1 << LPART(dev));
845 break;
846 case OTYP_LYR:
847 softp->lyr_open[LPART(dev)]++;
848 break;
849 default:
850 mutex_exit(&(softp)->ata_mutex);
851 return (EINVAL);
852 }
853
854 mutex_exit(&(softp)->ata_mutex);
855
856 return (0);
857 }
858
859
860
861 /* ARGSUSED */
862 int
pcata_close(dev_t dev,int flag,int otyp,cred_t * cred_p)863 pcata_close(dev_t dev, int flag, int otyp, cred_t *cred_p)
864 {
865 ata_soft_t *softp;
866 int i;
867 int lyr_count = 0;
868 void *instance;
869
870 #ifdef ATA_DEBUG
871 if (pcata_debug & DIO)
872 cmn_err(CE_CONT, "_close: dev=%x flag=%x otyp=%x cred_p=%p\n",
873 (int)dev, flag, otyp, (void *)cred_p);
874 #endif
875
876 if (pcata_getinfo(NULL, DDI_INFO_DEVT2INSTANCE, (void *) dev,
877 &instance) != DDI_SUCCESS)
878 return (ENODEV);
879
880 softp = ddi_get_soft_state(pcata_soft, (int)(uintptr_t)instance);
881
882 #ifdef ATA_DEBUG
883 if (pcata_debug & DIO)
884 cmn_err(CE_CONT,
885 "_close: part=%d blk_open=%x chr_open=%x lyr_open=%d\n",
886 LPART(dev), softp->blk_open, softp->chr_open,
887 softp->lyr_open[LPART(dev)]);
888 #endif
889
890
891 mutex_enter(&(softp)->ata_mutex);
892
893 switch (otyp) {
894 case OTYP_BLK:
895 softp->blk_open &= ~(1 << LPART(dev));
896 break;
897 case OTYP_CHR:
898 softp->chr_open &= ~(1 << LPART(dev));
899 break;
900 case OTYP_LYR:
901 softp->lyr_open[LPART(dev)]--;
902 break;
903 default:
904 mutex_exit(&(softp)->ata_mutex);
905 return (EINVAL);
906 }
907
908 if ((softp->blk_open) || (softp->chr_open)) {
909 /* not done yet */
910 mutex_exit(&(softp)->ata_mutex);
911 return (0);
912 } else {
913 for (i = 0; i < LPART(dev); i++) {
914 if (softp->lyr_open[LPART(dev)] != 0)
915 lyr_count++;
916 }
917
918 if (lyr_count) {
919 /* not done yet */
920 mutex_exit(&(softp)->ata_mutex);
921 return (0);
922 }
923 }
924
925 if (softp->ejected_while_mounted)
926 softp->ejected_while_mounted = 0;
927
928 mutex_exit(&(softp)->ata_mutex);
929
930 return (0);
931 }
932
933 static int
pcata_redo_vtoc(ata_soft_t * softp,buf_t * fdiskbp)934 pcata_redo_vtoc(ata_soft_t *softp, buf_t *fdiskbp)
935 {
936 struct dk_geom dkg;
937 ata_unit_t *unitp;
938 buf_t *bp;
939 int status;
940 dev_t dev;
941
942
943 unitp = softp->ab_link;
944 if (!unitp)
945 return (EFAULT);
946
947 /* given any maj/min convert to fdisk partition 0 */
948 dev = makedevice(getmajor(fdiskbp->b_edev),
949 PCATA_SETMINOR(softp->sn, FDISK_OFFSET));
950
951 if ((bp = pcata_lblk_alloc(dev)) == NULL)
952 return (EFAULT);
953
954 bcopy(fdiskbp->b_un.b_addr, bp->b_un.b_addr, NBPSCTR);
955
956 bzero((caddr_t)&dkg, sizeof (struct dk_geom));
957 dkg.dkg_ncyl = unitp->au_cyl;
958 dkg.dkg_nhead = unitp->au_hd;
959 dkg.dkg_nsect = unitp->au_sec;
960
961 status = pcfdisk_parse(bp, unitp);
962
963 /* release buffer allocated by getrbuf */
964 kmem_free(bp->b_un.b_addr, NBPSCTR);
965 freerbuf(bp);
966
967 if (status == DDI_FAILURE)
968 return (EFAULT);
969 return (0);
970 }
971
972 /*
973 *
974 */
975 int
pcata_update_vtoc(ata_soft_t * softp,dev_t dev)976 pcata_update_vtoc(ata_soft_t *softp, dev_t dev)
977 {
978 ata_unit_t *unitp;
979 buf_t *bp;
980 int status;
981
982 unitp = softp->ab_link;
983 if (!unitp)
984 return (EFAULT);
985
986 /* given any maj/min convert to fdisk partition 0 */
987 dev = makedevice(getmajor(dev),
988 PCATA_SETMINOR(softp->sn, FDISK_OFFSET));
989
990 if ((bp = pcata_lblk_alloc(dev)) == NULL)
991 return (EFAULT);
992
993 /*
994 * The dev is passed here for use later by the dsklbl_rdvtoc()
995 * and pcata_dsklbl_read_label() to check for card present before
996 * calling biowait.
997 */
998 status = pcfdisk_read(bp, unitp);
999
1000 /* release buffer allocated by getrbuf */
1001 kmem_free(bp->b_un.b_addr, NBPSCTR);
1002 freerbuf(bp);
1003
1004 if (status == DDI_FAILURE)
1005 return (EFAULT);
1006 return (0);
1007 }
1008
1009 static buf_t *
pcata_lblk_alloc(dev_t dev)1010 pcata_lblk_alloc(dev_t dev)
1011 {
1012 buf_t *bp;
1013 char *secbuf;
1014
1015 /* allocate memory to hold disk label */
1016 secbuf = kmem_zalloc(NBPSCTR, KM_SLEEP);
1017 if (!secbuf)
1018 return (NULL);
1019
1020 /* allocate a buf_t to manage the disk label block */
1021 bp = getrbuf(KM_SLEEP);
1022 if (!bp) {
1023 kmem_free(secbuf, NBPSCTR);
1024 return (NULL);
1025 }
1026
1027 /* initialize the buf_t */
1028 bp->b_edev = dev;
1029 bp->b_dev = cmpdev(dev);
1030 bp->b_flags |= B_BUSY;
1031 bp->b_resid = 0;
1032 bp->b_bcount = NBPSCTR;
1033 bp->b_un.b_addr = (caddr_t)secbuf;
1034
1035 return (bp);
1036 }
1037
1038
1039 int
pcata_write_dskvtoc(ata_soft_t * softp,dev_t dev,dsk_label_t * lblp,struct vtoc * vtocp)1040 pcata_write_dskvtoc(ata_soft_t *softp, dev_t dev, dsk_label_t *lblp,
1041 struct vtoc *vtocp)
1042 {
1043 buf_t *bp;
1044 int status;
1045
1046 dev = makedevice(getmajor(dev),
1047 PCATA_SETMINOR(softp->sn, FDISK_OFFSET));
1048
1049 if ((bp = pcata_lblk_alloc(dev)) == NULL)
1050 return (EFAULT);
1051
1052 #ifdef ATA_DEBUG
1053 cmn_err(CE_CONT, "_write_dskvtoc: edev = %lx dev = %x\n",
1054 bp->b_edev,
1055 bp->b_dev);
1056 #endif
1057
1058
1059 bp->b_edev = dev; /* used by probe_for_card() */
1060 status = pcdsklbl_wrvtoc(lblp, vtocp, bp);
1061
1062 /* release buffer allocated by getrbuf */
1063 kmem_free(bp->b_un.b_addr, NBPSCTR);
1064 freerbuf(bp);
1065
1066 return (status);
1067 }
1068 /*
1069 * Check media insertion/ejection status
1070 */
1071 static int
pcata_check_media(ata_soft_t * rs,enum dkio_state state)1072 pcata_check_media(ata_soft_t *rs, enum dkio_state state)
1073 {
1074 int err;
1075 get_status_t get_status;
1076
1077
1078 mutex_enter(&rs->ata_mutex);
1079
1080 /*
1081 * Do a CS call to see if the card is present
1082 */
1083 if ((err = csx_GetStatus(rs->client_handle, &get_status))
1084 != CS_SUCCESS) {
1085 error2text_t cft;
1086
1087 mutex_exit(&rs->ata_mutex);
1088
1089 cft.item = err;
1090 (void) csx_Error2Text(&cft);
1091 cmn_err(CE_CONT, "pcata_check_media: socket %d "
1092 "GetStatus failed %s (0x%x)\n",
1093 rs->sn, cft.text, err);
1094 return (ENXIO);
1095 }
1096
1097 /* Register rs->media_state */
1098 if ((get_status.CardState & CS_EVENT_CARD_INSERTION)) {
1099 rs->media_state = DKIO_INSERTED;
1100 } else {
1101 if (state == DKIO_NONE) {
1102 rs->media_state = DKIO_NONE;
1103 } else {
1104 rs->media_state = DKIO_EJECTED;
1105 }
1106 }
1107
1108
1109 /*
1110 * XXXX - In order not to modify the volume management
1111 * we have to follow the current SCSI CDROM model
1112 * for checking media state (broken way, sigh!)
1113 * start with state = DKIO_NONE
1114 * wait until mediastate = DKIO_INSERTED
1115 * wait until mediastate = DKIO_EJECTED
1116 * if DKIOCSTATE ioctl() is called second time
1117 * with state = DKIO_EJECTED,
1118 * return state = DKIO_NONE
1119 * restart with state = DKIO_NONE
1120 *
1121 */
1122 if (state != DKIO_NONE) {
1123 if (rs->ejected_media_flag &&
1124 (rs->media_state == DKIO_EJECTED)) {
1125 rs->media_state = DKIO_NONE;
1126 rs->ejected_media_flag = 0;
1127 mutex_exit(&rs->ata_mutex);
1128 return (0);
1129 }
1130 }
1131
1132 #ifdef ATA_DEBUG
1133 if (pcata_debug & DVOLD) {
1134 cmn_err(CE_CONT, "pcata_check_media: socket %d \n"
1135 "\tWaiting state change: rs->media_state %d state %d\n"
1136 "\tDKIO_NONE %d DKIO_EJECTED %d DKIO_INSERTED %d\n",
1137 rs->sn, rs->media_state, state,
1138 DKIO_NONE, DKIO_EJECTED, DKIO_INSERTED);
1139 }
1140 #endif
1141
1142 /*
1143 * wait for Card Detect Change Interrupt handler
1144 * see either pcata_card_insertion/pcata_card_removal
1145 * for cv_broadcast
1146 */
1147 while (rs->media_state == state) {
1148 rs->checkmedia_flag++;
1149 if (cv_wait_sig(&rs->condvar_mediastate,
1150 &rs->ata_mutex) == 0) {
1151 mutex_exit(&rs->ata_mutex);
1152 return (EINTR);
1153 }
1154 }
1155
1156 #ifdef ATA_DEBUG
1157 if (pcata_debug & DVOLD) {
1158 cmn_err(CE_CONT, "pcata_check_media: socket %d \n"
1159 "\tAfter state change: rs->media_state %d state %d\n"
1160 "\tDKIO_NONE %d DKIO_EJECTED %d DKIO_INSERTED %d\n",
1161 rs->sn, rs->media_state, state,
1162 DKIO_NONE, DKIO_EJECTED, DKIO_INSERTED);
1163 }
1164 #endif
1165
1166 if (state != DKIO_NONE) {
1167 if (!rs->ejected_media_flag &&
1168 (rs->media_state == DKIO_EJECTED)) {
1169 rs->ejected_media_flag++;
1170 }
1171 }
1172
1173 mutex_exit(&rs->ata_mutex);
1174
1175 return (0);
1176 }
1177
1178 int
pcata_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)1179 pcata_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op,
1180 int mod_flags, char *name, caddr_t valuep, int *lengthp)
1181 {
1182 int instance = ddi_get_instance(dip);
1183 ata_soft_t *softp;
1184 ata_unit_t *unitp;
1185 uint64_t nblocks64;
1186
1187 /*
1188 * Our dynamic properties are all device specific and size oriented.
1189 * Requests issued under conditions where size is valid are passed
1190 * to ddi_prop_op_nblocks with the size information, otherwise the
1191 * request is passed to ddi_prop_op.
1192 */
1193 softp = ddi_get_soft_state(pcata_soft, instance);
1194 if ((dev == DDI_DEV_T_ANY) || (softp == NULL) ||
1195 !(CARD_PRESENT_VALID(softp)) ||
1196 ((unitp = softp->ab_link) == NULL)) {
1197 return (ddi_prop_op(dev, dip, prop_op, mod_flags,
1198 name, valuep, lengthp));
1199 } else {
1200 /* get nblocks value */
1201 nblocks64 = (ulong_t)unitp->lbl.pmap[LPART(dev)].p_size;
1202
1203 return (ddi_prop_op_nblocks(dev, dip, prop_op, mod_flags,
1204 name, valuep, lengthp, nblocks64));
1205 }
1206 }
1207