6901121 assertion failed: hubd->h_intr_pipe_state == HUBD_INTR_PIPE_ACTIVE
[unleashed.git] / usr / src / uts / common / io / pcmcia / pcram.c
blob6c2c3da8da84c64e03d82dabc21c8c6ed6661a77
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
19 * CDDL HEADER END
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
27 #if defined(DEBUG)
28 #define PCRAM_DEBUG
29 #endif
32 * PCMCIA SRAM/DRAM/MROM Memory Card Driver
35 * The PCMCIA memory card driver will be used to support disk-like
36 * I/O access to any standard PCMCIA memory cards such as:
38 * - Non-Volatile Static RAM (SRAM)
39 * - Non-Volatile Dynamic RAM (DRAM)
40 * - Mask ROM (MROM)
42 * The PCMCIA memory cards can be used as pseudo-floppy disks.
44 * Features:
46 * - DO NOT support the FLASH, EEPROM, and OTP memory card.
47 * - modeling after the ramdisk pseudo-device.
48 * - currently supporting character device and block device.
49 * - supporting only single partition.
51 * Support Utility:
53 * The fdformat(1) utility has to use PCRAM_PROBESIZE ioctl
54 * to request the card size information.
56 * If a memory card has a Card Information Structure (CIS)
57 * then the card size is from a Common Memory CISTPL_DEVICE
58 * tuple. If there is no CIS the driver must use
59 * write/read/restore operation on first byte of every 512KB
60 * block of data to determine the total card size.
61 * Refer to pcram_card_sizing().
63 * We do not need to support set geometry (DKIOCSGEOM) since we
64 * provide PCRAM_PROBESIZE ioctl to probe the memory card size.
65 * PCRAM_PROBESIZE ioctl is a private interface which is
66 * used by the SunVTS and fdformat(1) utility.
68 * SS2 CACHE+ problem note:
70 * Refer to card_byte_wr() for the problem of the SS2 CACHE+
71 * double word write to the 16-bit slave device.
75 #include <sys/types.h>
76 #include <sys/file.h>
77 #include <sys/errno.h>
78 #include <sys/uio.h>
79 #include <sys/open.h>
80 #include <sys/cred.h>
81 #include <sys/kmem.h>
82 #include <sys/conf.h>
83 #include <sys/cmn_err.h>
84 #include <sys/ksynch.h>
85 #include <sys/modctl.h>
88 * needed for: S_IFBLK - block special
89 * S_IFCHR - character special
91 #include <sys/stat.h>
93 /* supporting eject(1) command (struct fd_drive) */
94 #include <sys/fdio.h>
96 /* The next headers may not be DDI-compliant */
97 #include <sys/dkio.h>
98 #include <sys/dklabel.h> /* logical partitions */
99 #include <sys/vtoc.h>
101 /* DOS label */
102 #include <sys/fs/pc_label.h>
105 * PCMCIA and DDI related header files
107 #include <sys/pccard.h>
108 #include <sys/ddi.h>
109 #include <sys/sunddi.h>
112 * pcram-related header files
114 #include <sys/pcmcia/pcramio.h>
115 #include <sys/pcmcia/pcramvar.h>
118 * Character/Block Operations (cb_ops) Structure
120 static int pcram_getinstance(dev_t);
121 static int pcram_open(dev_t *devp, int flag, int otyp, cred_t *cred);
122 static int pcram_close(dev_t dev, int flag, int otyp, cred_t *cred);
123 static int pcram_read(dev_t dev, struct uio *uiop, cred_t *credp);
124 static int pcram_write(dev_t dev, struct uio *uiop, cred_t *credp);
125 static int pcram_prop_op(dev_t dev, dev_info_t *dip,
126 ddi_prop_op_t prop_op,
127 int flags, char *name, caddr_t valuep,
128 int *lengthp);
129 static int pcram_ioctl(dev_t dev, int cmd, intptr_t arg, int mode,
130 cred_t *credp, int *rvalp);
131 static int pcram_strategy(struct buf *bp);
132 static int pcram_print(dev_t dev, char *str);
135 * Device Operations (dev_ops) Structure
137 static int pcram_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd,
138 void *arg, void **resultp);
139 static int pcram_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
140 static int pcram_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
143 * Called from pcram_strategy
145 static void pcram_start(pcram_state_t *rs);
148 * Misc functions
150 static uint32_t pcram_softintr();
153 static int pcram_event(event_t, int, event_callback_args_t *);
154 static int pcram_card_insertion(pcram_state_t *);
155 static int pcram_card_removal(pcram_state_t *);
156 static int pcram_build_region_lists(pcram_state_t *);
157 static int pcram_build_region_list(pcram_state_t *,
158 mem_region_t **, uint32_t);
159 static int pcram_get_bpbfat_info(pcram_state_t *, mem_region_t *);
160 static int pcram_get_solaris_info(pcram_state_t *, mem_region_t *);
162 static void pcram_destroy_region_lists(pcram_state_t *);
163 static void pcram_destroy_region_list(mem_region_t **, int *);
165 static mem_region_t *pcram_get_firstnext_region(mem_region_t *, uint32_t,
166 uint32_t, uint32_t *);
168 #ifdef PCRAM_DEBUG
169 int pcram_debug = 0;
170 int pcram_debug_events = 1;
171 static void pcram_display_card_status(get_status_t *);
172 static void pcram_debug_report_event(pcram_state_t *pcram, event_t event,
173 int priority);
174 #endif
177 /* Character/Block Operations (cb_ops) Structure */
178 static struct cb_ops pcram_cb_ops = {
179 pcram_open, /* open */
180 pcram_close, /* close */
181 pcram_strategy, /* strategy */
182 pcram_print, /* print */
183 nodev, /* dump */
184 pcram_read, /* read */
185 pcram_write, /* write */
186 pcram_ioctl, /* ioctl */
187 nodev, /* devmap */
188 nodev, /* mmap */
189 ddi_segmap, /* segmap */
190 nochpoll, /* poll */
191 pcram_prop_op, /* prop_op */
192 NULL, /* streamtab */
193 D_NEW | D_MP /* Driver compatibility flag */
197 /* Device Operations (dev_ops) Structure */
198 static struct dev_ops pcram_ops = {
199 DEVO_REV, /* devo_rev */
200 0, /* refcnt */
201 pcram_getinfo, /* info */
202 nulldev, /* identify */
203 nulldev, /* probe */
204 pcram_attach, /* attach */
205 pcram_detach, /* detach */
206 nodev, /* reset (currently not supported) */
207 &pcram_cb_ops, /* cb_ops pointer for leaf driver */
208 (struct bus_ops *)NULL, /* bus_ops pointer for nexus driver */
209 NULL, /* power */
210 ddi_quiesce_not_supported, /* devo_quiesce */
214 /* Module linkage information for the kernel */
215 extern struct mod_ops mod_driverops;
217 static struct modldrv md = {
218 &mod_driverops, /* Type of module. This is a driver */
219 PCRAM_DRIVERID, /* Driver Identifier string */
220 &pcram_ops, /* Device Operation Structure */
223 static struct modlinkage modlinkage = {
224 MODREV_1,
225 &md,
226 NULL
231 * Local driver data
233 static void *pcram_soft_state_p = NULL;
235 /* Determine PCMCIA memory card size */
236 static int pcram_card_sizing(pcram_state_t *rs);
238 /* Updating window size */
239 static int update_mapmempage(pcram_state_t *rs, int offset);
241 /* Byte write to the memory card */
242 static void card_byte_wr(pcram_state_t *rs, int xfer_size, int offset);
244 /* SPARC UNIX File System label checksum */
245 static int cksum(struct dk_label *label);
247 /* Writing disk label */
248 static int pcram_build_label_vtoc(pcram_state_t *rs, struct vtoc *vtoc);
249 static void pcram_write_label(pcram_state_t *rs);
251 /* Check media insertion/ejection status */
252 static int pcram_check_media(pcram_state_t *rs, enum dkio_state state);
254 /* Update drive characteristic structure */
255 static void update_hdrv_chars(pcram_state_t *, mem_region_t *);
257 /* external data of interest to us */
258 char *pcram_name = PCRAM_NAME;
262 * Module Initialization functions.
263 * 1. _init() routine
264 * 2. _info() routine
265 * 3. _fini() routine
268 _init(void)
270 int error;
272 #ifdef PCRAM_DEBUG
273 if (pcram_debug & PCRAM_DEBUG_TRACE)
274 cmn_err(CE_CONT, "pcram_init here\n");
275 #endif
277 error = ddi_soft_state_init(&pcram_soft_state_p,
278 sizeof (pcram_state_t),
279 1 /* n_items */);
280 if (error) {
281 return (error);
284 error = mod_install(&modlinkage);
285 if (error) {
286 ddi_soft_state_fini(&pcram_soft_state_p);
287 return (error);
290 return (error);
294 _info(struct modinfo *modinfop)
297 #ifdef PCRAM_DEBUG
298 if (pcram_debug & PCRAM_DEBUG_TRACE)
299 cmn_err(CE_CONT, "pcram_info here\n");
300 #endif
302 return (mod_info(&modlinkage, modinfop));
306 _fini(void)
308 int error;
310 #ifdef PCRAM_DEBUG
311 if (pcram_debug & PCRAM_DEBUG_TRACE)
312 cmn_err(CE_CONT, "pcram_fini here\n");
313 #endif
315 error = mod_remove(&modlinkage);
316 if (error)
317 return (error);
318 ddi_soft_state_fini(&pcram_soft_state_p);
320 return (error);
325 * Autoconfiguration Routines
326 * pcram_attach()
327 * pcram_detach()
328 * pcram_getinfo()
335 * Wait for minor nodes to be created before returning from attach,
336 * with a 5 sec. timeout to avoid hangs should an error occur.
338 static void
339 pcram_minor_wait(pcram_state_t *rs)
341 clock_t timeout;
343 timeout = ddi_get_lbolt() + drv_usectohz(5000000);
344 mutex_enter(&rs->event_hilock);
345 while ((rs->flags & PCRAM_MAKEDEVICENODE) == 0) {
346 if (cv_timedwait(&rs->firstopenwait_cv, &rs->event_hilock,
347 timeout) == (clock_t)-1)
348 break;
350 mutex_exit(&rs->event_hilock);
355 * pcram_attach() - performs board initialization
357 * This routine initializes the PCMCIA memory card driver
358 * and the board.
360 * Returns: DDI_SUCCESS, if able to attach.
361 * DDI_FAILURE, if unable to attach.
363 static int
364 pcram_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
366 int instance;
367 pcram_state_t *rs;
368 /* CardServices variables */
369 client_reg_t client_reg;
370 sockmask_t sockmask;
371 int ret;
372 map_log_socket_t map_log_socket;
373 get_status_t get_status;
376 instance = ddi_get_instance(dip);
378 #ifdef PCRAM_DEBUG
379 if (pcram_debug & PCRAM_DEBUG_TRACE)
380 cmn_err(CE_CONT,
381 "pcram_attach: instance %d cmd 0x%x\n",
382 instance, cmd);
383 #endif
385 /* resume from a checkpoint */
386 if (cmd == DDI_RESUME) {
387 return (DDI_SUCCESS);
388 /* NOTREACHED */
393 * make sure we're only being asked to do an attach
395 if (cmd != DDI_ATTACH) {
396 cmn_err(CE_NOTE, "pcram_attach[%d]: "
397 "cmd != DDI_ATTACH\n", instance);
398 return (DDI_FAILURE);
399 /* NOTREACHED */
402 if (ddi_soft_state_zalloc(pcram_soft_state_p,
403 instance) != DDI_SUCCESS) {
404 cmn_err(CE_NOTE, "pcram_attach: could not allocate "
405 "state structure for instance %d.", instance);
406 return (DDI_FAILURE);
407 /* NOTREACHED */
410 rs = ddi_get_soft_state(pcram_soft_state_p, instance);
411 if (rs == NULL) {
412 cmn_err(CE_NOTE, "pcram_attach: could not get "
413 "state structure for instance %d.",
414 instance);
415 goto out;
419 /* Remember dev_info structure for getinfo */
420 rs->dip = dip;
421 rs->instance = instance;
422 ddi_set_driver_private(dip, rs);
425 * clear the per-unit flags field
427 rs->flags = 0;
430 * Initialize the card event; initially say that the card
431 * is removed; when we get a card insertion event and
432 * validate the card, this will change.
434 rs->card_event = 0;
437 * Clear the memory region pointers.
439 rs->cm_regions = NULL;
440 rs->am_regions = NULL;
442 rs->host_sp = kmem_zalloc(HOST_BUF_SIZE, KM_SLEEP);
444 rs->blk_open = 0;
445 rs->chr_open = 0;
446 rs->nlayered = 0;
447 rs->busy = 0;
448 rs->busy_wr = 0;
449 rs->busy_rd = 0;
452 * Initialize to 0 until it is incremented in pcram_check_media
454 rs->checkmedia_flag = 0;
455 rs->ejected_media_flag = 0;
456 rs->media_state = DKIO_NONE;
459 * Continueing to return EIO if the card is ejected while
460 * it is mounted until the LAST layered close is called
462 rs->ejected_while_mounting = 0;
464 rs->wp_posted = 0;
467 /* initialize isit_pseudofloppy flag in each card struct */
468 rs->isit_pseudofloppy = 0;
471 * Allocate hard drive characteristic structure
473 rs->hdrv_chars = (struct hd_char *)
474 kmem_alloc(sizeof (struct hd_char), KM_SLEEP);
476 /* allocate transfer list header */
477 rs->blist = getrbuf(KM_SLEEP);
478 if (rs->blist == NULL) {
479 cmn_err(CE_NOTE, "pcram%d: attach card: "
480 "could not allocate transfer list header",
481 instance);
482 goto out;
485 /* queue is empty */
486 rs->blist->av_forw = NULL;
488 /* Add Medium priority soft interrupt to the system */
489 if (ddi_add_softintr(dip, DDI_SOFTINT_MED, &rs->softint_id,
490 &rs->soft_blk_cookie, (ddi_idevice_cookie_t *)NULL,
491 pcram_softintr, (caddr_t)rs) != DDI_SUCCESS) {
492 cmn_err(CE_NOTE, "pcram%d attach: "
493 "could not add soft interrupt",
494 instance);
495 goto out;
498 rs->flags |= PCRAM_SOFTINTROK;
500 #ifdef PCRAM_DEBUG
501 if (pcram_debug & PCRAM_DEBUG_TRACE) {
502 cmn_err(CE_CONT, "pcram_attach: "
503 "calling RegisterClient for instance %d\n",
504 instance);
506 #endif
509 * Register with Card Services
510 * Note that we set CS_EVENT_CARD_REMOVAL_LOWP so that we get
511 * low priority CS_EVENT_CARD_REMOVAL events as well.
513 client_reg.Attributes = (INFO_MEM_CLIENT |
514 INFO_CARD_SHARE |
515 INFO_CARD_EXCL);
516 client_reg.EventMask = (CS_EVENT_CARD_INSERTION |
517 CS_EVENT_CARD_REMOVAL |
518 CS_EVENT_CARD_REMOVAL_LOWP |
519 CS_EVENT_CLIENT_INFO |
520 CS_EVENT_REGISTRATION_COMPLETE);
521 client_reg.event_handler = (csfunction_t *)pcram_event;
522 client_reg.event_callback_args.client_data = rs;
523 client_reg.Version = _VERSION(2, 1);
524 client_reg.dip = dip;
525 (void) strcpy(client_reg.driver_name, pcram_name);
526 if ((ret = csx_RegisterClient(&rs->client_handle,
527 &client_reg)) != CS_SUCCESS) {
528 error2text_t cft;
530 cft.item = ret;
531 (void) csx_Error2Text(&cft);
532 cmn_err(CE_CONT, "pcram_attach: "
533 "RegisterClient failed %s (0x%x)\n",
534 cft.text, ret);
535 goto out;
538 rs->flags |= PCRAM_REGCLIENT;
540 #ifdef PCRAM_DEBUG
541 if (pcram_debug & PCRAM_DEBUG_TRACE) {
542 cmn_err(CE_CONT, "pcram_attach: "
543 "RegisterClient client_handle 0x%x\n",
544 rs->client_handle);
546 #endif
548 /* Get logical socket number and store in pcram_state_t */
549 if ((ret = csx_MapLogSocket(rs->client_handle,
550 &map_log_socket)) != CS_SUCCESS) {
551 error2text_t cft;
553 cft.item = ret;
554 (void) csx_Error2Text(&cft);
556 cmn_err(CE_CONT, "pcram_attach: "
557 "MapLogSocket failed %s (0x%x)\n",
558 cft.text, ret);
561 rs->sn = map_log_socket.PhySocket;
563 #ifdef PCRAM_DEBUG
564 if (pcram_debug & PCRAM_DEBUG_TRACE) {
565 cmn_err(CE_CONT, "pcram_attach: "
566 "MapLogSocket for socket %d\n", rs->sn);
568 #endif
570 /* Setup the event handler hi-level mutex */
571 mutex_init(&rs->event_hilock, NULL, MUTEX_DRIVER,
572 *(client_reg.iblk_cookie));
574 /* set up the mutex to protect the pcram_state_t */
575 mutex_init(&rs->mutex, NULL, MUTEX_DRIVER, (void *)rs->soft_blk_cookie);
577 /* strategy(): waiting for I/O to complete */
578 cv_init(&rs->condvar, NULL, CV_DRIVER, NULL);
579 /* write(): waiting for I/O to complete */
580 cv_init(&rs->condvar_wr, NULL, CV_DRIVER, NULL);
581 /* read(): waiting for I/O to complete */
582 cv_init(&rs->condvar_rd, NULL, CV_DRIVER, NULL);
583 /* for DKIOCSTATE ioctl() */
584 cv_init(&rs->condvar_mediastate, NULL, CV_DRIVER, NULL);
585 /* Init firstopenwait_cv */
586 cv_init(&rs->firstopenwait_cv, NULL, CV_DRIVER, NULL);
588 /* mutex to protect region lists */
589 mutex_init(&rs->region_lock, NULL, MUTEX_DRIVER,
590 (void *)(rs->soft_blk_cookie));
592 rs->flags |= PCRAM_DIDLOCKS;
596 * After the RequestSocketMask call,
597 * we can start receiving events
599 sockmask.EventMask = (CS_EVENT_CARD_INSERTION |
600 CS_EVENT_CARD_REMOVAL);
602 if ((ret = csx_RequestSocketMask(rs->client_handle,
603 &sockmask)) != CS_SUCCESS) {
604 error2text_t cft;
606 cft.item = ret;
607 (void) csx_Error2Text(&cft);
609 cmn_err(CE_CONT, "pcram_attach: RequestSocketMask "
610 "failed %s (0x%x)\n", cft.text, ret);
611 goto out;
614 rs->flags |= PCRAM_REQSOCKMASK;
616 #ifdef PCRAM_DEBUG
617 if (pcram_debug & PCRAM_DEBUG_TRACE)
618 cmn_err(CE_CONT,
619 "pcram_attach: RequestSocketMask OK\n");
620 #endif
623 * Wait for minor node creation before continuing
625 pcram_minor_wait(rs);
626 if ((rs->flags & PCRAM_MAKEDEVICENODE) == 0) {
627 goto out;
631 * Check to see if the card is inserted and if this
632 * attach is triggered by an open, that open
633 * will wait until pcram_card_insertion() is
634 * completed
636 /* XXX function return value ignored */
637 (void) csx_GetStatus(rs->client_handle, &get_status);
638 if (get_status.CardState & CS_EVENT_CARD_INSERTION) {
639 if (!PCRAM_CARD_PRESENT(rs)) {
640 mutex_enter(&rs->event_hilock);
641 cv_wait(&rs->firstopenwait_cv, &rs->event_hilock);
642 mutex_exit(&rs->event_hilock);
643 #ifdef PCRAM_DEBUG
644 if (!PCRAM_CARD_PRESENT(rs)) {
645 cmn_err(CE_CONT, "pcram_attach:Card not found\n");
646 } else {
647 cmn_err(CE_CONT, "pcram_attach:Card found\n");
649 #endif
654 ddi_report_dev(dip);
657 * set a flag that pcram_open() can look at so that
658 * if this board doesn't make it all the way through
659 * pcram_attach(), we won't try to open it
661 rs->flags |= PCRAM_ATTACHOK;
663 return (DDI_SUCCESS);
664 /* NOTREACHED */
666 out:
667 (void) pcram_detach(dip, DDI_DETACH);
668 return (DDI_FAILURE);
672 static int
673 pcram_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
675 int instance, ret;
676 pcram_state_t *rs;
679 instance = ddi_get_instance(dip);
681 #ifdef PCRAM_DEBUG
682 if (pcram_debug & PCRAM_DEBUG_TRACE)
683 cmn_err(CE_CONT,
684 "pcram_detach: instance %d cmd 0x%x\n",
685 instance, cmd);
686 #endif
688 /* suspend */
689 if (cmd == DDI_SUSPEND) {
690 return (DDI_SUCCESS);
691 /* NOTREACHED */
694 if (cmd != DDI_DETACH) {
695 return (DDI_FAILURE);
696 /* NOTREACHED */
699 rs = ddi_get_soft_state(pcram_soft_state_p, instance);
700 if (rs == NULL) {
701 cmn_err(CE_NOTE, "pcram_detach: "
702 "could not get state structure "
703 "for instance %d.", instance);
704 return (DDI_FAILURE);
705 /* NOTREACHED */
709 * Clear the PCRAM_ATTACHOK so that other layers of the code
710 * will know that we're going away.
712 rs->flags &= ~PCRAM_ATTACHOK;
715 * Call pcram_card_removal to do any final card cleanup
717 (void) pcram_card_removal(rs);
720 * Release our socket mask - note that we can't do much
721 * if we fail these calls other than to note that
722 * the system will probably panic shortly. Perhaps
723 * we should fail the detach in the case where these
724 * CS calls fail?
726 if (rs->flags & PCRAM_REQSOCKMASK) {
727 release_socket_mask_t rsm;
728 if ((ret = csx_ReleaseSocketMask(rs->client_handle, &rsm))
729 != CS_SUCCESS) {
730 error2text_t cft;
732 cft.item = ret;
733 (void) csx_Error2Text(&cft);
735 cmn_err(CE_CONT, "pcram_detach: Socket %d "
736 "ReleaseSocketMask failed %s (0x%x)\n",
737 rs->sn, cft.text, ret);
742 * Deregister with Card Services - we will stop getting
743 * events at this point.
745 if (rs->flags & PCRAM_REGCLIENT) {
746 if ((ret = csx_DeregisterClient(rs->client_handle))
747 != CS_SUCCESS) {
748 error2text_t cft;
750 cft.item = ret;
751 (void) csx_Error2Text(&cft);
753 cmn_err(CE_CONT, "pcram_detach: Socket %d "
754 "DeregisterClient failed %s (0x%x)\n",
755 rs->sn, cft.text, ret);
759 if (rs->host_sp) {
760 kmem_free(rs->host_sp, HOST_BUF_SIZE);
763 if (rs->hdrv_chars) {
764 kmem_free(rs->hdrv_chars, sizeof (struct hd_char));
767 /* Free transfer list header */
768 if (rs->blist) {
769 freerbuf(rs->blist);
772 /* unregister the softinterrupt handler */
773 if (rs->flags & PCRAM_SOFTINTROK) {
774 ddi_remove_softintr(rs->softint_id);
777 /* free the various mutexii */
778 if (rs->flags & PCRAM_DIDLOCKS) {
779 mutex_destroy(&rs->event_hilock);
780 mutex_destroy(&rs->region_lock);
781 mutex_destroy(&rs->mutex);
782 /* strategy(): waiting for I/O to complete */
783 cv_destroy(&rs->condvar);
784 /* write(): waiting for I/O to complete */
785 cv_destroy(&rs->condvar_wr);
786 /* read(): waiting for I/O to complete */
787 cv_destroy(&rs->condvar_rd);
788 /* for DKIOCSTATE ioctl() */
789 cv_destroy(&rs->condvar_mediastate);
790 /* Free firstopenwait_cv */
791 cv_destroy(&rs->firstopenwait_cv);
794 ddi_soft_state_free(pcram_soft_state_p, instance);
796 return (DDI_SUCCESS);
801 * pcram_getinfo() this routine translates the dip
802 * info dev_t and vice versa.
804 * Returns: DDI_SUCCESS, if successful.
805 * DDI_FAILURE, if unsuccessful.
807 /*ARGSUSED*/
808 static int
809 pcram_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg,
810 void **result)
812 int error = DDI_SUCCESS;
813 pcram_state_t *rs;
814 cs_ddi_info_t cs_ddi_info;
817 switch (cmd) {
819 case DDI_INFO_DEVT2DEVINFO:
820 case DDI_INFO_DEVT2INSTANCE:
821 cs_ddi_info.Socket = PCRAM_SOCKET((dev_t)arg);
823 #ifdef PCRAM_DEBUG
824 if (pcram_debug & PCRAM_DEBUG_TRACE)
825 cmn_err(CE_CONT, "pcram_getinfo: socket %d\n",
826 cs_ddi_info.Socket);
827 #endif
829 cs_ddi_info.driver_name = pcram_name;
830 if (csx_CS_DDI_Info(&cs_ddi_info) != CS_SUCCESS) {
831 return (DDI_FAILURE);
832 /* NOTREACHED */
835 switch (cmd) {
836 case DDI_INFO_DEVT2DEVINFO:
837 if (!(rs = ddi_get_soft_state(
838 pcram_soft_state_p,
839 cs_ddi_info.instance))) {
840 *result = NULL;
841 } else {
842 *result = rs->dip;
844 break;
846 case DDI_INFO_DEVT2INSTANCE:
847 *result = (void *)(uintptr_t)cs_ddi_info.instance;
848 break;
849 } /* switch */
850 break;
851 default:
852 error = DDI_FAILURE;
853 break;
854 } /* switch */
856 return (error);
861 static int
862 pcram_getinstance(dev_t devp)
864 int rval;
865 cs_ddi_info_t ddi_info;
866 error2text_t cft;
868 ddi_info.Socket = PCRAM_SOCKET(devp);
869 ddi_info.driver_name = pcram_name;
870 if ((rval = csx_CS_DDI_Info(&ddi_info)) != CS_SUCCESS) {
871 cft.item = rval;
872 (void) csx_Error2Text(&cft);
873 cmn_err(CE_NOTE,
874 "pcram[%d]: csx_CS_DDI_Info failed - %s\n",
875 PCRAM_SOCKET(devp), cft.text);
876 return (-1);
879 return (ddi_info.instance);
884 * User context (system call request)
886 * Character Driver/Block Drivers:
888 * pcram_open()
889 * pcram_close()
890 * pcram_prop_op()
891 * pcram_print()
893 * Unique to character drivers:
895 * pcram_read()
896 * pcram_write()
897 * pcram_ioctl()
898 * xxxxx_segmap() ( ddi_segmap )
899 * xxxxx_chpoll() ( nochpoll )
901 /*ARGSUSED*/
902 static int
903 pcram_open(dev_t *devp, int flag, int otyp, cred_t *cred)
905 int instance;
906 int err;
907 pcram_state_t *rs;
908 get_status_t get_status;
910 /* get instance number */
911 if ((instance = pcram_getinstance(*devp)) == -1) {
912 cmn_err(CE_NOTE,
913 "pcram_open: pcram_getinfo failed\n");
914 return (ENXIO);
917 rs = ddi_get_soft_state(pcram_soft_state_p, instance);
918 if (rs == NULL) {
919 cmn_err(CE_NOTE, "pcram_open: "
920 "could not get state for instance %d\n",
921 instance);
922 return (ENXIO);
925 #ifdef PCRAM_DEBUG
926 if (pcram_debug & PCRAM_DEBUG_TRACE)
927 cmn_err(CE_CONT, "pcram_open: socket %d "
928 "flag 0x%x otyp 0x%x\n", rs->sn, flag, otyp);
929 #endif
931 mutex_enter(&rs->mutex);
933 if (!(rs->flags & PCRAM_ATTACHOK)) {
934 mutex_exit(&rs->mutex);
935 return (ENXIO);
936 /* NOTREACHED */
940 * Do a CS call to see if the card is present
942 if ((err = csx_GetStatus(rs->client_handle, &get_status))
943 != CS_SUCCESS) {
944 error2text_t cft;
946 mutex_exit(&rs->mutex);
948 cft.item = err;
949 (void) csx_Error2Text(&cft);
951 cmn_err(CE_CONT, "pcram_open: socket %d "
952 "GetStatus failed %s (0x%x)\n",
953 rs->sn, cft.text, err);
954 return (ENXIO);
955 /* NOTREACHED */
958 #ifdef PCRAM_DEBUG
959 if (pcram_debug & PCRAM_DEBUG_CARD_STATUS) {
960 cmn_err(CE_CONT,
961 "pcram_open: socket %d GetStatus returns:\n",
962 rs->sn);
963 pcram_display_card_status(&get_status);
965 #endif
968 * Check to see if the card is present.
969 * If there is no card in the socket,
970 * then return ENXIO.
972 if (!(get_status.CardState & CS_EVENT_CARD_INSERTION)) {
974 #ifdef PCRAM_DEBUG
975 if (pcram_debug & PCRAM_DEBUG_CARD_STATUS) {
976 cmn_err(CE_CONT, "pcram_open: socket %d "
977 "ERROR: Found no memory card\n", rs->sn);
979 #endif
981 mutex_exit(&rs->mutex);
982 return (ENXIO);
983 /* NOTREACHED */
986 if (get_status.CardState & CS_EVENT_BATTERY_DEAD) {
987 if (!rs->batter_dead_posted) {
988 cmn_err(CE_WARN, "pcram_open: socket %d "
989 "Battery & Data integrity "
990 "is not guaranteed\n", rs->sn);
991 /* Display once on the system console */
992 rs->batter_dead_posted++;
994 if (flag & FWRITE) {
995 mutex_exit(&rs->mutex);
996 return (ENXIO);
997 /* NOTREACHED */
1001 if (get_status.CardState & CS_EVENT_BATTERY_LOW) {
1002 if (!rs->batter_low_posted) {
1003 cmn_err(CE_WARN, "pcram_open: socket %d "
1004 "Battery should be replaced; "
1005 "Data is OK\n", rs->sn);
1006 /* Display once on the system console */
1007 rs->batter_low_posted++;
1011 /* Next check for read only file system */
1012 if ((flag & FWRITE) &&
1013 (get_status.CardState & CS_EVENT_WRITE_PROTECT)) {
1014 mutex_exit(&rs->mutex);
1015 return (EROFS);
1016 /* NOTREACHED */
1021 * Only honor FEXCL. If a regular open or a layered open
1022 * is still outstanding on the device, the exclusive open
1023 * must fail.
1025 if ((flag & FEXCL) && (rs->blk_open || rs->chr_open ||
1026 rs->nlayered)) {
1027 mutex_exit(&rs->mutex);
1028 return (EAGAIN);
1029 /* NOTREACHED */
1032 switch (otyp) {
1034 case OTYP_BLK:
1035 rs->blk_open = 1;
1036 break;
1038 case OTYP_CHR:
1039 rs->chr_open = 1;
1040 break;
1042 case OTYP_LYR:
1043 rs->nlayered++;
1044 break;
1046 default:
1047 mutex_exit(&rs->mutex);
1048 return (EINVAL);
1049 /* NOTREACHED */
1052 #ifdef PCRAM_DEBUG
1053 if (pcram_debug & PCRAM_DEBUG_TRACE) {
1054 cmn_err(CE_CONT, "pcram_open: default_size_flag=%d \n",
1055 rs->default_size_flag);
1057 #endif
1061 * For cards without attribute memory, probe the card to
1062 * determine the memory size.
1065 err = 0;
1066 if (rs->default_size_flag) {
1068 /* Setup for default maximum size of 64MB */
1069 *rs->hdrv_chars = hdtypes;
1070 rs->card_size = MAX_CARD_SIZE;
1073 if ((rs->card_size = pcram_card_sizing(rs))
1074 != UNRECOGNIZED_MEDIA) {
1075 rs->hdrv_chars->drv_ncyl =
1076 GET_NCYL(rs->card_size,
1077 rs->hdrv_chars->drv_nhead,
1078 rs->hdrv_chars->drv_sec_size,
1079 rs->hdrv_chars->drv_secptrack);
1081 * Actual card size is determined
1082 * so disable default_size_flag
1084 rs->default_size_flag = 0;
1085 } else {
1087 * Found unregconized PCMCIA Static RAM media
1088 * so treat it as an unlabeled memory card
1089 * with a maximum size of 64MB (PCMCIA 2.0
1090 * specification)
1092 cmn_err(CE_NOTE, "pcram: socket %d - "
1093 "Unregconized PCMCIA Static RAM media",
1094 rs->sn);
1095 err = ENXIO;
1098 mutex_exit(&rs->mutex);
1099 return (err);
1104 /*ARGSUSED*/
1105 static int
1106 pcram_close(dev_t dev, int flag, int otyp, cred_t *cred)
1108 int instance;
1109 pcram_state_t *rs;
1111 if ((instance = pcram_getinstance(dev)) == -1) {
1112 cmn_err(CE_NOTE,
1113 "pcram_close: pcram_getinfo failed\n");
1114 return (ENXIO);
1117 rs = ddi_get_soft_state(pcram_soft_state_p, instance);
1118 if (rs == NULL) {
1119 cmn_err(CE_NOTE, "pcram_close: "
1120 "could not get state for instance %d\n",
1121 instance);
1122 return (ENXIO);
1123 /* NOTREACHED */
1126 #ifdef PCRAM_DEBUG
1127 if (pcram_debug & PCRAM_DEBUG_TRACE)
1128 cmn_err(CE_CONT, "pcram_close: socket %d "
1129 "flag 0x%x otyp 0x%x\n", rs->sn, flag, otyp);
1130 #endif
1132 mutex_enter(&rs->mutex);
1134 switch (otyp) {
1136 case OTYP_BLK:
1137 rs->blk_open = 0;
1138 break;
1140 case OTYP_CHR:
1141 rs->chr_open = 0;
1142 break;
1144 case OTYP_LYR:
1145 rs->nlayered--;
1146 break;
1148 default:
1149 mutex_exit(&rs->mutex);
1150 return (EINVAL);
1151 /* NOTREACHED */
1154 if (rs->blk_open || rs->chr_open || rs->nlayered) {
1155 /* not done yet */
1156 mutex_exit(&rs->mutex);
1157 return (0);
1158 /* NOTREACHED */
1162 * Continueing to return EIO if the card is ejected
1163 * while it is mounted until the LAST layered close
1164 * is called
1166 if (rs->nlayered == 0) {
1167 #ifdef PCRAM_DEBUG
1168 if (pcram_debug & PCRAM_DEBUG_TRACE) {
1169 cmn_err(CE_CONT, "pcram_close: "
1170 "Reset ejected_while_mounting flag\n");
1172 #endif
1173 rs->ejected_while_mounting = 0;
1176 mutex_exit(&rs->mutex);
1177 return (0);
1182 static int
1183 pcram_print(dev_t dev, char *str)
1185 int instance;
1186 pcram_state_t *rs;
1189 if ((instance = pcram_getinstance(dev)) == -1) {
1190 cmn_err(CE_NOTE,
1191 "pcram_print: pcram_getinfo failed\n");
1192 return (ENXIO);
1195 rs = ddi_get_soft_state(pcram_soft_state_p, instance);
1196 if (rs == NULL) {
1197 cmn_err(CE_NOTE, "pcram_print: "
1198 "could not get state for instance %d.", instance);
1199 return (ENXIO);
1200 /* NOTREACHED */
1203 cmn_err(CE_NOTE, "pcram_print: socket %d %s", rs->sn, str);
1204 return (0);
1210 * Character driver routines
1211 * pcram_read()
1212 * pcram_write()
1214 /*ARGSUSED*/
1215 static int
1216 pcram_read(dev_t dev, struct uio *uiop, cred_t *credp)
1218 int instance;
1219 int error;
1220 int nbytes;
1221 int offset, next_offset;
1222 int remainder_wsize;
1223 int rval;
1224 int err;
1225 pcram_state_t *rs;
1226 get_status_t get_status;
1228 if ((instance = pcram_getinstance(dev)) == -1) {
1229 cmn_err(CE_NOTE,
1230 "pcram_read: pcram_getinfo failed\n");
1231 return (ENXIO);
1234 rs = ddi_get_soft_state(pcram_soft_state_p, instance);
1235 if (rs == NULL) {
1236 cmn_err(CE_NOTE, "pcram_read: "
1237 "could not get state for instance %d.",
1238 instance);
1239 return (ENXIO);
1240 /* NOTREACHED */
1243 #ifdef PCRAM_DEBUG
1244 if (pcram_debug & PCRAM_DEBUG_TRACE)
1245 cmn_err(CE_CONT, "pcram_read: socket %d\n", rs->sn);
1246 #endif
1248 mutex_enter(&rs->mutex);
1251 * Do a CS call to see if the card is present
1253 if ((err = csx_GetStatus(rs->client_handle,
1254 &get_status)) != CS_SUCCESS) {
1255 error2text_t cft;
1257 mutex_exit(&rs->mutex);
1259 cft.item = err;
1260 (void) csx_Error2Text(&cft);
1262 cmn_err(CE_CONT, "pcram_read: socket %d "
1263 "GetStatus failed %s (0x%x)\n",
1264 rs->sn, cft.text, err);
1265 return (ENXIO);
1266 /* NOTREACHED */
1269 #ifdef PCRAM_DEBUG
1270 if (pcram_debug & PCRAM_DEBUG_CARD_STATUS) {
1271 cmn_err(CE_CONT, "pcram_read: socket %d "
1272 "GetStatus returns:\n", rs->sn);
1273 pcram_display_card_status(&get_status);
1275 #endif
1278 * Check to see if the card is present.
1279 * If the memory card has been removed or
1280 * was ever removed, return an I/O error (EIO)
1281 * not "No such device or address" (EMXIO).
1283 * Continueing to return EIO if the card is ejected
1284 * while it is mounted until the LAST layered close
1285 * is called
1287 if (!(get_status.CardState & CS_EVENT_CARD_INSERTION) ||
1288 rs->ejected_while_mounting) {
1289 if (!rs->card_eject_posted) {
1290 /* XXX WARNING - card is ejected */
1291 rs->card_eject_posted++;
1292 rs->ejected_while_mounting = 1;
1293 cmn_err(CE_WARN, "pcram: socket%d "
1294 "Card is ejected & "
1295 "Data integrity is not guaranteed",
1296 rs->sn);
1298 mutex_exit(&rs->mutex);
1299 return (EIO);
1300 /* NOTREACHED */
1303 mutex_exit(&rs->mutex);
1306 * Wait for the current request to finish. We can
1307 * safely release the mutex once we complete the write
1308 * operation, because anyone else calling pcram_read
1309 * will wait here until we release it with a cv_signal.
1311 mutex_enter(&rs->mutex);
1312 while (rs->busy_rd == 1) {
1313 cv_wait(&rs->condvar_rd, &rs->mutex);
1315 rs->busy_rd = 1;
1316 mutex_exit(&rs->mutex);
1318 if (uiop->uio_offset >= rs->card_size) {
1319 rval = ENOSPC;
1320 goto out;
1323 offset = uiop->uio_offset;
1324 nbytes = min(uiop->uio_resid, rs->card_size - uiop->uio_offset);
1326 while (nbytes > 0) {
1327 int copybytes;
1329 next_offset = update_mapmempage(rs, offset);
1330 if (next_offset < 0) {
1331 /* something wrong with MapMemPage function */
1332 rval = EFAULT;
1333 goto out;
1336 remainder_wsize = offset % rs->win_size;
1337 copybytes = min(rs->win_size - remainder_wsize, nbytes);
1339 #ifdef PCRAM_DEBUG
1340 if (pcram_debug & PCRAM_DEBUG_SIZE) {
1341 if (nbytes > (rs->win_size-remainder_wsize))
1342 cmn_err(CE_CONT, "pcram_read: socket %d - "
1343 "READ: size not on window boundary\n"
1344 "\toffset 0x%x, rs->win_size 0x%x\n"
1345 "\tnbytes 0x%x, remainder_wsize 0x%x\n",
1346 rs->sn, offset, (int)rs->win_size,
1347 nbytes, remainder_wsize);
1349 #endif
1351 if (PCRAM_CARD_PRESENT(rs)) {
1353 * Transfer block in between the two windows
1355 uchar_t *pbuf;
1358 * We cannot use uiomoveto xfer directly
1359 * between pcram device to user area because
1360 * 64 byte * block xfers may be done in copyout.
1361 * PCMCIA memory cards are cannot be read
1362 * thru block move instructions.
1363 * just allocate pbuf
1364 * buffer and to use csx_RepGet8()
1365 * call to transfer from the
1366 * memory card to pbuf then use
1367 * uiomove() to move from pbuf
1368 * to the buffer(s) described by
1369 * uiop structure.
1371 pbuf = kmem_zalloc(copybytes, KM_SLEEP);
1372 csx_RepGet8(
1373 /* Card access handle */
1374 rs->access_handle,
1375 /* base dest addr */
1376 (uchar_t *)pbuf,
1377 /* card window offset */
1378 (uint32_t)remainder_wsize,
1379 /* num_bytes xfer */
1380 copybytes,
1381 /* flag */
1382 DDI_DEV_AUTOINCR);
1383 error = uiomove((caddr_t)pbuf,
1384 copybytes, UIO_READ, uiop);
1386 /* now free csbuf */
1387 kmem_free(pbuf, copybytes);
1389 if (error != 0) {
1390 rval = EFAULT;
1391 goto out;
1394 nbytes -= copybytes;
1395 offset += copybytes;
1396 } else {
1398 * stop to read the card when
1399 * there is a card removal event
1401 rval = EFAULT;
1402 goto out;
1404 } /* while */
1406 rval = 0;
1408 out:
1409 mutex_enter(&rs->mutex);
1411 * End of read operation, release the
1412 * cv_wait() for the next thread
1414 rs->busy_rd = 0;
1415 cv_signal(&rs->condvar_rd);
1416 mutex_exit(&rs->mutex);
1418 return (rval);
1422 /*ARGSUSED*/
1423 static int
1424 pcram_write(dev_t dev, struct uio *uiop, cred_t *credp)
1426 int instance;
1427 int error;
1428 int nbytes;
1429 int offset;
1430 int rval;
1431 int err;
1432 pcram_state_t *rs;
1433 get_status_t get_status;
1436 if ((instance = pcram_getinstance(dev)) == -1) {
1437 cmn_err(CE_NOTE,
1438 "pcram_write: pcram_getinfo failed\n");
1439 return (ENXIO);
1442 rs = ddi_get_soft_state(pcram_soft_state_p, instance);
1443 if (rs == NULL) {
1444 cmn_err(CE_NOTE, "pcram_write: "
1445 "could not get state for instance %d.",
1446 instance);
1447 return (ENXIO);
1448 /* NOTREACHED */
1451 #ifdef PCRAM_DEBUG
1452 if (pcram_debug & PCRAM_DEBUG_TRACE)
1453 cmn_err(CE_CONT, "pcram_write: socket %d\n", rs->sn);
1454 #endif
1456 mutex_enter(&rs->mutex);
1459 * Do a CS call to see if the card is present
1461 if ((err = csx_GetStatus(rs->client_handle, &get_status))
1462 != CS_SUCCESS) {
1463 error2text_t cft;
1465 mutex_exit(&rs->mutex);
1467 cft.item = err;
1468 (void) csx_Error2Text(&cft);
1470 cmn_err(CE_CONT, "pcram_write: socket %d "
1471 "GetStatus failed %s (0x%x)\n",
1472 rs->sn, cft.text, err);
1473 return (ENXIO);
1474 /* NOTREACHED */
1479 * Check to see if the card is present.
1480 * If the memory card has been removed or
1481 * was ever removed, return an I/O error (EIO)
1482 * not "No such device or address" (EMXIO).
1484 * Continueing to return EIO if the card is ejected
1485 * while it is mounted until the LAST layered close
1486 * is called
1488 if (!(get_status.CardState & CS_EVENT_CARD_INSERTION) ||
1489 rs->ejected_while_mounting) {
1490 if (!rs->card_eject_posted) {
1491 /* XXX WARNING - card is ejected */
1492 rs->card_eject_posted++;
1493 rs->ejected_while_mounting = 1;
1494 cmn_err(CE_WARN, "pcram: socket%d "
1495 "Card is ejected & "
1496 "Data integrity is not guaranteed",
1497 rs->sn);
1499 mutex_exit(&rs->mutex);
1500 return (EIO);
1501 /* NOTREACHED */
1504 mutex_exit(&rs->mutex);
1507 * Wait for the current request to finish. We can
1508 * safely release the mutex once we complete the write
1509 * operation, because anyone else calling pcram_write
1510 * will wait here until we release it with a cv_signal.
1512 mutex_enter(&rs->mutex);
1513 while (rs->busy_wr == 1) {
1514 cv_wait(&rs->condvar_wr, &rs->mutex);
1516 rs->busy_wr = 1;
1517 mutex_exit(&rs->mutex);
1519 if (uiop->uio_offset >= rs->card_size) {
1520 rval = ENOSPC;
1521 goto out;
1524 /* Save offset and byte count from uiop structure */
1525 offset = uiop->uio_offset;
1526 nbytes = min(uiop->uio_resid, rs->card_size-uiop->uio_offset);
1529 * Start to transfer 1KB data to kernel buffer at a time
1530 * The 1MB window offset is handled in card_byte_wr()
1533 while (nbytes > 0) {
1534 int copybytes;
1535 int next_offset;
1536 int remainder_wsize;
1539 next_offset = update_mapmempage(rs, offset);
1540 if (next_offset < 0) {
1541 /* something wrong with MapMemPage function */
1542 rval = EFAULT;
1543 goto out;
1546 remainder_wsize = offset % rs->win_size;
1547 copybytes = min(rs->win_size - remainder_wsize, nbytes);
1548 copybytes = min(copybytes, HOST_BUF_SIZE);
1550 #ifdef PCRAM_DEBUG
1551 if (pcram_debug & PCRAM_DEBUG_SIZE) {
1552 if (nbytes > (rs->win_size-remainder_wsize))
1553 cmn_err(CE_CONT, "pcram_write: socket %d - "
1554 "WRITE: size not on window boundary\n"
1555 "\toffset 0x%x, rs->win_size 0x%x\n"
1556 "\tnbytes 0x%x, remainder_wsize 0x%x\n",
1557 rs->sn, offset, (int)rs->win_size,
1558 nbytes, remainder_wsize);
1560 #endif
1562 if (PCRAM_CARD_PRESENT(rs)) {
1564 * Transfer block size is in between
1565 * the two windows
1567 error = uiomove(rs->host_sp, copybytes,
1568 UIO_WRITE, uiop);
1569 if (error != 0) {
1570 rval = EFAULT;
1571 goto out;
1574 mutex_enter(&rs->mutex);
1575 card_byte_wr(rs, copybytes, remainder_wsize);
1576 mutex_exit(&rs->mutex);
1578 nbytes -= copybytes;
1579 offset += copybytes;
1580 } else {
1582 * stop to write to the card when
1583 * there is a card removal event
1585 rval = EFAULT;
1586 goto out;
1588 } /* while */
1590 rval = 0;
1592 out:
1593 mutex_enter(&rs->mutex);
1595 * End of write operation, release the
1596 * cv_wait() for the next thread
1598 rs->busy_wr = 0;
1599 cv_signal(&rs->condvar_wr);
1600 mutex_exit(&rs->mutex);
1602 return (rval);
1608 /*ARGSUSED*/
1609 static int
1610 pcram_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp,
1611 int *rvalp)
1613 int i;
1614 int instance;
1615 int err;
1616 int fdchange;
1617 daddr_t nblks;
1618 struct dk_geom dkg; /* disk geometry */
1619 struct vtoc vtoc;
1620 struct dk_cinfo dkc; /* disk controller info */
1621 struct pcmm_info pcmminfo; /* memory media type */
1622 struct fd_drive drvchar; /* supporting eject(1) */
1623 struct dk_map dkmap[NDKMAP];
1624 pcram_state_t *rs;
1625 enum dkio_state state;
1626 get_status_t get_status;
1629 if ((instance = pcram_getinstance(dev)) == -1) {
1630 cmn_err(CE_NOTE,
1631 "pcram_ioctl: pcram_getinfo failed\n");
1632 return (ENXIO);
1635 rs = ddi_get_soft_state(pcram_soft_state_p, instance);
1636 if (rs == NULL) {
1637 cmn_err(CE_NOTE, "pcram_ioctl: "
1638 "could not get state for instance %d.",
1639 instance);
1640 return (ENXIO);
1641 /* NOTREACHED */
1644 #ifdef PCRAM_DEBUG
1645 if (pcram_debug & PCRAM_DEBUG_TRACE) {
1646 cmn_err(CE_CONT, "pcram_ioctl: socket %d "
1647 "cmd 0x%x arg 0x%lx mode 0x%x\n",
1648 rs->sn, cmd, arg, mode);
1650 #endif
1653 switch (cmd) {
1655 case DKIOCEJECT:
1657 * Since we do not have hardware support for ejecting
1658 * a memory card, we must not support the generic eject
1659 * ioctl (DKIOCEJECT) which is used for eject(1) command
1660 * because it leads the user to expect behavior that is
1661 * not present.
1663 return (ENOSYS);
1664 /* NOTREACHED */
1666 case DKIOCGGEOM:
1668 * newfs does this first
1669 * return dk_geom structure
1671 if (!rs->default_size_flag) {
1673 * If the card is built with DOS_BPB or
1674 * Solaris VTOC or CIS info.
1675 * we just return the disk geometry
1676 * information
1678 bzero(&dkg, sizeof (struct dk_geom));
1679 dkg.dkg_ncyl = rs->hdrv_chars->drv_ncyl;
1680 dkg.dkg_nhead = rs->hdrv_chars->drv_nhead;
1681 dkg.dkg_nsect = rs->hdrv_chars->drv_secptrack;
1682 dkg.dkg_pcyl = rs->hdrv_chars->drv_ncyl;
1683 if (ddi_copyout(&dkg, (void *)arg,
1684 sizeof (struct dk_geom), mode) != 0) {
1685 return (EFAULT);
1686 /* NOTREACHED */
1688 return (0);
1689 } else {
1691 * Return error when we can not find
1692 * the actual card size.
1694 return (EFAULT);
1695 /* NOTREACHED */
1697 /* NOTREACHED */
1699 case DKIOCGVTOC:
1701 * newfs does this second
1702 * return vtoc structure. 1 partion.
1704 bzero(&vtoc, sizeof (struct vtoc));
1705 vtoc.v_sanity = VTOC_SANE;
1706 vtoc.v_version = V_VERSION;
1707 bcopy("pccard", vtoc.v_volume, 7);
1708 vtoc.v_sectorsz = DEV_BSIZE;
1709 vtoc.v_nparts = 1;
1710 vtoc.v_part[0].p_tag = V_UNASSIGNED;
1711 vtoc.v_part[0].p_flag = V_UNMNT;
1712 vtoc.v_part[0].p_start = (daddr_t)0;
1713 vtoc.v_part[0].p_size = rs->card_size / DEV_BSIZE;
1714 #ifdef _MULTI_DATAMODEL
1715 switch (ddi_model_convert_from(mode & FMODELS)) {
1716 case DDI_MODEL_ILP32: {
1717 struct vtoc32 vtoc32;
1719 vtoctovtoc32(vtoc, vtoc32);
1720 if (ddi_copyout(&vtoc32, (void *)arg,
1721 sizeof (struct vtoc32), mode))
1722 return (EFAULT);
1723 break;
1725 case DDI_MODEL_NONE:
1726 if (ddi_copyout(&vtoc, (void *)arg,
1727 sizeof (struct vtoc), mode))
1728 return (EFAULT);
1729 break;
1731 #else /* ! _MULTI_DATAMODEL */
1732 if (ddi_copyout(&vtoc, (void *)arg,
1733 sizeof (struct vtoc), mode) != 0)
1734 return (EFAULT);
1736 #endif /* _MULTI_DATAMODEL */
1737 return (0);
1738 /* NOTREACHED */
1740 case DKIOCINFO:
1742 * newfs does this third
1743 * return dk_cinfo structure.
1745 bzero(&dkc, sizeof (struct dk_cinfo));
1748 * SunVTS uses PCRAM_DKC_CNAME "pcram"
1749 * for checking if it is a pcram controller
1751 (void) strcpy(dkc.dki_cname, PCRAM_DKC_CNAME);
1752 dkc.dki_ctype = DKC_PCMCIA_MEM;
1755 * For pseudo floppy disk setup (pcfs file system)
1756 * dkc.dki_flags = DKI_PCMCIA_PFD;
1758 dkc.dki_flags = rs->isit_pseudofloppy;
1760 (void) strcpy(dkc.dki_dname, PCRAM_DKC_DNAME);
1763 * volmgt will use this dki_unit as a PCMCIA
1764 * socket info. during a static mode
1765 * During a dynamic mode (physically
1766 * remove and insert a card), the socket
1767 * info. is from PCMCIA User Daemon
1769 dkc.dki_unit = (uint32_t)rs->sn;
1771 dkc.dki_maxtransfer = 1;
1773 if (ddi_copyout(&dkc, (void *)arg,
1774 sizeof (struct dk_cinfo), mode) != 0) {
1775 return (EFAULT);
1776 /* NOTREACHED */
1778 return (0);
1779 /* NOTREACHED */
1781 case DKIOCGAPART:
1782 nblks = rs->hdrv_chars->drv_nhead *
1783 rs->hdrv_chars->drv_secptrack;
1784 #ifdef _MULTI_DATAMODEL
1785 switch (ddi_model_convert_from(mode & FMODELS)) {
1786 case DDI_MODEL_ILP32: {
1787 struct dk_map32 dkmap32[NDKMAP];
1790 * XXX - support only one partition now
1791 * should be NDKMAP later
1793 for (i = 0; i < 1; i++) {
1794 dkmap32[i].dkl_cylno = (daddr_t)0;
1795 dkmap32[i].dkl_nblk = nblks;
1797 i = NDKMAP * sizeof (struct dk_map32);
1798 if (ddi_copyout(&dkmap32, (void *)arg, i, mode))
1799 return (EFAULT);
1801 break;
1802 case DDI_MODEL_NONE:
1803 for (i = 0; i < 1; i++) {
1804 dkmap[i].dkl_cylno = (daddr_t)0;
1805 dkmap[i].dkl_nblk = nblks;
1807 i = NDKMAP * sizeof (struct dk_map);
1808 if (ddi_copyout(&dkmap, (void *)arg, i, mode))
1809 return (EFAULT);
1811 #else /* ! _MULTI_DATAMODEL */
1812 for (i = 0; i < 1; i++) {
1813 dkmap[i].dkl_cylno = (daddr_t)0;
1814 dkmap[i].dkl_nblk = nblks;
1816 i = NDKMAP * sizeof (struct dk_map);
1817 if (ddi_copyout(&dkmap, (void *)arg, i, mode))
1818 return (EFAULT);
1819 #endif /* _MULTI_DATAMODEL */
1820 return (0);
1822 case DKIOCSTATE:
1823 if (ddi_copyin((void *)arg, &state, sizeof (int), mode)) {
1824 return (EFAULT);
1825 /* NOTREACHED */
1829 * This function is used by the volume management
1830 * to check the memory card state
1832 if (err = pcram_check_media(rs, state)) {
1833 return (err);
1834 /* NOTREACHED */
1837 if (ddi_copyout(&rs->media_state, (void *)arg,
1838 sizeof (int), mode)) {
1839 return (EFAULT);
1840 /* NOTREACHED */
1842 return (0);
1843 /* NOTREACHED */
1845 case DKIOCSVTOC:
1847 * fdformat(1) uses this ioctl() to ask the driver
1848 * to construct the disk label.
1850 #ifdef _MULTI_DATAMODEL
1851 switch (ddi_model_convert_from(mode & FMODELS)) {
1852 case DDI_MODEL_ILP32: {
1854 struct vtoc32 vtoc32;
1856 if (ddi_copyin((void *)arg, &vtoc32,
1857 sizeof (struct vtoc32), mode))
1858 return (EFAULT);
1859 vtoc32tovtoc(vtoc32, vtoc);
1860 break;
1863 case DDI_MODEL_NONE:
1864 if (ddi_copyin((void *)arg, &vtoc,
1865 sizeof (struct vtoc), mode))
1866 return (EFAULT);
1867 break;
1869 #else /* _MULTI_DATAMODEL */
1870 if (ddi_copyin((void *)arg, &vtoc, sizeof (struct vtoc), mode))
1871 return (EFAULT);
1873 #endif /* _MULTI_DATAMODEL */
1875 if ((err = pcram_build_label_vtoc(rs, &vtoc)) != 0) {
1876 return (err);
1877 /* NOTREACHED */
1880 pcram_write_label(rs);
1881 return (0);
1882 /* NOTREACHED */
1884 case DKIOCREMOVABLE:
1886 * Supporting volmgt by returning a constant
1887 * since PCMCIA is a removable media.
1888 * Refer to PSARC/1996/004.
1890 i = 1;
1891 if (ddi_copyout(&i, (void *)arg, sizeof (int), mode)) {
1892 return (EFAULT);
1893 /* NOTREACHED */
1895 return (0);
1896 /* NOTREACHED */
1898 case PCRAM_GETMEDIA:
1900 * Support memory media type of SRAM/Masked ROM/DRAM
1902 mutex_enter(&rs->mutex);
1903 pcmminfo.pcmm_type = PCMM_TYPE_RAM;
1904 mutex_exit(&rs->mutex);
1906 if (ddi_copyout(&pcmminfo, (void *)arg,
1907 sizeof (struct pcmm_info), mode) != 0) {
1908 return (EFAULT);
1909 /* NOTREACHED */
1911 return (0);
1912 /* NOTREACHED */
1914 case PCRAM_PROBESIZE:
1916 * After getting an error return from calling
1917 * DKIOCGGEOM ioctl, fdformat(1) *must* use
1918 * this ioctl() to get get the memory card size
1919 * before formatting the memory card. This
1920 * allows the driver to do some destructive
1921 * write and verify operation (backup data
1922 * before writing to the card).
1924 * If the card is built with DOS_BPB or Solaris VTOC
1925 * or CIS info., we do not need to probe card
1926 * size. If the card is built with a default
1927 * size of 64MB then we need to probe the actual
1928 * card size
1930 if (!rs->default_size_flag) {
1931 #ifdef PCRAM_DEBUG
1932 if (pcram_debug & PCRAM_DEBUG_CIS) {
1933 cmn_err(CE_CONT, "pcram_ioctl: socket %d\n"
1934 "\tPCRAM_PROBESIZE: card size "
1935 "is already\n\t\tdetermined from "
1936 "DOS_BPB, VTOC, or CIS\n", rs->sn);
1938 #endif
1939 bzero(&dkg, sizeof (struct dk_geom));
1940 dkg.dkg_ncyl = rs->hdrv_chars->drv_ncyl;
1941 dkg.dkg_nhead = rs->hdrv_chars->drv_nhead;
1942 dkg.dkg_nsect = rs->hdrv_chars->drv_secptrack;
1943 dkg.dkg_pcyl = rs->hdrv_chars->drv_ncyl;
1944 if (ddi_copyout(&dkg, (void *)arg,
1945 sizeof (struct dk_geom), mode) != 0) {
1946 return (EFAULT);
1947 /* NOTREACHED */
1949 return (0);
1950 /* NOTREACHED */
1953 mutex_enter(&rs->mutex);
1954 /* Setup for default maximum size of 64MB */
1955 *rs->hdrv_chars = hdtypes;
1956 rs->card_size = MAX_CARD_SIZE;
1960 * Do a CS call to see if the card is present
1962 if ((err = csx_GetStatus(rs->client_handle, &get_status))
1963 != CS_SUCCESS) {
1964 error2text_t cft;
1966 mutex_exit(&rs->mutex);
1967 cft.item = err;
1968 (void) csx_Error2Text(&cft);
1969 cmn_err(CE_CONT, "pcram_ioctl: socket %d "
1970 "GetStatus failed %s (0x%x)\n",
1971 rs->sn, cft.text, err);
1972 return (ENXIO);
1973 /* NOTREACHED */
1976 if (get_status.CardState & CS_EVENT_WRITE_PROTECT) {
1977 err = EROFS;
1978 } else if ((rs->card_size = pcram_card_sizing(rs))
1979 != UNRECOGNIZED_MEDIA) {
1980 rs->hdrv_chars->drv_ncyl =
1981 GET_NCYL(rs->card_size,
1982 rs->hdrv_chars->drv_nhead,
1983 rs->hdrv_chars->drv_sec_size,
1984 rs->hdrv_chars->drv_secptrack);
1986 * Actual card size is determined
1987 * so disable default_size_flag
1989 rs->default_size_flag = 0;
1990 err = 0;
1991 } else {
1993 * Found unregconized PCMCIA Static RAM media
1994 * so treat it as an unlabeled memory card
1995 * with a maximum size of 64MB (PCMCIA 2.0
1996 * specification)
1998 cmn_err(CE_NOTE, "pcram: socket %d - "
1999 "Unregconized PCMCIA Static RAM media",
2000 rs->sn);
2001 err = ENXIO;
2004 mutex_exit(&rs->mutex);
2006 bzero(&dkg, sizeof (struct dk_geom));
2007 dkg.dkg_ncyl = rs->hdrv_chars->drv_ncyl;
2008 dkg.dkg_nhead = rs->hdrv_chars->drv_nhead;
2009 dkg.dkg_nsect = rs->hdrv_chars->drv_secptrack;
2010 dkg.dkg_pcyl = rs->hdrv_chars->drv_ncyl;
2011 if (ddi_copyout(&dkg, (void *)arg,
2012 sizeof (struct dk_geom), mode) != 0) {
2013 return (EFAULT);
2014 /* NOTREACHED */
2017 return (err);
2018 /* NOTREACHED */
2020 case FDGETDRIVECHAR:
2021 /* supporting eject(1) command */
2022 if (ddi_copyin((void *)arg, &drvchar,
2023 sizeof (struct fd_drive), mode)) {
2024 return (EFAULT);
2025 /* NOTREACHED */
2027 drvchar.fdd_ejectable = 0; /* manually ejectable */
2028 drvchar.fdd_flags = 0; /* not FDD_POLLABLE */
2029 if (ddi_copyout(&drvchar, (void *)arg,
2030 sizeof (struct fd_drive), mode)) {
2031 return (EFAULT);
2032 /* NOTREACHED */
2034 return (0);
2035 /* NOTREACHED */
2037 case FDGETCHANGE:
2039 * supporting volcheck(1) command
2041 * FDGC_HISTORY disk has changed since last i/o
2042 * FDGC_CURRENT current state of disk change
2043 * FDGC_CURWPROT current state of write protect
2044 * FDGC_DETECTED previous state of DISK CHANGE
2047 if (ddi_copyin((void *)arg, &fdchange, sizeof (int), mode)) {
2048 return (EFAULT);
2049 /* NOTREACHED */
2052 /* GetStatus */
2053 if ((err = csx_GetStatus(rs->client_handle, &get_status))
2054 != CS_SUCCESS) {
2055 error2text_t cft;
2057 mutex_exit(&rs->mutex);
2058 cft.item = err;
2059 (void) csx_Error2Text(&cft);
2060 cmn_err(CE_CONT, "pcram_ioctl: FDGETCHANGE - "
2061 "socket %d GetStatus failed %s (0x%x)\n",
2062 rs->sn, cft.text, err);
2063 return (ENXIO);
2064 /* NOTREACHED */
2068 * See eject.c or fdformat.c for bit definition
2070 if (get_status.CardState & CS_EVENT_CARD_INSERTION) {
2071 /* Simulating - floppy is present */
2072 fdchange &= ~FDGC_CURRENT;
2073 if (get_status.CardState &
2074 CS_EVENT_WRITE_PROTECT) {
2076 * Simulating
2077 * floppy is write protected
2079 fdchange |= FDGC_CURWPROT;
2080 } else {
2082 * Simulating
2083 * floppy is NOT write protected
2085 fdchange &= ~FDGC_CURWPROT;
2087 } else {
2088 /* Simulating - floppy is NOT present */
2089 fdchange |= FDGC_CURRENT;
2092 if (ddi_copyout(&fdchange, (void *)arg, sizeof (int), mode)) {
2093 return (EFAULT);
2094 /* NOTREACHED */
2097 return (0);
2098 /* NOTREACHED */
2100 default:
2101 return (ENOTTY);
2102 /* NOTREACHED */
2109 * pcram_prop_op() - Property Management
2111 * All block drivers must support the "Nblocks" property,
2112 * and all character drivers must support the "size" property.
2113 * Since we support hot plugging for many different memory
2114 * card size and the Nblocks and the size property are changed
2115 * dynamically, so these property should be maintained by the
2116 * driver.
2118 static int
2119 pcram_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op,
2120 int mod_flags, char *name, caddr_t valuep, int *lengthp)
2122 int instance;
2123 pcram_state_t *rs;
2124 uint64_t size64;
2127 * Our dynamic properties are all device specific and size oriented.
2128 * Requests issued under conditions where size is valid are passed
2129 * to ddi_prop_op_size with the size information, otherwise the
2130 * request is passed to ddi_prop_op.
2132 if (dev == DDI_DEV_T_ANY) {
2133 pass: return (ddi_prop_op(dev, dip, prop_op, mod_flags,
2134 name, valuep, lengthp));
2135 } else {
2136 if ((instance = pcram_getinstance(dev)) == -1) {
2137 cmn_err(CE_NOTE, "pcram_prop_op: "
2138 "pcram_getinfo failed\n");
2139 goto pass;
2142 rs = ddi_get_soft_state(pcram_soft_state_p, instance);
2143 if (rs == NULL) {
2144 cmn_err(CE_NOTE, "pcram_prop_op: "
2145 "no state for instance %d", instance);
2146 goto pass;
2149 /* get size in bytes */
2150 size64 = (uint_t)rs->card_size;
2151 return (ddi_prop_op_size(dev, dip, prop_op, mod_flags,
2152 name, valuep, lengthp, size64));
2158 * Block driver routines
2159 * pcram_strategy()
2160 * pcram_start()
2162 static int
2163 pcram_strategy(struct buf *bp)
2165 int instance;
2166 int err;
2167 int offset = bp->b_blkno * DEV_BSIZE;
2168 pcram_state_t *rs;
2169 get_status_t get_status;
2172 if ((instance = pcram_getinstance(bp->b_edev)) == -1) {
2173 cmn_err(CE_NOTE,
2174 "pcram_strategy: pcram_getinfo failed\n");
2175 err = ENXIO;
2176 goto out;
2179 rs = ddi_get_soft_state(pcram_soft_state_p, instance);
2180 if (rs == NULL) {
2181 cmn_err(CE_NOTE, "pcram_strategy: "
2182 "could not get state for instance %d.",
2183 instance);
2184 err = ENXIO;
2185 goto out;
2188 #ifdef PCRAM_DEBUG
2189 if (pcram_debug & PCRAM_DEBUG_TRACE)
2190 cmn_err(CE_CONT, "pcram_strategy: socket %d\n", rs->sn);
2191 #endif
2193 mutex_enter(&rs->mutex);
2195 /* Do a CS call to see if the card is present */
2196 if ((err = csx_GetStatus(rs->client_handle, &get_status))
2197 != CS_SUCCESS) {
2198 error2text_t cft;
2200 mutex_exit(&rs->mutex);
2201 cft.item = err;
2202 (void) csx_Error2Text(&cft);
2203 cmn_err(CE_CONT, "pcram_strategy: socket %d "
2204 "GetStatus failed %s (0x%x)\n",
2205 rs->sn, cft.text, err);
2206 err = ENXIO;
2207 goto out;
2210 #ifdef PCRAM_DEBUG
2211 if (pcram_debug & PCRAM_DEBUG_CARD_STATUS) {
2212 cmn_err(CE_CONT, "pcram_strategy: socket %d "
2213 "GetStatus returns:\n", rs->sn);
2214 pcram_display_card_status(&get_status);
2216 #endif
2219 * Check to see if the card is present.
2220 * If the memory card has been removed or
2221 * was ever removed, return an I/O error (EIO)
2222 * not "No such device or address" (EMXIO).
2224 * Continueing to return EIO if the card is ejected
2225 * while it is mounted until the LAST layered close
2226 * is called
2228 if (!(get_status.CardState & CS_EVENT_CARD_INSERTION) ||
2229 rs->ejected_while_mounting) {
2230 if (!rs->card_eject_posted) {
2231 /* XXX WARNING - card is ejected */
2232 rs->card_eject_posted++;
2233 rs->ejected_while_mounting = 1;
2234 cmn_err(CE_WARN, "pcram: socket%d "
2235 "Card is ejected & Data integrity is not guaranteed",
2236 rs->sn);
2238 mutex_exit(&rs->mutex);
2240 #ifdef PCRAM_DEBUG
2241 if (pcram_debug & PCRAM_DEBUG_CARD_STATUS) {
2242 cmn_err(CE_CONT, "pcram_strategy: socket %d - ERROR: "
2243 "Found no memory card\n", rs->sn);
2245 #endif
2247 err = EIO;
2248 goto out;
2251 mutex_exit(&rs->mutex);
2254 * Do not need the mutex around rs->card_size, since it
2255 * will not change until detach/attach.
2257 * XXXX: Is it still true for PCMCIA memory card driver?
2258 * XXX Was this the cause of a tar causing a panic on too
2259 * small a card?
2261 if (offset >= rs->card_size) {
2262 err = ENOSPC;
2263 goto out;
2267 * Wait for the current request to finish. We can safely
2268 * release the mutex once we complete the write operation,
2269 * because anyone else calling pcram_strategy will wait here
2270 * until we release it with a cv_signal.
2272 mutex_enter(&rs->mutex);
2274 while (rs->busy == 1) {
2275 cv_wait(&rs->condvar, &rs->mutex);
2278 rs->busy = 1;
2280 bp_mapin(bp);
2282 if (rs->blist->av_forw == NULL) {
2283 /* nothing on queue */
2284 bp->av_forw = NULL;
2285 bp->av_back = NULL;
2286 rs->blist->av_forw = bp;
2287 rs->blist->av_back = bp;
2288 /* start it */
2289 pcram_start(rs);
2290 } else {
2291 /* put on work list */
2292 bp->av_forw = NULL;
2293 rs->blist->av_back->av_forw = bp;
2294 rs->blist->av_back = bp;
2295 rs->busy = 0;
2296 cv_signal(&rs->condvar);
2299 mutex_exit(&rs->mutex);
2300 return (0);
2302 out:
2303 bioerror(bp, err);
2304 bp->b_resid = bp->b_bcount;
2305 biodone(bp);
2306 return (0);
2311 static void
2312 pcram_start(pcram_state_t *rs)
2315 int offset;
2316 int nbytes, origbytes;
2317 int next_offset;
2318 int remainder_wsize;
2319 caddr_t buf_addr;
2320 struct buf *bp;
2323 #ifdef PCRAM_DEBUG
2324 if (pcram_debug & PCRAM_DEBUG_TRACE)
2325 cmn_err(CE_CONT, "pcram_start: socket %d\n", rs->sn);
2326 #endif
2328 bp = rs->blist->av_forw;
2329 offset = bp->b_blkno * DEV_BSIZE;
2330 nbytes = min(bp->b_bcount, rs->card_size-offset);
2331 buf_addr = bp->b_un.b_addr;
2332 origbytes = nbytes; /* save the original byte count */
2334 while (nbytes > 0) {
2335 int copybytes;
2337 next_offset = update_mapmempage(rs, offset);
2338 if (next_offset < 0) {
2339 /* something failed so abort */
2340 bp->b_error = EIO;
2341 break;
2344 /* get partial block size if not on window boundary */
2345 remainder_wsize = offset % rs->win_size;
2346 copybytes = min(nbytes, rs->win_size - remainder_wsize);
2349 #ifdef PCRAM_DEBUG
2350 if (pcram_debug & PCRAM_DEBUG_SIZE) {
2351 if (nbytes > (rs->win_size-remainder_wsize)) {
2352 cmn_err(CE_CONT, "pcram_start: socket %d - "
2353 "%s: size not on window boundary\n"
2354 "\toffset 0x%x, rs->win_size 0x%x\n"
2355 "\tnbytes 0x%x, remainder_wsize 0x%x\n",
2356 rs->sn,
2357 (bp->b_flags & B_READ) ?
2358 "READ" : "WRITE",
2359 offset, (int)rs->win_size,
2360 nbytes, remainder_wsize);
2363 #endif
2365 if (bp->b_flags & B_READ) {
2366 /* Read direct from PC Card memory */
2367 csx_RepGet8(/* Card access handle */
2368 rs->access_handle,
2369 /* base dest addr */
2370 (uchar_t *)buf_addr,
2371 /* card window offset */
2372 (uint32_t)remainder_wsize,
2373 /* num_bytes xfer */
2374 copybytes,
2375 /* flag */
2376 DDI_DEV_AUTOINCR);
2378 } else { /* WRITE operation */
2380 * Start to transfer 1KB data
2381 * to kernel buffer at a time
2384 copybytes = min(copybytes, HOST_BUF_SIZE);
2386 * Update PC Card memory from the kernel buffer
2388 bcopy(buf_addr, rs->host_sp, copybytes);
2390 * does not need mutex because it is already
2391 * handled in pcram_strategy and pcram_softintr
2393 card_byte_wr(rs, copybytes, remainder_wsize);
2395 nbytes -= copybytes;
2396 buf_addr += copybytes;
2397 offset += copybytes;
2399 if (!PCRAM_CARD_PRESENT(rs)) {
2400 /* stop when there is a card removal event */
2401 bp->b_error = EIO;
2402 break;
2405 } /* while (nbytes) */
2407 bp->b_resid = bp->b_bcount - origbytes;
2409 ddi_trigger_softintr(rs->softint_id);
2416 * Software Interrupt Handler
2417 * pcram_softintr()
2419 static uint32_t
2420 pcram_softintr(pcram_state_t *rs)
2422 struct buf *bp;
2425 #ifdef PCRAM_DEBUG
2426 if (pcram_debug & PCRAM_DEBUG_TRACE)
2427 cmn_err(CE_CONT, "pcram_softintr: socket %d\n", rs->sn);
2428 #endif
2430 if (!(rs->flags & PCRAM_ATTACHOK)) {
2431 return (DDI_INTR_UNCLAIMED);
2434 mutex_enter(&rs->mutex);
2436 if (rs->busy) {
2437 /* got work to do */
2438 bp = rs->blist->av_forw;
2439 rs->blist->av_forw = bp->av_forw;
2440 if (rs->blist->av_forw != NULL) {
2441 pcram_start(rs);
2442 } else {
2443 rs->busy = 0;
2445 * End of write operation, release the
2446 * cv_wait() for the next thread
2448 cv_signal(&rs->condvar);
2450 biodone(bp);
2451 } /* rs->busy */
2453 mutex_exit(&rs->mutex);
2455 return (DDI_INTR_CLAIMED);
2456 /* NOTREACHED */
2462 * SPARCstation-2 CACHE+ bug
2464 * bcopy() with double-word write in SS2 machine only
2465 * supports only word acknowledge. The DoRight PCMCIA
2466 * ASIC is a 16-bit device so it will not work correctly
2467 * during a write from SS2 host to the PCMCIA memory card.
2468 * Therefore we have to write *one* byte at a time.
2469 * In order to avoid to have two version of the driver
2470 * for SS2 and other platforms, we can use the same
2471 * byte write mechanism for all platform.
2473 * bcopy() is commonly used in pcram_start and pcram_strategy.
2475 * There is no major performance impact between
2476 * using bcopy() for writing to card and card_byte_wr().
2478 * Using double buffer write to transfer data from host
2479 * memory (allocate 1KB) to the memory card.
2482 static void
2483 card_byte_wr(pcram_state_t *rs, int xfer_size, int offset)
2485 int i;
2486 uint32_t cardoffset = offset;
2487 uchar_t *hostmempt;
2489 hostmempt = (uchar_t *)(rs->host_sp);
2490 for (i = 0; i < xfer_size; i++) {
2491 if (PCRAM_CARD_PRESENT(rs)) {
2492 if (rs->card_event & PCRAM_WRITE_PROTECT) {
2493 if (!rs->wp_posted) {
2494 rs->wp_posted++;
2495 cmn_err(CE_WARN, "pcram: socket%d "
2496 "Write-Protect is enabled",
2497 rs->sn);
2500 * stop writing when
2501 * write-protect is enabled
2503 break;
2504 } else {
2505 csx_Put8(rs->access_handle,
2506 cardoffset, *hostmempt);
2507 hostmempt++;
2508 cardoffset++;
2510 } else {
2512 * stop to write to the card when
2513 * there is a card removal event
2515 break;
2523 * Updating window size
2525 static int
2526 update_mapmempage(pcram_state_t *rs, int offset)
2529 int ret;
2530 int i;
2531 int err;
2532 map_mem_page_t map_mem_page;
2533 get_status_t get_status;
2537 * Do a CS call to see if the card is present
2539 if ((err = csx_GetStatus(rs->client_handle, &get_status))
2540 != CS_SUCCESS) {
2541 error2text_t cft;
2543 cft.item = err;
2544 (void) csx_Error2Text(&cft);
2546 cmn_err(CE_CONT, "update_mapmempage: socket %d "
2547 "GetStatus failed %s (0x%x)\n",
2548 rs->sn, cft.text, err);
2549 /* Let caller knows that there is some thing wrong */
2550 return (-1);
2551 /* NOTREACHED */
2554 if (!(get_status.CardState & CS_EVENT_CARD_INSERTION)) {
2555 #ifdef PCRAM_DEBUG
2556 cmn_err(CE_CONT, "update_mapmempage: "
2557 "\tFound no memory card in socket %d\n", rs->sn);
2558 #endif
2559 /* Let caller knows that there is no card */
2560 return (-1);
2561 /* NOTREACHED */
2566 * Do following setup AFTER checking if card is inserted
2567 * or we will get "zero divide trap panic"
2570 /* We do not support page mode */
2571 map_mem_page.Page = 0;
2573 if (rs->win_size == 0) {
2574 cmn_err(CE_CONT, "update_mapmempage: "
2575 "Found zero rs->win_size %d\n",
2576 (int)rs->win_size);
2577 /* To avoid zero divide problem */
2578 return (-1);
2579 /* NOTREACHED */
2580 } else {
2581 /* setup for CardOffset of MapMemPage */
2582 i = offset / rs->win_size;
2586 * Now map the offset to the card
2588 map_mem_page.CardOffset = i * rs->win_size;
2590 offset -= (i * rs->win_size);
2593 if ((ret = csx_MapMemPage(rs->window_handle, &map_mem_page))
2594 != CS_SUCCESS) {
2595 error2text_t cft;
2597 cft.item = ret;
2598 (void) csx_Error2Text(&cft);
2599 cmn_err(CE_CONT, "update_mapmempage: "
2600 "MapMemPage failed %s (0x%x)\n", cft.text, ret);
2602 if ((ret = csx_ReleaseWindow(rs->window_handle))
2603 != CS_SUCCESS) {
2604 error2text_t cft;
2606 cft.item = ret;
2607 (void) csx_Error2Text(&cft);
2608 cmn_err(CE_CONT, "update_mapmempage: "
2609 "ReleaseWindow failed %s (0x%x)\n",
2610 cft.text, ret);
2613 /* Let caller knows that there is some thing wrong */
2614 return (-1);
2615 /* NOTREACHED */
2618 return (offset);
2619 /* NOTREACHED */
2625 * pcram_card_sizing - Determine memory card size
2626 * by writing every block of window size.
2628 * The window size must be a multiple of 1KB size?.
2630 * returns: n - card size of n bytes
2631 * -1 - if we can not read after writing
2632 * a know value. (e.g. ROM/FLASH)
2634 static int pcram_card_sizing(pcram_state_t *rs)
2637 int ret;
2638 int offset;
2639 int next_offset;
2640 int blocksize, nbs;
2641 uchar_t test_pattern;
2642 uchar_t restore_data;
2643 uchar_t cm_addr_zero, cm_next_addr;
2646 offset = 0;
2647 ret = update_mapmempage(rs, offset);
2648 if (ret < 0) {
2649 /* something failed so abort */
2650 return (-1);
2651 /* NOTREACHED */
2654 cm_addr_zero = csx_Get8(rs->access_handle, 0);
2656 /* Select test data pattern */
2657 if (cm_addr_zero != PATTERN_1) {
2658 test_pattern = PATTERN_1;
2659 } else {
2660 test_pattern = PATTERN_2;
2663 /* Select block size sample */
2664 if (rs->win_size >= HALF_MEG) {
2665 blocksize = HALF_MEG;
2666 } else {
2667 blocksize = rs->win_size;
2670 nbs = blocksize - (blocksize%SIZE_1KB);
2671 if (nbs < SIZE_1KB) {
2672 blocksize = SIZE_1KB;
2673 } else {
2674 blocksize = nbs;
2677 #ifdef PCRAM_DEBUG
2678 if (pcram_debug & PCRAM_DEBUG_SIZE) {
2679 cmn_err(CE_CONT, "pcram_card_sizing: socket %d \n"
2680 "\tBlock size sample [%d bytes]\n",
2681 rs->sn, blocksize);
2683 #endif
2685 while (offset < MAX_CARD_SIZE) {
2686 offset += blocksize;
2687 ret = update_mapmempage(rs, offset);
2688 if (ret < 0) {
2689 /* something failed so abort */
2690 return (-1);
2691 /* NOTREACHED */
2694 next_offset = ret;
2695 /* Save data information */
2696 cm_next_addr = csx_Get8(rs->access_handle, next_offset);
2697 restore_data = cm_next_addr;
2699 /* Write this location with test_pattern */
2700 csx_Put8(rs->access_handle, next_offset, test_pattern);
2703 * Write verification
2704 * If it is not a writen data,
2705 * this could be a ROM or FLASH card.
2707 cm_next_addr = csx_Get8(rs->access_handle, next_offset);
2708 if (cm_next_addr != test_pattern) {
2709 return (UNRECOGNIZED_MEDIA);
2710 /* NOTREACHED */
2713 ret = update_mapmempage(rs, 0);
2714 if (ret < 0) {
2715 /* something failed so abort */
2716 return (-1);
2717 /* NOTREACHED */
2720 cm_addr_zero = csx_Get8(rs->access_handle, 0);
2721 if (cm_addr_zero == test_pattern) {
2722 /* Restore location 0 data */
2723 csx_Put8(rs->access_handle, 0, restore_data);
2724 break;
2727 ret = update_mapmempage(rs, offset);
2728 if (ret < 0) {
2729 /* something failed so abort */
2730 return (-1);
2731 /* NOTREACHED */
2735 /* Restore previous write data */
2736 csx_Put8(rs->access_handle, next_offset, restore_data);
2738 } /* while */
2740 #ifdef PCRAM_DEBUG
2741 if (pcram_debug & PCRAM_DEBUG_SIZE) {
2742 cmn_err(CE_CONT, "pcram_card_sizing: socket %d \n"
2743 "\tFound card_size [%d bytes]\n",
2744 rs->sn, offset);
2746 #endif
2748 return (offset);
2749 /* NOTREACHED */
2755 * SPARC UFS label checksum
2757 static int
2758 cksum(struct dk_label *label)
2760 int i;
2761 unsigned char value;
2762 uchar_t *data;
2765 data = (uchar_t *)label;
2767 for (i = 0, value = 0; i < sizeof (struct dk_label); i++) {
2768 value ^= *data++;
2771 return (value);
2772 /* NOTREACHED */
2777 * Check media insertion/ejection status
2779 static int
2780 pcram_check_media(pcram_state_t *rs, enum dkio_state state)
2782 int err;
2783 get_status_t get_status;
2786 mutex_enter(&rs->mutex);
2789 * Do a CS call to see if the card is present
2791 if ((err = csx_GetStatus(rs->client_handle, &get_status))
2792 != CS_SUCCESS) {
2793 error2text_t cft;
2795 mutex_exit(&rs->mutex);
2797 cft.item = err;
2798 (void) csx_Error2Text(&cft);
2799 cmn_err(CE_CONT, "pcram_check_media: socket %d "
2800 "GetStatus failed %s (0x%x)\n",
2801 rs->sn, cft.text, err);
2802 return (ENXIO);
2803 /* NOTREACHED */
2806 /* Register rs->media_state */
2807 if ((get_status.CardState & CS_EVENT_CARD_INSERTION)) {
2808 rs->media_state = DKIO_INSERTED;
2809 } else {
2810 if (state == DKIO_NONE) {
2811 rs->media_state = DKIO_NONE;
2812 } else {
2813 rs->media_state = DKIO_EJECTED;
2819 * XXXX - In order not to modify the volume management
2820 * we have to follow the current SCSI CDROM model
2821 * for checking media state (broken way, sigh!)
2822 * start with state = DKIO_NONE
2823 * wait until mediastate = DKIO_INSERTED
2824 * wait until mediastate = DKIO_EJECTED
2825 * if DKIOCSTATE ioctl() is called second time
2826 * with state = DKIO_EJECTED,
2827 * return state = DKIO_NONE
2828 * restart with state = DKIO_NONE
2831 if (state != DKIO_NONE) {
2832 if (rs->ejected_media_flag &&
2833 (rs->media_state == DKIO_EJECTED)) {
2834 rs->media_state = DKIO_NONE;
2835 rs->ejected_media_flag = 0;
2836 mutex_exit(&rs->mutex);
2837 return (0);
2838 /* NOTREACHED */
2842 #ifdef PCRAM_DEBUG
2843 if (pcram_debug & PCRAM_DEBUG_VOLD) {
2844 cmn_err(CE_CONT, "pcram_check_media: socket %d \n"
2845 "\tWaiting state change: rs->media_state %d state %d\n"
2846 "\tDKIO_NONE %d DKIO_EJECTED %d DKIO_INSERTED %d\n",
2847 rs->sn, rs->media_state, state,
2848 DKIO_NONE, DKIO_EJECTED, DKIO_INSERTED);
2850 #endif
2853 * wait for Card Detect Change Interrupt handler
2854 * see either pcram_card_insertion/pcram_card_removal
2855 * for cv_broadcast
2857 while (rs->media_state == state) {
2858 rs->checkmedia_flag++;
2859 if (cv_wait_sig(&rs->condvar_mediastate,
2860 &rs->mutex) == 0) {
2861 mutex_exit(&rs->mutex);
2862 return (EINTR);
2863 /* NOTREACHED */
2867 #ifdef PCRAM_DEBUG
2868 if (pcram_debug & PCRAM_DEBUG_VOLD) {
2869 cmn_err(CE_CONT, "pcram_check_media: socket %d \n"
2870 "\tAfter state change: rs->media_state %d state %d\n"
2871 "\tDKIO_NONE %d DKIO_EJECTED %d DKIO_INSERTED %d\n",
2872 rs->sn, rs->media_state, state,
2873 DKIO_NONE, DKIO_EJECTED, DKIO_INSERTED);
2875 #endif
2877 if (state != DKIO_NONE) {
2878 if (!rs->ejected_media_flag &&
2879 (rs->media_state == DKIO_EJECTED)) {
2880 rs->ejected_media_flag++;
2884 mutex_exit(&rs->mutex);
2886 return (0);
2887 /* NOTREACHED */
2893 * Constructing disk label
2895 static int
2896 pcram_build_label_vtoc(pcram_state_t *rs, struct vtoc *vtoc)
2899 int i;
2900 short sum, *sp;
2901 struct dk_map2 *lpart;
2902 #if defined(__sparc)
2903 daddr_t nblks;
2904 #ifdef _SYSCALL32
2905 struct dk_map32 *lmap;
2906 #else
2907 struct dk_map *lmap;
2908 #endif
2909 struct partition *vpart;
2910 #endif /* __sparc */
2913 mutex_enter(&rs->mutex);
2915 /* Sanity-check the vtoc */
2916 if (vtoc->v_sanity != VTOC_SANE) {
2917 mutex_exit(&rs->mutex);
2918 return (EINVAL);
2919 /* NOTREACHED */
2922 bzero(&rs->un_label, sizeof (struct dk_label));
2924 bcopy(vtoc->v_bootinfo, rs->un_label.dkl_vtoc.v_bootinfo,
2925 sizeof (vtoc->v_bootinfo));
2927 rs->un_label.dkl_vtoc.v_sanity = vtoc->v_sanity;
2928 rs->un_label.dkl_vtoc.v_version = vtoc->v_version;
2930 bcopy(vtoc->v_volume, rs->un_label.dkl_vtoc.v_volume, LEN_DKL_VVOL);
2932 #if defined(__i386) || defined(__amd64)
2933 rs->un_label.dkl_vtoc.v_sectorsz = vtoc->v_sectorsz;
2934 #endif
2936 rs->un_label.dkl_vtoc.v_nparts = vtoc->v_nparts;
2938 bcopy(vtoc->v_reserved, rs->un_label.dkl_vtoc.v_reserved,
2939 sizeof (vtoc->v_reserved));
2941 lpart = (struct dk_map2 *)rs->un_label.dkl_vtoc.v_part;
2943 for (i = 0; i < NDKMAP; i++) {
2944 lpart->p_tag = vtoc->v_part[i].p_tag;
2945 lpart->p_flag = vtoc->v_part[i].p_flag;
2946 #ifdef XX
2947 /* XXX - does not compile for x86 ??? */
2948 #if defined(__i386) || defined(__amd64)
2949 lpart->p_start = vtoc->v_part[i].p_start;
2950 lpart->p_size = vtoc->v_part[i].p_size;
2951 #endif
2952 #endif /* XX */
2953 lpart++;
2956 bcopy(vtoc->timestamp, rs->un_label.dkl_vtoc.v_timestamp,
2957 sizeof (vtoc->timestamp));
2959 #if defined(__i386) || defined(__amd64)
2960 bcopy(vtoc->v_asciilabel, rs->un_label.dkl_vtoc.v_asciilabel,
2961 LEN_DKL_ASCII);
2962 #endif
2965 #if defined(__sparc)
2966 bcopy(vtoc->v_asciilabel, rs->un_label.dkl_asciilabel, LEN_DKL_ASCII);
2968 nblks = rs->hdrv_chars->drv_nhead *
2969 rs->hdrv_chars->drv_secptrack;
2971 lmap = rs->un_label.dkl_map;
2972 vpart = vtoc->v_part;
2973 for (i = 0; i < NDKMAP; i++) {
2974 lmap->dkl_cylno = vpart->p_start / nblks;
2975 lmap->dkl_nblk = vpart->p_size;
2976 lmap++;
2977 vpart++;
2979 #endif /* __sparc */
2981 rs->un_label.dkl_ncyl = rs->hdrv_chars->drv_ncyl;
2982 rs->un_label.dkl_nhead = rs->hdrv_chars->drv_nhead;
2983 rs->un_label.dkl_nsect = rs->hdrv_chars->drv_secptrack;
2984 rs->un_label.dkl_pcyl = rs->hdrv_chars->drv_ncyl;
2986 rs->un_label.dkl_intrlv = 1;
2988 rs->un_label.dkl_magic = DKL_MAGIC;
2990 sum = 0;
2991 rs->un_label.dkl_cksum = 0;
2992 sp = (short *)&rs->un_label;
2994 i = sizeof (struct dk_label)/sizeof (short);
2995 while (i--) {
2996 sum ^= *sp++;
2999 rs->un_label.dkl_cksum = sum;
3001 mutex_exit(&rs->mutex);
3003 #ifdef PCRAM_DEBUG
3004 if (pcram_debug > 1) {
3005 cmn_err(CE_CONT, "pcram_build_label_vtoc: socket %d\n"
3006 "\tncyl %d, nhd %d, nsec %d, pcyl %d\n",
3007 rs->sn,
3008 rs->un_label.dkl_ncyl, rs->un_label.dkl_nhead,
3009 rs->un_label.dkl_nsect, rs->un_label.dkl_pcyl);
3011 #endif
3013 return (0);
3014 /* NOTREACHED */
3020 * Writing disk label to the memory card
3022 static void
3023 pcram_write_label(pcram_state_t *rs)
3026 * Update the kernel buffer with the dk_label structure
3028 bzero(rs->host_sp, HOST_BUF_SIZE);
3029 bcopy(&rs->un_label, rs->host_sp, sizeof (struct dk_label));
3030 /* Write to the memory card */
3031 mutex_enter(&rs->mutex);
3032 card_byte_wr(rs, sizeof (struct dk_label), (int)0);
3033 mutex_exit(&rs->mutex);
3040 * pcram_event - this is the event handler
3042 static int
3043 pcram_event(event_t event, int priority, event_callback_args_t *eca)
3045 int retcode = CS_UNSUPPORTED_EVENT;
3046 pcram_state_t *rs = eca->client_data;
3047 client_info_t *ci = &eca->client_info;
3049 #ifdef DEBUG
3050 if (pcram_debug_events) {
3051 pcram_debug_report_event(rs, event, priority);
3053 #endif
3056 if (priority & CS_EVENT_PRI_HIGH) {
3057 mutex_enter(&rs->event_hilock);
3060 #ifdef PCRAM_DEBUG
3061 if (pcram_debug > 1) {
3062 event2text_t event2text;
3064 event2text.event = event;
3065 (void) csx_Event2Text(&event2text);
3067 cmn_err(CE_CONT, "pcram_event: socket %d \n"
3068 "\tevent %s (0x%x) priority 0x%x\n",
3069 rs->sn, event2text.text, event, priority);
3071 #endif
3073 * Find out which event we got and do the appropriate thing
3075 switch (event) {
3076 case CS_EVENT_REGISTRATION_COMPLETE:
3077 break;
3078 case CS_EVENT_CARD_INSERTION:
3079 if (priority & CS_EVENT_PRI_LOW) {
3080 retcode = pcram_card_insertion(rs);
3082 break;
3083 case CS_EVENT_BATTERY_LOW:
3084 break;
3085 case CS_EVENT_BATTERY_DEAD:
3086 break;
3087 case CS_EVENT_WRITE_PROTECT:
3088 if (priority & CS_EVENT_PRI_LOW) {
3089 mutex_enter(&rs->mutex);
3091 if (eca->info) {
3092 rs->card_event |= PCRAM_WRITE_PROTECT;
3093 } else {
3094 rs->card_event &= ~PCRAM_WRITE_PROTECT;
3095 rs->wp_posted = 0;
3097 if (priority & CS_EVENT_PRI_LOW) {
3098 mutex_exit(&rs->mutex);
3100 break;
3102 * Note that we get two CS_EVENT_CARD_REMOVAL events -
3103 * one at high priority and the other at low priority.
3104 * This is determined by the setting of the
3105 * CS_EVENT_CARD_REMOVAL_LOWP bit in either of the
3106 * event masks.
3107 * (See the call to RegisterClient).
3109 case CS_EVENT_CARD_REMOVAL:
3110 if (priority & CS_EVENT_PRI_HIGH) {
3111 retcode = CS_SUCCESS;
3112 rs->card_event &= ~PCRAM_CARD_INSERTED;
3113 } else {
3114 retcode = pcram_card_removal(rs);
3115 mutex_enter(&rs->event_hilock);
3116 rs->card_event &= ~PCRAM_CARD_INSERTED;
3117 mutex_exit(&rs->event_hilock);
3119 break;
3120 case CS_EVENT_CLIENT_INFO:
3121 if (GET_CLIENT_INFO_SUBSVC(ci->Attributes) ==
3122 CS_CLIENT_INFO_SUBSVC_CS) {
3123 ci->Revision = PCRAM_REV_LEVEL;
3124 ci->CSLevel = CS_VERSION;
3125 ci->RevDate = PCRAM_REV_DATE;
3126 (void) strcpy(ci->ClientName,
3127 PCRAM_CLIENT_DESCRIPTION);
3128 (void) strcpy(ci->VendorName,
3129 PCRAM_VENDOR_DESCRIPTION);
3130 ci->Attributes |= CS_CLIENT_INFO_VALID;
3131 retcode = CS_SUCCESS;
3132 } /* CS_CLIENT_INFO_SUBSVC_CS */
3133 break;
3136 if (priority & CS_EVENT_PRI_HIGH) {
3137 mutex_exit(&rs->event_hilock);
3140 return (retcode);
3141 /* NOTREACHED */
3147 * pcram_card_insertion - handles card insertion events
3149 static int
3150 pcram_card_insertion(pcram_state_t *rs)
3152 int ret;
3153 int rval = CS_SUCCESS;
3154 uint32_t first;
3155 sockevent_t se;
3156 win_req_t win_req;
3157 convert_speed_t convert_speed;
3158 map_mem_page_t map_mem_page;
3159 get_status_t get_status;
3160 mem_region_t *mrp;
3163 mutex_enter(&rs->mutex);
3165 /* Reset battery DEAD/LOW status posted flag */
3166 rs->batter_dead_posted = 0;
3167 rs->batter_low_posted = 0;
3169 /* XXXX - for Volume Manager */
3170 if (rs->checkmedia_flag) {
3171 rs->checkmedia_flag = 0;
3172 rs->media_state = DKIO_INSERTED;
3173 cv_broadcast(&rs->condvar_mediastate);
3175 #ifdef PCRAM_DEBUG
3176 if (pcram_debug & PCRAM_DEBUG_VOLD) {
3177 cmn_err(CE_CONT, "pcram_card_insertion: socket %d \n"
3178 "\tdoing cv_broadcast - "
3179 "rs->media_state of DKIO_INSERTED\n", rs->sn);
3181 #endif
3185 * used by PCRAM_PROBESIZE ioctl() to determine if
3186 * there is a DOS_BPB, Solaris VTOC, or CIS info
3188 rs->default_size_flag = 0;
3191 * XXX need more work search further for CIS tuple
3192 * level-2 and level-3 to determine the partition info.
3194 rs->isit_pseudofloppy = DKI_PCMCIA_PFD;
3195 rs->card_eject_posted = 0;
3197 mutex_exit(&rs->mutex);
3200 * Do a CS call to check the card state
3202 if ((ret = csx_GetStatus(rs->client_handle, &get_status))
3203 != CS_SUCCESS) {
3204 error2text_t cft;
3206 cft.item = ret;
3207 (void) csx_Error2Text(&cft);
3208 cmn_err(CE_CONT, "pcram_card_insertion: socket %d "
3209 "GetStatus failed %s (0x%x)\n",
3210 rs->sn, cft.text, ret);
3211 mutex_enter(&rs->event_hilock);
3212 cv_broadcast(&rs->firstopenwait_cv);
3213 mutex_exit(&rs->event_hilock);
3214 return (ret);
3215 /* NOTREACHED */
3218 /* Make sure that there is a card in the socket */
3219 if (!(get_status.CardState & CS_EVENT_CARD_INSERTION)) {
3220 #ifdef PCRAM_DEBUG
3221 if (pcram_debug & PCRAM_DEBUG_CARD_STATUS) {
3222 cmn_err(CE_CONT, "pcram_card_insertion: socket %d "
3223 "ERROR: Found no memory card\n", rs->sn);
3225 #endif
3226 mutex_enter(&rs->event_hilock);
3227 cv_broadcast(&rs->firstopenwait_cv);
3228 mutex_exit(&rs->event_hilock);
3229 return (CS_NO_CARD);
3230 /* NOTREACHED */
3234 * Set up the client event mask to give us WP and battery
3235 * events as well as what other events we have already
3236 * registered for.
3237 * Note that since we set the global event mask in the call
3238 * to RegisterClient in pcram_attach, we don't have to
3239 * duplicate those events in this event mask.
3241 se.Attributes = CONF_EVENT_MASK_CLIENT;
3242 if ((ret = csx_GetEventMask(rs->client_handle, &se))
3243 != CS_SUCCESS) {
3244 error2text_t cft;
3246 cft.item = ret;
3247 (void) csx_Error2Text(&cft);
3248 cmn_err(CE_CONT, "pcram_card_insertion: socket %d "
3249 "GetEventMask failed %s (0x%x)\n",
3250 rs->sn, cft.text, ret);
3251 mutex_enter(&rs->event_hilock);
3252 cv_broadcast(&rs->firstopenwait_cv);
3253 mutex_exit(&rs->event_hilock);
3254 return (ret);
3255 /* NOTREACHED */
3258 se.EventMask |= (CS_EVENT_BATTERY_LOW | CS_EVENT_BATTERY_DEAD |
3259 CS_EVENT_WRITE_PROTECT);
3261 if ((ret = csx_SetEventMask(rs->client_handle, &se))
3262 != CS_SUCCESS) {
3263 error2text_t cft;
3265 cft.item = ret;
3266 (void) csx_Error2Text(&cft);
3267 cmn_err(CE_CONT, "pcram_card_insertion: socket %d "
3268 "SetEventMask failed %s (0x%x)\n",
3269 rs->sn, cft.text, ret);
3270 mutex_enter(&rs->event_hilock);
3271 cv_broadcast(&rs->firstopenwait_cv);
3272 mutex_exit(&rs->event_hilock);
3273 return (ret);
3274 /* NOTREACHED */
3278 * If we had a window, make sure to release
3279 * before we request for the new window
3281 if (rs->flags & PCRAM_HAS_WINDOW) {
3283 mutex_enter(&rs->mutex);
3284 rs->flags &= ~PCRAM_HAS_WINDOW;
3285 mutex_exit(&rs->mutex);
3287 if ((ret = csx_ReleaseWindow(rs->window_handle))
3288 != CS_SUCCESS) {
3289 error2text_t cft;
3291 cft.item = ret;
3292 (void) csx_Error2Text(&cft);
3293 cmn_err(CE_CONT,
3294 "pcram_card_insertion: socket %d "
3295 "ReleaseWindow failed %s (0x%x)\n",
3296 rs->sn, cft.text, ret);
3301 * Try to get a memory window to CM space
3303 win_req.Attributes = (WIN_MEMORY_TYPE_CM | WIN_DATA_WIDTH_16 |
3304 WIN_ENABLE);
3305 win_req.Base.base = 0; /* let CS find us a base address */
3306 win_req.Size = 0; /* let CS return the smallest size */
3307 /* window it finds */
3309 convert_speed.Attributes = CONVERT_NS_TO_DEVSPEED;
3310 convert_speed.nS = 250;
3311 (void) csx_ConvertSpeed(&convert_speed);
3313 /* XXX - set to 0x32 until cis_convert_devspeed is fixed */
3314 convert_speed.devspeed = 0x32;
3316 win_req.win_params.AccessSpeed = convert_speed.devspeed;
3318 if ((ret = csx_RequestWindow(rs->client_handle,
3319 &rs->window_handle, &win_req)) != CS_SUCCESS) {
3320 error2text_t cft;
3322 cft.item = ret;
3323 (void) csx_Error2Text(&cft);
3324 cmn_err(CE_CONT, "pcram_card_insertion: socket %d "
3325 "RequestWindow failed %s (0x%x)\n",
3326 rs->sn, cft.text, ret);
3327 mutex_enter(&rs->event_hilock);
3328 cv_broadcast(&rs->firstopenwait_cv);
3329 mutex_exit(&rs->event_hilock);
3330 return (ret);
3331 /* NOTREACHED */
3334 mutex_enter(&rs->mutex);
3335 rs->flags |= PCRAM_HAS_WINDOW;
3336 mutex_exit(&rs->mutex);
3338 #ifdef PCRAM_DEBUG
3339 if (pcram_debug & PCRAM_DEBUG_TRACE) {
3340 cmn_err(CE_CONT, "pcram_card_insertion: socket %d \n"
3341 "\tRequestWindow successful handle 0x%x\n"
3342 "\tAttributes 0x%x Base 0x%x \n"
3343 "\tSize 0x%x AccessSpeed 0x%x\n",
3344 rs->sn, rs->window_handle,
3345 win_req.Attributes,
3346 win_req.Base.base,
3347 win_req.Size,
3348 win_req.win_params.AccessSpeed);
3350 #endif
3353 * Now map the offset to the start of the card
3355 map_mem_page.CardOffset = 0;
3356 map_mem_page.Page = 0;
3358 if ((ret = csx_MapMemPage(rs->window_handle,
3359 &map_mem_page)) != CS_SUCCESS) {
3360 error2text_t cft;
3362 cft.item = ret;
3363 (void) csx_Error2Text(&cft);
3365 mutex_enter(&rs->mutex);
3366 rs->flags &= ~PCRAM_HAS_WINDOW;
3367 mutex_exit(&rs->mutex);
3369 cmn_err(CE_CONT, "pcram_card_insertion: socket %d "
3370 "MapMemPage failed %s (0x%x)\n",
3371 rs->sn, cft.text, ret);
3373 if ((ret = csx_ReleaseWindow(rs->window_handle))
3374 != CS_SUCCESS) {
3375 error2text_t cft;
3377 cft.item = ret;
3378 (void) csx_Error2Text(&cft);
3379 cmn_err(CE_CONT,
3380 "pcram_card_insertion: socket %d "
3381 "ReleaseWindow failed %s (0x%x)\n",
3382 rs->sn, cft.text, ret);
3384 mutex_enter(&rs->event_hilock);
3385 cv_broadcast(&rs->firstopenwait_cv);
3386 mutex_exit(&rs->event_hilock);
3387 return (ret);
3388 /* NOTREACHED */
3391 /* Store rs->access_handle */
3392 mutex_enter(&rs->mutex);
3393 rs->access_handle = win_req.Base.handle;
3394 rs->win_size = win_req.Size;
3395 mutex_exit(&rs->mutex);
3397 #ifdef PCRAM_DEBUG
3398 if (pcram_debug & PCRAM_DEBUG_TRACE) {
3399 cmn_err(CE_CONT, "pcram_card_insertion: socket %d \n"
3400 "\tBase 0x%x rs->access_handle 0x%p\n"
3401 "\tSize 0x%x rs->win_size 0x%x\n",
3402 rs->sn,
3403 win_req.Base.base, (void *)rs->access_handle,
3404 win_req.Size, (int)rs->win_size);
3406 #endif
3409 * Build the memory region lists. This function will build
3410 * the lists whether or not there is a CIS on the card
3412 mutex_enter(&rs->region_lock);
3413 if ((ret = pcram_build_region_lists(rs)) <= 0) {
3414 /* error */
3415 rval = CS_GENERAL_FAILURE;
3416 if (ret == 0) {
3417 cmn_err(CE_CONT,
3418 "pcram_card_insertion: socket %d \n"
3419 "\tERROR - pcram_build_region_lists - "
3420 "AM[%d], CM[%d]\n",
3421 rs->sn, rs->num_am_regions,
3422 rs->num_cm_regions);
3423 } else if (ret == -2) {
3425 * Found unsupported Device error
3426 * Specified socket is invalid
3428 rval = CS_BAD_SOCKET;
3430 } else {
3431 /* no error */
3433 #ifdef PCRAM_DEBUG
3434 if (pcram_debug & PCRAM_DEBUG_CIS) {
3435 cmn_err(CE_CONT, "pcram_card_insertion: socket %d \n"
3436 "\tRegion number - AM[%d], CM[%d]\n",
3437 rs->sn, rs->num_am_regions, rs->num_cm_regions);
3439 #endif
3442 * Set "first" to one before you call the function if
3443 * you want it to behave as a "get first" function; the
3444 * function will automatically manipulate "first" from
3445 * then on and it will behave as a "get next" function.
3446 * Don't forget to set "first" back to one if you want
3447 * a "get first" function again.
3450 /* XXX - Need more work on how to handle */
3451 /* multiple regions later */
3453 /* Point to Common Memory region list */
3454 mrp = rs->cm_regions;
3456 /* Get BUILD_DOS_BPBFAT_LIST list */
3457 first = 1;
3458 while (mrp = pcram_get_firstnext_region(mrp,
3459 REGION_DOS_BPBFAT,
3460 CISTPL_DEVICE_DTYPE_SRAM,
3461 &first)) {
3462 /* XXX - For now assuming there is ONLY */
3463 /* one DOS region */
3465 /* Note that rs->hdrv_chars is setup in */
3466 /* pcram_get_bpbfat_info */
3468 #ifdef PCRAM_DEBUG
3469 if (pcram_debug & PCRAM_DEBUG_CIS) {
3470 cmn_err(CE_CONT,
3471 "pcram_card_insertion: socket %d - "
3472 "BUILD_DOS_BPBFAT_LIST\n\tdevice speed [%d]\n",
3473 rs->sn, (int)mrp->nS_speed);
3475 #endif
3477 /* for VERBOSE mode */
3478 cmn_err(CE_CONT, "?pcram: "
3479 "(MSDOS) socket %d card size %d\n",
3480 rs->sn, rs->card_size);
3482 } /* while */
3485 /* Get BUILD_SOLARIS_LIST list */
3486 mrp = rs->cm_regions;
3487 first = 1;
3488 while (mrp = pcram_get_firstnext_region(mrp,
3489 REGION_SOLARIS,
3490 CISTPL_DEVICE_DTYPE_SRAM,
3491 &first)) {
3492 /* XXX - For now assuming there is ONLY */
3493 /* one Solaris region */
3495 /* Note that rs->hdrv_chars is setup in */
3496 /* pcram_get_solaris_info */
3498 #ifdef PCRAM_DEBUG
3499 if (pcram_debug & PCRAM_DEBUG_CIS) {
3500 cmn_err(CE_CONT,
3501 "pcram_card_insertion: socket %d - BUILD_SOLARIS_LIST\n"
3502 "\tdevice speed [%d]\n", rs->sn, (int)mrp->nS_speed);
3504 #endif
3506 /* for VERBOSE mode */
3507 cmn_err(CE_CONT, "?pcram: "
3508 "(SOLARIS) socket %d card size %d\n",
3509 rs->sn, rs->card_size);
3511 } /* while */
3514 /* Get BUILD_DEFAULT_LIST list */
3515 mrp = rs->cm_regions;
3516 first = 1;
3517 while (mrp = pcram_get_firstnext_region(mrp,
3518 REGION_DEFAULT,
3519 CISTPL_DEVICE_DTYPE_SRAM,
3520 &first)) {
3521 /* XXX - For now assuming there is ONLY */
3522 /* one DEFAULT region */
3525 * XXX - check for non-zero for drv_nhead,
3526 * drv_secptrack, drv_sec_size to avoid
3527 * zero divide panic
3530 #ifdef PCRAM_DEBUG
3531 if (pcram_debug & PCRAM_DEBUG_CIS) {
3532 cmn_err(CE_CONT,
3533 "pcram_card_insertion: socket %d - BUILD_DEFAULT_LIST\n"
3534 "\tdevice speed [%d]\n", rs->sn, (int)mrp->nS_speed);
3536 #endif
3537 update_hdrv_chars(rs, mrp);
3539 /* for VERBOSE mode */
3540 cmn_err(CE_CONT, "?pcram: "
3541 "(DEFAULT) socket %d card size %d\n",
3542 rs->sn, rs->card_size);
3544 } /* while */
3547 /* Get BUILD_CM_LIST list */
3548 mrp = rs->cm_regions;
3549 first = 1;
3550 while (mrp = pcram_get_firstnext_region(mrp,
3551 REGION_VALID,
3552 CISTPL_DEVICE_DTYPE_SRAM,
3553 &first)) {
3554 /* XXX - For now assuming there is ONLY */
3555 /* one CM CIS region */
3558 * XXX - check for non-zero for drv_nhead,
3559 * drv_secptrack, drv_sec_size to avoid
3560 * zero divide panic
3563 #ifdef PCRAM_DEBUG
3564 if (pcram_debug & PCRAM_DEBUG_CIS) {
3565 cmn_err(CE_CONT, "pcram_card_insertion: socket %d - "
3566 "BUILD_CM_LIST\n\tdevice speed [%d]\n",
3567 rs->sn, (int)mrp->nS_speed);
3569 #endif
3571 update_hdrv_chars(rs, mrp);
3573 /* for VERBOSE mode */
3574 cmn_err(CE_CONT,
3575 "?pcram: (CIS) socket %d card size %d\n",
3576 rs->sn, rs->card_size);
3578 } /* while */
3582 * Create the device nodes.
3583 * This is an example that assumes
3584 * that we want to create four devices
3585 * for this instance.
3588 int n;
3589 char devname[80];
3590 char *dname;
3591 devnode_desc_t *dnd;
3592 make_device_node_t make_device_node;
3595 make_device_node.Action = CREATE_DEVICE_NODE;
3596 make_device_node.NumDevNodes = 2;
3598 make_device_node.devnode_desc =
3599 kmem_zalloc(sizeof (struct devnode_desc) *
3600 make_device_node.NumDevNodes, KM_SLEEP);
3602 dname = devname;
3605 * Create only "c" partition for now since
3606 * the driver support only one parttion
3609 for (n = 0; n < (make_device_node.NumDevNodes);
3610 n++) {
3612 dnd = &make_device_node.devnode_desc[n];
3614 dnd->name = dname;
3615 dnd->minor_num =
3616 PCRAM_SETMINOR(rs->sn, (n+4)/2);
3618 if (n&1) {
3619 dnd->spec_type = S_IFCHR;
3620 (void) sprintf(dname, "%c,raw",
3621 (((n+4)/2)+'a'));
3622 } else {
3623 dnd->spec_type = S_IFBLK;
3624 (void) sprintf(dname, "%c",
3625 (((n+4)/2)+'a'));
3628 dnd->node_type = DDI_NT_BLOCK_CHAN;
3630 dname = &dname[strlen(dname)+1];
3631 } /* for */
3633 if ((ret = csx_MakeDeviceNode(rs->client_handle,
3634 &make_device_node)) != CS_SUCCESS) {
3636 error2text_t cft;
3638 cft.item = ret;
3639 (void) csx_Error2Text(&cft);
3641 cmn_err(CE_CONT,
3642 "pcram_card_insertion: socket %d "
3643 "MakeDeviceNode failed %s (0x%x)\n",
3644 rs->sn, cft.text, ret);
3648 * We don't need this structure anymore
3649 * since we've created the devices.
3650 * If we need to keep track of the
3651 * devices that we've created for
3652 * some reason, then you' want to keep
3653 * this structure and the
3654 * make_device_node_t structure around
3655 * in a global data area.
3657 kmem_free(make_device_node.devnode_desc,
3658 sizeof (struct devnode_desc) *
3659 make_device_node.NumDevNodes);
3661 make_device_node.devnode_desc = NULL;
3663 } /* create device nodes */
3665 #ifdef PCRAM_DEBUG
3666 if (pcram_debug & PCRAM_DEBUG_TRACE) {
3667 cmn_err(CE_CONT, "pcram_card_insertion: socket %d\n"
3668 "\tRegion list - hard drive structure\n"
3669 "\tcsize [%d] ncyl [%d] hd [%d] "
3670 "spt [%d] ssize [%d]\n", rs->sn,
3671 rs->card_size,
3672 rs->hdrv_chars->drv_ncyl,
3673 rs->hdrv_chars->drv_nhead,
3674 rs->hdrv_chars->drv_secptrack,
3675 rs->hdrv_chars->drv_sec_size);
3677 cmn_err(CE_CONT, "pcram: socket%d card size [%d bytes]\n",
3678 rs->sn, rs->card_size);
3680 #endif
3683 } /* if (!pcram_build_region_lists(rs)) */
3685 mutex_exit(&rs->region_lock);
3687 mutex_enter(&rs->event_hilock);
3688 rs->card_event |= PCRAM_CARD_INSERTED;
3689 rs->card_event |= PCRAM_FIRST_OPEN;
3690 rs->flags |= PCRAM_MAKEDEVICENODE;
3692 * Wake up firstopenwait_cv in pcram_open()
3694 cv_broadcast(&rs->firstopenwait_cv);
3695 mutex_exit(&rs->event_hilock);
3697 return (rval);
3698 /* NOTREACHED */
3704 * pcram_card_removal - handles card removal events; can only
3705 * be called from the low priority card
3706 * removal event
3708 static int
3709 pcram_card_removal(pcram_state_t *rs)
3711 int ret;
3712 get_status_t get_status;
3713 sockevent_t se;
3716 mutex_enter(&rs->mutex);
3718 /* Reset battery DEAD/LOW status posted flag */
3719 rs->batter_dead_posted = 0;
3720 rs->batter_low_posted = 0;
3722 /* Misc. flags */
3723 rs->busy = 0;
3724 rs->busy_wr = 0;
3725 rs->busy_rd = 0;
3727 /* XXX - DO NOT need to set win_size to zero */
3728 /* due to "zero divide trap panic" */
3729 /* rs->win_size = 0; */
3731 /* XXXX - for Volume Manager */
3732 if (rs->checkmedia_flag) {
3733 rs->checkmedia_flag = 0;
3734 rs->media_state = DKIO_EJECTED;
3735 cv_broadcast(&rs->condvar_mediastate);
3736 #ifdef PCRAM_DEBUG
3737 if (pcram_debug & PCRAM_DEBUG_VOLD) {
3738 cmn_err(CE_CONT,
3739 "pcram_card_removal: socket %d \n"
3740 "\tdoing cv_broadcast - "
3741 "rs->media_state of DKIO_EJECTED\n",
3742 rs->sn);
3744 #endif
3747 rs->card_eject_posted = 0;
3748 rs->wp_posted = 0;
3751 * Remove all the device nodes. We don't have to explictly
3752 * specify the names if we want Card Services to remove
3753 * all of the devices.
3754 * Note that when you call MakeDeviceNode with the Action
3755 * argument set to REMOVAL_ALL_DEVICE_NODES, the
3756 * NumDevNodes must be zero.
3758 if (rs->flags & PCRAM_REGCLIENT) {
3759 make_device_node_t make_device_node;
3761 make_device_node.Action = REMOVAL_ALL_DEVICE_NODES;
3762 make_device_node.NumDevNodes = 0;
3764 if ((ret = csx_MakeDeviceNode(rs->client_handle,
3765 &make_device_node)) != CS_SUCCESS) {
3767 error2text_t cft;
3769 cft.item = ret;
3770 (void) csx_Error2Text(&cft);
3772 cmn_err(CE_CONT,
3773 "pcram_card_removal: socket %d "
3774 "MakeDeviceNode failed %s (0x%x)\n",
3775 rs->sn, cft.text, ret);
3777 } /* remove device nodes */
3779 mutex_exit(&rs->mutex);
3782 * Do a CS call to check the card state
3784 if ((ret = csx_GetStatus(rs->client_handle, &get_status))
3785 != CS_SUCCESS) {
3786 error2text_t cft;
3788 cft.item = ret;
3789 (void) csx_Error2Text(&cft);
3790 cmn_err(CE_CONT, "pcram_card_removal: socket %d "
3791 "GetStatus failed %s (0x%x)\n",
3792 rs->sn, cft.text, ret);
3793 return (ret);
3794 /* NOTREACHED */
3797 #ifdef PCRAM_DEBUG
3798 if (pcram_debug & PCRAM_DEBUG_CARD_STATUS) {
3799 cmn_err(CE_CONT, "pcram_card_removal: socket %d "
3800 "GetStatus returns:\n", rs->sn);
3801 pcram_display_card_status(&get_status);
3803 #endif
3806 * Destroy the memory region lists.
3808 mutex_enter(&rs->region_lock);
3809 pcram_destroy_region_lists(rs);
3810 mutex_exit(&rs->region_lock);
3813 * Release the window if we allocated one
3815 if (rs->flags & PCRAM_HAS_WINDOW) {
3817 #ifdef PCRAM_DEBUG
3818 if (pcram_debug & PCRAM_DEBUG_TRACE) {
3819 cmn_err(CE_CONT, "pcram_card_removal: socket %d "
3820 "PCRAM_HAS_WINDOW [0x%x]\n"
3821 "\trs->flags [0x%x]:\n", rs->sn,
3822 PCRAM_HAS_WINDOW, (int)rs->flags);
3824 #endif
3826 mutex_enter(&rs->mutex);
3827 rs->flags &= ~PCRAM_HAS_WINDOW;
3828 mutex_exit(&rs->mutex);
3830 if ((ret = csx_ReleaseWindow(rs->window_handle))
3831 != CS_SUCCESS) {
3832 error2text_t cft;
3834 cft.item = ret;
3835 (void) csx_Error2Text(&cft);
3837 cmn_err(CE_CONT,
3838 "pcram_card_removal: socket %d "
3839 "ReleaseWindow failed %s (0x%x)\n",
3840 rs->sn, cft.text, ret);
3841 return (ret);
3842 /* NOTREACHED */
3847 * Set up the client event mask to clear WP and battery
3848 * events as well as what other events we have already
3849 * registered for.
3850 * Note that since we set the global event mask in the call
3851 * to RegisterClient in pcram_attach, we don't have to
3852 * duplicate those events in this event mask.
3854 se.Attributes = CONF_EVENT_MASK_CLIENT;
3855 if ((ret = csx_GetEventMask(rs->client_handle, &se))
3856 != CS_SUCCESS) {
3857 error2text_t cft;
3859 cft.item = ret;
3860 (void) csx_Error2Text(&cft);
3862 cmn_err(CE_CONT, "pcram_card_removal: socket %d"
3863 "GetEventMask failed %s (0x%x)\n",
3864 rs->sn, cft.text, ret);
3865 return (ret);
3866 /* NOTREACHED */
3869 se.EventMask &= ~(CS_EVENT_BATTERY_LOW |
3870 CS_EVENT_BATTERY_DEAD |
3871 CS_EVENT_WRITE_PROTECT);
3873 if ((ret = csx_SetEventMask(rs->client_handle, &se))
3874 != CS_SUCCESS) {
3875 error2text_t cft;
3877 cft.item = ret;
3878 (void) csx_Error2Text(&cft);
3880 cmn_err(CE_CONT, "pcram_card_removal: socket %d"
3881 "SetEventMask failed %s (0x%x)\n",
3882 rs->sn, cft.text, ret);
3883 return (ret);
3884 /* NOTREACHED */
3887 mutex_enter(&rs->mutex);
3888 rs->card_event &= ~PCRAM_FIRST_OPEN;
3889 rs->flags &= ~PCRAM_MAKEDEVICENODE;
3890 mutex_exit(&rs->mutex);
3892 return (CS_SUCCESS);
3893 /* NOTREACHED */
3898 #ifdef PCRAM_DEBUG
3901 * pcram_display_card_status - wrapper for GetStatus CS function
3903 static void
3904 pcram_display_card_status(get_status_t *gs)
3906 event2text_t event2text;
3908 event2text.event = gs->CardState;
3909 (void) csx_Event2Text(&event2text);
3911 if (pcram_debug & PCRAM_DEBUG_CARD_STATUS) {
3912 cmn_err(CE_CONT, "\tCardState [%s]\n", event2text.text);
3915 event2text.event = gs->SocketState;
3916 (void) csx_Event2Text(&event2text);
3918 if (pcram_debug & PCRAM_DEBUG_CARD_STATUS) {
3919 cmn_err(CE_CONT, "\tSocketState [%s]\n",
3920 event2text.text);
3924 #endif
3929 * pcram_build_region_lists - builds a card memory region list for
3930 * the passed card
3932 * calling: pcram_state_t *rs - pointer to the
3933 * per-card structure
3935 * returns: 0 if error building region list
3936 * 1 if region list built
3937 * -1 if found UNSUPPORTED DEVICE types
3939 * Note: There are two lists that can be built - one for AM regions
3940 * and one for CM regions. We can be called whether or not there is
3941 * a CIS on the card. If there is a CIS, we use the inforamtion that
3942 * we find in it to build the lists; if there is no CIS on the card,
3943 * we look for an MS-DOS BPB-FAT pseudo floppy image; if it is found,
3944 * only a CM list is created which describes the one BPB-FAT region
3945 * in CM. No AM list is built in this case.
3947 * If neither a CIS nor a BPB-FAT are found, we create only one list.
3948 * That list is for the CM space and specifies one region that is as
3949 * large as the card. In this case, it is expected the the driver
3950 * will provide read-only access to this one region.
3952 * If the driver is asked to format the card, the existing lists will
3953 * be destroyed, a new CIS written to the card (if necessary), and both
3954 * lists recreated.
3956 * XXX - need to think about the non-CIS non-DOS case
3958 static int
3959 pcram_build_region_lists(pcram_state_t *rs)
3961 int ret;
3962 cisinfo_t cisinfo;
3966 * Check for a CIS on this card - if there is one, our job
3967 * is very easy.
3969 if ((ret = csx_ValidateCIS(rs->client_handle, &cisinfo))
3970 != CS_SUCCESS) {
3971 error2text_t cft;
3973 cft.item = ret;
3974 (void) csx_Error2Text(&cft);
3976 if (ret != CS_NO_CIS) {
3977 cmn_err(CE_CONT, "pcram_build_region_lists: "
3978 "socket %d"
3979 "ValidateCIS failed %s (0x%x)\n",
3980 rs->sn, cft.text, ret);
3981 return (0);
3982 /* NOTREACHED */
3984 * No CIS on card, try to find an MS-DOS BPB-FAT
3985 * filesystem and build our list from that.
3987 } else {
3989 if ((rs->num_cm_regions =
3990 pcram_build_region_list(rs,
3991 &rs->cm_regions,
3992 BUILD_DOS_BPBFAT_LIST)) <= 0) {
3995 * Couldn't find a BPB-FAT filesystem, so first
3996 * destroy the CM list that was just built and
3997 * build the default CM region list.
3999 pcram_destroy_region_lists(rs);
4001 if ((rs->num_cm_regions =
4002 pcram_build_region_list(
4003 rs, &rs->cm_regions,
4004 BUILD_SOLARIS_LIST)) <= 0) {
4006 pcram_destroy_region_lists(rs);
4008 if ((rs->num_cm_regions =
4009 pcram_build_region_list(
4010 rs, &rs->cm_regions,
4011 BUILD_DEFAULT_LIST)) <= 0) {
4012 cmn_err(CE_CONT,
4013 "pcram_build_region_lists: "
4014 "socket %d \n"
4015 "\terror building "
4016 "default list\n",
4017 rs->sn);
4018 return (0);
4019 /* NOTREACHED */
4020 } /* (BUILD_DEFAULT_LIST) */
4022 } /* (BUILD_SOLARIS_LIST) */
4024 } /* (BUILD_DOS_BPBFAT_LIST) */
4026 } /* CS_NO_CIS */
4028 * There is a CIS - build the lists.
4030 } else {
4032 * Build the AM space list. It is OK to have
4033 * an empty AM space list.
4035 if ((rs->num_am_regions = pcram_build_region_list(rs,
4036 &rs->am_regions, BUILD_AM_LIST)) < 0) {
4037 cmn_err(CE_CONT, "pcram_build_region_lists: "
4038 "socket %d \n"
4039 "\terror building AM region list\n",
4040 rs->sn);
4041 return (0);
4042 /* NOTREACHED */
4046 * Build the CM space list. We need something in here
4047 * for the driver to work at all.
4049 if ((rs->num_cm_regions = pcram_build_region_list(rs,
4050 &rs->cm_regions, BUILD_CM_LIST)) < 0) {
4051 if (rs->num_cm_regions == -2) {
4053 * Found unsupported Device
4054 * Error Return
4056 return (-1);
4057 /* NOTREACHED */
4058 } else {
4059 cmn_err(CE_CONT,
4060 "pcram_build_region_lists: "
4061 "socket %d \n"
4062 "\terror building CM "
4063 "region list\n", rs->sn);
4064 return (0);
4065 /* NOTREACHED */
4067 } else if (!rs->num_cm_regions) {
4069 * If we couldn't find any CM regions, the card
4070 * could have a badly-formed CIS.
4071 * Create a default CM region.
4073 * XXX - is this the best thing to do, or should
4074 * we just return an error instead?
4076 rs->num_cm_regions = pcram_build_region_list(rs,
4077 &rs->cm_regions,
4078 (BUILD_CM_LIST |
4079 BUILD_DEFAULT_LIST));
4082 #ifdef PCRAM_DEBUG
4083 if (pcram_debug & PCRAM_DEBUG_CIS) {
4084 cmn_err(CE_CONT,
4085 "pcram_build_region_lists: socket %d \n"
4086 "\t(BUILD_AM_LIST | BUILD_CM_LIST)\n", rs->sn);
4088 #endif
4090 } /* ValidateCIS */
4092 return (1);
4093 /* NOTREACHED */
4099 * pcram_build_region_list - builds a region list for the passed
4100 * memory region
4102 * calling: rs - pointer to caller's state structure
4103 * rlist - pointer to a mem_region_t * region
4104 * list pointer
4105 * flags - type of list to build
4107 * returns: -1 if region list could not be built; region
4108 * list pointer is not changed
4109 * >=0 number of regions found if region list
4110 * could be built
4112 * returns: -2 if card is not supported
4114 * Note: If a region list could not be built, the region list must
4115 * be destroyed to prevent any memory leaks. For this
4116 * reason, if an error occurs building the region list,
4117 * the rlist pointer address is not set to NULL since
4118 * it may still have a partial region list.
4120 static int
4121 pcram_build_region_list(pcram_state_t *rs,
4122 mem_region_t **rlist, uint32_t flags)
4124 mem_region_t *mr;
4125 convert_speed_t convert_speed;
4126 convert_size_t convert_size;
4127 cisdata_t device_tuple, JEDEC_tuple;
4128 tuple_t tuple;
4129 int ret, region_num;
4133 * Make sure that we don't have an existing list hanging
4134 * off of this pointer - if we do, this is an error.
4136 if (*rlist) {
4137 #ifdef PCRAM_DEBUG
4138 if (pcram_debug & PCRAM_DEBUG_CIS) {
4139 cmn_err(CE_CONT, "pcram_build_region_list: socket %d "
4140 "ERROR *rlist = 0x%p\n", rs->sn, (void *)*rlist);
4142 #endif
4143 return (-1);
4144 /* NOTREACHED */
4148 * Do the common setup for a default or DOS partition.
4150 if (flags & (BUILD_DEFAULT_LIST |
4151 BUILD_DOS_BPBFAT_LIST | BUILD_SOLARIS_LIST)) {
4152 *rlist = kmem_zalloc(sizeof (mem_region_t), KM_SLEEP);
4153 mr = *rlist;
4154 mr->region_num = 0;
4155 mr->flags = 0;
4157 mr->next = NULL;
4158 mr->prev = NULL;
4160 mr->nS_speed = DEFAULT_CM_SPEED;
4161 convert_speed.Attributes = CONVERT_NS_TO_DEVSPEED;
4162 convert_speed.nS = mr->nS_speed;
4163 (void) csx_ConvertSpeed(&convert_speed);
4164 mr->speed = convert_speed.devspeed;
4166 } /* if (BUILD_DEFAULT_LIST | BUILD_DOS_BPBFAT_LIST) */
4169 * See if were being asked to build a default region list.
4170 * If so, build a single region that is as large as the
4171 * max card size and mark it as a default read-only
4172 * region.
4173 * XXX We set the device type to say it's a
4174 * ROM device as well.
4176 if (flags & BUILD_DEFAULT_LIST) {
4177 mr->rflags = REGION_DEFAULT;
4178 mr->type = CISTPL_DEVICE_DTYPE_SRAM;
4180 mr->size_in_bytes = MAX_CARD_SIZE;
4181 convert_size.Attributes = CONVERT_BYTES_TO_DEVSIZE;
4182 convert_size.bytes = mr->size_in_bytes;
4183 (void) csx_ConvertSize(&convert_size);
4184 mr->size = convert_size.devsize;
4186 #ifdef PCRAM_DEBUG
4187 if (pcram_debug & PCRAM_DEBUG_CIS) {
4188 cmn_err(CE_CONT, "pcram_build_region_list: socket %d "
4189 "BUILD_DEFAULT_LIST\n"
4190 "\tsize_in_bytes - [%d] size [0x%x]\n",
4191 rs->sn, (int)mr->size_in_bytes, (int)mr->size);
4193 #endif
4196 * Enable default_size_flag so we will probe card
4197 * size when PCRAM_PROBESIZE ioctl() is called.
4198 * This default_size_flag is not enabled when the
4199 * card contains DOS_BPBFAT or Solaris VTOC or
4200 * CIS info.
4202 rs->default_size_flag++;
4204 return (1);
4205 /* NOTREACHED */
4210 * Create a list from an MS-DOS BPB-FAT filesystem.
4212 if (flags & BUILD_DOS_BPBFAT_LIST) {
4214 * Check for an MS-DOS BPB-FAT filesystem.
4215 * If it exists, the mem_region_t structure
4216 * will be filled in with the correct values.
4218 if (!pcram_get_bpbfat_info(rs, mr)) {
4219 return (-1);
4220 /* NOTREACHED */
4224 * Convert the device size
4225 * from bytes to a devsize value.
4227 convert_size.Attributes = CONVERT_BYTES_TO_DEVSIZE;
4228 convert_size.bytes = mr->size_in_bytes;
4229 (void) csx_ConvertSize(&convert_size);
4230 mr->size = convert_size.devsize;
4232 #ifdef PCRAM_DEBUG
4233 if (pcram_debug & PCRAM_DEBUG_CIS) {
4234 cmn_err(CE_CONT, "pcram_build_region_list: socket %d "
4235 "BUILD_DOS_BPBFAT_LIST\n"
4236 "\tsize_in_bytes - [%d] size [0x%x]\n",
4237 rs->sn, (int)mr->size_in_bytes, (int)mr->size);
4239 #endif
4241 return (1);
4242 /* NOTREACHED */
4248 * Create a list from a Solaris VTOC filesystem.
4250 if (flags & BUILD_SOLARIS_LIST) {
4251 if (!pcram_get_solaris_info(rs, mr)) {
4252 return (-1);
4253 /* NOTREACHED */
4257 * Convert the device size
4258 * from bytes to a devsize value.
4260 convert_size.Attributes = CONVERT_BYTES_TO_DEVSIZE;
4261 convert_size.bytes = mr->size_in_bytes;
4262 (void) csx_ConvertSize(&convert_size);
4263 mr->size = convert_size.devsize;
4265 #ifdef PCRAM_DEBUG
4266 if (pcram_debug & PCRAM_DEBUG_CIS) {
4267 cmn_err(CE_CONT, "pcram_build_region_list: socket %d "
4268 "BUILD_SOLARIS_LIST\n"
4269 "\tsize_in_bytes - [%d] size [0x%x]\n",
4270 rs->sn, (int)mr->size_in_bytes, (int)mr->size);
4272 #endif
4274 return (1);
4275 /* NOTREACHED */
4280 * We've got a CIS so sort out the correct tuples to look for.
4282 switch (flags & (BUILD_AM_LIST | BUILD_CM_LIST)) {
4283 case BUILD_AM_LIST:
4284 device_tuple = CISTPL_DEVICE_A;
4285 JEDEC_tuple = CISTPL_JEDEC_A;
4286 break;
4287 case BUILD_CM_LIST:
4288 device_tuple = CISTPL_DEVICE;
4289 JEDEC_tuple = CISTPL_JEDEC_C;
4290 break;
4291 default:
4292 return (-1);
4293 /* NOTREACHED */
4294 } /* switch (flags) */
4297 * Search for the first device tuple - if it's not found,
4298 * there's no point in searching for anything else.
4300 tuple.Attributes = 0;
4301 tuple.DesiredTuple = device_tuple;
4302 if ((ret = csx_GetFirstTuple(rs->client_handle, &tuple))
4303 != CS_SUCCESS) {
4304 if (ret != CS_NO_MORE_ITEMS) {
4305 /* this is a real error */
4306 return (-1);
4307 /* NOTREACHED */
4308 } else {
4309 /* XXX - is 0 the right thing to return here? */
4310 return (0);
4311 /* NOTREACHED */
4316 * Got the device tuple, now parse it.
4318 region_num = 0;
4320 do {
4321 cistpl_device_t cistpl_device;
4322 mem_region_t *mrr = NULL;
4323 int i;
4326 * We shouldn't ever fail parsing this tuple.
4327 * If we do, there's probably an internal
4328 * error in the CIS parser.
4330 bzero(&cistpl_device, sizeof (struct cistpl_device_t));
4331 if (csx_Parse_CISTPL_DEVICE(rs->client_handle,
4332 &tuple, &cistpl_device) != CS_SUCCESS) {
4333 return (-1);
4334 /* NOTREACHED */
4338 * We should see at least one region.
4339 * This is definately an error.
4341 if (!cistpl_device.num_devices) {
4342 return (-1);
4343 /* NOTREACHED */
4346 for (i = 0; i < cistpl_device.num_devices; i++) {
4348 cistpl_device_node_t *cistpl_device_node;
4350 cistpl_device_node = &cistpl_device.devnode[i];
4352 mr = kmem_zalloc(sizeof (mem_region_t), KM_SLEEP);
4355 * IMPORTANT
4356 * setup for next CISTPL_DEVICE tuple
4358 mrr = mr;
4361 * If this is the first entry in the list,
4362 * then assign it to the head of
4363 * the list pointer.
4365 if (!*rlist) {
4366 *rlist = mr;
4367 mr->prev = NULL;
4368 } else {
4369 mrr->next = mr;
4370 mr->prev = mrr;
4373 mrr->region_num = region_num++;
4374 mrr->rflags = REGION_VALID;
4376 mrr->flags = cistpl_device_node->flags;
4377 mrr->speed = cistpl_device_node->speed;
4378 mrr->nS_speed = cistpl_device_node->nS_speed;
4380 if ((mrr->type = cistpl_device_node->type) ==
4381 CISTPL_DEVICE_DTYPE_NULL) {
4382 mrr->rflags |= REGION_HOLE;
4385 mrr->size = cistpl_device_node->size;
4386 mrr->size_in_bytes =
4387 cistpl_device_node->size_in_bytes;
4391 * Supporting Common Memory (CM) with
4392 * Masked-ROM(MROM) and Dynamic RAM(DRAM)
4394 if (device_tuple == CISTPL_DEVICE) {
4396 char *unsupported_fmt_string =
4397 "pcram: WARNING - Found unsupported "
4398 "%s device at socket %d\n";
4399 char *supported_fmt_string =
4400 "?pcram: Found %s device at socket %d "
4401 "card size %d\n";
4403 switch (cistpl_device_node->type) {
4405 case CISTPL_DEVICE_DTYPE_SRAM:
4406 /* Support this main device */
4407 break;
4409 case CISTPL_DEVICE_DTYPE_ROM:
4410 /* for VERBOSE mode */
4411 cmn_err(CE_CONT, supported_fmt_string,
4412 "Masked ROM", rs->sn,
4413 (int)cistpl_device_node->size_in_bytes);
4414 /* Now consider as SRAM type */
4415 mrr->type = CISTPL_DEVICE_DTYPE_SRAM;
4416 break;
4418 case CISTPL_DEVICE_DTYPE_DRAM:
4419 /* for VERBOSE mode */
4420 cmn_err(CE_CONT, supported_fmt_string,
4421 "Dynamic RAM", rs->sn,
4422 (int)cistpl_device_node->size_in_bytes);
4423 /* Now consider as SRAM type */
4424 mrr->type = CISTPL_DEVICE_DTYPE_SRAM;
4425 break;
4427 case CISTPL_DEVICE_DTYPE_OTPROM:
4428 cmn_err(CE_CONT, unsupported_fmt_string,
4429 "OTPROM", rs->sn);
4430 return (-2);
4431 /* NOTREACHED */
4433 case CISTPL_DEVICE_DTYPE_EPROM:
4434 cmn_err(CE_CONT, unsupported_fmt_string,
4435 "UV EPROM", rs->sn);
4436 return (-2);
4437 /* NOTREACHED */
4439 case CISTPL_DEVICE_DTYPE_EEPROM:
4440 cmn_err(CE_CONT, unsupported_fmt_string,
4441 "EEPROM", rs->sn);
4442 return (-2);
4443 /* NOTREACHED */
4445 case CISTPL_DEVICE_DTYPE_FLASH:
4446 cmn_err(CE_CONT, unsupported_fmt_string,
4447 "FLASH", rs->sn);
4448 return (-2);
4449 /* NOTREACHED */
4451 default:
4452 cmn_err(CE_CONT, unsupported_fmt_string,
4453 "UNKNOWN", rs->sn);
4454 return (-2);
4455 /* NOTREACHED */
4457 } /* switch (cistpl_device_node->type) */
4459 } /* if (device_tuple) */
4462 * Initialize the JEDEC information.
4463 * XXX - need to find out what
4464 * reasonable default values are
4466 mrr->id = 0;
4467 mrr->info = 0;
4469 mrr->next = NULL;
4471 } /* for (cistpl_device_node->num_devices) */
4473 } while ((ret = csx_GetNextTuple(rs->client_handle, &tuple))
4474 == CS_SUCCESS);
4477 * If GetNextTuple gave us any error code other than
4478 * CS_NO_MORE_ITEMS, it means that there is probably
4479 * an internal error in the CIS parser.
4481 if (ret != CS_NO_MORE_ITEMS) {
4482 return (-1); /* this is a real error */
4483 /* NOTREACHED */
4487 * Now that we've built the region list, search for the
4488 * first JEDEC tuple - if it's not found, that's not
4489 * necessarily an error.
4491 tuple.Attributes = 0;
4492 tuple.DesiredTuple = JEDEC_tuple;
4493 if ((ret = csx_GetFirstTuple(rs->client_handle, &tuple))
4494 != CS_SUCCESS) {
4495 if (ret != CS_NO_MORE_ITEMS) {
4496 /* this is a real error */
4497 return (-1);
4498 /* NOTREACHED */
4499 } else {
4500 return (region_num);
4501 /* NOTREACHED */
4506 * Got the JEDEC tuple, now parse it.
4507 * We will always get here with a non-NULL
4508 * region list pointer.
4510 mr = *rlist; /* point to head of region list */
4512 do {
4513 cistpl_jedec_t cistpl_jedec;
4514 int i;
4517 * We shouldn't ever fail parsing this tuple.
4518 * If we do, there's probably an internal
4519 * error in the CIS parser.
4521 bzero(&cistpl_jedec, sizeof (struct cistpl_jedec_t));
4522 if (csx_Parse_CISTPL_JEDEC_C(rs->client_handle,
4523 &tuple, &cistpl_jedec) != CS_SUCCESS) {
4524 return (-1);
4525 /* NOTREACHED */
4529 * We should see at least one region definition.
4530 * It is definately an error if we don't see any.
4532 if (!cistpl_jedec.nid) {
4533 return (-1);
4534 /* NOTREACHED */
4537 for (i = 0; i < cistpl_jedec.nid; i++) {
4539 * Check the region list pointer;
4540 * if this pointer is NULL, it means
4541 * that we either have an internal
4542 * code error in the way we process
4543 * the device tuples or that the card
4544 * has more JEDEC identifiers than device
4545 * tuple device node entries. We still
4546 * return the number of regions
4547 * found, since this may or may not
4548 * be a serious error.
4550 if (!mr) {
4551 cmn_err(CE_CONT,
4552 "pcram_build_region_list: socket %d"
4553 "too many JEDEC device entries"
4554 "in %s memory list\n",
4555 rs->sn, (flags & BUILD_AM_LIST)?
4556 "ATTRIBUTE":"COMMON");
4557 return (region_num);
4558 /* NOTREACHED */
4561 mr->id = cistpl_jedec.jid[i].id;
4562 mr->info = cistpl_jedec.jid[i].info;
4565 * Point to the next region in the list.
4567 mr = mr->next;
4569 } /* for (cistpl_jedec.nid) */
4571 } while ((ret = csx_GetNextTuple(rs->client_handle,
4572 &tuple)) == CS_SUCCESS);
4575 * If GetNextTuple gave us any error code other than
4576 * CS_NO_MORE_ITEMS, it means that there is probably
4577 * an internal error in the CIS parser.
4579 if (ret != CS_NO_MORE_ITEMS) {
4580 return (-1); /* this is a real error */
4581 /* NOTREACHED */
4585 * Return the number of region entries in this list.
4587 return (region_num);
4588 /* NOTREACHED */
4594 * pcram_get_bpbfat_info - scan the CM area looking for an
4595 * MS-DOS BPB-FAT filesystem.
4597 * calling: rs - pointer to caller's state structure
4598 * mr - pointer to memory region to fill in
4599 * if BPB found
4601 * returns: 0 - if BPB-FAT not found
4602 * 1 - if BPB-FAT found; the mem_region_t struct
4603 * will be initialized with the correct values
4605 static int
4606 pcram_get_bpbfat_info(pcram_state_t *rs, mem_region_t *mr)
4609 int tsecvol;
4610 struct bootblock bootblk;
4614 * If there is a BPB-FAT filesystem on the device return 1.
4615 * If there isn't, then just return a 0.
4619 * If there is a way to determine from the BPB-FAT if the
4620 * filesystem is read only, you should set the REGION_READONLY
4621 * flag in the mr->rflags member.
4622 * mr->rflags = (REGION_DOS_BPBFAT | REGION_VALID);
4626 * Note here about the device type - I don't know what
4627 * type to put in here, since it's possible to have a
4628 * BPB-FAT filesystem on a Flash or EEPROM card. You might
4629 * consider doing some sort of testing to see if you can
4630 * determine what type of device is actually in common
4631 * memory.
4632 * I think that you can interrogate many Flash and EEPROM
4633 * devices and they will return their manufacturer and
4634 * device code, or maybe a JEDEC code. Ask Chuck about
4635 * this too. If you can find out that the CM area that
4636 * has the DOS filesystem on it is something other than
4637 * SRAM, you can set the REGION_READONLY flag in
4638 * mr->rflags and possibily also the correct device type
4639 * in the mr->type member.
4641 * mr->type = XXX;
4645 * Fill this in with the size of the region after you get this
4646 * information from the BPB-FAT header.
4648 * mr->size_in_bytes = XXX;
4651 mr->rflags = REGION_DOS_BPBFAT;
4652 mr->type = CISTPL_DEVICE_DTYPE_SRAM;
4654 csx_RepGet8(rs->access_handle, (uchar_t *)&bootblk, (uint32_t)0,
4655 sizeof (struct bootblock), DDI_DEV_AUTOINCR);
4657 if (bootblk.sig[0] == DOS_ID1 ||
4658 (bootblk.sig[0] == DOS_ID2a &&
4659 bootblk.sig[2] == DOS_ID2b)) {
4661 rs->hdrv_chars->drv_sec_size =
4662 GET_INFO(bootblk.bps[0], bootblk.bps[1]);
4663 rs->hdrv_chars->drv_secptrack =
4664 GET_INFO(bootblk.sectrack[0],
4665 bootblk.sectrack[1]);
4666 rs->hdrv_chars->drv_nhead =
4667 GET_INFO(bootblk.heads[0], bootblk.heads[1]);
4669 tsecvol = GET_INFO(bootblk.tsec[0], bootblk.tsec[1]);
4671 rs->card_size = GET_CSIZ_DOS(tsecvol,
4672 rs->hdrv_chars->drv_sec_size);
4674 /* Return error if found invalid DOS label */
4675 /* Avoiding zero divide panic when compute drv_ncyl */
4676 if ((rs->card_size == 0) ||
4677 (rs->hdrv_chars->drv_sec_size == 0) ||
4678 (rs->hdrv_chars->drv_secptrack == 0) ||
4679 (rs->hdrv_chars->drv_nhead == 0)) {
4681 /* set to default default size of 64MB */
4682 *rs->hdrv_chars = hdtypes;
4683 rs->card_size = MAX_CARD_SIZE;
4684 cmn_err(CE_WARN, "pcram: socket%d "
4685 "Found invalid DOS label", rs->sn);
4686 return (0);
4687 /* NOTREACHED */
4690 rs->hdrv_chars->drv_ncyl = GET_NCYL(rs->card_size,
4691 rs->hdrv_chars->drv_nhead,
4692 rs->hdrv_chars->drv_sec_size,
4693 rs->hdrv_chars->drv_secptrack);
4695 mr->size_in_bytes = rs->card_size;
4697 #ifdef PCRAM_DEBUG
4698 if (pcram_debug & PCRAM_DEBUG_CIS) {
4699 cmn_err(CE_CONT, "pcram_get_bpbfat_info: socket %d \n"
4700 "\trs->card_size [%d] mr->size_in_bytes [%d]\n",
4701 rs->sn, rs->card_size, (int)mr->size_in_bytes);
4703 #endif
4704 return (1);
4705 /* NOTREACHED */
4708 /* Found NO DOS BPBFAT */
4709 return (0);
4710 /* NOTREACHED */
4716 * pcram_get_solaris_info - scan the CM area looking for an
4717 * Solaris partition filesystem.
4719 * calling: rs - pointer to caller's state structure
4720 * mr - pointer to memory region to fill in
4721 * if BPB found
4723 * returns: 0 - if Solaris VTOC not found
4724 * 1 - if Solaris VTOC found; the mem_region_t struct
4725 * will be initialized with the correct values
4727 static int
4728 pcram_get_solaris_info(pcram_state_t *rs, mem_region_t *mr)
4730 struct dk_label label;
4733 #ifdef USE_REGION_VALID
4734 mr->rflags = (REGION_SOLARIS | REGION_VALID);
4735 #endif
4737 mr->rflags = REGION_SOLARIS;
4738 mr->type = CISTPL_DEVICE_DTYPE_SRAM;
4740 csx_RepGet8(rs->access_handle, (uchar_t *)&label, (uint32_t)0,
4741 sizeof (struct dk_label), DDI_DEV_AUTOINCR);
4743 if ((label.dkl_magic == DKL_MAGIC) && (cksum(&label) == 0)) {
4745 * If there is no CIS, try to read dk_label
4746 * to get card size information
4748 rs->hdrv_chars->drv_sec_size = 512;
4749 rs->hdrv_chars->drv_secptrack = label.dkl_nsect;
4750 rs->hdrv_chars->drv_nhead = label.dkl_nhead;
4751 rs->hdrv_chars->drv_ncyl = label.dkl_pcyl;
4753 rs->card_size = GET_CSIZ(rs->hdrv_chars->drv_ncyl,
4754 rs->hdrv_chars->drv_nhead,
4755 rs->hdrv_chars->drv_sec_size,
4756 rs->hdrv_chars->drv_secptrack);
4758 /* Return error if found invalid SunOS label */
4759 if (rs->card_size == 0) {
4760 /* set to default default size of 64MB */
4761 *rs->hdrv_chars = hdtypes;
4762 rs->card_size = MAX_CARD_SIZE;
4763 cmn_err(CE_WARN, "pcram: socket%d "
4764 "Found invalid SunOS label", rs->sn);
4765 return (0);
4766 /* NOTREACHED */
4769 mr->size_in_bytes = rs->card_size;
4771 #ifdef PCRAM_DEBUG
4772 if (pcram_debug & PCRAM_DEBUG_CIS) {
4773 cmn_err(CE_CONT, "pcram_get_solaris_info: socket %d \n"
4774 "\trs->card_size [%d] mr->size_in_bytes [%d]\n",
4775 rs->sn, rs->card_size, (int)mr->size_in_bytes);
4777 #endif
4779 return (1);
4780 /* NOTREACHED */
4783 /* Found no Solaris partition */
4784 return (0);
4785 /* NOTREACHED */
4791 * pcram_destroy_region_lists - destroys all memory region lists
4792 * on the caller's state structure
4794 * calling: rs - pointer to caller's state structure
4796 static void
4797 pcram_destroy_region_lists(pcram_state_t *rs)
4801 pcram_destroy_region_list(&rs->am_regions,
4802 &rs->num_am_regions);
4804 pcram_destroy_region_list(&rs->cm_regions,
4805 &rs->num_cm_regions);
4810 * pcram_destroy_region_list - destroys the region list pointed
4811 * to be the rlist pointer
4813 * Note: when we return, the region list pointer is set to NULL,
4814 * and the region count is set to zero;
4816 static void
4817 pcram_destroy_region_list(mem_region_t **rlist, int *num)
4819 mem_region_t *mr, *mrr;
4822 if ((mr = *rlist) == 0) {
4823 return;
4824 /* NOTREACHED */
4827 do {
4828 mrr = mr->next;
4829 kmem_free(mr, sizeof (mem_region_t));
4830 /* LINTED */
4831 } while (mr = mrr);
4833 *rlist = NULL;
4834 *num = 0;
4839 * pcram_get_firstnext_region - returns memory region pointer for
4840 * passed region type
4842 static mem_region_t *
4843 pcram_get_firstnext_region(mem_region_t *mrp, uint32_t flags,
4844 uint32_t type, uint32_t *first)
4847 if (!mrp) {
4848 return (NULL);
4849 /* NOTREACHED */
4852 if (*first) {
4853 *first = 0;
4855 do {
4856 if (((mrp->rflags & flags) == flags) &&
4857 (mrp->type == type)) {
4858 return (mrp);
4859 /* NOTREACHED */
4861 /* LINTED */
4862 } while (mrp = mrp->next);
4863 } else {
4865 * This is a get next function.
4867 /* LINTED */
4868 while (mrp = mrp->next) {
4869 if (((mrp->rflags & flags) == flags) &&
4870 (mrp->type == type)) {
4871 return (mrp);
4872 /* NOTREACHED */
4877 return (NULL);
4878 /* NOTREACHED */
4882 static void
4883 update_hdrv_chars(pcram_state_t *rs, mem_region_t *mrp)
4887 mutex_enter(&rs->mutex);
4888 *rs->hdrv_chars = hdtypes;
4889 rs->card_size = mrp->size_in_bytes;
4892 * XXX - check for non-zero of drv_nhead, drv_secptrack,
4893 * drv_sec_size to avoid zero divide panic
4895 rs->hdrv_chars->drv_ncyl = GET_NCYL(rs->card_size,
4896 rs->hdrv_chars->drv_nhead,
4897 rs->hdrv_chars->drv_sec_size,
4898 rs->hdrv_chars->drv_secptrack);
4899 mutex_exit(&rs->mutex);
4904 #ifdef DEBUG
4905 static void
4906 pcram_debug_report_event(pcram_state_t *pcram, event_t event, int priority)
4908 char *event_priority;
4909 char *event_text;
4910 char buf[64];
4912 event_priority = (priority & CS_EVENT_PRI_HIGH) ? "high" : "low";
4914 switch (event) {
4915 case CS_EVENT_REGISTRATION_COMPLETE:
4916 event_text = "Registration Complete";
4917 break;
4918 case CS_EVENT_PM_RESUME:
4919 event_text = "Power Management Resume";
4920 break;
4921 case CS_EVENT_CARD_INSERTION:
4922 event_text = "Card Insertion";
4923 break;
4924 case CS_EVENT_CARD_READY:
4925 event_text = "Card Ready";
4926 break;
4927 case CS_EVENT_BATTERY_LOW:
4928 event_text = "Battery Low";
4929 break;
4930 case CS_EVENT_BATTERY_DEAD:
4931 event_text = "Battery Dead";
4932 break;
4933 case CS_EVENT_CARD_LOCK:
4934 event_text = "Card Lock";
4935 break;
4936 case CS_EVENT_PM_SUSPEND:
4937 event_text = "Power Management Suspend";
4938 break;
4939 case CS_EVENT_CARD_RESET:
4940 event_text = "Card Reset";
4941 break;
4942 case CS_EVENT_CARD_UNLOCK:
4943 event_text = "Card Unlock";
4944 break;
4945 case CS_EVENT_EJECTION_COMPLETE:
4946 event_text = "Ejection Complete";
4947 break;
4948 case CS_EVENT_EJECTION_REQUEST:
4949 event_text = "Ejection Request";
4950 break;
4951 case CS_EVENT_ERASE_COMPLETE:
4952 event_text = "Erase Complete";
4953 break;
4954 case CS_EVENT_EXCLUSIVE_COMPLETE:
4955 event_text = "Exclusive Complete";
4956 break;
4957 case CS_EVENT_EXCLUSIVE_REQUEST:
4958 event_text = "Exclusive Request";
4959 break;
4960 case CS_EVENT_INSERTION_COMPLETE:
4961 event_text = "Insertion Complete";
4962 break;
4963 case CS_EVENT_INSERTION_REQUEST:
4964 event_text = "Insertion Request";
4965 break;
4966 case CS_EVENT_RESET_COMPLETE:
4967 event_text = "Reset Complete";
4968 break;
4969 case CS_EVENT_RESET_PHYSICAL:
4970 event_text = "Reset Physical";
4971 break;
4972 case CS_EVENT_RESET_REQUEST:
4973 event_text = "Reset Request";
4974 break;
4975 case CS_EVENT_MTD_REQUEST:
4976 event_text = "MTD Request";
4977 break;
4978 case CS_EVENT_CLIENT_INFO:
4979 event_text = "Client Info";
4980 break;
4981 case CS_EVENT_TIMER_EXPIRED:
4982 event_text = "Timer Expired";
4983 break;
4984 case CS_EVENT_WRITE_PROTECT:
4985 event_text = "Write Protect";
4986 break;
4987 case CS_EVENT_SS_UPDATED:
4988 event_text = "SS Updated";
4989 break;
4990 case CS_EVENT_STATUS_CHANGE:
4991 event_text = "Status Change";
4992 break;
4993 case CS_EVENT_CARD_REMOVAL:
4994 event_text = "Card Removal";
4995 break;
4996 case CS_EVENT_CARD_REMOVAL_LOWP:
4997 event_text = "Card Removal Low Power";
4998 break;
4999 default:
5000 event_text = buf;
5001 (void) sprintf(buf, "Unknown Event (0x%x)", event);
5002 break;
5005 cmn_err(CE_CONT,
5006 "pcram%d [socket %d]: %s (%s priority)\n",
5007 ddi_get_instance(pcram->dip), pcram->sn,
5008 event_text, event_priority);
5010 #endif