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]
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
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)
42 * The PCMCIA memory cards can be used as pseudo-floppy disks.
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.
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>
77 #include <sys/errno.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
93 /* supporting eject(1) command (struct fd_drive) */
96 /* The next headers may not be DDI-compliant */
98 #include <sys/dklabel.h> /* logical partitions */
102 #include <sys/fs/pc_label.h>
105 * PCMCIA and DDI related header files
107 #include <sys/pccard.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
,
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
);
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 *);
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
,
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 */
184 pcram_read
, /* read */
185 pcram_write
, /* write */
186 pcram_ioctl
, /* ioctl */
189 ddi_segmap
, /* segmap */
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 */
201 pcram_getinfo
, /* info */
202 nulldev
, /* identify */
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 */
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
= {
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.
273 if (pcram_debug
& PCRAM_DEBUG_TRACE
)
274 cmn_err(CE_CONT
, "pcram_init here\n");
277 error
= ddi_soft_state_init(&pcram_soft_state_p
,
278 sizeof (pcram_state_t
),
284 error
= mod_install(&modlinkage
);
286 ddi_soft_state_fini(&pcram_soft_state_p
);
294 _info(struct modinfo
*modinfop
)
298 if (pcram_debug
& PCRAM_DEBUG_TRACE
)
299 cmn_err(CE_CONT
, "pcram_info here\n");
302 return (mod_info(&modlinkage
, modinfop
));
311 if (pcram_debug
& PCRAM_DEBUG_TRACE
)
312 cmn_err(CE_CONT
, "pcram_fini here\n");
315 error
= mod_remove(&modlinkage
);
318 ddi_soft_state_fini(&pcram_soft_state_p
);
325 * Autoconfiguration Routines
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.
339 pcram_minor_wait(pcram_state_t
*rs
)
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)
350 mutex_exit(&rs
->event_hilock
);
355 * pcram_attach() - performs board initialization
357 * This routine initializes the PCMCIA memory card driver
360 * Returns: DDI_SUCCESS, if able to attach.
361 * DDI_FAILURE, if unable to attach.
364 pcram_attach(dev_info_t
*dip
, ddi_attach_cmd_t cmd
)
368 /* CardServices variables */
369 client_reg_t client_reg
;
372 map_log_socket_t map_log_socket
;
373 get_status_t get_status
;
376 instance
= ddi_get_instance(dip
);
379 if (pcram_debug
& PCRAM_DEBUG_TRACE
)
381 "pcram_attach: instance %d cmd 0x%x\n",
385 /* resume from a checkpoint */
386 if (cmd
== DDI_RESUME
) {
387 return (DDI_SUCCESS
);
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
);
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
);
410 rs
= ddi_get_soft_state(pcram_soft_state_p
, instance
);
412 cmn_err(CE_NOTE
, "pcram_attach: could not get "
413 "state structure for instance %d.",
419 /* Remember dev_info structure for getinfo */
421 rs
->instance
= instance
;
422 ddi_set_driver_private(dip
, rs
);
425 * clear the per-unit flags field
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.
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
);
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;
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",
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",
498 rs
->flags
|= PCRAM_SOFTINTROK
;
501 if (pcram_debug
& PCRAM_DEBUG_TRACE
) {
502 cmn_err(CE_CONT
, "pcram_attach: "
503 "calling RegisterClient for instance %d\n",
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
|
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
) {
531 (void) csx_Error2Text(&cft
);
532 cmn_err(CE_CONT
, "pcram_attach: "
533 "RegisterClient failed %s (0x%x)\n",
538 rs
->flags
|= PCRAM_REGCLIENT
;
541 if (pcram_debug
& PCRAM_DEBUG_TRACE
) {
542 cmn_err(CE_CONT
, "pcram_attach: "
543 "RegisterClient client_handle 0x%x\n",
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
) {
554 (void) csx_Error2Text(&cft
);
556 cmn_err(CE_CONT
, "pcram_attach: "
557 "MapLogSocket failed %s (0x%x)\n",
561 rs
->sn
= map_log_socket
.PhySocket
;
564 if (pcram_debug
& PCRAM_DEBUG_TRACE
) {
565 cmn_err(CE_CONT
, "pcram_attach: "
566 "MapLogSocket for socket %d\n", rs
->sn
);
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
) {
607 (void) csx_Error2Text(&cft
);
609 cmn_err(CE_CONT
, "pcram_attach: RequestSocketMask "
610 "failed %s (0x%x)\n", cft
.text
, ret
);
614 rs
->flags
|= PCRAM_REQSOCKMASK
;
617 if (pcram_debug
& PCRAM_DEBUG_TRACE
)
619 "pcram_attach: RequestSocketMask OK\n");
623 * Wait for minor node creation before continuing
625 pcram_minor_wait(rs
);
626 if ((rs
->flags
& PCRAM_MAKEDEVICENODE
) == 0) {
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
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
);
644 if (!PCRAM_CARD_PRESENT(rs
)) {
645 cmn_err(CE_CONT
, "pcram_attach:Card not found\n");
647 cmn_err(CE_CONT
, "pcram_attach:Card found\n");
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
);
667 (void) pcram_detach(dip
, DDI_DETACH
);
668 return (DDI_FAILURE
);
673 pcram_detach(dev_info_t
*dip
, ddi_detach_cmd_t cmd
)
679 instance
= ddi_get_instance(dip
);
682 if (pcram_debug
& PCRAM_DEBUG_TRACE
)
684 "pcram_detach: instance %d cmd 0x%x\n",
689 if (cmd
== DDI_SUSPEND
) {
690 return (DDI_SUCCESS
);
694 if (cmd
!= DDI_DETACH
) {
695 return (DDI_FAILURE
);
699 rs
= ddi_get_soft_state(pcram_soft_state_p
, instance
);
701 cmn_err(CE_NOTE
, "pcram_detach: "
702 "could not get state structure "
703 "for instance %d.", instance
);
704 return (DDI_FAILURE
);
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
726 if (rs
->flags
& PCRAM_REQSOCKMASK
) {
727 release_socket_mask_t rsm
;
728 if ((ret
= csx_ReleaseSocketMask(rs
->client_handle
, &rsm
))
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
))
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
);
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 */
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.
809 pcram_getinfo(dev_info_t
*dip
, ddi_info_cmd_t cmd
, void *arg
,
812 int error
= DDI_SUCCESS
;
814 cs_ddi_info_t cs_ddi_info
;
819 case DDI_INFO_DEVT2DEVINFO
:
820 case DDI_INFO_DEVT2INSTANCE
:
821 cs_ddi_info
.Socket
= PCRAM_SOCKET((dev_t
)arg
);
824 if (pcram_debug
& PCRAM_DEBUG_TRACE
)
825 cmn_err(CE_CONT
, "pcram_getinfo: socket %d\n",
829 cs_ddi_info
.driver_name
= pcram_name
;
830 if (csx_CS_DDI_Info(&cs_ddi_info
) != CS_SUCCESS
) {
831 return (DDI_FAILURE
);
836 case DDI_INFO_DEVT2DEVINFO
:
837 if (!(rs
= ddi_get_soft_state(
839 cs_ddi_info
.instance
))) {
846 case DDI_INFO_DEVT2INSTANCE
:
847 *result
= (void *)(uintptr_t)cs_ddi_info
.instance
;
862 pcram_getinstance(dev_t devp
)
865 cs_ddi_info_t ddi_info
;
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
) {
872 (void) csx_Error2Text(&cft
);
874 "pcram[%d]: csx_CS_DDI_Info failed - %s\n",
875 PCRAM_SOCKET(devp
), cft
.text
);
879 return (ddi_info
.instance
);
884 * User context (system call request)
886 * Character Driver/Block Drivers:
893 * Unique to character drivers:
898 * xxxxx_segmap() ( ddi_segmap )
899 * xxxxx_chpoll() ( nochpoll )
903 pcram_open(dev_t
*devp
, int flag
, int otyp
, cred_t
*cred
)
908 get_status_t get_status
;
910 /* get instance number */
911 if ((instance
= pcram_getinstance(*devp
)) == -1) {
913 "pcram_open: pcram_getinfo failed\n");
917 rs
= ddi_get_soft_state(pcram_soft_state_p
, instance
);
919 cmn_err(CE_NOTE
, "pcram_open: "
920 "could not get state for instance %d\n",
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
);
931 mutex_enter(&rs
->mutex
);
933 if (!(rs
->flags
& PCRAM_ATTACHOK
)) {
934 mutex_exit(&rs
->mutex
);
940 * Do a CS call to see if the card is present
942 if ((err
= csx_GetStatus(rs
->client_handle
, &get_status
))
946 mutex_exit(&rs
->mutex
);
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
);
959 if (pcram_debug
& PCRAM_DEBUG_CARD_STATUS
) {
961 "pcram_open: socket %d GetStatus returns:\n",
963 pcram_display_card_status(&get_status
);
968 * Check to see if the card is present.
969 * If there is no card in the socket,
972 if (!(get_status
.CardState
& CS_EVENT_CARD_INSERTION
)) {
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
);
981 mutex_exit(&rs
->mutex
);
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
++;
995 mutex_exit(&rs
->mutex
);
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
);
1021 * Only honor FEXCL. If a regular open or a layered open
1022 * is still outstanding on the device, the exclusive open
1025 if ((flag
& FEXCL
) && (rs
->blk_open
|| rs
->chr_open
||
1027 mutex_exit(&rs
->mutex
);
1047 mutex_exit(&rs
->mutex
);
1053 if (pcram_debug
& PCRAM_DEBUG_TRACE
) {
1054 cmn_err(CE_CONT
, "pcram_open: default_size_flag=%d \n",
1055 rs
->default_size_flag
);
1061 * For cards without attribute memory, probe the card to
1062 * determine the memory size.
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;
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
1092 cmn_err(CE_NOTE
, "pcram: socket %d - "
1093 "Unregconized PCMCIA Static RAM media",
1098 mutex_exit(&rs
->mutex
);
1106 pcram_close(dev_t dev
, int flag
, int otyp
, cred_t
*cred
)
1111 if ((instance
= pcram_getinstance(dev
)) == -1) {
1113 "pcram_close: pcram_getinfo failed\n");
1117 rs
= ddi_get_soft_state(pcram_soft_state_p
, instance
);
1119 cmn_err(CE_NOTE
, "pcram_close: "
1120 "could not get state for instance %d\n",
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
);
1132 mutex_enter(&rs
->mutex
);
1149 mutex_exit(&rs
->mutex
);
1154 if (rs
->blk_open
|| rs
->chr_open
|| rs
->nlayered
) {
1156 mutex_exit(&rs
->mutex
);
1162 * Continueing to return EIO if the card is ejected
1163 * while it is mounted until the LAST layered close
1166 if (rs
->nlayered
== 0) {
1168 if (pcram_debug
& PCRAM_DEBUG_TRACE
) {
1169 cmn_err(CE_CONT
, "pcram_close: "
1170 "Reset ejected_while_mounting flag\n");
1173 rs
->ejected_while_mounting
= 0;
1176 mutex_exit(&rs
->mutex
);
1183 pcram_print(dev_t dev
, char *str
)
1189 if ((instance
= pcram_getinstance(dev
)) == -1) {
1191 "pcram_print: pcram_getinfo failed\n");
1195 rs
= ddi_get_soft_state(pcram_soft_state_p
, instance
);
1197 cmn_err(CE_NOTE
, "pcram_print: "
1198 "could not get state for instance %d.", instance
);
1203 cmn_err(CE_NOTE
, "pcram_print: socket %d %s", rs
->sn
, str
);
1210 * Character driver routines
1216 pcram_read(dev_t dev
, struct uio
*uiop
, cred_t
*credp
)
1221 int offset
, next_offset
;
1222 int remainder_wsize
;
1226 get_status_t get_status
;
1228 if ((instance
= pcram_getinstance(dev
)) == -1) {
1230 "pcram_read: pcram_getinfo failed\n");
1234 rs
= ddi_get_soft_state(pcram_soft_state_p
, instance
);
1236 cmn_err(CE_NOTE
, "pcram_read: "
1237 "could not get state for instance %d.",
1244 if (pcram_debug
& PCRAM_DEBUG_TRACE
)
1245 cmn_err(CE_CONT
, "pcram_read: socket %d\n", rs
->sn
);
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
) {
1257 mutex_exit(&rs
->mutex
);
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
);
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
);
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
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",
1298 mutex_exit(&rs
->mutex
);
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
);
1316 mutex_exit(&rs
->mutex
);
1318 if (uiop
->uio_offset
>= rs
->card_size
) {
1323 offset
= uiop
->uio_offset
;
1324 nbytes
= min(uiop
->uio_resid
, rs
->card_size
- uiop
->uio_offset
);
1326 while (nbytes
> 0) {
1329 next_offset
= update_mapmempage(rs
, offset
);
1330 if (next_offset
< 0) {
1331 /* something wrong with MapMemPage function */
1336 remainder_wsize
= offset
% rs
->win_size
;
1337 copybytes
= min(rs
->win_size
- remainder_wsize
, nbytes
);
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
);
1351 if (PCRAM_CARD_PRESENT(rs
)) {
1353 * Transfer block in between the two windows
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
1371 pbuf
= kmem_zalloc(copybytes
, KM_SLEEP
);
1373 /* Card access handle */
1375 /* base dest addr */
1377 /* card window offset */
1378 (uint32_t)remainder_wsize
,
1379 /* num_bytes xfer */
1383 error
= uiomove((caddr_t
)pbuf
,
1384 copybytes
, UIO_READ
, uiop
);
1386 /* now free csbuf */
1387 kmem_free(pbuf
, copybytes
);
1394 nbytes
-= copybytes
;
1395 offset
+= copybytes
;
1398 * stop to read the card when
1399 * there is a card removal event
1409 mutex_enter(&rs
->mutex
);
1411 * End of read operation, release the
1412 * cv_wait() for the next thread
1415 cv_signal(&rs
->condvar_rd
);
1416 mutex_exit(&rs
->mutex
);
1424 pcram_write(dev_t dev
, struct uio
*uiop
, cred_t
*credp
)
1433 get_status_t get_status
;
1436 if ((instance
= pcram_getinstance(dev
)) == -1) {
1438 "pcram_write: pcram_getinfo failed\n");
1442 rs
= ddi_get_soft_state(pcram_soft_state_p
, instance
);
1444 cmn_err(CE_NOTE
, "pcram_write: "
1445 "could not get state for instance %d.",
1452 if (pcram_debug
& PCRAM_DEBUG_TRACE
)
1453 cmn_err(CE_CONT
, "pcram_write: socket %d\n", rs
->sn
);
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
))
1465 mutex_exit(&rs
->mutex
);
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
);
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
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",
1499 mutex_exit(&rs
->mutex
);
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
);
1517 mutex_exit(&rs
->mutex
);
1519 if (uiop
->uio_offset
>= rs
->card_size
) {
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) {
1536 int remainder_wsize
;
1539 next_offset
= update_mapmempage(rs
, offset
);
1540 if (next_offset
< 0) {
1541 /* something wrong with MapMemPage function */
1546 remainder_wsize
= offset
% rs
->win_size
;
1547 copybytes
= min(rs
->win_size
- remainder_wsize
, nbytes
);
1548 copybytes
= min(copybytes
, HOST_BUF_SIZE
);
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
);
1562 if (PCRAM_CARD_PRESENT(rs
)) {
1564 * Transfer block size is in between
1567 error
= uiomove(rs
->host_sp
, copybytes
,
1574 mutex_enter(&rs
->mutex
);
1575 card_byte_wr(rs
, copybytes
, remainder_wsize
);
1576 mutex_exit(&rs
->mutex
);
1578 nbytes
-= copybytes
;
1579 offset
+= copybytes
;
1582 * stop to write to the card when
1583 * there is a card removal event
1593 mutex_enter(&rs
->mutex
);
1595 * End of write operation, release the
1596 * cv_wait() for the next thread
1599 cv_signal(&rs
->condvar_wr
);
1600 mutex_exit(&rs
->mutex
);
1610 pcram_ioctl(dev_t dev
, int cmd
, intptr_t arg
, int mode
, cred_t
*credp
,
1618 struct dk_geom dkg
; /* disk geometry */
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
];
1625 enum dkio_state state
;
1626 get_status_t get_status
;
1629 if ((instance
= pcram_getinstance(dev
)) == -1) {
1631 "pcram_ioctl: pcram_getinfo failed\n");
1635 rs
= ddi_get_soft_state(pcram_soft_state_p
, instance
);
1637 cmn_err(CE_NOTE
, "pcram_ioctl: "
1638 "could not get state for instance %d.",
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
);
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
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
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) {
1691 * Return error when we can not find
1692 * the actual card size.
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
;
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
))
1725 case DDI_MODEL_NONE
:
1726 if (ddi_copyout(&vtoc
, (void *)arg
,
1727 sizeof (struct vtoc
), mode
))
1731 #else /* ! _MULTI_DATAMODEL */
1732 if (ddi_copyout(&vtoc
, (void *)arg
,
1733 sizeof (struct vtoc
), mode
) != 0)
1736 #endif /* _MULTI_DATAMODEL */
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) {
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
))
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
))
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
))
1819 #endif /* _MULTI_DATAMODEL */
1823 if (ddi_copyin((void *)arg
, &state
, sizeof (int), mode
)) {
1829 * This function is used by the volume management
1830 * to check the memory card state
1832 if (err
= pcram_check_media(rs
, state
)) {
1837 if (ddi_copyout(&rs
->media_state
, (void *)arg
,
1838 sizeof (int), mode
)) {
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
))
1859 vtoc32tovtoc(vtoc32
, vtoc
);
1863 case DDI_MODEL_NONE
:
1864 if (ddi_copyin((void *)arg
, &vtoc
,
1865 sizeof (struct vtoc
), mode
))
1869 #else /* _MULTI_DATAMODEL */
1870 if (ddi_copyin((void *)arg
, &vtoc
, sizeof (struct vtoc
), mode
))
1873 #endif /* _MULTI_DATAMODEL */
1875 if ((err
= pcram_build_label_vtoc(rs
, &vtoc
)) != 0) {
1880 pcram_write_label(rs
);
1884 case DKIOCREMOVABLE
:
1886 * Supporting volmgt by returning a constant
1887 * since PCMCIA is a removable media.
1888 * Refer to PSARC/1996/004.
1891 if (ddi_copyout(&i
, (void *)arg
, sizeof (int), mode
)) {
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) {
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
1930 if (!rs
->default_size_flag
) {
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
);
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) {
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
))
1966 mutex_exit(&rs
->mutex
);
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
);
1976 if (get_status
.CardState
& CS_EVENT_WRITE_PROTECT
) {
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;
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
1998 cmn_err(CE_NOTE
, "pcram: socket %d - "
1999 "Unregconized PCMCIA Static RAM media",
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) {
2020 case FDGETDRIVECHAR
:
2021 /* supporting eject(1) command */
2022 if (ddi_copyin((void *)arg
, &drvchar
,
2023 sizeof (struct fd_drive
), mode
)) {
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
)) {
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
)) {
2053 if ((err
= csx_GetStatus(rs
->client_handle
, &get_status
))
2057 mutex_exit(&rs
->mutex
);
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
);
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
) {
2077 * floppy is write protected
2079 fdchange
|= FDGC_CURWPROT
;
2083 * floppy is NOT write protected
2085 fdchange
&= ~FDGC_CURWPROT
;
2088 /* Simulating - floppy is NOT present */
2089 fdchange
|= FDGC_CURRENT
;
2092 if (ddi_copyout(&fdchange
, (void *)arg
, sizeof (int), mode
)) {
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
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
)
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
));
2136 if ((instance
= pcram_getinstance(dev
)) == -1) {
2137 cmn_err(CE_NOTE
, "pcram_prop_op: "
2138 "pcram_getinfo failed\n");
2142 rs
= ddi_get_soft_state(pcram_soft_state_p
, instance
);
2144 cmn_err(CE_NOTE
, "pcram_prop_op: "
2145 "no state for instance %d", instance
);
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
2163 pcram_strategy(struct buf
*bp
)
2167 int offset
= bp
->b_blkno
* DEV_BSIZE
;
2169 get_status_t get_status
;
2172 if ((instance
= pcram_getinstance(bp
->b_edev
)) == -1) {
2174 "pcram_strategy: pcram_getinfo failed\n");
2179 rs
= ddi_get_soft_state(pcram_soft_state_p
, instance
);
2181 cmn_err(CE_NOTE
, "pcram_strategy: "
2182 "could not get state for instance %d.",
2189 if (pcram_debug
& PCRAM_DEBUG_TRACE
)
2190 cmn_err(CE_CONT
, "pcram_strategy: socket %d\n", rs
->sn
);
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
))
2200 mutex_exit(&rs
->mutex
);
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
);
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
);
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
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",
2238 mutex_exit(&rs
->mutex
);
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
);
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
2261 if (offset
>= rs
->card_size
) {
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
);
2282 if (rs
->blist
->av_forw
== NULL
) {
2283 /* nothing on queue */
2286 rs
->blist
->av_forw
= bp
;
2287 rs
->blist
->av_back
= bp
;
2291 /* put on work list */
2293 rs
->blist
->av_back
->av_forw
= bp
;
2294 rs
->blist
->av_back
= bp
;
2296 cv_signal(&rs
->condvar
);
2299 mutex_exit(&rs
->mutex
);
2304 bp
->b_resid
= bp
->b_bcount
;
2312 pcram_start(pcram_state_t
*rs
)
2316 int nbytes
, origbytes
;
2318 int remainder_wsize
;
2324 if (pcram_debug
& PCRAM_DEBUG_TRACE
)
2325 cmn_err(CE_CONT
, "pcram_start: socket %d\n", rs
->sn
);
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) {
2337 next_offset
= update_mapmempage(rs
, offset
);
2338 if (next_offset
< 0) {
2339 /* something failed so abort */
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
);
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",
2357 (bp
->b_flags
& B_READ
) ?
2359 offset
, (int)rs
->win_size
,
2360 nbytes
, remainder_wsize
);
2365 if (bp
->b_flags
& B_READ
) {
2366 /* Read direct from PC Card memory */
2367 csx_RepGet8(/* Card access handle */
2369 /* base dest addr */
2370 (uchar_t
*)buf_addr
,
2371 /* card window offset */
2372 (uint32_t)remainder_wsize
,
2373 /* num_bytes xfer */
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 */
2405 } /* while (nbytes) */
2407 bp
->b_resid
= bp
->b_bcount
- origbytes
;
2409 ddi_trigger_softintr(rs
->softint_id
);
2416 * Software Interrupt Handler
2420 pcram_softintr(pcram_state_t
*rs
)
2426 if (pcram_debug
& PCRAM_DEBUG_TRACE
)
2427 cmn_err(CE_CONT
, "pcram_softintr: socket %d\n", rs
->sn
);
2430 if (!(rs
->flags
& PCRAM_ATTACHOK
)) {
2431 return (DDI_INTR_UNCLAIMED
);
2434 mutex_enter(&rs
->mutex
);
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
) {
2445 * End of write operation, release the
2446 * cv_wait() for the next thread
2448 cv_signal(&rs
->condvar
);
2453 mutex_exit(&rs
->mutex
);
2455 return (DDI_INTR_CLAIMED
);
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.
2483 card_byte_wr(pcram_state_t
*rs
, int xfer_size
, int offset
)
2486 uint32_t cardoffset
= offset
;
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
) {
2495 cmn_err(CE_WARN
, "pcram: socket%d "
2496 "Write-Protect is enabled",
2501 * write-protect is enabled
2505 csx_Put8(rs
->access_handle
,
2506 cardoffset
, *hostmempt
);
2512 * stop to write to the card when
2513 * there is a card removal event
2523 * Updating window size
2526 update_mapmempage(pcram_state_t
*rs
, int offset
)
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
))
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 */
2554 if (!(get_status
.CardState
& CS_EVENT_CARD_INSERTION
)) {
2556 cmn_err(CE_CONT
, "update_mapmempage: "
2557 "\tFound no memory card in socket %d\n", rs
->sn
);
2559 /* Let caller knows that there is no card */
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",
2577 /* To avoid zero divide problem */
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
))
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
))
2607 (void) csx_Error2Text(&cft
);
2608 cmn_err(CE_CONT
, "update_mapmempage: "
2609 "ReleaseWindow failed %s (0x%x)\n",
2613 /* Let caller knows that there is some thing wrong */
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
)
2641 uchar_t test_pattern
;
2642 uchar_t restore_data
;
2643 uchar_t cm_addr_zero
, cm_next_addr
;
2647 ret
= update_mapmempage(rs
, offset
);
2649 /* something failed so abort */
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
;
2660 test_pattern
= PATTERN_2
;
2663 /* Select block size sample */
2664 if (rs
->win_size
>= HALF_MEG
) {
2665 blocksize
= HALF_MEG
;
2667 blocksize
= rs
->win_size
;
2670 nbs
= blocksize
- (blocksize
%SIZE_1KB
);
2671 if (nbs
< SIZE_1KB
) {
2672 blocksize
= SIZE_1KB
;
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",
2685 while (offset
< MAX_CARD_SIZE
) {
2686 offset
+= blocksize
;
2687 ret
= update_mapmempage(rs
, offset
);
2689 /* something failed so abort */
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
);
2713 ret
= update_mapmempage(rs
, 0);
2715 /* something failed so abort */
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
);
2727 ret
= update_mapmempage(rs
, offset
);
2729 /* something failed so abort */
2735 /* Restore previous write data */
2736 csx_Put8(rs
->access_handle
, next_offset
, restore_data
);
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",
2755 * SPARC UFS label checksum
2758 cksum(struct dk_label
*label
)
2761 unsigned char value
;
2765 data
= (uchar_t
*)label
;
2767 for (i
= 0, value
= 0; i
< sizeof (struct dk_label
); i
++) {
2777 * Check media insertion/ejection status
2780 pcram_check_media(pcram_state_t
*rs
, enum dkio_state state
)
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
))
2795 mutex_exit(&rs
->mutex
);
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
);
2806 /* Register rs->media_state */
2807 if ((get_status
.CardState
& CS_EVENT_CARD_INSERTION
)) {
2808 rs
->media_state
= DKIO_INSERTED
;
2810 if (state
== DKIO_NONE
) {
2811 rs
->media_state
= DKIO_NONE
;
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
);
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
);
2853 * wait for Card Detect Change Interrupt handler
2854 * see either pcram_card_insertion/pcram_card_removal
2857 while (rs
->media_state
== state
) {
2858 rs
->checkmedia_flag
++;
2859 if (cv_wait_sig(&rs
->condvar_mediastate
,
2861 mutex_exit(&rs
->mutex
);
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
);
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
);
2893 * Constructing disk label
2896 pcram_build_label_vtoc(pcram_state_t
*rs
, struct vtoc
*vtoc
)
2901 struct dk_map2
*lpart
;
2902 #if defined(__sparc)
2905 struct dk_map32
*lmap
;
2907 struct dk_map
*lmap
;
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
);
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
;
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
;
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
;
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
,
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
;
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
;
2991 rs
->un_label
.dkl_cksum
= 0;
2992 sp
= (short *)&rs
->un_label
;
2994 i
= sizeof (struct dk_label
)/sizeof (short);
2999 rs
->un_label
.dkl_cksum
= sum
;
3001 mutex_exit(&rs
->mutex
);
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",
3008 rs
->un_label
.dkl_ncyl
, rs
->un_label
.dkl_nhead
,
3009 rs
->un_label
.dkl_nsect
, rs
->un_label
.dkl_pcyl
);
3020 * Writing disk label to the memory card
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
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
;
3050 if (pcram_debug_events
) {
3051 pcram_debug_report_event(rs
, event
, priority
);
3056 if (priority
& CS_EVENT_PRI_HIGH
) {
3057 mutex_enter(&rs
->event_hilock
);
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
);
3073 * Find out which event we got and do the appropriate thing
3076 case CS_EVENT_REGISTRATION_COMPLETE
:
3078 case CS_EVENT_CARD_INSERTION
:
3079 if (priority
& CS_EVENT_PRI_LOW
) {
3080 retcode
= pcram_card_insertion(rs
);
3083 case CS_EVENT_BATTERY_LOW
:
3085 case CS_EVENT_BATTERY_DEAD
:
3087 case CS_EVENT_WRITE_PROTECT
:
3088 if (priority
& CS_EVENT_PRI_LOW
) {
3089 mutex_enter(&rs
->mutex
);
3092 rs
->card_event
|= PCRAM_WRITE_PROTECT
;
3094 rs
->card_event
&= ~PCRAM_WRITE_PROTECT
;
3097 if (priority
& CS_EVENT_PRI_LOW
) {
3098 mutex_exit(&rs
->mutex
);
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
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
;
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
);
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 */
3136 if (priority
& CS_EVENT_PRI_HIGH
) {
3137 mutex_exit(&rs
->event_hilock
);
3147 * pcram_card_insertion - handles card insertion events
3150 pcram_card_insertion(pcram_state_t
*rs
)
3153 int rval
= CS_SUCCESS
;
3157 convert_speed_t convert_speed
;
3158 map_mem_page_t map_mem_page
;
3159 get_status_t get_status
;
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
);
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
);
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
))
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
);
3218 /* Make sure that there is a card in the socket */
3219 if (!(get_status
.CardState
& CS_EVENT_CARD_INSERTION
)) {
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
);
3226 mutex_enter(&rs
->event_hilock
);
3227 cv_broadcast(&rs
->firstopenwait_cv
);
3228 mutex_exit(&rs
->event_hilock
);
3229 return (CS_NO_CARD
);
3234 * Set up the client event mask to give us WP and battery
3235 * events as well as what other events we have already
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
))
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
);
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
))
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
);
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
))
3292 (void) csx_Error2Text(&cft
);
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
|
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
) {
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
);
3334 mutex_enter(&rs
->mutex
);
3335 rs
->flags
|= PCRAM_HAS_WINDOW
;
3336 mutex_exit(&rs
->mutex
);
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
,
3348 win_req
.win_params
.AccessSpeed
);
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
) {
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
))
3378 (void) csx_Error2Text(&cft
);
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
);
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
);
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",
3403 win_req
.Base
.base
, (void *)rs
->access_handle
,
3404 win_req
.Size
, (int)rs
->win_size
);
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) {
3415 rval
= CS_GENERAL_FAILURE
;
3418 "pcram_card_insertion: socket %d \n"
3419 "\tERROR - pcram_build_region_lists - "
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
;
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
);
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 */
3458 while (mrp
= pcram_get_firstnext_region(mrp
,
3460 CISTPL_DEVICE_DTYPE_SRAM
,
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 */
3469 if (pcram_debug
& PCRAM_DEBUG_CIS
) {
3471 "pcram_card_insertion: socket %d - "
3472 "BUILD_DOS_BPBFAT_LIST\n\tdevice speed [%d]\n",
3473 rs
->sn
, (int)mrp
->nS_speed
);
3477 /* for VERBOSE mode */
3478 cmn_err(CE_CONT
, "?pcram: "
3479 "(MSDOS) socket %d card size %d\n",
3480 rs
->sn
, rs
->card_size
);
3485 /* Get BUILD_SOLARIS_LIST list */
3486 mrp
= rs
->cm_regions
;
3488 while (mrp
= pcram_get_firstnext_region(mrp
,
3490 CISTPL_DEVICE_DTYPE_SRAM
,
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 */
3499 if (pcram_debug
& PCRAM_DEBUG_CIS
) {
3501 "pcram_card_insertion: socket %d - BUILD_SOLARIS_LIST\n"
3502 "\tdevice speed [%d]\n", rs
->sn
, (int)mrp
->nS_speed
);
3506 /* for VERBOSE mode */
3507 cmn_err(CE_CONT
, "?pcram: "
3508 "(SOLARIS) socket %d card size %d\n",
3509 rs
->sn
, rs
->card_size
);
3514 /* Get BUILD_DEFAULT_LIST list */
3515 mrp
= rs
->cm_regions
;
3517 while (mrp
= pcram_get_firstnext_region(mrp
,
3519 CISTPL_DEVICE_DTYPE_SRAM
,
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
3531 if (pcram_debug
& PCRAM_DEBUG_CIS
) {
3533 "pcram_card_insertion: socket %d - BUILD_DEFAULT_LIST\n"
3534 "\tdevice speed [%d]\n", rs
->sn
, (int)mrp
->nS_speed
);
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
);
3547 /* Get BUILD_CM_LIST list */
3548 mrp
= rs
->cm_regions
;
3550 while (mrp
= pcram_get_firstnext_region(mrp
,
3552 CISTPL_DEVICE_DTYPE_SRAM
,
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
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
);
3571 update_hdrv_chars(rs
, mrp
);
3573 /* for VERBOSE mode */
3575 "?pcram: (CIS) socket %d card size %d\n",
3576 rs
->sn
, rs
->card_size
);
3582 * Create the device nodes.
3583 * This is an example that assumes
3584 * that we want to create four devices
3585 * for this instance.
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
);
3605 * Create only "c" partition for now since
3606 * the driver support only one parttion
3609 for (n
= 0; n
< (make_device_node
.NumDevNodes
);
3612 dnd
= &make_device_node
.devnode_desc
[n
];
3616 PCRAM_SETMINOR(rs
->sn
, (n
+4)/2);
3619 dnd
->spec_type
= S_IFCHR
;
3620 (void) sprintf(dname
, "%c,raw",
3623 dnd
->spec_type
= S_IFBLK
;
3624 (void) sprintf(dname
, "%c",
3628 dnd
->node_type
= DDI_NT_BLOCK_CHAN
;
3630 dname
= &dname
[strlen(dname
)+1];
3633 if ((ret
= csx_MakeDeviceNode(rs
->client_handle
,
3634 &make_device_node
)) != CS_SUCCESS
) {
3639 (void) csx_Error2Text(&cft
);
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 */
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
,
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
);
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
);
3704 * pcram_card_removal - handles card removal events; can only
3705 * be called from the low priority card
3709 pcram_card_removal(pcram_state_t
*rs
)
3712 get_status_t get_status
;
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;
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
);
3737 if (pcram_debug
& PCRAM_DEBUG_VOLD
) {
3739 "pcram_card_removal: socket %d \n"
3740 "\tdoing cv_broadcast - "
3741 "rs->media_state of DKIO_EJECTED\n",
3747 rs
->card_eject_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
) {
3770 (void) csx_Error2Text(&cft
);
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
))
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
);
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
);
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
) {
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
);
3826 mutex_enter(&rs
->mutex
);
3827 rs
->flags
&= ~PCRAM_HAS_WINDOW
;
3828 mutex_exit(&rs
->mutex
);
3830 if ((ret
= csx_ReleaseWindow(rs
->window_handle
))
3835 (void) csx_Error2Text(&cft
);
3838 "pcram_card_removal: socket %d "
3839 "ReleaseWindow failed %s (0x%x)\n",
3840 rs
->sn
, cft
.text
, ret
);
3847 * Set up the client event mask to clear WP and battery
3848 * events as well as what other events we have already
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
))
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
);
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
))
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
);
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
);
3901 * pcram_display_card_status - wrapper for GetStatus CS function
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",
3929 * pcram_build_region_lists - builds a card memory region list for
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
3956 * XXX - need to think about the non-CIS non-DOS case
3959 pcram_build_region_lists(pcram_state_t
*rs
)
3966 * Check for a CIS on this card - if there is one, our job
3969 if ((ret
= csx_ValidateCIS(rs
->client_handle
, &cisinfo
))
3974 (void) csx_Error2Text(&cft
);
3976 if (ret
!= CS_NO_CIS
) {
3977 cmn_err(CE_CONT
, "pcram_build_region_lists: "
3979 "ValidateCIS failed %s (0x%x)\n",
3980 rs
->sn
, cft
.text
, ret
);
3984 * No CIS on card, try to find an MS-DOS BPB-FAT
3985 * filesystem and build our list from that.
3989 if ((rs
->num_cm_regions
=
3990 pcram_build_region_list(rs
,
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) {
4013 "pcram_build_region_lists: "
4020 } /* (BUILD_DEFAULT_LIST) */
4022 } /* (BUILD_SOLARIS_LIST) */
4024 } /* (BUILD_DOS_BPBFAT_LIST) */
4028 * There is a CIS - build the lists.
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: "
4039 "\terror building AM region list\n",
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
4060 "pcram_build_region_lists: "
4062 "\terror building CM "
4063 "region list\n", rs
->sn
);
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
,
4079 BUILD_DEFAULT_LIST
));
4083 if (pcram_debug
& PCRAM_DEBUG_CIS
) {
4085 "pcram_build_region_lists: socket %d \n"
4086 "\t(BUILD_AM_LIST | BUILD_CM_LIST)\n", rs
->sn
);
4099 * pcram_build_region_list - builds a region list for the passed
4102 * calling: rs - pointer to caller's state structure
4103 * rlist - pointer to a mem_region_t * region
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
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.
4121 pcram_build_region_list(pcram_state_t
*rs
,
4122 mem_region_t
**rlist
, uint32_t flags
)
4125 convert_speed_t convert_speed
;
4126 convert_size_t convert_size
;
4127 cisdata_t device_tuple
, JEDEC_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.
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
);
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
);
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
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
;
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
);
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
4202 rs
->default_size_flag
++;
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
)) {
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
;
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
);
4248 * Create a list from a Solaris VTOC filesystem.
4250 if (flags
& BUILD_SOLARIS_LIST
) {
4251 if (!pcram_get_solaris_info(rs
, mr
)) {
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
;
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
);
4280 * We've got a CIS so sort out the correct tuples to look for.
4282 switch (flags
& (BUILD_AM_LIST
| BUILD_CM_LIST
)) {
4284 device_tuple
= CISTPL_DEVICE_A
;
4285 JEDEC_tuple
= CISTPL_JEDEC_A
;
4288 device_tuple
= CISTPL_DEVICE
;
4289 JEDEC_tuple
= CISTPL_JEDEC_C
;
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
))
4304 if (ret
!= CS_NO_MORE_ITEMS
) {
4305 /* this is a real error */
4309 /* XXX - is 0 the right thing to return here? */
4316 * Got the device tuple, now parse it.
4321 cistpl_device_t cistpl_device
;
4322 mem_region_t
*mrr
= NULL
;
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
) {
4338 * We should see at least one region.
4339 * This is definately an error.
4341 if (!cistpl_device
.num_devices
) {
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
);
4356 * setup for next CISTPL_DEVICE tuple
4361 * If this is the first entry in the list,
4362 * then assign it to the head of
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 "
4403 switch (cistpl_device_node
->type
) {
4405 case CISTPL_DEVICE_DTYPE_SRAM
:
4406 /* Support this main device */
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
;
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
;
4427 case CISTPL_DEVICE_DTYPE_OTPROM
:
4428 cmn_err(CE_CONT
, unsupported_fmt_string
,
4433 case CISTPL_DEVICE_DTYPE_EPROM
:
4434 cmn_err(CE_CONT
, unsupported_fmt_string
,
4435 "UV EPROM", rs
->sn
);
4439 case CISTPL_DEVICE_DTYPE_EEPROM
:
4440 cmn_err(CE_CONT
, unsupported_fmt_string
,
4445 case CISTPL_DEVICE_DTYPE_FLASH
:
4446 cmn_err(CE_CONT
, unsupported_fmt_string
,
4452 cmn_err(CE_CONT
, unsupported_fmt_string
,
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
4471 } /* for (cistpl_device_node->num_devices) */
4473 } while ((ret
= csx_GetNextTuple(rs
->client_handle
, &tuple
))
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 */
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
))
4495 if (ret
!= CS_NO_MORE_ITEMS
) {
4496 /* this is a real error */
4500 return (region_num
);
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 */
4513 cistpl_jedec_t cistpl_jedec
;
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
) {
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
) {
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.
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
);
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.
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 */
4585 * Return the number of region entries in this list.
4587 return (region_num
);
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
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
4606 pcram_get_bpbfat_info(pcram_state_t
*rs
, mem_region_t
*mr
)
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
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.
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
);
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
;
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
);
4708 /* Found NO DOS BPBFAT */
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
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
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
);
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
);
4769 mr
->size_in_bytes
= rs
->card_size
;
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
);
4783 /* Found no Solaris partition */
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
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;
4817 pcram_destroy_region_list(mem_region_t
**rlist
, int *num
)
4819 mem_region_t
*mr
, *mrr
;
4822 if ((mr
= *rlist
) == 0) {
4829 kmem_free(mr
, sizeof (mem_region_t
));
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
)
4856 if (((mrp
->rflags
& flags
) == flags
) &&
4857 (mrp
->type
== type
)) {
4862 } while (mrp
= mrp
->next
);
4865 * This is a get next function.
4868 while (mrp
= mrp
->next
) {
4869 if (((mrp
->rflags
& flags
) == flags
) &&
4870 (mrp
->type
== type
)) {
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
);
4906 pcram_debug_report_event(pcram_state_t
*pcram
, event_t event
, int priority
)
4908 char *event_priority
;
4912 event_priority
= (priority
& CS_EVENT_PRI_HIGH
) ? "high" : "low";
4915 case CS_EVENT_REGISTRATION_COMPLETE
:
4916 event_text
= "Registration Complete";
4918 case CS_EVENT_PM_RESUME
:
4919 event_text
= "Power Management Resume";
4921 case CS_EVENT_CARD_INSERTION
:
4922 event_text
= "Card Insertion";
4924 case CS_EVENT_CARD_READY
:
4925 event_text
= "Card Ready";
4927 case CS_EVENT_BATTERY_LOW
:
4928 event_text
= "Battery Low";
4930 case CS_EVENT_BATTERY_DEAD
:
4931 event_text
= "Battery Dead";
4933 case CS_EVENT_CARD_LOCK
:
4934 event_text
= "Card Lock";
4936 case CS_EVENT_PM_SUSPEND
:
4937 event_text
= "Power Management Suspend";
4939 case CS_EVENT_CARD_RESET
:
4940 event_text
= "Card Reset";
4942 case CS_EVENT_CARD_UNLOCK
:
4943 event_text
= "Card Unlock";
4945 case CS_EVENT_EJECTION_COMPLETE
:
4946 event_text
= "Ejection Complete";
4948 case CS_EVENT_EJECTION_REQUEST
:
4949 event_text
= "Ejection Request";
4951 case CS_EVENT_ERASE_COMPLETE
:
4952 event_text
= "Erase Complete";
4954 case CS_EVENT_EXCLUSIVE_COMPLETE
:
4955 event_text
= "Exclusive Complete";
4957 case CS_EVENT_EXCLUSIVE_REQUEST
:
4958 event_text
= "Exclusive Request";
4960 case CS_EVENT_INSERTION_COMPLETE
:
4961 event_text
= "Insertion Complete";
4963 case CS_EVENT_INSERTION_REQUEST
:
4964 event_text
= "Insertion Request";
4966 case CS_EVENT_RESET_COMPLETE
:
4967 event_text
= "Reset Complete";
4969 case CS_EVENT_RESET_PHYSICAL
:
4970 event_text
= "Reset Physical";
4972 case CS_EVENT_RESET_REQUEST
:
4973 event_text
= "Reset Request";
4975 case CS_EVENT_MTD_REQUEST
:
4976 event_text
= "MTD Request";
4978 case CS_EVENT_CLIENT_INFO
:
4979 event_text
= "Client Info";
4981 case CS_EVENT_TIMER_EXPIRED
:
4982 event_text
= "Timer Expired";
4984 case CS_EVENT_WRITE_PROTECT
:
4985 event_text
= "Write Protect";
4987 case CS_EVENT_SS_UPDATED
:
4988 event_text
= "SS Updated";
4990 case CS_EVENT_STATUS_CHANGE
:
4991 event_text
= "Status Change";
4993 case CS_EVENT_CARD_REMOVAL
:
4994 event_text
= "Card Removal";
4996 case CS_EVENT_CARD_REMOVAL_LOWP
:
4997 event_text
= "Card Removal Low Power";
5001 (void) sprintf(buf
, "Unknown Event (0x%x)", event
);
5006 "pcram%d [socket %d]: %s (%s priority)\n",
5007 ddi_get_instance(pcram
->dip
), pcram
->sn
,
5008 event_text
, event_priority
);