xref: /onnv-gate/usr/src/uts/common/io/pcmcia/pcdisk.c (revision 0:68f95e015346)
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